[MSXML3_WINETEST]
[reactos.git] / rostests / winetests / msxml3 / saxreader.c
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 WIN32_NO_STATUS
24 #define _INC_WINDOWS
25 #define COM_NO_WINDOWS_H
26
27 #define COBJMACROS
28 #define CONST_VTABLE
29
30 #include <stdio.h>
31 #include <assert.h>
32
33 #include <wine/test.h>
34 //#include "windows.h"
35 #include <winnls.h>
36 #include <ole2.h>
37 #include <msxml2.h>
38 #include <msxml2did.h>
39 //#include "ocidl.h"
40 #include <dispex.h>
41
42 static const WCHAR emptyW[] = {0};
43
44 #define EXPECT_HR(hr,hr_exp) \
45 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
46
47 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
48 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
49 {
50 ULONG rc = IUnknown_AddRef(obj);
51 IUnknown_Release(obj);
52 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
53 }
54
55 static LONG get_refcount(void *iface)
56 {
57 IUnknown *unk = iface;
58 LONG ref;
59
60 ref = IUnknown_AddRef(unk);
61 IUnknown_Release(unk);
62 return ref-1;
63 }
64
65 struct msxmlsupported_data_t
66 {
67 const GUID *clsid;
68 const char *name;
69 BOOL supported;
70 };
71
72 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
73 {
74 while (table->clsid)
75 {
76 if (table->clsid == clsid) return table->supported;
77 table++;
78 }
79 return FALSE;
80 }
81
82 static BSTR alloc_str_from_narrow(const char *str)
83 {
84 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
85 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
86 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
87 return ret;
88 }
89
90 static BSTR alloced_bstrs[512];
91 static int alloced_bstrs_count;
92
93 static BSTR _bstr_(const char *str)
94 {
95 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
96 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
97 return alloced_bstrs[alloced_bstrs_count++];
98 }
99
100 static void free_bstrs(void)
101 {
102 int i;
103 for (i = 0; i < alloced_bstrs_count; i++)
104 SysFreeString(alloced_bstrs[i]);
105 alloced_bstrs_count = 0;
106 }
107
108 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount)
109 {
110 int len, lenexp, cmp;
111 WCHAR buf[1024];
112
113 len = SysStringLen(str);
114
115 if (!expected) {
116 if (str && todo)
117 {
118 (*failcount)++;
119 todo_wine
120 ok_(file, line) (!str, "got %p, expected null str\n", str);
121 }
122 else
123 ok_(file, line) (!str, "got %p, expected null str\n", str);
124
125 if (len && todo)
126 {
127 (*failcount)++;
128 todo_wine
129 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
130 }
131 else
132 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
133 return;
134 }
135
136 lenexp = strlen(expected);
137 if (lenexp != len && todo)
138 {
139 (*failcount)++;
140 todo_wine
141 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
142 }
143 else
144 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
145
146 /* exit earlier on length mismatch */
147 if (lenexp != len) return;
148
149 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
150
151 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
152 if (cmp && todo)
153 {
154 (*failcount)++;
155 todo_wine
156 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
157 wine_dbgstr_wn(str, len), expected);
158 }
159 else
160 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
161 wine_dbgstr_wn(str, len), expected);
162 }
163
164 typedef enum _CH {
165 CH_ENDTEST,
166 CH_PUTDOCUMENTLOCATOR,
167 CH_STARTDOCUMENT,
168 CH_ENDDOCUMENT,
169 CH_STARTPREFIXMAPPING,
170 CH_ENDPREFIXMAPPING,
171 CH_STARTELEMENT,
172 CH_ENDELEMENT,
173 CH_CHARACTERS,
174 CH_IGNORABLEWHITESPACE,
175 CH_PROCESSINGINSTRUCTION,
176 CH_SKIPPEDENTITY,
177 LH_STARTCDATA,
178 LH_ENDCDATA,
179 EH_ERROR,
180 EH_FATALERROR,
181 EH_IGNORABLEWARNING,
182 EVENT_LAST
183 } CH;
184
185 static const char *event_names[EVENT_LAST] = {
186 "endtest",
187 "putDocumentLocator",
188 "startDocument",
189 "endDocument",
190 "startPrefixMapping",
191 "endPrefixMapping",
192 "startElement",
193 "endElement",
194 "characters",
195 "ignorableWhitespace",
196 "processingInstruction",
197 "skippedEntity",
198 "startCDATA",
199 "endCDATA",
200 "error",
201 "fatalError",
202 "ignorableWarning"
203 };
204
205 struct attribute_entry {
206 const char *uri;
207 const char *local;
208 const char *qname;
209 const char *value;
210
211 /* used for actual call data only, null for expected call data */
212 BSTR uriW;
213 BSTR localW;
214 BSTR qnameW;
215 BSTR valueW;
216 };
217
218 struct call_entry {
219 CH id;
220 int line;
221 int column;
222 HRESULT ret;
223 const char *arg1;
224 const char *arg2;
225 const char *arg3;
226
227 /* allocated once at startElement callback */
228 struct attribute_entry *attributes;
229 int attr_count;
230
231 /* used for actual call data only, null for expected call data */
232 BSTR arg1W;
233 BSTR arg2W;
234 BSTR arg3W;
235 };
236
237 struct call_sequence
238 {
239 int count;
240 int size;
241 struct call_entry *sequence;
242 };
243
244 #define CONTENT_HANDLER_INDEX 0
245 #define NUM_CALL_SEQUENCES 1
246 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
247
248 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
249 {
250 memset(call, 0, sizeof(*call));
251 ISAXLocator_getLineNumber(locator, &call->line);
252 ISAXLocator_getColumnNumber(locator, &call->column);
253 }
254
255 static void add_call(struct call_sequence **seq, int sequence_index,
256 const struct call_entry *call)
257 {
258 struct call_sequence *call_seq = seq[sequence_index];
259
260 if (!call_seq->sequence)
261 {
262 call_seq->size = 10;
263 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
264 call_seq->size * sizeof (struct call_entry));
265 }
266
267 if (call_seq->count == call_seq->size)
268 {
269 call_seq->size *= 2;
270 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
271 call_seq->sequence,
272 call_seq->size * sizeof (struct call_entry));
273 }
274
275 assert(call_seq->sequence);
276
277 call_seq->sequence[call_seq->count].id = call->id;
278 call_seq->sequence[call_seq->count].line = call->line;
279 call_seq->sequence[call_seq->count].column = call->column;
280 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
281 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
282 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
283 call_seq->sequence[call_seq->count].ret = call->ret;
284 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
285 call_seq->sequence[call_seq->count].attributes = call->attributes;
286
287 call_seq->count++;
288 }
289
290 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
291 {
292 int i;
293
294 struct call_sequence *call_seq = seg[sequence_index];
295
296 for (i = 0; i < call_seq->count; i++)
297 {
298 int j;
299
300 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
301 {
302 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
303 SysFreeString(call_seq->sequence[i].attributes[j].localW);
304 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
305 }
306
307 SysFreeString(call_seq->sequence[i].arg1W);
308 SysFreeString(call_seq->sequence[i].arg2W);
309 SysFreeString(call_seq->sequence[i].arg3W);
310 }
311
312 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
313 call_seq->sequence = NULL;
314 call_seq->count = call_seq->size = 0;
315 }
316
317 static inline void flush_sequences(struct call_sequence **seq, int n)
318 {
319 int i;
320 for (i = 0; i < n; i++)
321 flush_sequence(seq, i);
322 }
323
324 static const char *get_event_name(CH event)
325 {
326 return event_names[event];
327 }
328
329 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
330 BOOL todo, const char *file, int line, int *failcount)
331 {
332 int i, lenexp = 0;
333
334 /* attribute count is not stored for expected data */
335 if (expected->attributes)
336 {
337 struct attribute_entry *ptr = expected->attributes;
338 while (ptr->uri) { lenexp++; ptr++; };
339 }
340
341 /* check count first and exit earlier */
342 if (actual->attr_count != lenexp && todo)
343 {
344 (*failcount)++;
345 todo_wine
346 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
347 context, get_event_name(actual->id), lenexp, actual->attr_count);
348 }
349 else
350 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
351 context, get_event_name(actual->id), lenexp, actual->attr_count);
352
353 if (actual->attr_count != lenexp) return;
354
355 /* now compare all attributes strings */
356 for (i = 0; i < actual->attr_count; i++)
357 {
358 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
359 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
360 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
361 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
362 }
363 }
364
365 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
366 const struct call_entry *expected, const char *context, BOOL todo,
367 const char *file, int line)
368 {
369 struct call_sequence *call_seq = seq[sequence_index];
370 static const struct call_entry end_of_sequence = { CH_ENDTEST };
371 const struct call_entry *actual, *sequence;
372 int failcount = 0;
373
374 add_call(seq, sequence_index, &end_of_sequence);
375
376 sequence = call_seq->sequence;
377 actual = sequence;
378
379 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
380 {
381 if (expected->id == actual->id)
382 {
383 if (expected->line != -1)
384 {
385 /* always test position data */
386 if (expected->line != actual->line && todo)
387 {
388 todo_wine
389 {
390 failcount++;
391 ok_(file, line) (FALSE,
392 "%s: in event %s expecting line %d got %d\n",
393 context, get_event_name(actual->id), expected->line, actual->line);
394 }
395 }
396 else
397 {
398 ok_(file, line) (expected->line == actual->line,
399 "%s: in event %s expecting line %d got %d\n",
400 context, get_event_name(actual->id), expected->line, actual->line);
401 }
402 }
403
404
405 if (expected->column != -1)
406 {
407 if (expected->column != actual->column && todo)
408 {
409 todo_wine
410 {
411 failcount++;
412 ok_(file, line) (FALSE,
413 "%s: in event %s expecting column %d got %d\n",
414 context, get_event_name(actual->id), expected->column, actual->column);
415 }
416 }
417 else
418 {
419 ok_(file, line) (expected->column == actual->column,
420 "%s: in event %s expecting column %d got %d\n",
421 context, get_event_name(actual->id), expected->column, actual->column);
422 }
423 }
424
425 switch (actual->id)
426 {
427 case CH_PUTDOCUMENTLOCATOR:
428 case CH_STARTDOCUMENT:
429 case CH_ENDDOCUMENT:
430 case LH_STARTCDATA:
431 case LH_ENDCDATA:
432 break;
433 case CH_STARTPREFIXMAPPING:
434 /* prefix, uri */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
437 break;
438 case CH_ENDPREFIXMAPPING:
439 /* prefix */
440 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
441 break;
442 case CH_STARTELEMENT:
443 /* compare attributes */
444 compare_attributes(actual, expected, context, todo, file, line, &failcount);
445 /* fallthrough */
446 case CH_ENDELEMENT:
447 /* uri, localname, qname */
448 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
449 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
450 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
451 break;
452 case CH_CHARACTERS:
453 case CH_IGNORABLEWHITESPACE:
454 /* char data */
455 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
456 break;
457 case CH_PROCESSINGINSTRUCTION:
458 /* target, data */
459 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
460 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
461 break;
462 case CH_SKIPPEDENTITY:
463 /* name */
464 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
465 break;
466 case EH_FATALERROR:
467 /* test return value only */
468 if (expected->ret != actual->ret && todo)
469 {
470 failcount++;
471 ok_(file, line) (FALSE,
472 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
473 context, get_event_name(actual->id), expected->ret, actual->ret);
474 }
475 else
476 ok_(file, line) (expected->ret == actual->ret,
477 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
478 context, get_event_name(actual->id), expected->ret, actual->ret);
479 break;
480 case EH_ERROR:
481 case EH_IGNORABLEWARNING:
482 default:
483 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
484 }
485 expected++;
486 actual++;
487 }
488 else if (todo)
489 {
490 failcount++;
491 todo_wine
492 {
493 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
494 context, get_event_name(expected->id), get_event_name(actual->id));
495 }
496
497 flush_sequence(seq, sequence_index);
498 return;
499 }
500 else
501 {
502 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
503 context, get_event_name(expected->id), get_event_name(actual->id));
504 expected++;
505 actual++;
506 }
507 }
508
509 if (todo)
510 {
511 todo_wine
512 {
513 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
514 {
515 failcount++;
516 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
517 context, get_event_name(expected->id), get_event_name(actual->id));
518 }
519 }
520 }
521 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
522 {
523 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
524 context, get_event_name(expected->id), get_event_name(actual->id));
525 }
526
527 if (todo && !failcount) /* succeeded yet marked todo */
528 {
529 todo_wine
530 {
531 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
532 }
533 }
534
535 flush_sequence(seq, sequence_index);
536 }
537
538 #define ok_sequence(seq, index, exp, contx, todo) \
539 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
540
541 static void init_call_sequences(struct call_sequence **seq, int n)
542 {
543 int i;
544
545 for (i = 0; i < n; i++)
546 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
547 }
548
549 static const WCHAR szSimpleXML[] = {
550 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
551 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
552 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
553 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
554 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
555 };
556
557 static const WCHAR carriage_ret_test[] = {
558 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
559 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
560 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
561 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
562 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
563 };
564
565 static const WCHAR szUtf16XML[] = {
566 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
567 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
568 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
569 };
570
571 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
572
573 static const CHAR szUtf8XML[] =
574 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
575
576 static const char utf8xml2[] =
577 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
578
579 static const char testXML[] =
580 "<?xml version=\"1.0\" ?>\n"
581 "<BankAccount>\n"
582 " <Number>1234</Number>\n"
583 " <Name>Captain Ahab</Name>\n"
584 "</BankAccount>\n";
585
586 static const char test_attributes[] =
587 "<?xml version=\"1.0\" ?>\n"
588 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
589 "<node1 xmlns:p=\"test\" />"
590 "</document>\n";
591
592 static const char test_cdata_xml[] =
593 "<?xml version=\"1.0\" ?>"
594 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
595
596 static const char test2_cdata_xml[] =
597 "<?xml version=\"1.0\" ?>"
598 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
599
600 static const char test3_cdata_xml[] =
601 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
602
603 static struct call_entry content_handler_test1[] = {
604 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
605 { CH_STARTDOCUMENT, 0, 0, S_OK },
606 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
607 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
608 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
609 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
610 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
611 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
612 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
613 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
614 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
615 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
616 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
617 { CH_ENDDOCUMENT, 0, 0, S_OK},
618 { CH_ENDTEST }
619 };
620
621 /* applies to versions 4 and 6 */
622 static struct call_entry content_handler_test1_alternate[] = {
623 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
624 { CH_STARTDOCUMENT, 1, 22, S_OK },
625 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
626 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
627 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
628 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
629 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
630 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
631 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
632 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
633 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
634 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
635 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
636 { CH_ENDDOCUMENT, 6, 0, S_OK },
637 { CH_ENDTEST }
638 };
639
640 static struct call_entry content_handler_test2[] = {
641 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
642 { CH_STARTDOCUMENT, 0, 0, S_OK },
643 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
644 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
645 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
646 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
647 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
648 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
649 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
650 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
651 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
652 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
653 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
654 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
655 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
656 { CH_ENDDOCUMENT, 0, 0, S_OK },
657 { CH_ENDTEST }
658 };
659
660 static struct call_entry content_handler_test2_alternate[] = {
661 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
662 { CH_STARTDOCUMENT, 1, 21, S_OK },
663 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
664 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
665 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
666 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
667 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
668 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
669 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
670 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
671 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
672 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
673 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
674 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
675 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
676 { CH_ENDDOCUMENT, 6, 0, S_OK },
677 { CH_ENDTEST }
678 };
679
680 static struct call_entry content_handler_testerror[] = {
681 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
682 { EH_FATALERROR, 0, 0, E_FAIL },
683 { CH_ENDTEST }
684 };
685
686 static struct call_entry content_handler_testerror_alternate[] = {
687 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
688 { EH_FATALERROR, 1, 0, E_FAIL },
689 { CH_ENDTEST }
690 };
691
692 static struct call_entry content_handler_test_callback_rets[] = {
693 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
694 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
695 { EH_FATALERROR, 0, 0, S_FALSE },
696 { CH_ENDTEST }
697 };
698
699 static struct call_entry content_handler_test_callback_rets_alt[] = {
700 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
701 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
702 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
703 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
704 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
705 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
706 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
707 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
708 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
709 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
710 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
711 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
712 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
713 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
714 { CH_ENDTEST }
715 };
716
717 static struct attribute_entry ch_attributes1[] = {
718 { "", "", "xmlns:test", "prefix_test" },
719 { "", "", "xmlns", "prefix" },
720 { "prefix_test", "arg1", "test:arg1", "arg1" },
721 { "", "arg2", "arg2", "arg2" },
722 { "prefix_test", "ar3", "test:ar3", "arg3" },
723 { NULL }
724 };
725
726 static struct attribute_entry ch_attributes2[] = {
727 { "", "", "xmlns:p", "test" },
728 { NULL }
729 };
730
731 static struct call_entry content_handler_test_attributes[] = {
732 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
733 { CH_STARTDOCUMENT, 0, 0, S_OK },
734 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
735 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
736 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
737 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
738 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
739 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
740 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
741 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
742 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
743 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
744 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
745 { CH_ENDDOCUMENT, 0, 0 },
746 { CH_ENDTEST }
747 };
748
749 static struct attribute_entry ch_attributes_alt_4[] = {
750 { "prefix_test", "arg1", "test:arg1", "arg1" },
751 { "", "arg2", "arg2", "arg2" },
752 { "prefix_test", "ar3", "test:ar3", "arg3" },
753 { "", "", "xmlns:test", "prefix_test" },
754 { "", "", "xmlns", "prefix" },
755 { NULL }
756 };
757
758 static struct call_entry content_handler_test_attributes_alternate_4[] = {
759 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
760 { CH_STARTDOCUMENT, 1, 22, S_OK },
761 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
762 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
763 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
764 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
765 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
766 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
767 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
768 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
769 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
770 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
771 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
772 { CH_ENDDOCUMENT, 4, 0, S_OK },
773 { CH_ENDTEST }
774 };
775
776 /* 'namespace' feature switched off */
777 static struct attribute_entry ch_attributes_alt_no_ns[] = {
778 { "", "", "xmlns:test", "prefix_test" },
779 { "", "", "xmlns", "prefix" },
780 { "", "", "test:arg1", "arg1" },
781 { "", "", "arg2", "arg2" },
782 { "", "", "test:ar3", "arg3" },
783 { NULL }
784 };
785
786 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
787 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
788 { CH_STARTDOCUMENT, 1, 22, S_OK },
789 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
790 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
791 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
792 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
793 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
794 { CH_ENDDOCUMENT, 4, 0, S_OK },
795 { CH_ENDTEST }
796 };
797
798 static struct attribute_entry ch_attributes_alt_6[] = {
799 { "prefix_test", "arg1", "test:arg1", "arg1" },
800 { "", "arg2", "arg2", "arg2" },
801 { "prefix_test", "ar3", "test:ar3", "arg3" },
802 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
803 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
804 { NULL }
805 };
806
807 static struct attribute_entry ch_attributes2_6[] = {
808 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
809 { NULL }
810 };
811
812 static struct call_entry content_handler_test_attributes_alternate_6[] = {
813 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
814 { CH_STARTDOCUMENT, 1, 22, S_OK },
815 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
816 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
817 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
818 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
819 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
820 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
821 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
822 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
823 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
824 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
825 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
826 { CH_ENDDOCUMENT, 4, 0, S_OK },
827 { CH_ENDTEST }
828 };
829
830 /* 'namespaces' is on, 'namespace-prefixes' if off */
831 static struct attribute_entry ch_attributes_no_prefix[] = {
832 { "prefix_test", "arg1", "test:arg1", "arg1" },
833 { "", "arg2", "arg2", "arg2" },
834 { "prefix_test", "ar3", "test:ar3", "arg3" },
835 { NULL }
836 };
837
838 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
839 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
840 { CH_STARTDOCUMENT, 1, 22, S_OK },
841 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
842 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
843 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
844 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
845 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
846 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
847 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
848 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
849 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
850 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
851 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
852 { CH_ENDDOCUMENT, 4, 0, S_OK },
853 { CH_ENDTEST }
854 };
855
856 static struct call_entry content_handler_test_attributes_no_prefix[] = {
857 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
858 { CH_STARTDOCUMENT, 0, 0, S_OK },
859 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
860 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
861 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
862 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
863 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
864 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
865 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
866 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
867 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
868 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
869 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
870 { CH_ENDDOCUMENT, 0, 0 },
871 { CH_ENDTEST }
872 };
873
874 static struct attribute_entry xmlspace_attrs[] = {
875 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
876 { NULL }
877 };
878
879 static struct call_entry xmlspaceattr_test[] = {
880 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
881 { CH_STARTDOCUMENT, 0, 0, S_OK },
882 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
883 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
884 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
885 { CH_ENDDOCUMENT, 0, 0, S_OK },
886 { CH_ENDTEST }
887 };
888
889 static struct call_entry xmlspaceattr_test_alternate[] = {
890 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
891 { CH_STARTDOCUMENT, 1, 39, S_OK },
892 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
893 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
894 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
895 { CH_ENDDOCUMENT, 1, 83, S_OK },
896 { CH_ENDTEST }
897 };
898
899 /* attribute value normalization test */
900 static const char attribute_normalize[] =
901 "<?xml version=\"1.0\" ?>\n"
902 "<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
903
904 static struct attribute_entry attribute_norm_attrs[] = {
905 { "", "attr1", "attr1", " attr_value A & & " },
906 { NULL }
907 };
908
909 static struct call_entry attribute_norm[] = {
910 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
911 { CH_STARTDOCUMENT, 0, 0, S_OK },
912 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
913 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
914 { CH_ENDDOCUMENT, 0, 0, S_OK },
915 { CH_ENDTEST }
916 };
917
918 static struct call_entry attribute_norm_alt[] = {
919 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
920 { CH_STARTDOCUMENT, 1, 22, S_OK },
921 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
922 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
923 { CH_ENDDOCUMENT, 9, 0, S_OK },
924 { CH_ENDTEST }
925 };
926
927 static struct call_entry cdata_test[] = {
928 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
929 { CH_STARTDOCUMENT, 0, 0, S_OK },
930 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
931 { LH_STARTCDATA, 1, 35, S_OK },
932 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
933 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
934 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
935 { LH_ENDCDATA, 1, 49, S_OK },
936 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
937 { CH_ENDDOCUMENT, 0, 0, S_OK },
938 { CH_ENDTEST }
939 };
940
941 static struct call_entry cdata_test2[] = {
942 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
943 { CH_STARTDOCUMENT, 0, 0, S_OK },
944 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
945 { LH_STARTCDATA, 1, 35, S_OK },
946 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
947 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
948 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
949 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
950 { LH_ENDCDATA, 1, 52, S_OK },
951 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
952 { CH_ENDDOCUMENT, 0, 0, S_OK },
953 { CH_ENDTEST }
954 };
955
956 static struct call_entry cdata_test3[] = {
957 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
958 { CH_STARTDOCUMENT, 0, 0, S_OK },
959 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
960 { LH_STARTCDATA, 1, 35, S_OK },
961 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
962 { LH_ENDCDATA, 1, 35, S_OK },
963 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
964 { CH_ENDDOCUMENT, 0, 0, S_OK },
965 { CH_ENDTEST }
966 };
967
968 /* this is what MSXML6 does */
969 static struct call_entry cdata_test_alt[] = {
970 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
971 { CH_STARTDOCUMENT, 1, 22, S_OK },
972 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
973 { LH_STARTCDATA, 1, 34, S_OK },
974 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
975 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
976 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
977 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
978 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
979 { LH_ENDCDATA, 6, 3, S_OK },
980 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
981 { CH_ENDDOCUMENT, 6, 7, S_OK },
982 { CH_ENDTEST }
983 };
984
985 static struct call_entry cdata_test2_alt[] = {
986 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
987 { CH_STARTDOCUMENT, 1, 22, S_OK },
988 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
989 { LH_STARTCDATA, 1, 34, S_OK },
990 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
991 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
992 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
993 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
994 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
995 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
996 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
997 { LH_ENDCDATA, 8, 3, S_OK },
998 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
999 { CH_ENDDOCUMENT, 8, 7, S_OK },
1000 { CH_ENDTEST }
1001 };
1002
1003 static struct call_entry cdata_test3_alt[] = {
1004 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
1005 { CH_STARTDOCUMENT, 1, 22, S_OK },
1006 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
1007 { LH_STARTCDATA, 1, 34, S_OK },
1008 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
1009 { LH_ENDCDATA, 1, 51, S_OK },
1010 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
1011 { CH_ENDDOCUMENT, 1, 55, S_OK },
1012 { CH_ENDTEST }
1013 };
1014
1015 static struct attribute_entry read_test_attrs[] = {
1016 { "", "attr", "attr", "val" },
1017 { NULL }
1018 };
1019
1020 static struct call_entry read_test_seq[] = {
1021 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
1022 { CH_STARTDOCUMENT, -1, -1, S_OK },
1023 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
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_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1028 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1029 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1030 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1031 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1032 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1033 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1034 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1035 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1036 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1037 { CH_ENDDOCUMENT, -1, -1, S_OK},
1038 { CH_ENDTEST }
1039 };
1040
1041 static const char xmlspace_attr[] =
1042 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1043 "<a xml:space=\"preserve\"> Some text data </a>";
1044
1045 static struct call_entry *expectCall;
1046 static ISAXLocator *locator;
1047 static ISAXXMLReader *g_reader;
1048 int msxml_version;
1049
1050 static void set_expected_seq(struct call_entry *expected)
1051 {
1052 expectCall = expected;
1053 }
1054
1055 /* to be called once on each tested callback return */
1056 static HRESULT get_expected_ret(void)
1057 {
1058 HRESULT hr = expectCall->ret;
1059 if (expectCall->id != CH_ENDTEST) expectCall++;
1060 return hr;
1061 }
1062
1063 static HRESULT WINAPI contentHandler_QueryInterface(
1064 ISAXContentHandler* iface,
1065 REFIID riid,
1066 void **ppvObject)
1067 {
1068 *ppvObject = NULL;
1069
1070 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1071 {
1072 *ppvObject = iface;
1073 }
1074 else
1075 {
1076 return E_NOINTERFACE;
1077 }
1078
1079 return S_OK;
1080 }
1081
1082 static ULONG WINAPI contentHandler_AddRef(
1083 ISAXContentHandler* iface)
1084 {
1085 return 2;
1086 }
1087
1088 static ULONG WINAPI contentHandler_Release(
1089 ISAXContentHandler* iface)
1090 {
1091 return 1;
1092 }
1093
1094 static HRESULT WINAPI contentHandler_putDocumentLocator(
1095 ISAXContentHandler* iface,
1096 ISAXLocator *pLocator)
1097 {
1098 struct call_entry call;
1099 IUnknown *unk;
1100 HRESULT hr;
1101
1102 locator = pLocator;
1103
1104 init_call_entry(locator, &call);
1105 call.id = CH_PUTDOCUMENTLOCATOR;
1106 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1107
1108 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
1109 EXPECT_HR(hr, E_NOINTERFACE);
1110
1111 if (msxml_version >= 6) {
1112 ISAXAttributes *attr, *attr1;
1113 IMXAttributes *mxattr;
1114
1115 EXPECT_REF(pLocator, 1);
1116 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1117 EXPECT_HR(hr, S_OK);
1118 EXPECT_REF(pLocator, 2);
1119 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1120 EXPECT_HR(hr, S_OK);
1121 EXPECT_REF(pLocator, 3);
1122 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1123
1124 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk);
1125 EXPECT_HR(hr, E_NOINTERFACE);
1126
1127 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1128 EXPECT_HR(hr, E_NOINTERFACE);
1129
1130 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1131 EXPECT_HR(hr, E_NOINTERFACE);
1132
1133 ISAXAttributes_Release(attr);
1134 ISAXAttributes_Release(attr1);
1135 }
1136
1137 return get_expected_ret();
1138 }
1139
1140 static ISAXAttributes *test_attr_ptr;
1141 static HRESULT WINAPI contentHandler_startDocument(
1142 ISAXContentHandler* iface)
1143 {
1144 struct call_entry call;
1145
1146 init_call_entry(locator, &call);
1147 call.id = CH_STARTDOCUMENT;
1148 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1149
1150 test_attr_ptr = NULL;
1151
1152 return get_expected_ret();
1153 }
1154
1155 static HRESULT WINAPI contentHandler_endDocument(
1156 ISAXContentHandler* iface)
1157 {
1158 struct call_entry call;
1159
1160 init_call_entry(locator, &call);
1161 call.id = CH_ENDDOCUMENT;
1162 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1163
1164 return get_expected_ret();
1165 }
1166
1167 static HRESULT WINAPI contentHandler_startPrefixMapping(
1168 ISAXContentHandler* iface,
1169 const WCHAR *prefix, int prefix_len,
1170 const WCHAR *uri, int uri_len)
1171 {
1172 struct call_entry call;
1173
1174 init_call_entry(locator, &call);
1175 call.id = CH_STARTPREFIXMAPPING;
1176 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1177 call.arg2W = SysAllocStringLen(uri, uri_len);
1178 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1179
1180 return get_expected_ret();
1181 }
1182
1183 static HRESULT WINAPI contentHandler_endPrefixMapping(
1184 ISAXContentHandler* iface,
1185 const WCHAR *prefix, int len)
1186 {
1187 struct call_entry call;
1188
1189 init_call_entry(locator, &call);
1190 call.id = CH_ENDPREFIXMAPPING;
1191 call.arg1W = SysAllocStringLen(prefix, len);
1192 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1193
1194 return get_expected_ret();
1195 }
1196
1197 static HRESULT WINAPI contentHandler_startElement(
1198 ISAXContentHandler* iface,
1199 const WCHAR *uri, int uri_len,
1200 const WCHAR *localname, int local_len,
1201 const WCHAR *qname, int qname_len,
1202 ISAXAttributes *saxattr)
1203 {
1204 struct call_entry call;
1205 IMXAttributes *mxattr;
1206 HRESULT hr;
1207 int len;
1208
1209 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1210 EXPECT_HR(hr, E_NOINTERFACE);
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 {
1229 VARIANT_BOOL v;
1230 int i;
1231
1232 struct attribute_entry *attr;
1233 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
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
1271 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1272
1273 return get_expected_ret();
1274 }
1275
1276 static HRESULT WINAPI contentHandler_endElement(
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 init_call_entry(locator, &call);
1285 call.id = CH_ENDELEMENT;
1286 call.arg1W = SysAllocStringLen(uri, uri_len);
1287 call.arg2W = SysAllocStringLen(localname, local_len);
1288 call.arg3W = SysAllocStringLen(qname, qname_len);
1289 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1290
1291 return get_expected_ret();
1292 }
1293
1294 static HRESULT WINAPI contentHandler_characters(
1295 ISAXContentHandler* iface,
1296 const WCHAR *chars,
1297 int len)
1298 {
1299 struct call_entry call;
1300
1301 init_call_entry(locator, &call);
1302 call.id = CH_CHARACTERS;
1303 call.arg1W = SysAllocStringLen(chars, len);
1304 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1305
1306 return get_expected_ret();
1307 }
1308
1309 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1310 ISAXContentHandler* iface,
1311 const WCHAR *chars, int len)
1312 {
1313 struct call_entry call;
1314
1315 init_call_entry(locator, &call);
1316 call.id = CH_IGNORABLEWHITESPACE;
1317 call.arg1W = SysAllocStringLen(chars, len);
1318 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1319
1320 return get_expected_ret();
1321 }
1322
1323 static HRESULT WINAPI contentHandler_processingInstruction(
1324 ISAXContentHandler* iface,
1325 const WCHAR *target, int target_len,
1326 const WCHAR *data, int data_len)
1327 {
1328 struct call_entry call;
1329
1330 init_call_entry(locator, &call);
1331 call.id = CH_PROCESSINGINSTRUCTION;
1332 call.arg1W = SysAllocStringLen(target, target_len);
1333 call.arg2W = SysAllocStringLen(data, data_len);
1334 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1335
1336 return get_expected_ret();
1337 }
1338
1339 static HRESULT WINAPI contentHandler_skippedEntity(
1340 ISAXContentHandler* iface,
1341 const WCHAR *name, int len)
1342 {
1343 struct call_entry call;
1344
1345 init_call_entry(locator, &call);
1346 call.id = CH_SKIPPEDENTITY;
1347 call.arg1W = SysAllocStringLen(name, len);
1348 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1349
1350 return get_expected_ret();
1351 }
1352
1353 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1354 {
1355 contentHandler_QueryInterface,
1356 contentHandler_AddRef,
1357 contentHandler_Release,
1358 contentHandler_putDocumentLocator,
1359 contentHandler_startDocument,
1360 contentHandler_endDocument,
1361 contentHandler_startPrefixMapping,
1362 contentHandler_endPrefixMapping,
1363 contentHandler_startElement,
1364 contentHandler_endElement,
1365 contentHandler_characters,
1366 contentHandler_ignorableWhitespace,
1367 contentHandler_processingInstruction,
1368 contentHandler_skippedEntity
1369 };
1370
1371 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1372
1373 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1374 ISAXErrorHandler* iface,
1375 REFIID riid,
1376 void **ppvObject)
1377 {
1378 *ppvObject = NULL;
1379
1380 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1381 {
1382 *ppvObject = iface;
1383 }
1384 else
1385 {
1386 return E_NOINTERFACE;
1387 }
1388
1389 return S_OK;
1390 }
1391
1392 static ULONG WINAPI isaxerrorHandler_AddRef(
1393 ISAXErrorHandler* iface)
1394 {
1395 return 2;
1396 }
1397
1398 static ULONG WINAPI isaxerrorHandler_Release(
1399 ISAXErrorHandler* iface)
1400 {
1401 return 1;
1402 }
1403
1404 static HRESULT WINAPI isaxerrorHandler_error(
1405 ISAXErrorHandler* iface,
1406 ISAXLocator *pLocator,
1407 const WCHAR *pErrorMessage,
1408 HRESULT hrErrorCode)
1409 {
1410 ok(0, "unexpected call\n");
1411 return S_OK;
1412 }
1413
1414 static HRESULT WINAPI isaxerrorHandler_fatalError(
1415 ISAXErrorHandler* iface,
1416 ISAXLocator *pLocator,
1417 const WCHAR *message,
1418 HRESULT hr)
1419 {
1420 struct call_entry call;
1421
1422 init_call_entry(locator, &call);
1423 call.id = EH_FATALERROR;
1424 call.ret = hr;
1425
1426 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1427
1428 get_expected_ret();
1429 return S_OK;
1430 }
1431
1432 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1433 ISAXErrorHandler* iface,
1434 ISAXLocator *pLocator,
1435 const WCHAR *pErrorMessage,
1436 HRESULT hrErrorCode)
1437 {
1438 ok(0, "unexpected call\n");
1439 return S_OK;
1440 }
1441
1442 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1443 {
1444 isaxerrorHandler_QueryInterface,
1445 isaxerrorHandler_AddRef,
1446 isaxerrorHandler_Release,
1447 isaxerrorHandler_error,
1448 isaxerrorHandler_fatalError,
1449 isaxerrorHandler_ignorableWarning
1450 };
1451
1452 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1453
1454 static HRESULT WINAPI isaxattributes_QueryInterface(
1455 ISAXAttributes* iface,
1456 REFIID riid,
1457 void **ppvObject)
1458 {
1459 *ppvObject = NULL;
1460
1461 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1462 {
1463 *ppvObject = iface;
1464 }
1465 else
1466 {
1467 return E_NOINTERFACE;
1468 }
1469
1470 return S_OK;
1471 }
1472
1473 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1474 {
1475 return 2;
1476 }
1477
1478 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1479 {
1480 return 1;
1481 }
1482
1483 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1484 {
1485 *length = 3;
1486 return S_OK;
1487 }
1488
1489 static HRESULT WINAPI isaxattributes_getURI(
1490 ISAXAttributes* iface,
1491 int nIndex,
1492 const WCHAR **pUrl,
1493 int *pUriSize)
1494 {
1495 ok(0, "unexpected call\n");
1496 return E_NOTIMPL;
1497 }
1498
1499 static HRESULT WINAPI isaxattributes_getLocalName(
1500 ISAXAttributes* iface,
1501 int nIndex,
1502 const WCHAR **pLocalName,
1503 int *pLocalNameLength)
1504 {
1505 ok(0, "unexpected call\n");
1506 return E_NOTIMPL;
1507 }
1508
1509 static HRESULT WINAPI isaxattributes_getQName(
1510 ISAXAttributes* iface,
1511 int index,
1512 const WCHAR **QName,
1513 int *QNameLength)
1514 {
1515 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1516 {'a','t','t','r','2','j','u','n','k',0},
1517 {'a','t','t','r','3',0}};
1518 static const int attrqnamelen[] = {7, 5, 5};
1519
1520 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1521
1522 if (index >= 0 && index <= 2) {
1523 *QName = attrqnamesW[index];
1524 *QNameLength = attrqnamelen[index];
1525 } else {
1526 *QName = NULL;
1527 *QNameLength = 0;
1528 }
1529
1530 return S_OK;
1531 }
1532
1533 static HRESULT WINAPI isaxattributes_getName(
1534 ISAXAttributes* iface,
1535 int nIndex,
1536 const WCHAR **pUri,
1537 int * pUriLength,
1538 const WCHAR ** pLocalName,
1539 int * pLocalNameSize,
1540 const WCHAR ** pQName,
1541 int * pQNameLength)
1542 {
1543 ok(0, "unexpected call\n");
1544 return E_NOTIMPL;
1545 }
1546
1547 static HRESULT WINAPI isaxattributes_getIndexFromName(
1548 ISAXAttributes* iface,
1549 const WCHAR * pUri,
1550 int cUriLength,
1551 const WCHAR * pLocalName,
1552 int cocalNameLength,
1553 int * index)
1554 {
1555 ok(0, "unexpected call\n");
1556 return E_NOTIMPL;
1557 }
1558
1559 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1560 ISAXAttributes* iface,
1561 const WCHAR * pQName,
1562 int nQNameLength,
1563 int * index)
1564 {
1565 ok(0, "unexpected call\n");
1566 return E_NOTIMPL;
1567 }
1568
1569 static HRESULT WINAPI isaxattributes_getType(
1570 ISAXAttributes* iface,
1571 int nIndex,
1572 const WCHAR ** pType,
1573 int * pTypeLength)
1574 {
1575 ok(0, "unexpected call\n");
1576 return E_NOTIMPL;
1577 }
1578
1579 static HRESULT WINAPI isaxattributes_getTypeFromName(
1580 ISAXAttributes* iface,
1581 const WCHAR * pUri,
1582 int nUri,
1583 const WCHAR * pLocalName,
1584 int nLocalName,
1585 const WCHAR ** pType,
1586 int * nType)
1587 {
1588 ok(0, "unexpected call\n");
1589 return E_NOTIMPL;
1590 }
1591
1592 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1593 ISAXAttributes* iface,
1594 const WCHAR * pQName,
1595 int nQName,
1596 const WCHAR ** pType,
1597 int * nType)
1598 {
1599 ok(0, "unexpected call\n");
1600 return E_NOTIMPL;
1601 }
1602
1603 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1604 const WCHAR **value, int *nValue)
1605 {
1606 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1607 {'a','2','j','u','n','k',0},
1608 {'<','&','"','>','\'',0}};
1609 static const int attrvalueslen[] = {2, 2, 5};
1610
1611 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1612
1613 if (index >= 0 && index <= 2) {
1614 *value = attrvaluesW[index];
1615 *nValue = attrvalueslen[index];
1616 } else {
1617 *value = NULL;
1618 *nValue = 0;
1619 }
1620
1621 return S_OK;
1622 }
1623
1624 static HRESULT WINAPI isaxattributes_getValueFromName(
1625 ISAXAttributes* iface,
1626 const WCHAR * pUri,
1627 int nUri,
1628 const WCHAR * pLocalName,
1629 int nLocalName,
1630 const WCHAR ** pValue,
1631 int * nValue)
1632 {
1633 ok(0, "unexpected call\n");
1634 return E_NOTIMPL;
1635 }
1636
1637 static HRESULT WINAPI isaxattributes_getValueFromQName(
1638 ISAXAttributes* iface,
1639 const WCHAR * pQName,
1640 int nQName,
1641 const WCHAR ** pValue,
1642 int * nValue)
1643 {
1644 ok(0, "unexpected call\n");
1645 return E_NOTIMPL;
1646 }
1647
1648 static const ISAXAttributesVtbl SAXAttributesVtbl =
1649 {
1650 isaxattributes_QueryInterface,
1651 isaxattributes_AddRef,
1652 isaxattributes_Release,
1653 isaxattributes_getLength,
1654 isaxattributes_getURI,
1655 isaxattributes_getLocalName,
1656 isaxattributes_getQName,
1657 isaxattributes_getName,
1658 isaxattributes_getIndexFromName,
1659 isaxattributes_getIndexFromQName,
1660 isaxattributes_getType,
1661 isaxattributes_getTypeFromName,
1662 isaxattributes_getTypeFromQName,
1663 isaxattributes_getValue,
1664 isaxattributes_getValueFromName,
1665 isaxattributes_getValueFromQName
1666 };
1667
1668 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1669
1670 struct saxlexicalhandler
1671 {
1672 ISAXLexicalHandler ISAXLexicalHandler_iface;
1673 LONG ref;
1674
1675 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1676 };
1677
1678 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1679 {
1680 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1681 }
1682
1683 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1684 {
1685 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1686
1687 *out = NULL;
1688
1689 if (IsEqualGUID(riid, &IID_IUnknown))
1690 {
1691 *out = iface;
1692 ok(0, "got unexpected IID_IUnknown query\n");
1693 }
1694 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1695 {
1696 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1697 *out = iface;
1698 }
1699
1700 if (*out)
1701 ISAXLexicalHandler_AddRef(iface);
1702 else
1703 return E_NOINTERFACE;
1704
1705 return S_OK;
1706 }
1707
1708 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1709 {
1710 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1711 return InterlockedIncrement(&handler->ref);
1712 }
1713
1714 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1715 {
1716 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1717 return InterlockedDecrement(&handler->ref);
1718 }
1719
1720 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1721 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1722 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1723 {
1724 ok(0, "call not expected\n");
1725 return E_NOTIMPL;
1726 }
1727
1728 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1729 {
1730 ok(0, "call not expected\n");
1731 return E_NOTIMPL;
1732 }
1733
1734 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1735 const WCHAR * pName, int nName)
1736 {
1737 ok(0, "call not expected\n");
1738 return E_NOTIMPL;
1739 }
1740
1741 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1742 const WCHAR * pName, int nName)
1743 {
1744 ok(0, "call not expected\n");
1745 return E_NOTIMPL;
1746 }
1747
1748 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1749 {
1750 struct call_entry call;
1751
1752 init_call_entry(locator, &call);
1753 call.id = LH_STARTCDATA;
1754 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1755
1756 return get_expected_ret();
1757 }
1758
1759 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1760 {
1761 struct call_entry call;
1762
1763 init_call_entry(locator, &call);
1764 call.id = LH_ENDCDATA;
1765 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1766
1767 return get_expected_ret();
1768 }
1769
1770 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1771 const WCHAR * pChars, int nChars)
1772 {
1773 ok(0, "call not expected\n");
1774 return E_NOTIMPL;
1775 }
1776
1777 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1778 {
1779 isaxlexical_QueryInterface,
1780 isaxlexical_AddRef,
1781 isaxlexical_Release,
1782 isaxlexical_startDTD,
1783 isaxlexical_endDTD,
1784 isaxlexical_startEntity,
1785 isaxlexical_endEntity,
1786 isaxlexical_startCDATA,
1787 isaxlexical_endCDATA,
1788 isaxlexical_comment
1789 };
1790
1791 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1792 {
1793 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1794 handler->ref = 1;
1795 handler->qi_hr = hr;
1796 }
1797
1798 struct saxdeclhandler
1799 {
1800 ISAXDeclHandler ISAXDeclHandler_iface;
1801 LONG ref;
1802
1803 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1804 };
1805
1806 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1807 {
1808 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1809 }
1810
1811 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1812 {
1813 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1814
1815 *out = NULL;
1816
1817 if (IsEqualGUID(riid, &IID_IUnknown))
1818 {
1819 *out = iface;
1820 ok(0, "got unexpected IID_IUnknown query\n");
1821 }
1822 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1823 {
1824 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1825 *out = iface;
1826 }
1827
1828 if (*out)
1829 ISAXDeclHandler_AddRef(iface);
1830 else
1831 return E_NOINTERFACE;
1832
1833 return S_OK;
1834 }
1835
1836 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1837 {
1838 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1839 return InterlockedIncrement(&handler->ref);
1840 }
1841
1842 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1843 {
1844 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1845 return InterlockedDecrement(&handler->ref);
1846 }
1847
1848 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1849 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1850 {
1851 ok(0, "call not expected\n");
1852 return E_NOTIMPL;
1853 }
1854
1855 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1856 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1857 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1858 int nValueDefault, const WCHAR * pValue, int nValue)
1859 {
1860 ok(0, "call not expected\n");
1861 return E_NOTIMPL;
1862 }
1863
1864 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1865 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1866 {
1867 ok(0, "call not expected\n");
1868 return E_NOTIMPL;
1869 }
1870
1871 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1872 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1873 const WCHAR * pSystemId, int nSystemId)
1874 {
1875 ok(0, "call not expected\n");
1876 return E_NOTIMPL;
1877 }
1878
1879 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1880 {
1881 isaxdecl_QueryInterface,
1882 isaxdecl_AddRef,
1883 isaxdecl_Release,
1884 isaxdecl_elementDecl,
1885 isaxdecl_attributeDecl,
1886 isaxdecl_internalEntityDecl,
1887 isaxdecl_externalEntityDecl
1888 };
1889
1890 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1891 {
1892 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1893 handler->ref = 1;
1894 handler->qi_hr = hr;
1895 }
1896
1897 typedef struct mxwriter_write_test_t {
1898 BOOL last;
1899 const BYTE *data;
1900 DWORD cb;
1901 BOOL null_written;
1902 BOOL fail_write;
1903 } mxwriter_write_test;
1904
1905 typedef struct mxwriter_stream_test_t {
1906 VARIANT_BOOL bom;
1907 const char *encoding;
1908 mxwriter_write_test expected_writes[4];
1909 } mxwriter_stream_test;
1910
1911 static const mxwriter_write_test *current_write_test;
1912 static DWORD current_stream_test_index;
1913
1914 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1915 {
1916 *ppvObject = NULL;
1917
1918 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1919 *ppvObject = iface;
1920 else
1921 return E_NOINTERFACE;
1922
1923 return S_OK;
1924 }
1925
1926 static ULONG WINAPI istream_AddRef(IStream *iface)
1927 {
1928 return 2;
1929 }
1930
1931 static ULONG WINAPI istream_Release(IStream *iface)
1932 {
1933 return 1;
1934 }
1935
1936 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1937 {
1938 ok(0, "unexpected call\n");
1939 return E_NOTIMPL;
1940 }
1941
1942 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1943 {
1944 ok(0, "unexpected call\n");
1945 return E_NOTIMPL;
1946 }
1947
1948 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1949 ULARGE_INTEGER *plibNewPosition)
1950 {
1951 ok(0, "unexpected call\n");
1952 return E_NOTIMPL;
1953 }
1954
1955 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1956 {
1957 ok(0, "unexpected call\n");
1958 return E_NOTIMPL;
1959 }
1960
1961 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1962 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1963 {
1964 ok(0, "unexpected call\n");
1965 return E_NOTIMPL;
1966 }
1967
1968 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1969 {
1970 ok(0, "unexpected call\n");
1971 return E_NOTIMPL;
1972 }
1973
1974 static HRESULT WINAPI istream_Revert(IStream *iface)
1975 {
1976 ok(0, "unexpected call\n");
1977 return E_NOTIMPL;
1978 }
1979
1980 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1981 ULARGE_INTEGER cb, DWORD dwLockType)
1982 {
1983 ok(0, "unexpected call\n");
1984 return E_NOTIMPL;
1985 }
1986
1987 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1988 ULARGE_INTEGER cb, DWORD dwLockType)
1989 {
1990 ok(0, "unexpected call\n");
1991 return E_NOTIMPL;
1992 }
1993
1994 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1995 {
1996 return E_NOTIMPL;
1997 }
1998
1999 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
2000 {
2001 ok(0, "unexpected call\n");
2002 return E_NOTIMPL;
2003 }
2004
2005 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
2006 {
2007 BOOL fail = FALSE;
2008
2009 ok(pv != NULL, "pv == NULL\n");
2010
2011 if(current_write_test->last) {
2012 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2013 return E_FAIL;
2014 }
2015
2016 fail = current_write_test->fail_write;
2017
2018 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2019 current_write_test->cb, cb, current_stream_test_index);
2020
2021 if(!pcbWritten)
2022 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2023 else
2024 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2025
2026 ++current_write_test;
2027
2028 if(pcbWritten)
2029 *pcbWritten = cb;
2030
2031 return fail ? E_FAIL : S_OK;
2032 }
2033
2034 static const IStreamVtbl mxstreamVtbl = {
2035 istream_QueryInterface,
2036 istream_AddRef,
2037 istream_Release,
2038 istream_Read,
2039 mxstream_Write,
2040 istream_Seek,
2041 istream_SetSize,
2042 istream_CopyTo,
2043 istream_Commit,
2044 istream_Revert,
2045 istream_LockRegion,
2046 istream_UnlockRegion,
2047 istream_Stat,
2048 istream_Clone
2049 };
2050
2051 static IStream mxstream = { &mxstreamVtbl };
2052
2053 static int read_cnt;
2054
2055 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2056 {
2057 static const char *ret_str;
2058
2059 if(!read_cnt)
2060 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2061 else if(read_cnt < 5)
2062 ret_str = "<elem attr=\"val\">text</elem>";
2063 else if(read_cnt == 5)
2064 ret_str = "</rootelem>\n";
2065 else
2066 ret_str = "";
2067
2068 read_cnt++;
2069 strcpy(pv, ret_str);
2070 *pcbRead = strlen(ret_str);
2071 return S_OK;
2072 }
2073
2074 static const IStreamVtbl instreamVtbl = {
2075 istream_QueryInterface,
2076 istream_AddRef,
2077 istream_Release,
2078 instream_Read,
2079 istream_Write,
2080 istream_Seek,
2081 istream_SetSize,
2082 istream_CopyTo,
2083 istream_Commit,
2084 istream_Revert,
2085 istream_LockRegion,
2086 istream_UnlockRegion,
2087 istream_Stat,
2088 istream_Clone
2089 };
2090
2091 static IStream instream = { &instreamVtbl };
2092
2093 static struct msxmlsupported_data_t reader_support_data[] =
2094 {
2095 { &CLSID_SAXXMLReader, "SAXReader" },
2096 { &CLSID_SAXXMLReader30, "SAXReader30" },
2097 { &CLSID_SAXXMLReader40, "SAXReader40" },
2098 { &CLSID_SAXXMLReader60, "SAXReader60" },
2099 { NULL }
2100 };
2101
2102 static struct saxlexicalhandler lexicalhandler;
2103 static struct saxdeclhandler declhandler;
2104
2105 static IStream *create_test_stream(const char *data, int len)
2106 {
2107 ULARGE_INTEGER size;
2108 LARGE_INTEGER pos;
2109 IStream *stream;
2110 ULONG written;
2111
2112 if (len == -1) len = strlen(data);
2113 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2114 size.QuadPart = len;
2115 IStream_SetSize(stream, size);
2116 IStream_Write(stream, data, len, &written);
2117 pos.QuadPart = 0;
2118 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2119
2120 return stream;
2121 }
2122
2123 static void test_saxreader(void)
2124 {
2125 const struct msxmlsupported_data_t *table = reader_support_data;
2126 HRESULT hr;
2127 ISAXXMLReader *reader = NULL;
2128 VARIANT var;
2129 ISAXContentHandler *content;
2130 ISAXErrorHandler *lpErrorHandler;
2131 SAFEARRAY *sa;
2132 SAFEARRAYBOUND SADim[1];
2133 char *ptr = NULL;
2134 IStream *stream;
2135 ULONG written;
2136 HANDLE file;
2137 static const CHAR testXmlA[] = "test.xml";
2138 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2139 IXMLDOMDocument *doc;
2140 char seqname[50];
2141 VARIANT_BOOL v;
2142
2143 while (table->clsid)
2144 {
2145 struct call_entry *test_seq;
2146 ISAXEntityResolver *resolver;
2147 BSTR str;
2148
2149 if (!is_clsid_supported(table->clsid, reader_support_data))
2150 {
2151 table++;
2152 continue;
2153 }
2154
2155 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2156 EXPECT_HR(hr, S_OK);
2157 g_reader = reader;
2158
2159 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2160 msxml_version = 4;
2161 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2162 msxml_version = 6;
2163 else
2164 msxml_version = 0;
2165
2166 /* crashes on old versions */
2167 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2168 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2169 {
2170 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2171 EXPECT_HR(hr, E_POINTER);
2172
2173 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2174 EXPECT_HR(hr, E_POINTER);
2175 }
2176
2177 hr = ISAXXMLReader_getContentHandler(reader, &content);
2178 EXPECT_HR(hr, S_OK);
2179 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2180
2181 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2182 EXPECT_HR(hr, S_OK);
2183 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2184
2185 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2186 EXPECT_HR(hr, S_OK);
2187
2188 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2189 EXPECT_HR(hr, S_OK);
2190
2191 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2192 EXPECT_HR(hr, S_OK);
2193
2194 hr = ISAXXMLReader_getContentHandler(reader, &content);
2195 EXPECT_HR(hr, S_OK);
2196 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2197
2198 V_VT(&var) = VT_BSTR;
2199 V_BSTR(&var) = SysAllocString(szSimpleXML);
2200
2201 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2202 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2203 test_seq = content_handler_test1_alternate;
2204 else
2205 test_seq = content_handler_test1;
2206 set_expected_seq(test_seq);
2207 hr = ISAXXMLReader_parse(reader, var);
2208 EXPECT_HR(hr, S_OK);
2209 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2210
2211 VariantClear(&var);
2212
2213 SADim[0].lLbound = 0;
2214 SADim[0].cElements = sizeof(testXML)-1;
2215 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2216 SafeArrayAccessData(sa, (void**)&ptr);
2217 memcpy(ptr, testXML, sizeof(testXML)-1);
2218 SafeArrayUnaccessData(sa);
2219 V_VT(&var) = VT_ARRAY|VT_UI1;
2220 V_ARRAY(&var) = sa;
2221
2222 set_expected_seq(test_seq);
2223 hr = ISAXXMLReader_parse(reader, var);
2224 EXPECT_HR(hr, S_OK);
2225 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2226
2227 SafeArrayDestroy(sa);
2228
2229 stream = create_test_stream(testXML, -1);
2230 V_VT(&var) = VT_UNKNOWN;
2231 V_UNKNOWN(&var) = (IUnknown*)stream;
2232
2233 set_expected_seq(test_seq);
2234 hr = ISAXXMLReader_parse(reader, var);
2235 EXPECT_HR(hr, S_OK);
2236 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2237
2238 IStream_Release(stream);
2239
2240 stream = create_test_stream(test_attributes, -1);
2241 V_VT(&var) = VT_UNKNOWN;
2242 V_UNKNOWN(&var) = (IUnknown*)stream;
2243
2244 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2245 test_seq = content_handler_test_attributes_alternate_4;
2246 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2247 test_seq = content_handler_test_attributes_alternate_6;
2248 else
2249 test_seq = content_handler_test_attributes;
2250
2251 set_expected_seq(test_seq);
2252 hr = ISAXXMLReader_parse(reader, var);
2253 EXPECT_HR(hr, S_OK);
2254
2255 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2256 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2257 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2258 else
2259 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2260
2261 IStream_Release(stream);
2262
2263 V_VT(&var) = VT_UNKNOWN;
2264 V_UNKNOWN(&var) = (IUnknown*)&instream;
2265
2266 test_seq = read_test_seq;
2267 read_cnt = 0;
2268 set_expected_seq(test_seq);
2269 hr = ISAXXMLReader_parse(reader, var);
2270 EXPECT_HR(hr, S_OK);
2271 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2272 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2273
2274 V_VT(&var) = VT_BSTR;
2275 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2276
2277 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2278 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2279 test_seq = content_handler_test2_alternate;
2280 else
2281 test_seq = content_handler_test2;
2282
2283 set_expected_seq(test_seq);
2284 hr = ISAXXMLReader_parse(reader, var);
2285 EXPECT_HR(hr, S_OK);
2286 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2287
2288 VariantClear(&var);
2289
2290 /* from file url */
2291 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2292 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2293 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2294 CloseHandle(file);
2295
2296 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2297 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2298 test_seq = content_handler_test1_alternate;
2299 else
2300 test_seq = content_handler_test1;
2301 set_expected_seq(test_seq);
2302 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2303 EXPECT_HR(hr, S_OK);
2304 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2305
2306 /* error handler */
2307 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2308 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2309 test_seq = content_handler_testerror_alternate;
2310 else
2311 test_seq = content_handler_testerror;
2312 set_expected_seq(test_seq);
2313 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2314 EXPECT_HR(hr, E_FAIL);
2315 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2316
2317 /* callback ret values */
2318 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2319 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2320 {
2321 test_seq = content_handler_test_callback_rets_alt;
2322 set_expected_seq(test_seq);
2323 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2324 EXPECT_HR(hr, S_OK);
2325 }
2326 else
2327 {
2328 test_seq = content_handler_test_callback_rets;
2329 set_expected_seq(test_seq);
2330 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2331 EXPECT_HR(hr, S_FALSE);
2332 }
2333 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2334
2335 DeleteFileA(testXmlA);
2336
2337 /* parse from IXMLDOMDocument */
2338 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2339 &IID_IXMLDOMDocument, (void**)&doc);
2340 EXPECT_HR(hr, S_OK);
2341
2342 str = SysAllocString(szSimpleXML);
2343 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2344 EXPECT_HR(hr, S_OK);
2345 SysFreeString(str);
2346
2347 V_VT(&var) = VT_UNKNOWN;
2348 V_UNKNOWN(&var) = (IUnknown*)doc;
2349
2350 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2351 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2352 test_seq = content_handler_test2_alternate;
2353 else
2354 test_seq = content_handler_test2;
2355
2356 set_expected_seq(test_seq);
2357 hr = ISAXXMLReader_parse(reader, var);
2358 EXPECT_HR(hr, S_OK);
2359 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2360 IXMLDOMDocument_Release(doc);
2361
2362 /* xml:space test */
2363 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2364 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2365 {
2366 test_seq = xmlspaceattr_test_alternate;
2367 }
2368 else
2369 test_seq = xmlspaceattr_test;
2370
2371 set_expected_seq(test_seq);
2372 V_VT(&var) = VT_BSTR;
2373 V_BSTR(&var) = _bstr_(xmlspace_attr);
2374 hr = ISAXXMLReader_parse(reader, var);
2375 EXPECT_HR(hr, S_OK);
2376
2377 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2378 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2379 {
2380 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2381 }
2382 else
2383 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2384
2385 /* switch off 'namespaces' feature */
2386 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2387 EXPECT_HR(hr, S_OK);
2388
2389 stream = create_test_stream(test_attributes, -1);
2390 V_VT(&var) = VT_UNKNOWN;
2391 V_UNKNOWN(&var) = (IUnknown*)stream;
2392
2393 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2394 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2395 {
2396 test_seq = content_handler_test_attributes_alt_no_ns;
2397 }
2398 else
2399 test_seq = content_handler_test_attributes;
2400
2401 set_expected_seq(test_seq);
2402 hr = ISAXXMLReader_parse(reader, var);
2403 EXPECT_HR(hr, S_OK);
2404 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2405 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2406 EXPECT_HR(hr, S_OK);
2407
2408 /* switch off 'namespace-prefixes' feature */
2409 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2410 EXPECT_HR(hr, S_OK);
2411
2412 stream = create_test_stream(test_attributes, -1);
2413 V_VT(&var) = VT_UNKNOWN;
2414 V_UNKNOWN(&var) = (IUnknown*)stream;
2415
2416 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2417 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2418 {
2419 test_seq = content_handler_test_attributes_alt_no_prefix;
2420 }
2421 else
2422 test_seq = content_handler_test_attributes_no_prefix;
2423
2424 set_expected_seq(test_seq);
2425 hr = ISAXXMLReader_parse(reader, var);
2426 EXPECT_HR(hr, S_OK);
2427 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2428
2429 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2430 EXPECT_HR(hr, S_OK);
2431
2432 /* attribute normalization */
2433 stream = create_test_stream(attribute_normalize, -1);
2434 V_VT(&var) = VT_UNKNOWN;
2435 V_UNKNOWN(&var) = (IUnknown*)stream;
2436
2437 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2438 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2439 {
2440 test_seq = attribute_norm_alt;
2441 }
2442 else
2443 test_seq = attribute_norm;
2444
2445 set_expected_seq(test_seq);
2446 hr = ISAXXMLReader_parse(reader, var);
2447 EXPECT_HR(hr, S_OK);
2448 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2449 IStream_Release(stream);
2450
2451 resolver = (void*)0xdeadbeef;
2452 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2453 ok(hr == S_OK, "got 0x%08x\n", hr);
2454 ok(resolver == NULL, "got %p\n", resolver);
2455
2456 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2457 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2458
2459 /* CDATA sections */
2460 init_saxlexicalhandler(&lexicalhandler, S_OK);
2461
2462 V_VT(&var) = VT_UNKNOWN;
2463 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2464 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2465 ok(hr == S_OK, "got 0x%08x\n", hr);
2466
2467 stream = create_test_stream(test_cdata_xml, -1);
2468 V_VT(&var) = VT_UNKNOWN;
2469 V_UNKNOWN(&var) = (IUnknown*)stream;
2470
2471 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2472 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2473 test_seq = cdata_test_alt;
2474 else
2475 test_seq = cdata_test;
2476
2477 set_expected_seq(test_seq);
2478 hr = ISAXXMLReader_parse(reader, var);
2479 ok(hr == S_OK, "got 0x%08x\n", hr);
2480 sprintf(seqname, "%s: cdata test", table->name);
2481 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2482
2483 IStream_Release(stream);
2484
2485 /* 2. CDATA sections */
2486 stream = create_test_stream(test2_cdata_xml, -1);
2487 V_VT(&var) = VT_UNKNOWN;
2488 V_UNKNOWN(&var) = (IUnknown*)stream;
2489
2490 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2491 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2492 test_seq = cdata_test2_alt;
2493 else
2494 test_seq = cdata_test2;
2495
2496 set_expected_seq(test_seq);
2497 hr = ISAXXMLReader_parse(reader, var);
2498 ok(hr == S_OK, "got 0x%08x\n", hr);
2499 sprintf(seqname, "%s: cdata test 2", table->name);
2500 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2501
2502 IStream_Release(stream);
2503
2504 /* 3. CDATA sections */
2505 stream = create_test_stream(test3_cdata_xml, -1);
2506 V_VT(&var) = VT_UNKNOWN;
2507 V_UNKNOWN(&var) = (IUnknown*)stream;
2508
2509 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2510 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2511 test_seq = cdata_test3_alt;
2512 else
2513 test_seq = cdata_test3;
2514
2515 set_expected_seq(test_seq);
2516 hr = ISAXXMLReader_parse(reader, var);
2517 ok(hr == S_OK, "got 0x%08x\n", hr);
2518 sprintf(seqname, "%s: cdata test 3", table->name);
2519 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2520
2521 IStream_Release(stream);
2522
2523 ISAXXMLReader_Release(reader);
2524 table++;
2525 }
2526
2527 free_bstrs();
2528 }
2529
2530 struct saxreader_props_test_t
2531 {
2532 const char *prop_name;
2533 IUnknown *iface;
2534 };
2535
2536 static const struct saxreader_props_test_t props_test_data[] = {
2537 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2538 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2539 { 0 }
2540 };
2541
2542 static void test_saxreader_properties(void)
2543 {
2544 const struct saxreader_props_test_t *ptr = props_test_data;
2545 ISAXXMLReader *reader;
2546 HRESULT hr;
2547 VARIANT v;
2548 BSTR str;
2549
2550 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2551 &IID_ISAXXMLReader, (void**)&reader);
2552 EXPECT_HR(hr, S_OK);
2553
2554 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2555 EXPECT_HR(hr, E_POINTER);
2556
2557 while (ptr->prop_name)
2558 {
2559 VARIANT varref;
2560 LONG ref;
2561
2562 init_saxlexicalhandler(&lexicalhandler, S_OK);
2563 init_saxdeclhandler(&declhandler, S_OK);
2564
2565 V_VT(&v) = VT_EMPTY;
2566 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2567 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2568 EXPECT_HR(hr, S_OK);
2569 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2570 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2571
2572 /* VT_UNKNOWN */
2573 V_VT(&v) = VT_UNKNOWN;
2574 V_UNKNOWN(&v) = ptr->iface;
2575 ref = get_refcount(ptr->iface);
2576 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2577 EXPECT_HR(hr, S_OK);
2578 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2579
2580 /* VT_DISPATCH */
2581 V_VT(&v) = VT_DISPATCH;
2582 V_UNKNOWN(&v) = ptr->iface;
2583 ref = get_refcount(ptr->iface);
2584 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2585 EXPECT_HR(hr, S_OK);
2586 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2587
2588 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2589 V_VT(&varref) = VT_UNKNOWN;
2590 V_UNKNOWN(&varref) = ptr->iface;
2591
2592 V_VT(&v) = VT_VARIANT|VT_BYREF;
2593 V_VARIANTREF(&v) = &varref;
2594 ref = get_refcount(ptr->iface);
2595 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2596 EXPECT_HR(hr, S_OK);
2597 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2598
2599 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2600 V_VT(&varref) = VT_DISPATCH;
2601 V_UNKNOWN(&varref) = ptr->iface;
2602
2603 V_VT(&v) = VT_VARIANT|VT_BYREF;
2604 V_VARIANTREF(&v) = &varref;
2605 ref = get_refcount(ptr->iface);
2606 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2607 EXPECT_HR(hr, S_OK);
2608 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2609
2610 V_VT(&v) = VT_EMPTY;
2611 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2612
2613 ref = get_refcount(ptr->iface);
2614 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2615 EXPECT_HR(hr, S_OK);
2616 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2617 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2618 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2619 VariantClear(&v);
2620
2621 V_VT(&v) = VT_EMPTY;
2622 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2623 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2624 EXPECT_HR(hr, S_OK);
2625
2626 V_VT(&v) = VT_EMPTY;
2627 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2628 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2629 EXPECT_HR(hr, S_OK);
2630 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2631 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2632
2633 V_VT(&v) = VT_UNKNOWN;
2634 V_UNKNOWN(&v) = ptr->iface;
2635 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2636 EXPECT_HR(hr, S_OK);
2637
2638 /* only VT_EMPTY seems to be valid to reset property */
2639 V_VT(&v) = VT_I4;
2640 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2641 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2642 EXPECT_HR(hr, E_INVALIDARG);
2643
2644 V_VT(&v) = VT_EMPTY;
2645 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2646 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2647 EXPECT_HR(hr, S_OK);
2648 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2649 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2650 VariantClear(&v);
2651
2652 V_VT(&v) = VT_UNKNOWN;
2653 V_UNKNOWN(&v) = NULL;
2654 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2655 EXPECT_HR(hr, S_OK);
2656
2657 V_VT(&v) = VT_EMPTY;
2658 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2659 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2660 EXPECT_HR(hr, S_OK);
2661 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2662 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2663
2664 /* block QueryInterface on handler riid */
2665 V_VT(&v) = VT_UNKNOWN;
2666 V_UNKNOWN(&v) = ptr->iface;
2667 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2668 EXPECT_HR(hr, S_OK);
2669
2670 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2671 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2672
2673 V_VT(&v) = VT_UNKNOWN;
2674 V_UNKNOWN(&v) = ptr->iface;
2675 EXPECT_REF(ptr->iface, 1);
2676 ref = get_refcount(ptr->iface);
2677 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2678 EXPECT_HR(hr, E_NOINTERFACE);
2679 EXPECT_REF(ptr->iface, 1);
2680
2681 V_VT(&v) = VT_EMPTY;
2682 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2683 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2684 EXPECT_HR(hr, S_OK);
2685 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2686 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2687
2688 ptr++;
2689 free_bstrs();
2690 }
2691
2692 ISAXXMLReader_Release(reader);
2693
2694 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2695 return;
2696
2697 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2698 &IID_ISAXXMLReader, (void**)&reader);
2699 EXPECT_HR(hr, S_OK);
2700
2701 /* xmldecl-version property */
2702 V_VT(&v) = VT_EMPTY;
2703 V_BSTR(&v) = (void*)0xdeadbeef;
2704 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2705 EXPECT_HR(hr, S_OK);
2706 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2707 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2708
2709 /* stream without declaration */
2710 V_VT(&v) = VT_BSTR;
2711 V_BSTR(&v) = _bstr_("<element></element>");
2712 hr = ISAXXMLReader_parse(reader, v);
2713 EXPECT_HR(hr, S_OK);
2714
2715 V_VT(&v) = VT_EMPTY;
2716 V_BSTR(&v) = (void*)0xdeadbeef;
2717 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2718 EXPECT_HR(hr, S_OK);
2719 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2720 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2721
2722 /* stream with declaration */
2723 V_VT(&v) = VT_BSTR;
2724 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2725 hr = ISAXXMLReader_parse(reader, v);
2726 EXPECT_HR(hr, S_OK);
2727
2728 /* VT_BSTR|VT_BYREF input type */
2729 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2730 V_VT(&v) = VT_BSTR|VT_BYREF;
2731 V_BSTRREF(&v) = &str;
2732 hr = ISAXXMLReader_parse(reader, v);
2733 EXPECT_HR(hr, S_OK);
2734
2735 V_VT(&v) = VT_EMPTY;
2736 V_BSTR(&v) = (void*)0xdeadbeef;
2737 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2738 EXPECT_HR(hr, S_OK);
2739 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2740 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2741 VariantClear(&v);
2742
2743 ISAXXMLReader_Release(reader);
2744 free_bstrs();
2745 }
2746
2747 struct feature_ns_entry_t {
2748 const GUID *guid;
2749 const char *clsid;
2750 VARIANT_BOOL value;
2751 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2752 };
2753
2754 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2755 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2756 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2757 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2758 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2759 { 0 }
2760 };
2761
2762 static const char *feature_names[] = {
2763 "http://xml.org/sax/features/namespaces",
2764 "http://xml.org/sax/features/namespace-prefixes",
2765 0
2766 };
2767
2768 static void test_saxreader_features(void)
2769 {
2770 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2771 ISAXXMLReader *reader;
2772
2773 while (entry->guid)
2774 {
2775 VARIANT_BOOL value;
2776 const char **name;
2777 HRESULT hr;
2778
2779 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2780 if (hr != S_OK)
2781 {
2782 win_skip("can't create %s instance\n", entry->clsid);
2783 entry++;
2784 continue;
2785 }
2786
2787 name = feature_names;
2788 while (*name)
2789 {
2790 value = 0xc;
2791 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2792 EXPECT_HR(hr, S_OK);
2793 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2794
2795 value = 0xc;
2796 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2797 EXPECT_HR(hr, S_OK);
2798
2799 value = 0xd;
2800 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2801 EXPECT_HR(hr, S_OK);
2802 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2803
2804 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2805 EXPECT_HR(hr, S_OK);
2806 value = 0xd;
2807 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2808 EXPECT_HR(hr, S_OK);
2809 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2810
2811 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2812 EXPECT_HR(hr, S_OK);
2813 value = 0xd;
2814 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2815 EXPECT_HR(hr, S_OK);
2816 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2817
2818 name++;
2819 }
2820
2821 ISAXXMLReader_Release(reader);
2822
2823 entry++;
2824 }
2825 }
2826
2827 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2828 static const CHAR UTF8BOMTest[] =
2829 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2830 <