43f041c9f18f68205d7887002b62c58fd2000772
[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 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2399 EXPECT_HR(hr, S_OK);
2400
2401 /* switch off 'namespace-prefixes' feature */
2402 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2403 EXPECT_HR(hr, S_OK);
2404
2405 stream = create_test_stream(test_attributes, -1);
2406 V_VT(&var) = VT_UNKNOWN;
2407 V_UNKNOWN(&var) = (IUnknown*)stream;
2408
2409 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2410 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2411 {
2412 test_seq = content_handler_test_attributes_alt_no_prefix;
2413 }
2414 else
2415 test_seq = content_handler_test_attributes_no_prefix;
2416
2417 set_expected_seq(test_seq);
2418 hr = ISAXXMLReader_parse(reader, var);
2419 EXPECT_HR(hr, S_OK);
2420 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2421
2422 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2423 EXPECT_HR(hr, S_OK);
2424
2425 /* attribute normalization */
2426 stream = create_test_stream(attribute_normalize, -1);
2427 V_VT(&var) = VT_UNKNOWN;
2428 V_UNKNOWN(&var) = (IUnknown*)stream;
2429
2430 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2431 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2432 {
2433 test_seq = attribute_norm_alt;
2434 }
2435 else
2436 test_seq = attribute_norm;
2437
2438 set_expected_seq(test_seq);
2439 hr = ISAXXMLReader_parse(reader, var);
2440 EXPECT_HR(hr, S_OK);
2441 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2442 IStream_Release(stream);
2443
2444 resolver = (void*)0xdeadbeef;
2445 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2446 ok(hr == S_OK, "got 0x%08x\n", hr);
2447 ok(resolver == NULL, "got %p\n", resolver);
2448
2449 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2450 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2451
2452 /* CDATA sections */
2453 init_saxlexicalhandler(&lexicalhandler, S_OK);
2454
2455 V_VT(&var) = VT_UNKNOWN;
2456 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2457 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2458 ok(hr == S_OK, "got 0x%08x\n", hr);
2459
2460 stream = create_test_stream(test_cdata_xml, -1);
2461 V_VT(&var) = VT_UNKNOWN;
2462 V_UNKNOWN(&var) = (IUnknown*)stream;
2463
2464 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2465 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2466 test_seq = cdata_test_alt;
2467 else
2468 test_seq = cdata_test;
2469
2470 set_expected_seq(test_seq);
2471 hr = ISAXXMLReader_parse(reader, var);
2472 ok(hr == S_OK, "got 0x%08x\n", hr);
2473 sprintf(seqname, "%s: cdata test", table->name);
2474 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2475
2476 IStream_Release(stream);
2477
2478 /* 2. CDATA sections */
2479 stream = create_test_stream(test2_cdata_xml, -1);
2480 V_VT(&var) = VT_UNKNOWN;
2481 V_UNKNOWN(&var) = (IUnknown*)stream;
2482
2483 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2484 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2485 test_seq = cdata_test2_alt;
2486 else
2487 test_seq = cdata_test2;
2488
2489 set_expected_seq(test_seq);
2490 hr = ISAXXMLReader_parse(reader, var);
2491 ok(hr == S_OK, "got 0x%08x\n", hr);
2492 sprintf(seqname, "%s: cdata test 2", table->name);
2493 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2494
2495 IStream_Release(stream);
2496
2497 /* 3. CDATA sections */
2498 stream = create_test_stream(test3_cdata_xml, -1);
2499 V_VT(&var) = VT_UNKNOWN;
2500 V_UNKNOWN(&var) = (IUnknown*)stream;
2501
2502 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2503 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2504 test_seq = cdata_test3_alt;
2505 else
2506 test_seq = cdata_test3;
2507
2508 set_expected_seq(test_seq);
2509 hr = ISAXXMLReader_parse(reader, var);
2510 ok(hr == S_OK, "got 0x%08x\n", hr);
2511 sprintf(seqname, "%s: cdata test 3", table->name);
2512 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2513
2514 IStream_Release(stream);
2515
2516 ISAXXMLReader_Release(reader);
2517 table++;
2518 }
2519
2520 free_bstrs();
2521 }
2522
2523 struct saxreader_props_test_t
2524 {
2525 const char *prop_name;
2526 IUnknown *iface;
2527 };
2528
2529 static const struct saxreader_props_test_t props_test_data[] = {
2530 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2531 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2532 { 0 }
2533 };
2534
2535 static void test_saxreader_properties(void)
2536 {
2537 const struct saxreader_props_test_t *ptr = props_test_data;
2538 ISAXXMLReader *reader;
2539 HRESULT hr;
2540 VARIANT v;
2541 BSTR str;
2542
2543 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2544 &IID_ISAXXMLReader, (void**)&reader);
2545 EXPECT_HR(hr, S_OK);
2546
2547 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2548 EXPECT_HR(hr, E_POINTER);
2549
2550 while (ptr->prop_name)
2551 {
2552 VARIANT varref;
2553 LONG ref;
2554
2555 init_saxlexicalhandler(&lexicalhandler, S_OK);
2556 init_saxdeclhandler(&declhandler, S_OK);
2557
2558 V_VT(&v) = VT_EMPTY;
2559 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2560 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2561 EXPECT_HR(hr, S_OK);
2562 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2563 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2564
2565 /* VT_UNKNOWN */
2566 V_VT(&v) = VT_UNKNOWN;
2567 V_UNKNOWN(&v) = ptr->iface;
2568 ref = get_refcount(ptr->iface);
2569 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2570 EXPECT_HR(hr, S_OK);
2571 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2572
2573 /* VT_DISPATCH */
2574 V_VT(&v) = VT_DISPATCH;
2575 V_UNKNOWN(&v) = ptr->iface;
2576 ref = get_refcount(ptr->iface);
2577 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2578 EXPECT_HR(hr, S_OK);
2579 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2580
2581 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2582 V_VT(&varref) = VT_UNKNOWN;
2583 V_UNKNOWN(&varref) = ptr->iface;
2584
2585 V_VT(&v) = VT_VARIANT|VT_BYREF;
2586 V_VARIANTREF(&v) = &varref;
2587 ref = get_refcount(ptr->iface);
2588 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2589 EXPECT_HR(hr, S_OK);
2590 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2591
2592 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2593 V_VT(&varref) = VT_DISPATCH;
2594 V_UNKNOWN(&varref) = ptr->iface;
2595
2596 V_VT(&v) = VT_VARIANT|VT_BYREF;
2597 V_VARIANTREF(&v) = &varref;
2598 ref = get_refcount(ptr->iface);
2599 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2600 EXPECT_HR(hr, S_OK);
2601 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2602
2603 V_VT(&v) = VT_EMPTY;
2604 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2605
2606 ref = get_refcount(ptr->iface);
2607 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2608 EXPECT_HR(hr, S_OK);
2609 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2610 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2611 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2612 VariantClear(&v);
2613
2614 V_VT(&v) = VT_EMPTY;
2615 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2616 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2617 EXPECT_HR(hr, S_OK);
2618
2619 V_VT(&v) = VT_EMPTY;
2620 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2621 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2622 EXPECT_HR(hr, S_OK);
2623 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2624 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2625
2626 V_VT(&v) = VT_UNKNOWN;
2627 V_UNKNOWN(&v) = ptr->iface;
2628 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2629 EXPECT_HR(hr, S_OK);
2630
2631 /* only VT_EMPTY seems to be valid to reset property */
2632 V_VT(&v) = VT_I4;
2633 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2634 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2635 EXPECT_HR(hr, E_INVALIDARG);
2636
2637 V_VT(&v) = VT_EMPTY;
2638 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2639 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2640 EXPECT_HR(hr, S_OK);
2641 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2642 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2643 VariantClear(&v);
2644
2645 V_VT(&v) = VT_UNKNOWN;
2646 V_UNKNOWN(&v) = NULL;
2647 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2648 EXPECT_HR(hr, S_OK);
2649
2650 V_VT(&v) = VT_EMPTY;
2651 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2652 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2653 EXPECT_HR(hr, S_OK);
2654 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2655 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2656
2657 /* block QueryInterface on handler riid */
2658 V_VT(&v) = VT_UNKNOWN;
2659 V_UNKNOWN(&v) = ptr->iface;
2660 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2661 EXPECT_HR(hr, S_OK);
2662
2663 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2664 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2665
2666 V_VT(&v) = VT_UNKNOWN;
2667 V_UNKNOWN(&v) = ptr->iface;
2668 EXPECT_REF(ptr->iface, 1);
2669 ref = get_refcount(ptr->iface);
2670 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2671 EXPECT_HR(hr, E_NOINTERFACE);
2672 EXPECT_REF(ptr->iface, 1);
2673
2674 V_VT(&v) = VT_EMPTY;
2675 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2676 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2677 EXPECT_HR(hr, S_OK);
2678 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2679 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2680
2681 ptr++;
2682 free_bstrs();
2683 }
2684
2685 ISAXXMLReader_Release(reader);
2686
2687 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2688 return;
2689
2690 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2691 &IID_ISAXXMLReader, (void**)&reader);
2692 EXPECT_HR(hr, S_OK);
2693
2694 /* xmldecl-version property */
2695 V_VT(&v) = VT_EMPTY;
2696 V_BSTR(&v) = (void*)0xdeadbeef;
2697 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2698 EXPECT_HR(hr, S_OK);
2699 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2700 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2701
2702 /* stream without declaration */
2703 V_VT(&v) = VT_BSTR;
2704 V_BSTR(&v) = _bstr_("<element></element>");
2705 hr = ISAXXMLReader_parse(reader, v);
2706 EXPECT_HR(hr, S_OK);
2707
2708 V_VT(&v) = VT_EMPTY;
2709 V_BSTR(&v) = (void*)0xdeadbeef;
2710 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2711 EXPECT_HR(hr, S_OK);
2712 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2713 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2714
2715 /* stream with declaration */
2716 V_VT(&v) = VT_BSTR;
2717 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2718 hr = ISAXXMLReader_parse(reader, v);
2719 EXPECT_HR(hr, S_OK);
2720
2721 /* VT_BSTR|VT_BYREF input type */
2722 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2723 V_VT(&v) = VT_BSTR|VT_BYREF;
2724 V_BSTRREF(&v) = &str;
2725 hr = ISAXXMLReader_parse(reader, v);
2726 EXPECT_HR(hr, S_OK);
2727
2728 V_VT(&v) = VT_EMPTY;
2729 V_BSTR(&v) = (void*)0xdeadbeef;
2730 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2731 EXPECT_HR(hr, S_OK);
2732 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2733 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2734 VariantClear(&v);
2735
2736 ISAXXMLReader_Release(reader);
2737 free_bstrs();
2738 }
2739
2740 struct feature_ns_entry_t {
2741 const GUID *guid;
2742 const char *clsid;
2743 VARIANT_BOOL value;
2744 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2745 };
2746
2747 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2748 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2749 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2750 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2751 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2752 { 0 }
2753 };
2754
2755 static const char *feature_names[] = {
2756 "http://xml.org/sax/features/namespaces",
2757 "http://xml.org/sax/features/namespace-prefixes",
2758 0
2759 };
2760
2761 static void test_saxreader_features(void)
2762 {
2763 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2764 ISAXXMLReader *reader;
2765
2766 while (entry->guid)
2767 {
2768 VARIANT_BOOL value;
2769 const char **name;
2770 HRESULT hr;
2771
2772 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2773 if (hr != S_OK)
2774 {
2775 win_skip("can't create %s instance\n", entry->clsid);
2776 entry++;
2777 continue;
2778 }
2779
2780 name = feature_names;
2781 while (*name)
2782 {
2783 value = 0xc;
2784 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2785 EXPECT_HR(hr, S_OK);
2786 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2787
2788 value = 0xc;
2789 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2790 EXPECT_HR(hr, S_OK);
2791
2792 value = 0xd;
2793 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2794 EXPECT_HR(hr, S_OK);
2795 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2796
2797 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2798 EXPECT_HR(hr, S_OK);
2799 value = 0xd;
2800 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2801 EXPECT_HR(hr, S_OK);
2802 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2803
2804 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2805 EXPECT_HR(hr, S_OK);
2806 value = 0xd;
2807 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2808 EXPECT_HR(hr, S_OK);
2809 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2810
2811 name++;
2812 }
2813
2814 ISAXXMLReader_Release(reader);
2815
2816 entry++;
2817 }
2818 }
2819
2820 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2821 static const CHAR UTF8BOMTest[] =
2822 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2823 "<a></a>\n";
2824
2825 struct enc_test_entry_t {
2826 const GUID *guid;
2827 const char *clsid;
2828 const char *data;
2829 HRESULT hr;
2830 BOOL todo;
2831 };
2832
2833 static const struct enc_test_entry_t encoding_test_data[] = {
2834 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2835 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2836 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2837 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2838 { 0 }
2839 };
2840
2841 static void test_saxreader_encoding(void)
2842 {
2843 const struct enc_test_entry_t *entry = encoding_test_data;
2844 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2845 static const CHAR testXmlA[] = "test.xml";
2846
2847 while (entry->guid)
2848 {
2849 ISAXXMLReader *reader;
2850 VARIANT input;
2851 DWORD written;
2852 HANDLE file;
2853 HRESULT hr;
2854
2855 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2856 if (hr != S_OK)
2857 {
2858 win_skip("can't create %s instance\n", entry->clsid);
2859 entry++;
2860 continue;
2861 }
2862
2863 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2864 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2865 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2866 CloseHandle(file);
2867
2868 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2869 if (entry->todo)
2870 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2871 else
2872 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2873
2874 DeleteFileA(testXmlA);
2875
2876 /* try BSTR input with no BOM or '<?xml' instruction */
2877 V_VT(&input) = VT_BSTR;
2878 V_BSTR(&input) = _bstr_("<element></element>");
2879 hr = ISAXXMLReader_parse(reader, input);
2880 EXPECT_HR(hr, S_OK);
2881
2882 ISAXXMLReader_Release(reader);
2883
2884 free_bstrs();
2885 entry++;
2886 }
2887 }
2888
2889 static void test_mxwriter_handlers(void)
2890 {
2891 IMXWriter *writer;
2892 HRESULT hr;
2893 int i;
2894
2895 static REFIID riids[] =
2896 {
2897 &IID_ISAXContentHandler,
2898 &IID_ISAXLexicalHandler,
2899 &IID_ISAXDeclHandler,
2900 &IID_ISAXDTDHandler,
2901 &IID_ISAXErrorHandler,
2902 &IID_IVBSAXDeclHandler,
2903 &IID_IVBSAXLexicalHandler,
2904 &IID_IVBSAXContentHandler,
2905 &IID_IVBSAXDTDHandler,
2906 &IID_IVBSAXErrorHandler
2907 };
2908
2909 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2910 &IID_IMXWriter, (void**)&writer);
2911 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2912
2913 EXPECT_REF(writer, 1);
2914
2915 for (i = 0; i < sizeof(riids)/sizeof(REFIID); i++)
2916 {
2917 IUnknown *handler;
2918 IMXWriter *writer2;
2919
2920 /* handler from IMXWriter */
2921 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2922 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2923 EXPECT_REF(writer, 2);
2924 EXPECT_REF(handler, 2);
2925
2926 /* IMXWriter from a handler */
2927 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2928 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2929 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2930 EXPECT_REF(writer, 3);
2931 EXPECT_REF(writer2, 3);
2932 IMXWriter_Release(writer2);
2933 IUnknown_Release(handler);
2934 }
2935
2936 IMXWriter_Release(writer);
2937 }
2938
2939 static struct msxmlsupported_data_t mxwriter_support_data[] =
2940 {
2941 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2942 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2943 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2944 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2945 { NULL }
2946 };
2947
2948 static struct msxmlsupported_data_t mxattributes_support_data[] =
2949 {
2950 { &CLSID_SAXAttributes, "SAXAttributes" },
2951 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2952 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2953 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2954 { NULL }
2955 };
2956
2957 struct mxwriter_props_t
2958 {
2959 const GUID *clsid;
2960 VARIANT_BOOL bom;
2961 VARIANT_BOOL disable_escape;
2962 VARIANT_BOOL indent;
2963 VARIANT_BOOL omitdecl;
2964 VARIANT_BOOL standalone;
2965 const char *encoding;
2966 };
2967
2968 static const struct mxwriter_props_t mxwriter_default_props[] =
2969 {
2970 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2971 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2972 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2973 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2974 { NULL }
2975 };
2976
2977 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2978 {
2979 int i = 0;
2980
2981 while (table->clsid)
2982 {
2983 IMXWriter *writer;
2984 VARIANT_BOOL b;
2985 BSTR encoding;
2986 HRESULT hr;
2987
2988 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2989 {
2990 table++;
2991 i++;
2992 continue;
2993 }
2994
2995 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2996 &IID_IMXWriter, (void**)&writer);
2997 EXPECT_HR(hr, S_OK);
2998
2999 b = !table->bom;
3000 hr = IMXWriter_get_byteOrderMark(writer, &b);
3001 EXPECT_HR(hr, S_OK);
3002 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3003
3004 b = !table->disable_escape;
3005 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3006 EXPECT_HR(hr, S_OK);
3007 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3008 table->disable_escape);
3009
3010 b = !table->indent;
3011 hr = IMXWriter_get_indent(writer, &b);
3012 EXPECT_HR(hr, S_OK);
3013 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3014
3015 b = !table->omitdecl;
3016 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3017 EXPECT_HR(hr, S_OK);
3018 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3019
3020 b = !table->standalone;
3021 hr = IMXWriter_get_standalone(writer, &b);
3022 EXPECT_HR(hr, S_OK);
3023 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3024
3025 hr = IMXWriter_get_encoding(writer, &encoding);
3026 EXPECT_HR(hr, S_OK);
3027 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3028 i, wine_dbgstr_w(encoding), table->encoding);
3029 SysFreeString(encoding);
3030
3031 IMXWriter_Release(writer);
3032
3033 table++;
3034 i++;
3035 }
3036 }
3037
3038 static void test_mxwriter_properties(void)
3039 {
3040 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3041 static const WCHAR testW[] = {'t','e','s','t',0};
3042 ISAXContentHandler *content;
3043 IMXWriter *writer;
3044 VARIANT_BOOL b;
3045 HRESULT hr;
3046 BSTR str, str2;
3047 VARIANT dest;
3048
3049 test_mxwriter_default_properties(mxwriter_default_props);
3050
3051 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3052 &IID_IMXWriter, (void**)&writer);
3053 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3054
3055 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3056 ok(hr == E_POINTER, "got %08x\n", hr);
3057
3058 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3059 ok(hr == E_POINTER, "got %08x\n", hr);
3060
3061 hr = IMXWriter_get_indent(writer, NULL);
3062 ok(hr == E_POINTER, "got %08x\n", hr);
3063
3064 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3065 ok(hr == E_POINTER, "got %08x\n", hr);
3066
3067 hr = IMXWriter_get_standalone(writer, NULL);
3068 ok(hr == E_POINTER, "got %08x\n", hr);
3069
3070 /* set and check */
3071 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3072 ok(hr == S_OK, "got %08x\n", hr);
3073
3074 b = VARIANT_FALSE;
3075 hr = IMXWriter_get_standalone(writer, &b);
3076 ok(hr == S_OK, "got %08x\n", hr);
3077 ok(b == VARIANT_TRUE, "got %d\n", b);
3078
3079 hr = IMXWriter_get_encoding(writer, NULL);
3080 EXPECT_HR(hr, E_POINTER);
3081
3082 /* UTF-16 is a default setting apparently */
3083 str = (void*)0xdeadbeef;
3084 hr = IMXWriter_get_encoding(writer, &str);
3085 EXPECT_HR(hr, S_OK);
3086 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3087
3088 str2 = (void*)0xdeadbeef;
3089 hr = IMXWriter_get_encoding(writer, &str2);
3090 ok(hr == S_OK, "got %08x\n", hr);
3091 ok(str != str2, "expected newly allocated, got same %p\n", str);
3092
3093 SysFreeString(str2);
3094 SysFreeString(str);
3095
3096 /* put empty string */
3097 str = SysAllocString(emptyW);
3098 hr = IMXWriter_put_encoding(writer, str);
3099 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3100 SysFreeString(str);
3101
3102 str = (void*)0xdeadbeef;
3103 hr = IMXWriter_get_encoding(writer, &str);
3104 EXPECT_HR(hr, S_OK);
3105 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3106 SysFreeString(str);
3107
3108 /* invalid encoding name */
3109 str = SysAllocString(testW);
3110 hr = IMXWriter_put_encoding(writer, str);
3111 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3112 SysFreeString(str);
3113
3114 /* test case sensivity */
3115 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3116 EXPECT_HR(hr, S_OK);
3117 str = (void*)0xdeadbeef;
3118 hr = IMXWriter_get_encoding(writer, &str);
3119 EXPECT_HR(hr, S_OK);
3120 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3121 SysFreeString(str);
3122
3123 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3124 EXPECT_HR(hr, S_OK);
3125 str = (void*)0xdeadbeef;
3126 hr = IMXWriter_get_encoding(writer, &str);
3127 EXPECT_HR(hr, S_OK);
3128 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3129 SysFreeString(str);
3130
3131 /* how it affects document creation */
3132 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3133 EXPECT_HR(hr, S_OK);
3134
3135 hr = ISAXContentHandler_startDocument(content);
3136 EXPECT_HR(hr, S_OK);
3137 hr = ISAXContentHandler_endDocument(content);
3138 EXPECT_HR(hr, S_OK);
3139
3140 V_VT(&dest) = VT_EMPTY;
3141 hr = IMXWriter_get_output(writer, &dest);
3142 EXPECT_HR(hr, S_OK);
3143 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3144 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3145 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3146 VariantClear(&dest);
3147 ISAXContentHandler_Release(content);
3148
3149 hr = IMXWriter_get_version(writer, NULL);
3150 ok(hr == E_POINTER, "got %08x\n", hr);
3151 /* default version is 'surprisingly' 1.0 */
3152 hr = IMXWriter_get_version(writer, &str);
3153 ok(hr == S_OK, "got %08x\n", hr);
3154 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3155 SysFreeString(str);
3156
3157 /* store version string as is */
3158 hr = IMXWriter_put_version(writer, NULL);
3159 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3160
3161 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3162 ok(hr == S_OK, "got %08x\n", hr);
3163
3164 hr = IMXWriter_put_version(writer, _bstr_(""));
3165 ok(hr == S_OK, "got %08x\n", hr);
3166 hr = IMXWriter_get_version(writer, &str);
3167 ok(hr == S_OK, "got %08x\n", hr);
3168 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3169 SysFreeString(str);
3170
3171 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3172 ok(hr == S_OK, "got %08x\n", hr);
3173 hr = IMXWriter_get_version(writer, &str);
3174 ok(hr == S_OK, "got %08x\n", hr);
3175 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3176 SysFreeString(str);
3177
3178 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3179 ok(hr == S_OK, "got %08x\n", hr);
3180 hr = IMXWriter_get_version(writer, &str);
3181 ok(hr == S_OK, "got %08x\n", hr);
3182 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3183 SysFreeString(str);
3184
3185 IMXWriter_Release(writer);
3186 free_bstrs();
3187 }
3188
3189 static void test_mxwriter_flush(void)
3190 {
3191 ISAXContentHandler *content;
3192 IMXWriter *writer;
3193 LARGE_INTEGER pos;
3194 ULARGE_INTEGER pos2;
3195 IStream *stream;
3196 VARIANT dest;
3197 HRESULT hr;
3198 char *buff;
3199 LONG ref;
3200 int len;
3201
3202 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3203 &IID_IMXWriter, (void**)&writer);
3204 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3205
3206 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3207 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3208 EXPECT_REF(stream, 1);
3209
3210 /* detach when nothing was attached */
3211 V_VT(&dest) = VT_EMPTY;
3212 hr = IMXWriter_put_output(writer, dest);
3213 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3214
3215