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