[MSXML3]
[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 ok(0, "unexpected call\n");
1997 return E_NOTIMPL;
1998 }
1999
2000 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
2001 {
2002 ok(0, "unexpected call\n");
2003 return E_NOTIMPL;
2004 }
2005
2006 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
2007 {
2008 BOOL fail = FALSE;
2009
2010 ok(pv != NULL, "pv == NULL\n");
2011
2012 if(current_write_test->last) {
2013 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2014 return E_FAIL;
2015 }
2016
2017 fail = current_write_test->fail_write;
2018
2019 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2020 current_write_test->cb, cb, current_stream_test_index);
2021
2022 if(!pcbWritten)
2023 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2024 else
2025 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2026
2027 ++current_write_test;
2028
2029 if(pcbWritten)
2030 *pcbWritten = cb;
2031
2032 return fail ? E_FAIL : S_OK;
2033 }
2034
2035 static const IStreamVtbl mxstreamVtbl = {
2036 istream_QueryInterface,
2037 istream_AddRef,
2038 istream_Release,
2039 istream_Read,
2040 mxstream_Write,
2041 istream_Seek,
2042 istream_SetSize,
2043 istream_CopyTo,
2044 istream_Commit,
2045 istream_Revert,
2046 istream_LockRegion,
2047 istream_UnlockRegion,
2048 istream_Stat,
2049 istream_Clone
2050 };
2051
2052 static IStream mxstream = { &mxstreamVtbl };
2053
2054 static int read_cnt;
2055
2056 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2057 {
2058 static const char *ret_str;
2059
2060 if(!read_cnt)
2061 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2062 else if(read_cnt < 5)
2063 ret_str = "<elem attr=\"val\">text</elem>";
2064 else if(read_cnt == 5)
2065 ret_str = "</rootelem>\n";
2066 else
2067 ret_str = "";
2068
2069 read_cnt++;
2070 strcpy(pv, ret_str);
2071 *pcbRead = strlen(ret_str);
2072 return S_OK;
2073 }
2074
2075 static const IStreamVtbl instreamVtbl = {
2076 istream_QueryInterface,
2077 istream_AddRef,
2078 istream_Release,
2079 instream_Read,
2080 istream_Write,
2081 istream_Seek,
2082 istream_SetSize,
2083 istream_CopyTo,
2084 istream_Commit,
2085 istream_Revert,
2086 istream_LockRegion,
2087 istream_UnlockRegion,
2088 istream_Stat,
2089 istream_Clone
2090 };
2091
2092 static IStream instream = { &instreamVtbl };
2093
2094 static struct msxmlsupported_data_t reader_support_data[] =
2095 {
2096 { &CLSID_SAXXMLReader, "SAXReader" },
2097 { &CLSID_SAXXMLReader30, "SAXReader30" },
2098 { &CLSID_SAXXMLReader40, "SAXReader40" },
2099 { &CLSID_SAXXMLReader60, "SAXReader60" },
2100 { NULL }
2101 };
2102
2103 static struct saxlexicalhandler lexicalhandler;
2104 static struct saxdeclhandler declhandler;
2105
2106 static IStream *create_test_stream(const char *data, int len)
2107 {
2108 ULARGE_INTEGER size;
2109 LARGE_INTEGER pos;
2110 IStream *stream;
2111 ULONG written;
2112
2113 if (len == -1) len = strlen(data);
2114 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2115 size.QuadPart = len;
2116 IStream_SetSize(stream, size);
2117 IStream_Write(stream, data, len, &written);
2118 pos.QuadPart = 0;
2119 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2120
2121 return stream;
2122 }
2123
2124 static void test_saxreader(void)
2125 {
2126 const struct msxmlsupported_data_t *table = reader_support_data;
2127 HRESULT hr;
2128 ISAXXMLReader *reader = NULL;
2129 VARIANT var;
2130 ISAXContentHandler *content;
2131 ISAXErrorHandler *lpErrorHandler;
2132 SAFEARRAY *sa;
2133 SAFEARRAYBOUND SADim[1];
2134 char *ptr = NULL;
2135 IStream *stream;
2136 ULONG written;
2137 HANDLE file;
2138 static const CHAR testXmlA[] = "test.xml";
2139 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2140 IXMLDOMDocument *doc;
2141 char seqname[50];
2142 VARIANT_BOOL v;
2143
2144 while (table->clsid)
2145 {
2146 struct call_entry *test_seq;
2147 ISAXEntityResolver *resolver;
2148 BSTR str;
2149
2150 if (!is_clsid_supported(table->clsid, reader_support_data))
2151 {
2152 table++;
2153 continue;
2154 }
2155
2156 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2157 EXPECT_HR(hr, S_OK);
2158 g_reader = reader;
2159
2160 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2161 msxml_version = 4;
2162 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2163 msxml_version = 6;
2164 else
2165 msxml_version = 0;
2166
2167 /* crashes on old versions */
2168 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2169 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2170 {
2171 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2172 EXPECT_HR(hr, E_POINTER);
2173
2174 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2175 EXPECT_HR(hr, E_POINTER);
2176 }
2177
2178 hr = ISAXXMLReader_getContentHandler(reader, &content);
2179 EXPECT_HR(hr, S_OK);
2180 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2181
2182 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2183 EXPECT_HR(hr, S_OK);
2184 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2185
2186 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2187 EXPECT_HR(hr, S_OK);
2188
2189 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2190 EXPECT_HR(hr, S_OK);
2191
2192 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2193 EXPECT_HR(hr, S_OK);
2194
2195 hr = ISAXXMLReader_getContentHandler(reader, &content);
2196 EXPECT_HR(hr, S_OK);
2197 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2198
2199 V_VT(&var) = VT_BSTR;
2200 V_BSTR(&var) = SysAllocString(szSimpleXML);
2201
2202 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2203 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2204 test_seq = content_handler_test1_alternate;
2205 else
2206 test_seq = content_handler_test1;
2207 set_expected_seq(test_seq);
2208 hr = ISAXXMLReader_parse(reader, var);
2209 EXPECT_HR(hr, S_OK);
2210 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2211
2212 VariantClear(&var);
2213
2214 SADim[0].lLbound = 0;
2215 SADim[0].cElements = sizeof(testXML)-1;
2216 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2217 SafeArrayAccessData(sa, (void**)&ptr);
2218 memcpy(ptr, testXML, sizeof(testXML)-1);
2219 SafeArrayUnaccessData(sa);
2220 V_VT(&var) = VT_ARRAY|VT_UI1;
2221 V_ARRAY(&var) = sa;
2222
2223 set_expected_seq(test_seq);
2224 hr = ISAXXMLReader_parse(reader, var);
2225 EXPECT_HR(hr, S_OK);
2226 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2227
2228 SafeArrayDestroy(sa);
2229
2230 stream = create_test_stream(testXML, -1);
2231 V_VT(&var) = VT_UNKNOWN;
2232 V_UNKNOWN(&var) = (IUnknown*)stream;
2233
2234 set_expected_seq(test_seq);
2235 hr = ISAXXMLReader_parse(reader, var);
2236 EXPECT_HR(hr, S_OK);
2237 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2238
2239 IStream_Release(stream);
2240
2241 stream = create_test_stream(test_attributes, -1);
2242 V_VT(&var) = VT_UNKNOWN;
2243 V_UNKNOWN(&var) = (IUnknown*)stream;
2244
2245 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2246 test_seq = content_handler_test_attributes_alternate_4;
2247 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2248 test_seq = content_handler_test_attributes_alternate_6;
2249 else
2250 test_seq = content_handler_test_attributes;
2251
2252 set_expected_seq(test_seq);
2253 hr = ISAXXMLReader_parse(reader, var);
2254 EXPECT_HR(hr, S_OK);
2255
2256 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2257 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2258 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2259 else
2260 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2261
2262 IStream_Release(stream);
2263
2264 V_VT(&var) = VT_UNKNOWN;
2265 V_UNKNOWN(&var) = (IUnknown*)&instream;
2266
2267 test_seq = read_test_seq;
2268 read_cnt = 0;
2269 set_expected_seq(test_seq);
2270 hr = ISAXXMLReader_parse(reader, var);
2271 EXPECT_HR(hr, S_OK);
2272 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2273 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2274
2275 V_VT(&var) = VT_BSTR;
2276 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2277
2278 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2279 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2280 test_seq = content_handler_test2_alternate;
2281 else
2282 test_seq = content_handler_test2;
2283
2284 set_expected_seq(test_seq);
2285 hr = ISAXXMLReader_parse(reader, var);
2286 EXPECT_HR(hr, S_OK);
2287 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2288
2289 VariantClear(&var);
2290
2291 /* from file url */
2292 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2293 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2294 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2295 CloseHandle(file);
2296
2297 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2298 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2299 test_seq = content_handler_test1_alternate;
2300 else
2301 test_seq = content_handler_test1;
2302 set_expected_seq(test_seq);
2303 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2304 EXPECT_HR(hr, S_OK);
2305 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2306
2307 /* error handler */
2308 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2309 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2310 test_seq = content_handler_testerror_alternate;
2311 else
2312 test_seq = content_handler_testerror;
2313 set_expected_seq(test_seq);
2314 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2315 EXPECT_HR(hr, E_FAIL);
2316 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2317
2318 /* callback ret values */
2319 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2320 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2321 {
2322 test_seq = content_handler_test_callback_rets_alt;
2323 set_expected_seq(test_seq);
2324 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2325 EXPECT_HR(hr, S_OK);
2326 }
2327 else
2328 {
2329 test_seq = content_handler_test_callback_rets;
2330 set_expected_seq(test_seq);
2331 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2332 EXPECT_HR(hr, S_FALSE);
2333 }
2334 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2335
2336 DeleteFileA(testXmlA);
2337
2338 /* parse from IXMLDOMDocument */
2339 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2340 &IID_IXMLDOMDocument, (void**)&doc);
2341 EXPECT_HR(hr, S_OK);
2342
2343 str = SysAllocString(szSimpleXML);
2344 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2345 EXPECT_HR(hr, S_OK);
2346 SysFreeString(str);
2347
2348 V_VT(&var) = VT_UNKNOWN;
2349 V_UNKNOWN(&var) = (IUnknown*)doc;
2350
2351 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2352 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2353 test_seq = content_handler_test2_alternate;
2354 else
2355 test_seq = content_handler_test2;
2356
2357 set_expected_seq(test_seq);
2358 hr = ISAXXMLReader_parse(reader, var);
2359 EXPECT_HR(hr, S_OK);
2360 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2361 IXMLDOMDocument_Release(doc);
2362
2363 /* xml:space test */
2364 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2365 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2366 {
2367 test_seq = xmlspaceattr_test_alternate;
2368 }
2369 else
2370 test_seq = xmlspaceattr_test;
2371
2372 set_expected_seq(test_seq);
2373 V_VT(&var) = VT_BSTR;
2374 V_BSTR(&var) = _bstr_(xmlspace_attr);
2375 hr = ISAXXMLReader_parse(reader, var);
2376 EXPECT_HR(hr, S_OK);
2377
2378 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2379 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2380 {
2381 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2382 }
2383 else
2384 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2385
2386 /* switch off 'namespaces' feature */
2387 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2388 EXPECT_HR(hr, S_OK);
2389
2390 stream = create_test_stream(test_attributes, -1);
2391 V_VT(&var) = VT_UNKNOWN;
2392 V_UNKNOWN(&var) = (IUnknown*)stream;
2393
2394 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2395 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2396 {
2397 test_seq = content_handler_test_attributes_alt_no_ns;
2398 }
2399 else
2400 test_seq = content_handler_test_attributes;
2401
2402 set_expected_seq(test_seq);
2403 hr = ISAXXMLReader_parse(reader, var);
2404 EXPECT_HR(hr, S_OK);
2405 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2406 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2407 EXPECT_HR(hr, S_OK);
2408
2409 /* switch off 'namespace-prefixes' feature */
2410 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2411 EXPECT_HR(hr, S_OK);
2412
2413 stream = create_test_stream(test_attributes, -1);
2414 V_VT(&var) = VT_UNKNOWN;
2415 V_UNKNOWN(&var) = (IUnknown*)stream;
2416
2417 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2418 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2419 {
2420 test_seq = content_handler_test_attributes_alt_no_prefix;
2421 }
2422 else
2423 test_seq = content_handler_test_attributes_no_prefix;
2424
2425 set_expected_seq(test_seq);
2426 hr = ISAXXMLReader_parse(reader, var);
2427 EXPECT_HR(hr, S_OK);
2428 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2429
2430 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2431 EXPECT_HR(hr, S_OK);
2432
2433 /* attribute normalization */
2434 stream = create_test_stream(attribute_normalize, -1);
2435 V_VT(&var) = VT_UNKNOWN;
2436 V_UNKNOWN(&var) = (IUnknown*)stream;
2437
2438 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2439 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2440 {
2441 test_seq = attribute_norm_alt;
2442 }
2443 else
2444 test_seq = attribute_norm;
2445
2446 set_expected_seq(test_seq);
2447 hr = ISAXXMLReader_parse(reader, var);
2448 EXPECT_HR(hr, S_OK);
2449 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
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 /* 2. CDATA sections */
2484 stream = create_test_stream(test2_cdata_xml, -1);
2485 V_VT(&var) = VT_UNKNOWN;
2486 V_UNKNOWN(&var) = (IUnknown*)stream;
2487
2488 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2489 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2490 test_seq = cdata_test2_alt;
2491 else
2492 test_seq = cdata_test2;
2493
2494 set_expected_seq(test_seq);
2495 hr = ISAXXMLReader_parse(reader, var);
2496 ok(hr == S_OK, "got 0x%08x\n", hr);
2497 sprintf(seqname, "%s: cdata test 2", table->name);
2498 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2499
2500 IStream_Release(stream);
2501
2502 /* 3. CDATA sections */
2503 stream = create_test_stream(test3_cdata_xml, -1);
2504 V_VT(&var) = VT_UNKNOWN;
2505 V_UNKNOWN(&var) = (IUnknown*)stream;
2506
2507 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2508 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2509 test_seq = cdata_test3_alt;
2510 else
2511 test_seq = cdata_test3;
2512
2513 set_expected_seq(test_seq);
2514 hr = ISAXXMLReader_parse(reader, var);
2515 ok(hr == S_OK, "got 0x%08x\n", hr);
2516 sprintf(seqname, "%s: cdata test 3", table->name);
2517 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2518
2519 IStream_Release(stream);
2520
2521 ISAXXMLReader_Release(reader);
2522 table++;
2523 }
2524
2525 free_bstrs();
2526 }
2527
2528 struct saxreader_props_test_t
2529 {
2530 const char *prop_name;
2531 IUnknown *iface;
2532 };
2533
2534 static const struct saxreader_props_test_t props_test_data[] = {
2535 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2536 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2537 { 0 }
2538 };
2539
2540 static void test_saxreader_properties(void)
2541 {
2542 const struct saxreader_props_test_t *ptr = props_test_data;
2543 ISAXXMLReader *reader;
2544 HRESULT hr;
2545 VARIANT v;
2546 BSTR str;
2547
2548 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2549 &IID_ISAXXMLReader, (void**)&reader);
2550 EXPECT_HR(hr, S_OK);
2551
2552 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2553 EXPECT_HR(hr, E_POINTER);
2554
2555 while (ptr->prop_name)
2556 {
2557 VARIANT varref;
2558 LONG ref;
2559
2560 init_saxlexicalhandler(&lexicalhandler, S_OK);
2561 init_saxdeclhandler(&declhandler, S_OK);
2562
2563 V_VT(&v) = VT_EMPTY;
2564 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2565 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2566 EXPECT_HR(hr, S_OK);
2567 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2568 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2569
2570 /* VT_UNKNOWN */
2571 V_VT(&v) = VT_UNKNOWN;
2572 V_UNKNOWN(&v) = ptr->iface;
2573 ref = get_refcount(ptr->iface);
2574 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2575 EXPECT_HR(hr, S_OK);
2576 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2577
2578 /* VT_DISPATCH */
2579 V_VT(&v) = VT_DISPATCH;
2580 V_UNKNOWN(&v) = ptr->iface;
2581 ref = get_refcount(ptr->iface);
2582 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2583 EXPECT_HR(hr, S_OK);
2584 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2585
2586 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2587 V_VT(&varref) = VT_UNKNOWN;
2588 V_UNKNOWN(&varref) = ptr->iface;
2589
2590 V_VT(&v) = VT_VARIANT|VT_BYREF;
2591 V_VARIANTREF(&v) = &varref;
2592 ref = get_refcount(ptr->iface);
2593 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2594 EXPECT_HR(hr, S_OK);
2595 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2596
2597 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2598 V_VT(&varref) = VT_DISPATCH;
2599 V_UNKNOWN(&varref) = ptr->iface;
2600
2601 V_VT(&v) = VT_VARIANT|VT_BYREF;
2602 V_VARIANTREF(&v) = &varref;
2603 ref = get_refcount(ptr->iface);
2604 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2605 EXPECT_HR(hr, S_OK);
2606 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2607
2608 V_VT(&v) = VT_EMPTY;
2609 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2610
2611 ref = get_refcount(ptr->iface);
2612 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2613 EXPECT_HR(hr, S_OK);
2614 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2615 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2616 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2617 VariantClear(&v);
2618
2619 V_VT(&v) = VT_EMPTY;
2620 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2621 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2622 EXPECT_HR(hr, S_OK);
2623
2624 V_VT(&v) = VT_EMPTY;
2625 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2626 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2627 EXPECT_HR(hr, S_OK);
2628 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2629 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2630
2631 V_VT(&v) = VT_UNKNOWN;
2632 V_UNKNOWN(&v) = ptr->iface;
2633 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2634 EXPECT_HR(hr, S_OK);
2635
2636 /* only VT_EMPTY seems to be valid to reset property */
2637 V_VT(&v) = VT_I4;
2638 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2639 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2640 EXPECT_HR(hr, E_INVALIDARG);
2641
2642 V_VT(&v) = VT_EMPTY;
2643 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2644 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2645 EXPECT_HR(hr, S_OK);
2646 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2647 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2648 VariantClear(&v);
2649
2650 V_VT(&v) = VT_UNKNOWN;
2651 V_UNKNOWN(&v) = NULL;
2652 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2653 EXPECT_HR(hr, S_OK);
2654
2655 V_VT(&v) = VT_EMPTY;
2656 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2657 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2658 EXPECT_HR(hr, S_OK);
2659 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2660 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2661
2662 /* block QueryInterface on handler riid */
2663 V_VT(&v) = VT_UNKNOWN;
2664 V_UNKNOWN(&v) = ptr->iface;
2665 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2666 EXPECT_HR(hr, S_OK);
2667
2668 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2669 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2670
2671 V_VT(&v) = VT_UNKNOWN;
2672 V_UNKNOWN(&v) = ptr->iface;
2673 EXPECT_REF(ptr->iface, 1);
2674 ref = get_refcount(ptr->iface);
2675 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2676 EXPECT_HR(hr, E_NOINTERFACE);
2677 EXPECT_REF(ptr->iface, 1);
2678
2679 V_VT(&v) = VT_EMPTY;
2680 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2681 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2682 EXPECT_HR(hr, S_OK);
2683 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2684 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2685
2686 ptr++;
2687 free_bstrs();
2688 }
2689
2690 ISAXXMLReader_Release(reader);
2691
2692 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2693 return;
2694
2695 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2696 &IID_ISAXXMLReader, (void**)&reader);
2697 EXPECT_HR(hr, S_OK);
2698
2699 /* xmldecl-version property */
2700 V_VT(&v) = VT_EMPTY;
2701 V_BSTR(&v) = (void*)0xdeadbeef;
2702 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2703 EXPECT_HR(hr, S_OK);
2704 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2705 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2706
2707 /* stream without declaration */
2708 V_VT(&v) = VT_BSTR;
2709 V_BSTR(&v) = _bstr_("<element></element>");
2710 hr = ISAXXMLReader_parse(reader, v);
2711 EXPECT_HR(hr, S_OK);
2712
2713 V_VT(&v) = VT_EMPTY;
2714 V_BSTR(&v) = (void*)0xdeadbeef;
2715 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2716 EXPECT_HR(hr, S_OK);
2717 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2718 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2719
2720 /* stream with declaration */
2721 V_VT(&v) = VT_BSTR;
2722 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2723 hr = ISAXXMLReader_parse(reader, v);
2724 EXPECT_HR(hr, S_OK);
2725
2726 /* VT_BSTR|VT_BYREF input type */
2727 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2728 V_VT(&v) = VT_BSTR|VT_BYREF;
2729 V_BSTRREF(&v) = &str;
2730 hr = ISAXXMLReader_parse(reader, v);
2731 EXPECT_HR(hr, S_OK);
2732
2733 V_VT(&v) = VT_EMPTY;
2734 V_BSTR(&v) = (void*)0xdeadbeef;
2735 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2736 EXPECT_HR(hr, S_OK);
2737 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2738 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2739 VariantClear(&v);
2740
2741 ISAXXMLReader_Release(reader);
2742 free_bstrs();
2743 }
2744
2745 struct feature_ns_entry_t {
2746 const GUID *guid;
2747 const char *clsid;
2748 VARIANT_BOOL value;
2749 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2750 };
2751
2752 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2753 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2754 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2755 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2756 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2757 { 0 }
2758 };
2759
2760 static const char *feature_names[] = {
2761 "http://xml.org/sax/features/namespaces",
2762 "http://xml.org/sax/features/namespace-prefixes",
2763 0
2764 };
2765
2766 static void test_saxreader_features(void)
2767 {
2768 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2769 ISAXXMLReader *reader;
2770
2771 while (entry->guid)
2772 {
2773 VARIANT_BOOL value;
2774 const char **name;
2775 HRESULT hr;
2776
2777 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2778 if (hr != S_OK)
2779 {
2780 win_skip("can't create %s instance\n", entry->clsid);
2781 entry++;
2782 continue;
2783 }
2784
2785 name = feature_names;
2786 while (*name)
2787 {
2788 value = 0xc;
2789 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2790 EXPECT_HR(hr, S_OK);
2791 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2792
2793 value = 0xc;
2794 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2795 EXPECT_HR(hr, S_OK);
2796
2797 value = 0xd;
2798 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2799 EXPECT_HR(hr, S_OK);
2800 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2801
2802 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2803 EXPECT_HR(hr, S_OK);
2804 value = 0xd;
2805 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2806 EXPECT_HR(hr, S_OK);
2807 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2808
2809 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2810 EXPECT_HR(hr, S_OK);
2811 value = 0xd;
2812 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2813 EXPECT_HR(hr, S_OK);
2814 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2815
2816 name++;
2817 }
2818
2819 ISAXXMLReader_Release(reader);
2820
2821 entry++;
2822 }
2823 }
2824
2825 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2826 static const CHAR UTF8BOMTest[] =
2827 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2828 "<a></a>\n";
2829