[MSXML3_WINETEST]
[reactos.git] / rostests / winetests / msxml3 / saxreader.c
1 /*
2 * SAXReader/MXWriter tests
3 *
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #define WIN32_NO_STATUS
24 #define _INC_WINDOWS
25 #define COM_NO_WINDOWS_H
26
27 #define COBJMACROS
28 #define CONST_VTABLE
29
30 #include <stdio.h>
31 #include <assert.h>
32
33 #include <wine/test.h>
34 //#include "windows.h"
35 #include <winnls.h>
36 #include <ole2.h>
37 #include <msxml2.h>
38 #include <msxml2did.h>
39 //#include "ocidl.h"
40 #include <dispex.h>
41
42 static const WCHAR emptyW[] = {0};
43
44 #define EXPECT_HR(hr,hr_exp) \
45 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
46
47 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
48 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
49 {
50 ULONG rc = IUnknown_AddRef(obj);
51 IUnknown_Release(obj);
52 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
53 }
54
55 static LONG get_refcount(void *iface)
56 {
57 IUnknown *unk = iface;
58 LONG ref;
59
60 ref = IUnknown_AddRef(unk);
61 IUnknown_Release(unk);
62 return ref-1;
63 }
64
65 struct msxmlsupported_data_t
66 {
67 const GUID *clsid;
68 const char *name;
69 BOOL supported;
70 };
71
72 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
73 {
74 while (table->clsid)
75 {
76 if (table->clsid == clsid) return table->supported;
77 table++;
78 }
79 return FALSE;
80 }
81
82 static BSTR alloc_str_from_narrow(const char *str)
83 {
84 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
85 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
86 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
87 return ret;
88 }
89
90 static BSTR alloced_bstrs[512];
91 static int alloced_bstrs_count;
92
93 static BSTR _bstr_(const char *str)
94 {
95 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
96 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
97 return alloced_bstrs[alloced_bstrs_count++];
98 }
99
100 static void free_bstrs(void)
101 {
102 int i;
103 for (i = 0; i < alloced_bstrs_count; i++)
104 SysFreeString(alloced_bstrs[i]);
105 alloced_bstrs_count = 0;
106 }
107
108 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount)
109 {
110 int len, lenexp, cmp;
111 WCHAR buf[1024];
112
113 len = SysStringLen(str);
114
115 if (!expected) {
116 if (str && todo)
117 {
118 (*failcount)++;
119 todo_wine
120 ok_(file, line) (!str, "got %p, expected null str\n", str);
121 }
122 else
123 ok_(file, line) (!str, "got %p, expected null str\n", str);
124
125 if (len && todo)
126 {
127 (*failcount)++;
128 todo_wine
129 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
130 }
131 else
132 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
133 return;
134 }
135
136 lenexp = strlen(expected);
137 if (lenexp != len && todo)
138 {
139 (*failcount)++;
140 todo_wine
141 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
142 }
143 else
144 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
145
146 /* exit earlier on length mismatch */
147 if (lenexp != len) return;
148
149 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
150
151 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
152 if (cmp && todo)
153 {
154 (*failcount)++;
155 todo_wine
156 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
157 wine_dbgstr_wn(str, len), expected);
158 }
159 else
160 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
161 wine_dbgstr_wn(str, len), expected);
162 }
163
164 typedef enum _CH {
165 CH_ENDTEST,
166 CH_PUTDOCUMENTLOCATOR,
167 CH_STARTDOCUMENT,
168 CH_ENDDOCUMENT,
169 CH_STARTPREFIXMAPPING,
170 CH_ENDPREFIXMAPPING,
171 CH_STARTELEMENT,
172 CH_ENDELEMENT,
173 CH_CHARACTERS,
174 CH_IGNORABLEWHITESPACE,
175 CH_PROCESSINGINSTRUCTION,
176 CH_SKIPPEDENTITY,
177 LH_STARTCDATA,
178 LH_ENDCDATA,
179 EH_ERROR,
180 EH_FATALERROR,
181 EH_IGNORABLEWARNING,
182 EVENT_LAST
183 } CH;
184
185 static const char *event_names[EVENT_LAST] = {
186 "endtest",
187 "putDocumentLocator",
188 "startDocument",
189 "endDocument",
190 "startPrefixMapping",
191 "endPrefixMapping",
192 "startElement",
193 "endElement",
194 "characters",
195 "ignorableWhitespace",
196 "processingInstruction",
197 "skippedEntity",
198 "startCDATA",
199 "endCDATA",
200 "error",
201 "fatalError",
202 "ignorableWarning"
203 };
204
205 struct attribute_entry {
206 const char *uri;
207 const char *local;
208 const char *qname;
209 const char *value;
210
211 /* used for actual call data only, null for expected call data */
212 BSTR uriW;
213 BSTR localW;
214 BSTR qnameW;
215 BSTR valueW;
216 };
217
218 struct call_entry {
219 CH id;
220 int line;
221 int column;
222 HRESULT ret;
223 const char *arg1;
224 const char *arg2;
225 const char *arg3;
226
227 /* allocated once at startElement callback */
228 struct attribute_entry *attributes;
229 int attr_count;
230
231 /* used for actual call data only, null for expected call data */
232 BSTR arg1W;
233 BSTR arg2W;
234 BSTR arg3W;
235 };
236
237 struct call_sequence
238 {
239 int count;
240 int size;
241 struct call_entry *sequence;
242 };
243
244 #define CONTENT_HANDLER_INDEX 0
245 #define NUM_CALL_SEQUENCES 1
246 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
247
248 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
249 {
250 memset(call, 0, sizeof(*call));
251 ISAXLocator_getLineNumber(locator, &call->line);
252 ISAXLocator_getColumnNumber(locator, &call->column);
253 }
254
255 static void add_call(struct call_sequence **seq, int sequence_index,
256 const struct call_entry *call)
257 {
258 struct call_sequence *call_seq = seq[sequence_index];
259
260 if (!call_seq->sequence)
261 {
262 call_seq->size = 10;
263 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
264 call_seq->size * sizeof (struct call_entry));
265 }
266
267 if (call_seq->count == call_seq->size)
268 {
269 call_seq->size *= 2;
270 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
271 call_seq->sequence,
272 call_seq->size * sizeof (struct call_entry));
273 }
274
275 assert(call_seq->sequence);
276
277 call_seq->sequence[call_seq->count].id = call->id;
278 call_seq->sequence[call_seq->count].line = call->line;
279 call_seq->sequence[call_seq->count].column = call->column;
280 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
281 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
282 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
283 call_seq->sequence[call_seq->count].ret = call->ret;
284 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
285 call_seq->sequence[call_seq->count].attributes = call->attributes;
286
287 call_seq->count++;
288 }
289
290 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
291 {
292 int i;
293
294 struct call_sequence *call_seq = seg[sequence_index];
295
296 for (i = 0; i < call_seq->count; i++)
297 {
298 int j;
299
300 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
301 {
302 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
303 SysFreeString(call_seq->sequence[i].attributes[j].localW);
304 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
305 }
306
307 SysFreeString(call_seq->sequence[i].arg1W);
308 SysFreeString(call_seq->sequence[i].arg2W);
309 SysFreeString(call_seq->sequence[i].arg3W);
310 }
311
312 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
313 call_seq->sequence = NULL;
314 call_seq->count = call_seq->size = 0;
315 }
316
317 static inline void flush_sequences(struct call_sequence **seq, int n)
318 {
319 int i;
320 for (i = 0; i < n; i++)
321 flush_sequence(seq, i);
322 }
323
324 static const char *get_event_name(CH event)
325 {
326 return event_names[event];
327 }
328
329 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
330 BOOL todo, const char *file, int line, int *failcount)
331 {
332 int i, lenexp = 0;
333
334 /* attribute count is not stored for expected data */
335 if (expected->attributes)
336 {
337 struct attribute_entry *ptr = expected->attributes;
338 while (ptr->uri) { lenexp++; ptr++; };
339 }
340
341 /* check count first and exit earlier */
342 if (actual->attr_count != lenexp && todo)
343 {
344 (*failcount)++;
345 todo_wine
346 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
347 context, get_event_name(actual->id), lenexp, actual->attr_count);
348 }
349 else
350 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
351 context, get_event_name(actual->id), lenexp, actual->attr_count);
352
353 if (actual->attr_count != lenexp) return;
354
355 /* now compare all attributes strings */
356 for (i = 0; i < actual->attr_count; i++)
357 {
358 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
359 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
360 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
361 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
362 }
363 }
364
365 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
366 const struct call_entry *expected, const char *context, BOOL todo,
367 const char *file, int line)
368 {
369 struct call_sequence *call_seq = seq[sequence_index];
370 static const struct call_entry end_of_sequence = { CH_ENDTEST };
371 const struct call_entry *actual, *sequence;
372 int failcount = 0;
373
374 add_call(seq, sequence_index, &end_of_sequence);
375
376 sequence = call_seq->sequence;
377 actual = sequence;
378
379 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
380 {
381 if (expected->id == actual->id)
382 {
383 if (expected->line != -1)
384 {
385 /* always test position data */
386 if (expected->line != actual->line && todo)
387 {
388 todo_wine
389 {
390 failcount++;
391 ok_(file, line) (FALSE,
392 "%s: in event %s expecting line %d got %d\n",
393 context, get_event_name(actual->id), expected->line, actual->line);
394 }
395 }
396 else
397 {
398 ok_(file, line) (expected->line == actual->line,
399 "%s: in event %s expecting line %d got %d\n",
400 context, get_event_name(actual->id), expected->line, actual->line);
401 }
402 }
403
404
405 if (expected->column != -1)
406 {
407 if (expected->column != actual->column && todo)
408 {
409 todo_wine
410 {
411 failcount++;
412 ok_(file, line) (FALSE,
413 "%s: in event %s expecting column %d got %d\n",
414 context, get_event_name(actual->id), expected->column, actual->column);
415 }
416 }
417 else
418 {
419 ok_(file, line) (expected->column == actual->column,
420 "%s: in event %s expecting column %d got %d\n",
421 context, get_event_name(actual->id), expected->column, actual->column);
422 }
423 }
424
425 switch (actual->id)
426 {
427 case CH_PUTDOCUMENTLOCATOR:
428 case CH_STARTDOCUMENT:
429 case CH_ENDDOCUMENT:
430 case LH_STARTCDATA:
431 case LH_ENDCDATA:
432 break;
433 case CH_STARTPREFIXMAPPING:
434 /* prefix, uri */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
437 break;
438 case CH_ENDPREFIXMAPPING:
439 /* prefix */
440 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
441 break;
442 case CH_STARTELEMENT:
443 /* compare attributes */
444 compare_attributes(actual, expected, context, todo, file, line, &failcount);
445 /* fallthrough */
446 case CH_ENDELEMENT:
447 /* uri, localname, qname */
448 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
449 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
450 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
451 break;
452 case CH_CHARACTERS:
453 case CH_IGNORABLEWHITESPACE:
454 /* char data */
455 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
456 break;
457 case CH_PROCESSINGINSTRUCTION:
458 /* target, data */
459 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
460 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
461 break;
462 case CH_SKIPPEDENTITY:
463 /* name */
464 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
465 break;
466 case EH_FATALERROR:
467 /* test return value only */
468 if (expected->ret != actual->ret && todo)
469 {
470 failcount++;
471 ok_(file, line) (FALSE,
472 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
473 context, get_event_name(actual->id), expected->ret, actual->ret);
474 }
475 else
476 ok_(file, line) (expected->ret == actual->ret,
477 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
478 context, get_event_name(actual->id), expected->ret, actual->ret);
479 break;
480 case EH_ERROR:
481 case EH_IGNORABLEWARNING:
482 default:
483 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
484 }
485 expected++;
486 actual++;
487 }
488 else if (todo)
489 {
490 failcount++;
491 todo_wine
492 {
493 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
494 context, get_event_name(expected->id), get_event_name(actual->id));
495 }
496
497 flush_sequence(seq, sequence_index);
498 return;
499 }
500 else
501 {
502 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
503 context, get_event_name(expected->id), get_event_name(actual->id));
504 expected++;
505 actual++;
506 }
507 }
508
509 if (todo)
510 {
511 todo_wine
512 {
513 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
514 {
515 failcount++;
516 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
517 context, get_event_name(expected->id), get_event_name(actual->id));
518 }
519 }
520 }
521 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
522 {
523 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
524 context, get_event_name(expected->id), get_event_name(actual->id));
525 }
526
527 if (todo && !failcount) /* succeeded yet marked todo */
528 {
529 todo_wine
530 {
531 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
532 }
533 }
534
535 flush_sequence(seq, sequence_index);
536 }
537
538 #define ok_sequence(seq, index, exp, contx, todo) \
539 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
540
541 static void init_call_sequences(struct call_sequence **seq, int n)
542 {
543 int i;
544
545 for (i = 0; i < n; i++)
546 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
547 }
548
549 static const WCHAR szSimpleXML[] = {
550 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
551 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
552 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
553 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
554 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
555 };
556
557 static const WCHAR carriage_ret_test[] = {
558 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
559 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
560 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
561 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
562 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
563 };
564
565 static const WCHAR szUtf16XML[] = {
566 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
567 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
568 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
569 };
570
571 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
572
573 static const CHAR szUtf8XML[] =
574 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
575
576 static const char utf8xml2[] =
577 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
578
579 static const char testXML[] =
580 "<?xml version=\"1.0\" ?>\n"
581 "<BankAccount>\n"
582 " <Number>1234</Number>\n"
583 " <Name>Captain Ahab</Name>\n"
584 "</BankAccount>\n";
585
586 static const char test_attributes[] =
587 "<?xml version=\"1.0\" ?>\n"
588 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
589 "<node1 xmlns:p=\"test\" />"
590 "</document>\n";
591
592 static const char test_cdata_xml[] =
593 "<?xml version=\"1.0\" ?>"
594 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
595
596 static const char test2_cdata_xml[] =
597 "<?xml version=\"1.0\" ?>"
598 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
599
600 static const char test3_cdata_xml[] =
601 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
602
603 static struct call_entry content_handler_test1[] = {
604 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
605 { CH_STARTDOCUMENT, 0, 0, S_OK },
606 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
607 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
608 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
609 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
610 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
611 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
612 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
613 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
614 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
615 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
616 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
617 { CH_ENDDOCUMENT, 0, 0, S_OK},
618 { CH_ENDTEST }
619 };
620
621 /* applies to versions 4 and 6 */
622 static struct call_entry content_handler_test1_alternate[] = {
623 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
624 { CH_STARTDOCUMENT, 1, 22, S_OK },
625 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
626 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
627 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
628 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
629 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
630 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
631 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
632 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
633 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
634 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
635 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
636 { CH_ENDDOCUMENT, 6, 0, S_OK },
637 { CH_ENDTEST }
638 };
639
640 static struct call_entry content_handler_test2[] = {
641 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
642 { CH_STARTDOCUMENT, 0, 0, S_OK },
643 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
644 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
645 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
646 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
647 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
648 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
649 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
650 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
651 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
652 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
653 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
654 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
655 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
656 { CH_ENDDOCUMENT, 0, 0, S_OK },
657 { CH_ENDTEST }
658 };
659
660 static struct call_entry content_handler_test2_alternate[] = {
661 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
662 { CH_STARTDOCUMENT, 1, 21, S_OK },
663 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
664 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
665 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
666 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
667 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
668 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
669 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
670 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
671 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
672 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
673 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
674 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
675 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
676 { CH_ENDDOCUMENT, 6, 0, S_OK },
677 { CH_ENDTEST }
678 };
679
680 static struct call_entry content_handler_testerror[] = {
681 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
682 { EH_FATALERROR, 0, 0, E_FAIL },
683 { CH_ENDTEST }
684 };
685
686 static struct call_entry content_handler_testerror_alternate[] = {
687 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
688 { EH_FATALERROR, 1, 0, E_FAIL },
689 { CH_ENDTEST }
690 };
691
692 static struct call_entry content_handler_test_callback_rets[] = {
693 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
694 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
695 { EH_FATALERROR, 0, 0, S_FALSE },
696 { CH_ENDTEST }
697 };
698
699 static struct call_entry content_handler_test_callback_rets_alt[] = {
700 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
701 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
702 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
703 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
704 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
705 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
706 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
707 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
708 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
709 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
710 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
711 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
712 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
713 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
714 { CH_ENDTEST }
715 };
716
717 static struct attribute_entry ch_attributes1[] = {
718 { "", "", "xmlns:test", "prefix_test" },
719 { "", "", "xmlns", "prefix" },
720 { "prefix_test", "arg1", "test:arg1", "arg1" },
721 { "", "arg2", "arg2", "arg2" },
722 { "prefix_test", "ar3", "test:ar3", "arg3" },
723 { NULL }
724 };
725
726 static struct attribute_entry ch_attributes2[] = {
727 { "", "", "xmlns:p", "test" },
728 { NULL }
729 };
730
731 static struct call_entry content_handler_test_attributes[] = {
732 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
733 { CH_STARTDOCUMENT, 0, 0, S_OK },
734 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
735 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
736 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
737 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
738 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
739 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
740 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
741 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
742 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
743 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
744 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
745 { CH_ENDDOCUMENT, 0, 0 },
746 { CH_ENDTEST }
747 };
748
749 static struct attribute_entry ch_attributes_alt_4[] = {
750 { "prefix_test", "arg1", "test:arg1", "arg1" },
751 { "", "arg2", "arg2", "arg2" },
752 { "prefix_test", "ar3", "test:ar3", "arg3" },
753 { "", "", "xmlns:test", "prefix_test" },
754 { "", "", "xmlns", "prefix" },
755 { NULL }
756 };
757
758 static struct call_entry content_handler_test_attributes_alternate_4[] = {
759 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
760 { CH_STARTDOCUMENT, 1, 22, S_OK },
761 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
762 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
763 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
764 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
765 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
766 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
767 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
768 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
769 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
770 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
771 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
772 { CH_ENDDOCUMENT, 4, 0, S_OK },
773 { CH_ENDTEST }
774 };
775
776 /* 'namespace' feature switched off */
777 static struct attribute_entry ch_attributes_alt_no_ns[] = {
778 { "", "", "xmlns:test", "prefix_test" },
779 { "", "", "xmlns", "prefix" },
780 { "", "", "test:arg1", "arg1" },
781 { "", "", "arg2", "arg2" },
782 { "", "", "test:ar3", "arg3" },
783 { NULL }
784 };
785
786 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
787 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
788 { CH_STARTDOCUMENT, 1, 22, S_OK },
789 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
790 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
791 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
792 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
793 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
794 { CH_ENDDOCUMENT, 4, 0, S_OK },
795 { CH_ENDTEST }
796 };
797
798 static struct attribute_entry ch_attributes_alt_6[] = {
799 { "prefix_test", "arg1", "test:arg1", "arg1" },
800 { "", "arg2", "arg2", "arg2" },
801 { "prefix_test", "ar3", "test:ar3", "arg3" },
802 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
803 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
804 { NULL }
805 };
806
807 static struct attribute_entry ch_attributes2_6[] = {
808 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
809 { NULL }
810 };
811
812 static struct call_entry content_handler_test_attributes_alternate_6[] = {
813 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
814 { CH_STARTDOCUMENT, 1, 22, S_OK },
815 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
816 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
817 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
818 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
819 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
820 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
821 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
822 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
823 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
824 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
825 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
826 { CH_ENDDOCUMENT, 4, 0, S_OK },
827 { CH_ENDTEST }
828 };
829
830 /* 'namespaces' is on, 'namespace-prefixes' if off */
831 static struct attribute_entry ch_attributes_no_prefix[] = {
832 { "prefix_test", "arg1", "test:arg1", "arg1" },
833 { "", "arg2", "arg2", "arg2" },
834 { "prefix_test", "ar3", "test:ar3", "arg3" },
835 { NULL }
836 };
837
838 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
839 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
840 { CH_STARTDOCUMENT, 1, 22, S_OK },
841 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
842 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
843 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
844 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
845 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
846 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
847 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
848 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
849 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
850 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
851 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
852 { CH_ENDDOCUMENT, 4, 0, S_OK },
853 { CH_ENDTEST }
854 };
855
856 static struct call_entry content_handler_test_attributes_no_prefix[] = {
857 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
858 { CH_STARTDOCUMENT, 0, 0, S_OK },
859 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
860 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
861 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
862 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
863 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
864 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
865 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
866 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
867 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
868 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
869 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
870 { CH_ENDDOCUMENT, 0, 0 },
871 { CH_ENDTEST }
872 };
873
874 static struct attribute_entry xmlspace_attrs[] = {
875 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
876 { NULL }
877 };
878
879 static struct call_entry xmlspaceattr_test[] = {
880 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
881 { CH_STARTDOCUMENT, 0, 0, S_OK },
882 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
883 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
884 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
885 { CH_ENDDOCUMENT, 0, 0, S_OK },
886 { CH_ENDTEST }
887 };
888
889 static struct call_entry xmlspaceattr_test_alternate[] = {
890 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
891 { CH_STARTDOCUMENT, 1, 39, S_OK },
892 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
893 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
894 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
895 { CH_ENDDOCUMENT, 1, 83, S_OK },
896 { CH_ENDTEST }
897 };
898
899 /* attribute value normalization test */
900 static const char attribute_normalize[] =
901 "<?xml version=\"1.0\" ?>\n"
902 "<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
903
904 static struct attribute_entry attribute_norm_attrs[] = {
905 { "", "attr1", "attr1", " attr_value A & & " },
906 { NULL }
907 };
908
909 static struct call_entry attribute_norm[] = {
910 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
911 { CH_STARTDOCUMENT, 0, 0, S_OK },
912 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
913 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
914 { CH_ENDDOCUMENT, 0, 0, S_OK },
915 { CH_ENDTEST }
916 };
917
918 static struct call_entry attribute_norm_alt[] = {
919 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
920 { CH_STARTDOCUMENT, 1, 22, S_OK },
921 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
922 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
923 { CH_ENDDOCUMENT, 9, 0, S_OK },
924 { CH_ENDTEST }
925 };
926
927 static struct call_entry cdata_test[] = {
928 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
929 { CH_STARTDOCUMENT, 0, 0, S_OK },
930 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
931 { LH_STARTCDATA, 1, 35, S_OK },
932 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
933 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
934 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
935 { LH_ENDCDATA, 1, 49, S_OK },
936 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
937 { CH_ENDDOCUMENT, 0, 0, S_OK },
938 { CH_ENDTEST }
939 };
940
941 static struct call_entry cdata_test2[] = {
942 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
943 { CH_STARTDOCUMENT, 0, 0, S_OK },
944 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
945 { LH_STARTCDATA, 1, 35, S_OK },
946 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
947 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
948 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
949 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
950 { LH_ENDCDATA, 1, 52, S_OK },
951 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
952 { CH_ENDDOCUMENT, 0, 0, S_OK },
953 { CH_ENDTEST }
954 };
955
956 static struct call_entry cdata_test3[] = {
957 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
958 { CH_STARTDOCUMENT, 0, 0, S_OK },
959 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
960 { LH_STARTCDATA, 1, 35, S_OK },
961 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
962 { LH_ENDCDATA, 1, 35, S_OK },
963 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
964 { CH_ENDDOCUMENT, 0, 0, S_OK },
965 { CH_ENDTEST }
966 };
967
968 /* this is what MSXML6 does */
969 static struct call_entry cdata_test_alt[] = {
970 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
971 { CH_STARTDOCUMENT, 1, 22, S_OK },
972 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
973 { LH_STARTCDATA, 1, 34, S_OK },
974 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
975 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
976 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
977 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
978 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
979 { LH_ENDCDATA, 6, 3, S_OK },
980 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
981 { CH_ENDDOCUMENT, 6, 7, S_OK },
982 { CH_ENDTEST }
983 };
984
985 static struct call_entry cdata_test2_alt[] = {
986 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
987 { CH_STARTDOCUMENT, 1, 22, S_OK },
988 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
989 { LH_STARTCDATA, 1, 34, S_OK },
990 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
991 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
992 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
993 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
994 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
995 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
996 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
997 { LH_ENDCDATA, 8, 3, S_OK },
998 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
999 { CH_ENDDOCUMENT, 8, 7, S_OK },
1000 { CH_ENDTEST }
1001 };
1002
1003 static struct call_entry cdata_test3_alt[] = {
1004 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
1005 { CH_STARTDOCUMENT, 1, 22, S_OK },
1006 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
1007 { LH_STARTCDATA, 1, 34, S_OK },
1008 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
1009 { LH_ENDCDATA, 1, 51, S_OK },
1010 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
1011 { CH_ENDDOCUMENT, 1, 55, S_OK },
1012 { CH_ENDTEST }
1013 };
1014
1015 static struct attribute_entry read_test_attrs[] = {
1016 { "", "attr", "attr", "val" },
1017 { NULL }
1018 };
1019
1020 static struct call_entry read_test_seq[] = {
1021 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
1022 { CH_STARTDOCUMENT, -1, -1, S_OK },
1023 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1024 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1025 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1026 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1027 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1028 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1029 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1030 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1031 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1032 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1033 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1034 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1035 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1036 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1037 { CH_ENDDOCUMENT, -1, -1, S_OK},
1038 { CH_ENDTEST }
1039 };
1040
1041 static const char xmlspace_attr[] =
1042 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1043 "<a xml:space=\"preserve\"> Some text data </a>";
1044
1045 static struct call_entry *expectCall;
1046 static ISAXLocator *locator;
1047 static ISAXXMLReader *g_reader;
1048 int msxml_version;
1049
1050 static void set_expected_seq(struct call_entry *expected)
1051 {
1052 expectCall = expected;
1053 }
1054
1055 /* to be called once on each tested callback return */
1056 static HRESULT get_expected_ret(void)
1057 {
1058 HRESULT hr = expectCall->ret;
1059 if (expectCall->id != CH_ENDTEST) expectCall++;
1060 return hr;
1061 }
1062
1063 static HRESULT WINAPI contentHandler_QueryInterface(
1064 ISAXContentHandler* iface,
1065 REFIID riid,
1066 void **ppvObject)
1067 {
1068 *ppvObject = NULL;
1069
1070 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1071 {
1072 *ppvObject = iface;
1073 }
1074 else
1075 {
1076 return E_NOINTERFACE;
1077 }
1078
1079 return S_OK;
1080 }
1081
1082 static ULONG WINAPI contentHandler_AddRef(
1083 ISAXContentHandler* iface)
1084 {
1085 return 2;
1086 }
1087
1088 static ULONG WINAPI contentHandler_Release(
1089 ISAXContentHandler* iface)
1090 {
1091 return 1;
1092 }
1093
1094 static HRESULT WINAPI contentHandler_putDocumentLocator(
1095 ISAXContentHandler* iface,
1096 ISAXLocator *pLocator)
1097 {
1098 struct call_entry call;
1099 IUnknown *unk;
1100 HRESULT hr;
1101
1102 locator = pLocator;
1103
1104 init_call_entry(locator, &call);
1105 call.id = CH_PUTDOCUMENTLOCATOR;
1106 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1107
1108 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
1109 EXPECT_HR(hr, E_NOINTERFACE);
1110
1111 if (msxml_version >= 6) {
1112 ISAXAttributes *attr, *attr1;
1113 IMXAttributes *mxattr;
1114
1115 EXPECT_REF(pLocator, 1);
1116 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1117 EXPECT_HR(hr, S_OK);
1118 EXPECT_REF(pLocator, 2);
1119 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1120 EXPECT_HR(hr, S_OK);
1121 EXPECT_REF(pLocator, 3);
1122 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1123
1124 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk);
1125 EXPECT_HR(hr, E_NOINTERFACE);
1126
1127 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1128 EXPECT_HR(hr, E_NOINTERFACE);
1129
1130 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1131 EXPECT_HR(hr, E_NOINTERFACE);
1132
1133 ISAXAttributes_Release(attr);
1134 ISAXAttributes_Release(attr1);
1135 }
1136
1137 return get_expected_ret();
1138 }
1139
1140 static ISAXAttributes *test_attr_ptr;
1141 static HRESULT WINAPI contentHandler_startDocument(
1142 ISAXContentHandler* iface)
1143 {
1144 struct call_entry call;
1145
1146 init_call_entry(locator, &call);
1147 call.id = CH_STARTDOCUMENT;
1148 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1149
1150 test_attr_ptr = NULL;
1151
1152 return get_expected_ret();
1153 }
1154
1155 static HRESULT WINAPI contentHandler_endDocument(
1156 ISAXContentHandler* iface)
1157 {
1158 struct call_entry call;
1159
1160 init_call_entry(locator, &call);
1161 call.id = CH_ENDDOCUMENT;
1162 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1163
1164 return get_expected_ret();
1165 }
1166
1167 static HRESULT WINAPI contentHandler_startPrefixMapping(
1168 ISAXContentHandler* iface,
1169 const WCHAR *prefix, int prefix_len,
1170 const WCHAR *uri, int uri_len)
1171 {
1172 struct call_entry call;
1173
1174 init_call_entry(locator, &call);
1175 call.id = CH_STARTPREFIXMAPPING;
1176 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1177 call.arg2W = SysAllocStringLen(uri, uri_len);
1178 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1179
1180 return get_expected_ret();
1181 }
1182
1183 static HRESULT WINAPI contentHandler_endPrefixMapping(
1184 ISAXContentHandler* iface,
1185 const WCHAR *prefix, int len)
1186 {
1187 struct call_entry call;
1188
1189 init_call_entry(locator, &call);
1190 call.id = CH_ENDPREFIXMAPPING;
1191 call.arg1W = SysAllocStringLen(prefix, len);
1192 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1193
1194 return get_expected_ret();
1195 }
1196
1197 static HRESULT WINAPI contentHandler_startElement(
1198 ISAXContentHandler* iface,
1199 const WCHAR *uri, int uri_len,
1200 const WCHAR *localname, int local_len,
1201 const WCHAR *qname, int qname_len,
1202 ISAXAttributes *saxattr)
1203 {
1204 struct call_entry call;
1205 IMXAttributes *mxattr;
1206 HRESULT hr;
1207 int len;
1208
1209 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1210 EXPECT_HR(hr, E_NOINTERFACE);
1211
1212 init_call_entry(locator, &call);
1213 call.id = CH_STARTELEMENT;
1214 call.arg1W = SysAllocStringLen(uri, uri_len);
1215 call.arg2W = SysAllocStringLen(localname, local_len);
1216 call.arg3W = SysAllocStringLen(qname, qname_len);
1217
1218 if(!test_attr_ptr)
1219 test_attr_ptr = saxattr;
1220 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1221
1222 /* store actual attributes */
1223 len = 0;
1224 hr = ISAXAttributes_getLength(saxattr, &len);
1225 EXPECT_HR(hr, S_OK);
1226
1227 if (len)
1228 {
1229 VARIANT_BOOL v;
1230 int i;
1231
1232 struct attribute_entry *attr;
1233 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1234
1235 v = VARIANT_TRUE;
1236 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1237 EXPECT_HR(hr, S_OK);
1238
1239 for (i = 0; i < len; i++)
1240 {
1241 const WCHAR *value;
1242 int value_len;
1243
1244 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1245 &localname, &local_len, &qname, &qname_len);
1246 EXPECT_HR(hr, S_OK);
1247
1248 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1249 EXPECT_HR(hr, S_OK);
1250
1251 /* if 'namespaces' switched off uri and local name contains garbage */
1252 if (v == VARIANT_FALSE && msxml_version > 0)
1253 {
1254 attr[i].uriW = SysAllocStringLen(NULL, 0);
1255 attr[i].localW = SysAllocStringLen(NULL, 0);
1256 }
1257 else
1258 {
1259 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1260 attr[i].localW = SysAllocStringLen(localname, local_len);
1261 }
1262
1263 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1264 attr[i].valueW = SysAllocStringLen(value, value_len);
1265 }
1266
1267 call.attributes = attr;
1268 call.attr_count = len;
1269 }
1270
1271 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1272
1273 return get_expected_ret();
1274 }
1275
1276 static HRESULT WINAPI contentHandler_endElement(
1277 ISAXContentHandler* iface,
1278 const WCHAR *uri, int uri_len,
1279 const WCHAR *localname, int local_len,
1280 const WCHAR *qname, int qname_len)
1281 {
1282 struct call_entry call;
1283
1284 init_call_entry(locator, &call);
1285 call.id = CH_ENDELEMENT;
1286 call.arg1W = SysAllocStringLen(uri, uri_len);
1287 call.arg2W = SysAllocStringLen(localname, local_len);
1288 call.arg3W = SysAllocStringLen(qname, qname_len);
1289 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1290
1291 return get_expected_ret();
1292 }
1293
1294 static HRESULT WINAPI contentHandler_characters(
1295 ISAXContentHandler* iface,
1296 const WCHAR *chars,
1297 int len)
1298 {
1299 struct call_entry call;
1300
1301 init_call_entry(locator, &call);
1302 call.id = CH_CHARACTERS;
1303 call.arg1W = SysAllocStringLen(chars, len);
1304 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1305
1306 return get_expected_ret();
1307 }
1308
1309 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1310 ISAXContentHandler* iface,
1311 const WCHAR *chars, int len)
1312 {
1313 struct call_entry call;
1314
1315 init_call_entry(locator, &call);
1316 call.id = CH_IGNORABLEWHITESPACE;
1317 call.arg1W = SysAllocStringLen(chars, len);
1318 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1319
1320 return get_expected_ret();
1321 }
1322
1323 static HRESULT WINAPI contentHandler_processingInstruction(
1324 ISAXContentHandler* iface,
1325 const WCHAR *target, int target_len,
1326 const WCHAR *data, int data_len)
1327 {
1328 struct call_entry call;
1329
1330 init_call_entry(locator, &call);
1331 call.id = CH_PROCESSINGINSTRUCTION;
1332 call.arg1W = SysAllocStringLen(target, target_len);
1333 call.arg2W = SysAllocStringLen(data, data_len);
1334 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1335
1336 return get_expected_ret();
1337 }
1338
1339 static HRESULT WINAPI contentHandler_skippedEntity(
1340 ISAXContentHandler* iface,
1341 const WCHAR *name, int len)
1342 {
1343 struct call_entry call;
1344
1345 init_call_entry(locator, &call);
1346 call.id = CH_SKIPPEDENTITY;
1347 call.arg1W = SysAllocStringLen(name, len);
1348 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1349
1350 return get_expected_ret();
1351 }
1352
1353 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1354 {
1355 contentHandler_QueryInterface,
1356 contentHandler_AddRef,
1357 contentHandler_Release,
1358 contentHandler_putDocumentLocator,
1359 contentHandler_startDocument,
1360 contentHandler_endDocument,
1361 contentHandler_startPrefixMapping,
1362 contentHandler_endPrefixMapping,
1363 contentHandler_startElement,
1364 contentHandler_endElement,
1365 contentHandler_characters,
1366 contentHandler_ignorableWhitespace,
1367 contentHandler_processingInstruction,
1368 contentHandler_skippedEntity
1369 };
1370
1371 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1372
1373 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1374 ISAXErrorHandler* iface,
1375 REFIID riid,
1376 void **ppvObject)
1377 {
1378 *ppvObject = NULL;
1379
1380 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1381 {
1382 *ppvObject = iface;
1383 }
1384 else
1385 {
1386 return E_NOINTERFACE;
1387 }
1388
1389 return S_OK;
1390 }
1391
1392 static ULONG WINAPI isaxerrorHandler_AddRef(
1393 ISAXErrorHandler* iface)
1394 {
1395 return 2;
1396 }
1397
1398 static ULONG WINAPI isaxerrorHandler_Release(
1399 ISAXErrorHandler* iface)
1400 {
1401 return 1;
1402 }
1403
1404 static HRESULT WINAPI isaxerrorHandler_error(
1405 ISAXErrorHandler* iface,
1406 ISAXLocator *pLocator,
1407 const WCHAR *pErrorMessage,
1408 HRESULT hrErrorCode)
1409 {
1410 ok(0, "unexpected call\n");
1411 return S_OK;
1412 }
1413
1414 static HRESULT WINAPI isaxerrorHandler_fatalError(
1415 ISAXErrorHandler* iface,
1416 ISAXLocator *pLocator,
1417 const WCHAR *message,
1418 HRESULT hr)
1419 {
1420 struct call_entry call;
1421
1422 init_call_entry(locator, &call);
1423 call.id = EH_FATALERROR;
1424 call.ret = hr;
1425
1426 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1427
1428 get_expected_ret();
1429 return S_OK;
1430 }
1431
1432 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1433 ISAXErrorHandler* iface,
1434 ISAXLocator *pLocator,
1435 const WCHAR *pErrorMessage,
1436 HRESULT hrErrorCode)
1437 {
1438 ok(0, "unexpected call\n");
1439 return S_OK;
1440 }
1441
1442 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1443 {
1444 isaxerrorHandler_QueryInterface,
1445 isaxerrorHandler_AddRef,
1446 isaxerrorHandler_Release,
1447 isaxerrorHandler_error,
1448 isaxerrorHandler_fatalError,
1449 isaxerrorHandler_ignorableWarning
1450 };
1451
1452 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1453
1454 static HRESULT WINAPI isaxattributes_QueryInterface(
1455 ISAXAttributes* iface,
1456 REFIID riid,
1457 void **ppvObject)
1458 {
1459 *ppvObject = NULL;
1460
1461 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1462 {
1463 *ppvObject = iface;
1464 }
1465 else
1466 {
1467 return E_NOINTERFACE;
1468 }
1469
1470 return S_OK;
1471 }
1472
1473 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1474 {
1475 return 2;
1476 }
1477
1478 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1479 {
1480 return 1;
1481 }
1482
1483 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1484 {
1485 *length = 3;
1486 return S_OK;
1487 }
1488
1489 static HRESULT WINAPI isaxattributes_getURI(
1490 ISAXAttributes* iface,
1491 int nIndex,
1492 const WCHAR **pUrl,
1493 int *pUriSize)
1494 {
1495 ok(0, "unexpected call\n");
1496 return E_NOTIMPL;
1497 }
1498
1499 static HRESULT WINAPI isaxattributes_getLocalName(
1500 ISAXAttributes* iface,
1501 int nIndex,
1502 const WCHAR **pLocalName,
1503 int *pLocalNameLength)
1504 {
1505 ok(0, "unexpected call\n");
1506 return E_NOTIMPL;
1507 }
1508
1509 static HRESULT WINAPI isaxattributes_getQName(
1510 ISAXAttributes* iface,
1511 int index,
1512 const WCHAR **QName,
1513 int *QNameLength)
1514 {
1515 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1516 {'a','t','t','r','2','j','u','n','k',0},
1517 {'a','t','t','r','3',0}};
1518 static const int attrqnamelen[] = {7, 5, 5};
1519
1520 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1521
1522 if (index >= 0 && index <= 2) {
1523 *QName = attrqnamesW[index];
1524 *QNameLength = attrqnamelen[index];
1525 } else {
1526 *QName = NULL;
1527 *QNameLength = 0;
1528 }
1529
1530 return S_OK;
1531 }
1532
1533 static HRESULT WINAPI isaxattributes_getName(
1534 ISAXAttributes* iface,
1535 int nIndex,
1536 const WCHAR **pUri,
1537 int * pUriLength,
1538 const WCHAR ** pLocalName,
1539 int * pLocalNameSize,
1540 const WCHAR ** pQName,
1541 int * pQNameLength)
1542 {
1543 ok(0, "unexpected call\n");
1544 return E_NOTIMPL;
1545 }
1546
1547 static HRESULT WINAPI isaxattributes_getIndexFromName(
1548 ISAXAttributes* iface,
1549 const WCHAR * pUri,
1550 int cUriLength,
1551 const WCHAR * pLocalName,
1552 int cocalNameLength,
1553 int * index)
1554 {
1555 ok(0, "unexpected call\n");
1556 return E_NOTIMPL;
1557 }
1558
1559 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1560 ISAXAttributes* iface,
1561 const WCHAR * pQName,
1562 int nQNameLength,
1563 int * index)
1564 {
1565 ok(0, "unexpected call\n");
1566 return E_NOTIMPL;
1567 }
1568
1569 static HRESULT WINAPI isaxattributes_getType(
1570 ISAXAttributes* iface,
1571 int nIndex,
1572 const WCHAR ** pType,
1573 int * pTypeLength)
1574 {
1575 ok(0, "unexpected call\n");
1576 return E_NOTIMPL;
1577 }
1578
1579 static HRESULT WINAPI isaxattributes_getTypeFromName(
1580 ISAXAttributes* iface,
1581 const WCHAR * pUri,
1582 int nUri,
1583 const WCHAR * pLocalName,
1584 int nLocalName,
1585 const WCHAR ** pType,
1586 int * nType)
1587 {
1588 ok(0, "unexpected call\n");
1589 return E_NOTIMPL;
1590 }
1591
1592 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1593 ISAXAttributes* iface,
1594 const WCHAR * pQName,
1595 int nQName,
1596 const WCHAR ** pType,
1597 int * nType)
1598 {
1599 ok(0, "unexpected call\n");
1600 return E_NOTIMPL;
1601 }
1602
1603 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1604 const WCHAR **value, int *nValue)
1605 {
1606 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1607 {'a','2','j','u','n','k',0},
1608 {'<','&','"','>','\'',0}};
1609 static const int attrvalueslen[] = {2, 2, 5};
1610
1611 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1612
1613 if (index >= 0 && index <= 2) {
1614 *value = attrvaluesW[index];
1615 *nValue = attrvalueslen[index];
1616 } else {
1617 *value = NULL;
1618 *nValue = 0;
1619 }
1620
1621 return S_OK;
1622 }
1623
1624 static HRESULT WINAPI isaxattributes_getValueFromName(
1625 ISAXAttributes* iface,
1626 const WCHAR * pUri,
1627 int nUri,
1628 const WCHAR * pLocalName,
1629 int nLocalName,
1630 const WCHAR ** pValue,
1631 int * nValue)
1632 {
1633 ok(0, "unexpected call\n");
1634 return E_NOTIMPL;
1635 }
1636
1637 static HRESULT WINAPI isaxattributes_getValueFromQName(
1638 ISAXAttributes* iface,
1639 const WCHAR * pQName,
1640 int nQName,
1641 const WCHAR ** pValue,
1642 int * nValue)
1643 {
1644 ok(0, "unexpected call\n");
1645 return E_NOTIMPL;
1646 }
1647
1648 static const ISAXAttributesVtbl SAXAttributesVtbl =
1649 {
1650 isaxattributes_QueryInterface,
1651 isaxattributes_AddRef,
1652 isaxattributes_Release,
1653 isaxattributes_getLength,
1654 isaxattributes_getURI,
1655 isaxattributes_getLocalName,
1656 isaxattributes_getQName,
1657 isaxattributes_getName,
1658 isaxattributes_getIndexFromName,
1659 isaxattributes_getIndexFromQName,
1660 isaxattributes_getType,
1661 isaxattributes_getTypeFromName,
1662 isaxattributes_getTypeFromQName,
1663 isaxattributes_getValue,
1664 isaxattributes_getValueFromName,
1665 isaxattributes_getValueFromQName
1666 };
1667
1668 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1669
1670 struct saxlexicalhandler
1671 {
1672 ISAXLexicalHandler ISAXLexicalHandler_iface;
1673 LONG ref;
1674
1675 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1676 };
1677
1678 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1679 {
1680 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1681 }
1682
1683 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1684 {
1685 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1686
1687 *out = NULL;
1688
1689 if (IsEqualGUID(riid, &IID_IUnknown))
1690 {
1691 *out = iface;
1692 ok(0, "got unexpected IID_IUnknown query\n");
1693 }
1694 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1695 {
1696 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1697 *out = iface;
1698 }
1699
1700 if (*out)
1701 ISAXLexicalHandler_AddRef(iface);
1702 else
1703 return E_NOINTERFACE;
1704
1705 return S_OK;
1706 }
1707
1708 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1709 {
1710 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1711 return InterlockedIncrement(&handler->ref);
1712 }
1713
1714 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1715 {
1716 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1717 return InterlockedDecrement(&handler->ref);
1718 }
1719
1720 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1721 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1722 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1723 {
1724 ok(0, "call not expected\n");
1725 return E_NOTIMPL;
1726 }
1727
1728 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1729 {
1730 ok(0, "call not expected\n");
1731 return E_NOTIMPL;
1732 }
1733
1734 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1735 const WCHAR * pName, int nName)
1736 {
1737 ok(0, "call not expected\n");
1738 return E_NOTIMPL;
1739 }
1740
1741 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1742 const WCHAR * pName, int nName)
1743 {
1744 ok(0, "call not expected\n");
1745 return E_NOTIMPL;
1746 }
1747
1748 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1749 {
1750 struct call_entry call;
1751
1752 init_call_entry(locator, &call);
1753 call.id = LH_STARTCDATA;
1754 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1755
1756 return get_expected_ret();
1757 }
1758
1759 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1760 {
1761 struct call_entry call;
1762
1763 init_call_entry(locator, &call);
1764 call.id = LH_ENDCDATA;
1765 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1766
1767 return get_expected_ret();
1768 }
1769
1770 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1771 const WCHAR * pChars, int nChars)
1772 {
1773 ok(0, "call not expected\n");
1774 return E_NOTIMPL;
1775 }
1776
1777 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1778 {
1779 isaxlexical_QueryInterface,
1780 isaxlexical_AddRef,
1781 isaxlexical_Release,
1782 isaxlexical_startDTD,
1783 isaxlexical_endDTD,
1784 isaxlexical_startEntity,
1785 isaxlexical_endEntity,
1786 isaxlexical_startCDATA,
1787 isaxlexical_endCDATA,
1788 isaxlexical_comment
1789 };
1790
1791 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1792 {
1793 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1794 handler->ref = 1;
1795 handler->qi_hr = hr;
1796 }
1797
1798 struct saxdeclhandler
1799 {
1800 ISAXDeclHandler ISAXDeclHandler_iface;
1801 LONG ref;
1802
1803 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1804 };
1805
1806 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1807 {
1808 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1809 }
1810
1811 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1812 {
1813 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1814
1815 *out = NULL;
1816
1817 if (IsEqualGUID(riid, &IID_IUnknown))
1818 {
1819 *out = iface;
1820 ok(0, "got unexpected IID_IUnknown query\n");
1821 }
1822 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1823 {
1824 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1825 *out = iface;
1826 }
1827
1828 if (*out)
1829 ISAXDeclHandler_AddRef(iface);
1830 else
1831 return E_NOINTERFACE;
1832
1833 return S_OK;
1834 }
1835
1836 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1837 {
1838 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1839 return InterlockedIncrement(&handler->ref);
1840 }
1841
1842 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1843 {
1844 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1845 return InterlockedDecrement(&handler->ref);
1846 }
1847
1848 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1849 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1850 {
1851 ok(0, "call not expected\n");
1852 return E_NOTIMPL;
1853 }
1854
1855 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1856 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1857 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1858 int nValueDefault, const WCHAR * pValue, int nValue)
1859 {
1860 ok(0, "call not expected\n");
1861 return E_NOTIMPL;
1862 }
1863
1864 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1865 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1866 {
1867 ok(0, "call not expected\n");
1868 return E_NOTIMPL;
1869 }
1870
1871 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1872 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1873 const WCHAR * pSystemId, int nSystemId)
1874 {
1875 ok(0, "call not expected\n");
1876 return E_NOTIMPL;
1877 }
1878
1879 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1880 {
1881 isaxdecl_QueryInterface,
1882 isaxdecl_AddRef,
1883 isaxdecl_Release,
1884 isaxdecl_elementDecl,
1885 isaxdecl_attributeDecl,
1886 isaxdecl_internalEntityDecl,
1887 isaxdecl_externalEntityDecl
1888 };
1889
1890 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1891 {
1892 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1893 handler->ref = 1;
1894 handler->qi_hr = hr;
1895 }
1896
1897 typedef struct mxwriter_write_test_t {
1898 BOOL last;
1899 const BYTE *data;
1900 DWORD cb;
1901 BOOL null_written;
1902 BOOL fail_write;
1903 } mxwriter_write_test;
1904
1905 typedef struct mxwriter_stream_test_t {
1906 VARIANT_BOOL bom;
1907 const char *encoding;
1908 mxwriter_write_test expected_writes[4];
1909 } mxwriter_stream_test;
1910
1911 static const mxwriter_write_test *current_write_test;
1912 static DWORD current_stream_test_index;
1913
1914 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1915 {
1916 *ppvObject = NULL;
1917
1918 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1919 *ppvObject = iface;
1920 else
1921 return E_NOINTERFACE;
1922
1923 return S_OK;
1924 }
1925
1926 static ULONG WINAPI istream_AddRef(IStream *iface)
1927 {
1928 return 2;
1929 }
1930
1931 static ULONG WINAPI istream_Release(IStream *iface)
1932 {
1933 return 1;
1934 }
1935
1936 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1937 {
1938 ok(0, "unexpected call\n");
1939 return E_NOTIMPL;
1940 }
1941
1942 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1943 {
1944 ok(0, "unexpected call\n");
1945 return E_NOTIMPL;
1946 }
1947
1948 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1949 ULARGE_INTEGER *plibNewPosition)
1950 {
1951 ok(0, "unexpected call\n");
1952 return E_NOTIMPL;
1953 }
1954
1955 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1956 {
1957 ok(0, "unexpected call\n");
1958 return E_NOTIMPL;
1959 }
1960
1961 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1962 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1963 {
1964 ok(0, "unexpected call\n");
1965 return E_NOTIMPL;
1966 }
1967
1968 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1969 {
1970 ok(0, "unexpected call\n");
1971 return E_NOTIMPL;
1972 }
1973
1974 static HRESULT WINAPI istream_Revert(IStream *iface)
1975 {
1976 ok(0, "unexpected call\n");
1977 return E_NOTIMPL;
1978 }
1979
1980 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1981 ULARGE_INTEGER cb, DWORD dwLockType)
1982 {
1983 ok(0, "unexpected call\n");
1984 return E_NOTIMPL;
1985 }
1986
1987 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1988 ULARGE_INTEGER cb, DWORD dwLockType)
1989 {
1990 ok(0, "unexpected call\n");
1991 return E_NOTIMPL;
1992 }
1993
1994 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1995 {
1996 ok(0, "unexpected call\n");
1997 return E_NOTIMPL;
1998 }
1999
2000 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
2001 {
2002 ok(0, "unexpected call\n");
2003 return E_NOTIMPL;
2004 }
2005
2006 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
2007 {
2008 BOOL fail = FALSE;
2009
2010 ok(pv != NULL, "pv == NULL\n");
2011
2012 if(current_write_test->last) {
2013 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2014 return E_FAIL;
2015 }
2016
2017 fail = current_write_test->fail_write;
2018
2019 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2020 current_write_test->cb, cb, current_stream_test_index);
2021
2022 if(!pcbWritten)
2023 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2024 else
2025 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2026
2027 ++current_write_test;
2028
2029 if(pcbWritten)
2030 *pcbWritten = cb;
2031
2032 return fail ? E_FAIL : S_OK;
2033 }
2034
2035 static const IStreamVtbl mxstreamVtbl = {
2036 istream_QueryInterface,
2037 istream_AddRef,
2038 istream_Release,
2039 istream_Read,
2040 mxstream_Write,
2041 istream_Seek,
2042 istream_SetSize,
2043 istream_CopyTo,
2044 istream_Commit,
2045 istream_Revert,
2046 istream_LockRegion,
2047 istream_UnlockRegion,
2048 istream_Stat,
2049 istream_Clone
2050 };
2051
2052 static IStream mxstream = { &mxstreamVtbl };
2053
2054 static int read_cnt;
2055
2056 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2057 {
2058 static const char *ret_str;
2059
2060 if(!read_cnt)
2061 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2062 else if(read_cnt < 5)
2063 ret_str = "<elem attr=\"val\">text</elem>";
2064 else if(read_cnt == 5)
2065 ret_str = "</rootelem>\n";
2066 else
2067 ret_str = "";
2068
2069 read_cnt++;
2070 strcpy(pv, ret_str);
2071 *pcbRead = strlen(ret_str);
2072 return S_OK;
2073 }
2074
2075 static const IStreamVtbl instreamVtbl = {
2076 istream_QueryInterface,
2077 istream_AddRef,
2078 istream_Release,
2079 instream_Read,
2080 istream_Write,
2081 istream_Seek,
2082 istream_SetSize,
2083 istream_CopyTo,
2084 istream_Commit,
2085 istream_Revert,
2086 istream_LockRegion,
2087 istream_UnlockRegion,
2088 istream_Stat,
2089 istream_Clone
2090 };
2091
2092 static IStream instream = { &instreamVtbl };
2093
2094 static struct msxmlsupported_data_t reader_support_data[] =
2095 {
2096 { &CLSID_SAXXMLReader, "SAXReader" },
2097 { &CLSID_SAXXMLReader30, "SAXReader30" },
2098 { &CLSID_SAXXMLReader40, "SAXReader40" },
2099 { &CLSID_SAXXMLReader60, "SAXReader60" },
2100 { NULL }
2101 };
2102
2103 static struct saxlexicalhandler lexicalhandler;
2104 static struct saxdeclhandler declhandler;
2105
2106 static IStream *create_test_stream(const char *data, int len)
2107 {
2108 ULARGE_INTEGER size;
2109 LARGE_INTEGER pos;
2110 IStream *stream;
2111 ULONG written;
2112
2113 if (len == -1) len = strlen(data);
2114 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2115 size.QuadPart = len;
2116 IStream_SetSize(stream, size);
2117 IStream_Write(stream, data, len, &written);
2118 pos.QuadPart = 0;
2119 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2120
2121 return stream;
2122 }
2123
2124 static void test_saxreader(void)
2125 {
2126 const struct msxmlsupported_data_t *table = reader_support_data;
2127 HRESULT hr;
2128 ISAXXMLReader *reader = NULL;
2129 VARIANT var;
2130 ISAXContentHandler *content;
2131 ISAXErrorHandler *lpErrorHandler;
2132 SAFEARRAY *sa;
2133 SAFEARRAYBOUND SADim[1];
2134 char *ptr = NULL;
2135 IStream *stream;
2136 ULONG written;
2137 HANDLE file;
2138 static const CHAR testXmlA[] = "test.xml";
2139 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2140 IXMLDOMDocument *doc;
2141 char seqname[50];
2142 VARIANT_BOOL v;
2143
2144 while (table->clsid)
2145 {
2146 struct call_entry *test_seq;
2147 ISAXEntityResolver *resolver;
2148 BSTR str;
2149
2150 if (!is_clsid_supported(table->clsid, reader_support_data))
2151 {
2152 table++;
2153 continue;
2154 }
2155
2156 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2157 EXPECT_HR(hr, S_OK);
2158 g_reader = reader;
2159
2160 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2161 msxml_version = 4;
2162 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2163 msxml_version = 6;
2164 else
2165 msxml_version = 0;
2166
2167 /* crashes on old versions */
2168 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2169 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2170 {
2171 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2172 EXPECT_HR(hr, E_POINTER);
2173
2174 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2175 EXPECT_HR(hr, E_POINTER);
2176 }
2177
2178 hr = ISAXXMLReader_getContentHandler(reader, &content);
2179 EXPECT_HR(hr, S_OK);
2180 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2181
2182 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2183 EXPECT_HR(hr, S_OK);
2184 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2185
2186 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2187 EXPECT_HR(hr, S_OK);
2188
2189 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2190 EXPECT_HR(hr, S_OK);
2191
2192 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2193 EXPECT_HR(hr, S_OK);
2194
2195 hr = ISAXXMLReader_getContentHandler(reader, &content);
2196 EXPECT_HR(hr, S_OK);
2197 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2198
2199 V_VT(&var) = VT_BSTR;
2200 V_BSTR(&var) = SysAllocString(szSimpleXML);
2201
2202 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2203 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2204 test_seq = content_handler_test1_alternate;
2205 else
2206 test_seq = content_handler_test1;
2207 set_expected_seq(test_seq);
2208 hr = ISAXXMLReader_parse(reader, var);
2209 EXPECT_HR(hr, S_OK);
2210 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2211
2212 VariantClear(&var);
2213
2214 SADim[0].lLbound = 0;
2215 SADim[0].cElements = sizeof(testXML)-1;
2216 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2217 SafeArrayAccessData(sa, (void**)&ptr);
2218 memcpy(ptr, testXML, sizeof(testXML)-1);
2219 SafeArrayUnaccessData(sa);
2220 V_VT(&var) = VT_ARRAY|VT_UI1;
2221 V_ARRAY(&var) = sa;
2222
2223 set_expected_seq(test_seq);
2224 hr = ISAXXMLReader_parse(reader, var);
2225 EXPECT_HR(hr, S_OK);
2226 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2227
2228 SafeArrayDestroy(sa);
2229
2230 stream = create_test_stream(testXML, -1);
2231 V_VT(&var) = VT_UNKNOWN;
2232 V_UNKNOWN(&var) = (IUnknown*)stream;
2233
2234 set_expected_seq(test_seq);
2235 hr = ISAXXMLReader_parse(reader, var);
2236 EXPECT_HR(hr, S_OK);
2237 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2238
2239 IStream_Release(stream);
2240
2241 stream = create_test_stream(test_attributes, -1);
2242 V_VT(&var) = VT_UNKNOWN;
2243 V_UNKNOWN(&var) = (IUnknown*)stream;
2244
2245 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2246 test_seq = content_handler_test_attributes_alternate_4;
2247 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2248 test_seq = content_handler_test_attributes_alternate_6;
2249 else
2250 test_seq = content_handler_test_attributes;
2251
2252 set_expected_seq(test_seq);
2253 hr = ISAXXMLReader_parse(reader, var);
2254 EXPECT_HR(hr, S_OK);
2255
2256 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2257 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2258 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2259 else
2260 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2261
2262 IStream_Release(stream);
2263
2264 V_VT(&var) = VT_UNKNOWN;
2265 V_UNKNOWN(&var) = (IUnknown*)&instream;
2266
2267 test_seq = read_test_seq;
2268 read_cnt = 0;
2269 set_expected_seq(test_seq);
2270 hr = ISAXXMLReader_parse(reader, var);
2271 EXPECT_HR(hr, S_OK);
2272 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2273 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2274
2275 V_VT(&var) = VT_BSTR;
2276 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2277
2278 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2279 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2280 test_seq = content_handler_test2_alternate;
2281 else
2282 test_seq = content_handler_test2;
2283
2284 set_expected_seq(test_seq);
2285 hr = ISAXXMLReader_parse(reader, var);
2286 EXPECT_HR(hr, S_OK);
2287 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2288
2289 VariantClear(&var);
2290
2291 /* from file url */
2292 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2293 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2294 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2295 CloseHandle(file);
2296
2297 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2298 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2299 test_seq = content_handler_test1_alternate;
2300 else
2301 test_seq = content_handler_test1;
2302 set_expected_seq(test_seq);
2303 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2304 EXPECT_HR(hr, S_OK);
2305 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2306
2307 /* error handler */
2308 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2309 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2310 test_seq = content_handler_testerror_alternate;
2311 else
2312 test_seq = content_handler_testerror;
2313 set_expected_seq(test_seq);
2314 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2315 EXPECT_HR(hr, E_FAIL);
2316 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2317
2318 /* callback ret values */
2319 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2320 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2321 {
2322 test_seq = content_handler_test_callback_rets_alt;
2323 set_expected_seq(test_seq);
2324 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2325 EXPECT_HR(hr, S_OK);
2326 }
2327 else
2328 {
2329 test_seq = content_handler_test_callback_rets;
2330 set_expected_seq(test_seq);
2331 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2332 EXPECT_HR(hr, S_FALSE);
2333 }
2334 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2335
2336 DeleteFileA(testXmlA);
2337
2338 /* parse from IXMLDOMDocument */
2339 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2340 &IID_IXMLDOMDocument, (void**)&doc);
2341 EXPECT_HR(hr, S_OK);
2342
2343 str = SysAllocString(szSimpleXML);
2344 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2345 EXPECT_HR(hr, S_OK);
2346 SysFreeString(str);
2347
2348 V_VT(&var) = VT_UNKNOWN;
2349 V_UNKNOWN(&var) = (IUnknown*)doc;
2350
2351 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2352 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2353 test_seq = content_handler_test2_alternate;
2354 else
2355 test_seq = content_handler_test2;
2356
2357 set_expected_seq(test_seq);
2358 hr = ISAXXMLReader_parse(reader, var);
2359 EXPECT_HR(hr, S_OK);
2360 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2361 IXMLDOMDocument_Release(doc);
2362
2363 /* xml:space test */
2364 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2365 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2366 {
2367 test_seq = xmlspaceattr_test_alternate;
2368 }
2369 else
2370 test_seq = xmlspaceattr_test;
2371
2372 set_expected_seq(test_seq);
2373 V_VT(&var) = VT_BSTR;
2374 V_BSTR(&var) = _bstr_(xmlspace_attr);
2375 hr = ISAXXMLReader_parse(reader, var);
2376 EXPECT_HR(hr, S_OK);
2377
2378 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2379 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2380 {
2381 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2382 }
2383 else
2384 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2385
2386 /* switch off 'namespaces' feature */
2387 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2388 EXPECT_HR(hr, S_OK);
2389
2390 stream = create_test_stream(test_attributes, -1);
2391 V_VT(&var) = VT_UNKNOWN;
2392 V_UNKNOWN(&var) = (IUnknown*)stream;
2393
2394 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2395 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2396 {
2397 test_seq = content_handler_test_attributes_alt_no_ns;
2398 }
2399 else
2400 test_seq = content_handler_test_attributes;
2401
2402 set_expected_seq(test_seq);
2403 hr = ISAXXMLReader_parse(reader, var);
2404 EXPECT_HR(hr, S_OK);
2405 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2406 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2407 EXPECT_HR(hr, S_OK);
2408
2409 /* switch off 'namespace-prefixes' feature */
2410 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2411 EXPECT_HR(hr, S_OK);
2412
2413 stream = create_test_stream(test_attributes, -1);
2414 V_VT(&var) = VT_UNKNOWN;
2415 V_UNKNOWN(&var) = (IUnknown*)stream;
2416
2417 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2418 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2419 {
2420 test_seq = content_handler_test_attributes_alt_no_prefix;
2421 }
2422 else
2423 test_seq = content_handler_test_attributes_no_prefix;
2424
2425 set_expected_seq(test_seq);
2426 hr = ISAXXMLReader_parse(reader, var);
2427 EXPECT_HR(hr, S_OK);
2428 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2429
2430 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2431 EXPECT_HR(hr, S_OK);
2432
2433 /* attribute normalization */
2434 stream = create_test_stream(attribute_normalize, -1);
2435 V_VT(&var) = VT_UNKNOWN;
2436 V_UNKNOWN(&var) = (IUnknown*)stream;
2437
2438 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2439 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2440 {
2441 test_seq = attribute_norm_alt;
2442 }
2443 else
2444 test_seq = attribute_norm;
2445
2446 set_expected_seq(test_seq);
2447 hr = ISAXXMLReader_parse(reader, var);
2448 EXPECT_HR(hr, S_OK);
2449 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2450
2451 resolver = (void*)0xdeadbeef;
2452 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2453 ok(hr == S_OK, "got 0x%08x\n", hr);
2454 ok(resolver == NULL, "got %p\n", resolver);
2455
2456 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2457 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2458
2459 /* CDATA sections */
2460 init_saxlexicalhandler(&lexicalhandler, S_OK);
2461
2462 V_VT(&var) = VT_UNKNOWN;
2463 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2464 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2465 ok(hr == S_OK, "got 0x%08x\n", hr);
2466
2467 stream = create_test_stream(test_cdata_xml, -1);
2468 V_VT(&var) = VT_UNKNOWN;
2469 V_UNKNOWN(&var) = (IUnknown*)stream;
2470
2471 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2472 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2473 test_seq = cdata_test_alt;
2474 else
2475 test_seq = cdata_test;
2476
2477 set_expected_seq(test_seq);
2478 hr = ISAXXMLReader_parse(reader, var);
2479 ok(hr == S_OK, "got 0x%08x\n", hr);
2480 sprintf(seqname, "%s: cdata test", table->name);
2481 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2482
2483 /* 2. CDATA sections */
2484 stream = create_test_stream(test2_cdata_xml, -1);
2485 V_VT(&var) = VT_UNKNOWN;
2486 V_UNKNOWN(&var) = (IUnknown*)stream;
2487
2488 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2489 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2490 test_seq = cdata_test2_alt;
2491 else
2492 test_seq = cdata_test2;
2493
2494 set_expected_seq(test_seq);
2495 hr = ISAXXMLReader_parse(reader, var);
2496 ok(hr == S_OK, "got 0x%08x\n", hr);
2497 sprintf(seqname, "%s: cdata test 2", table->name);
2498 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2499
2500 IStream_Release(stream);
2501
2502 /* 3. CDATA sections */
2503 stream = create_test_stream(test3_cdata_xml, -1);
2504 V_VT(&var) = VT_UNKNOWN;
2505 V_UNKNOWN(&var) = (IUnknown*)stream;
2506
2507 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2508 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2509 test_seq = cdata_test3_alt;
2510 else
2511 test_seq = cdata_test3;
2512
2513 set_expected_seq(test_seq);
2514 hr = ISAXXMLReader_parse(reader, var);
2515 ok(hr == S_OK, "got 0x%08x\n", hr);
2516 sprintf(seqname, "%s: cdata test 3", table->name);
2517 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2518
2519 IStream_Release(stream);
2520
2521 ISAXXMLReader_Release(reader);
2522 table++;
2523 }
2524
2525 free_bstrs();
2526 }
2527
2528 struct saxreader_props_test_t
2529 {
2530 const char *prop_name;
2531 IUnknown *iface;
2532 };
2533
2534 static const struct saxreader_props_test_t props_test_data[] = {
2535 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2536 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2537 { 0 }
2538 };
2539
2540 static void test_saxreader_properties(void)
2541 {
2542 const struct saxreader_props_test_t *ptr = props_test_data;
2543 ISAXXMLReader *reader;
2544 HRESULT hr;
2545 VARIANT v;
2546 BSTR str;
2547
2548 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2549 &IID_ISAXXMLReader, (void**)&reader);
2550 EXPECT_HR(hr, S_OK);
2551
2552 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2553 EXPECT_HR(hr, E_POINTER);
2554
2555 while (ptr->prop_name)
2556 {
2557 VARIANT varref;
2558 LONG ref;
2559
2560 init_saxlexicalhandler(&lexicalhandler, S_OK);
2561 init_saxdeclhandler(&declhandler, S_OK);
2562
2563 V_VT(&v) = VT_EMPTY;
2564 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2565 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2566 EXPECT_HR(hr, S_OK);
2567 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2568 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2569
2570 /* VT_UNKNOWN */
2571 V_VT(&v) = VT_UNKNOWN;
2572 V_UNKNOWN(&v) = ptr->iface;
2573 ref = get_refcount(ptr->iface);
2574 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2575 EXPECT_HR(hr, S_OK);
2576 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2577
2578 /* VT_DISPATCH */
2579 V_VT(&v) = VT_DISPATCH;
2580 V_UNKNOWN(&v) = ptr->iface;
2581 ref = get_refcount(ptr->iface);
2582 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2583 EXPECT_HR(hr, S_OK);
2584 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2585
2586 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2587 V_VT(&varref) = VT_UNKNOWN;
2588 V_UNKNOWN(&varref) = ptr->iface;
2589
2590 V_VT(&v) = VT_VARIANT|VT_BYREF;
2591 V_VARIANTREF(&v) = &varref;
2592 ref = get_refcount(ptr->iface);
2593 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2594 EXPECT_HR(hr, S_OK);
2595 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2596
2597 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2598 V_VT(&varref) = VT_DISPATCH;
2599 V_UNKNOWN(&varref) = ptr->iface;
2600
2601 V_VT(&v) = VT_VARIANT|VT_BYREF;
2602 V_VARIANTREF(&v) = &varref;
2603 ref = get_refcount(ptr->iface);
2604 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2605 EXPECT_HR(hr, S_OK);
2606 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2607
2608 V_VT(&v) = VT_EMPTY;
2609 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2610
2611 ref = get_refcount(ptr->iface);
2612 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2613 EXPECT_HR(hr, S_OK);
2614 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2615 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2616 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2617 VariantClear(&v);
2618
2619 V_VT(&v) = VT_EMPTY;
2620 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2621 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2622 EXPECT_HR(hr, S_OK);
2623
2624 V_VT(&v) = VT_EMPTY;
2625 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2626 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2627 EXPECT_HR(hr, S_OK);
2628 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2629 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2630
2631 V_VT(&v) = VT_UNKNOWN;
2632 V_UNKNOWN(&v) = ptr->iface;
2633 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2634 EXPECT_HR(hr, S_OK);
2635
2636 /* only VT_EMPTY seems to be valid to reset property */
2637 V_VT(&v) = VT_I4;
2638 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2639 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2640 EXPECT_HR(hr, E_INVALIDARG);
2641
2642 V_VT(&v) = VT_EMPTY;
2643 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2644 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2645 EXPECT_HR(hr, S_OK);
2646 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2647 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2648 VariantClear(&v);
2649
2650 V_VT(&v) = VT_UNKNOWN;
2651 V_UNKNOWN(&v) = NULL;
2652 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2653 EXPECT_HR(hr, S_OK);
2654
2655 V_VT(&v) = VT_EMPTY;
2656 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2657 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2658 EXPECT_HR(hr, S_OK);
2659 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2660 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2661
2662 /* block QueryInterface on handler riid */
2663 V_VT(&v) = VT_UNKNOWN;
2664 V_UNKNOWN(&v) = ptr->iface;
2665 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2666 EXPECT_HR(hr, S_OK);
2667
2668 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2669 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2670
2671 V_VT(&v) = VT_UNKNOWN;
2672 V_UNKNOWN(&v) = ptr->iface;
2673 EXPECT_REF(ptr->iface, 1);
2674 ref = get_refcount(ptr->iface);
2675 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2676 EXPECT_HR(hr, E_NOINTERFACE);
2677 EXPECT_REF(ptr->iface, 1);
2678
2679 V_VT(&v) = VT_EMPTY;
2680 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2681 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2682 EXPECT_HR(hr, S_OK);
2683 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2684 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2685
2686 ptr++;
2687 free_bstrs();
2688 }
2689
2690 ISAXXMLReader_Release(reader);
2691
2692 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2693 return;
2694
2695 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2696 &IID_ISAXXMLReader, (void**)&reader);
2697 EXPECT_HR(hr, S_OK);
2698
2699 /* xmldecl-version property */
2700 V_VT(&v) = VT_EMPTY;
2701 V_BSTR(&v) = (void*)0xdeadbeef;
2702 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2703 EXPECT_HR(hr, S_OK);
2704 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2705 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2706
2707 /* stream without declaration */
2708 V_VT(&v) = VT_BSTR;
2709 V_BSTR(&v) = _bstr_("<element></element>");
2710 hr = ISAXXMLReader_parse(reader, v);
2711 EXPECT_HR(hr, S_OK);
2712
2713 V_VT(&v) = VT_EMPTY;
2714 V_BSTR(&v) = (void*)0xdeadbeef;
2715 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2716 EXPECT_HR(hr, S_OK);
2717 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2718 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2719
2720 /* stream with declaration */
2721 V_VT(&v) = VT_BSTR;
2722 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2723 hr = ISAXXMLReader_parse(reader, v);
2724 EXPECT_HR(hr, S_OK);
2725
2726 /* VT_BSTR|VT_BYREF input type */
2727 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2728 V_VT(&v) = VT_BSTR|VT_BYREF;
2729 V_BSTRREF(&v) = &str;
2730 hr = ISAXXMLReader_parse(reader, v);
2731 EXPECT_HR(hr, S_OK);
2732
2733 V_VT(&v) = VT_EMPTY;
2734 V_BSTR(&v) = (void*)0xdeadbeef;
2735 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2736 EXPECT_HR(hr, S_OK);
2737 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2738 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2739 VariantClear(&v);
2740
2741 ISAXXMLReader_Release(reader);
2742 free_bstrs();
2743 }
2744
2745 struct feature_ns_entry_t {
2746 const GUID *guid;
2747 const char *clsid;
2748 VARIANT_BOOL value;
2749 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2750 };
2751
2752 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2753 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2754 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2755 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2756 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2757 { 0 }
2758 };
2759
2760 static const char *feature_names[] = {
2761 "http://xml.org/sax/features/namespaces",
2762 "http://xml.org/sax/features/namespace-prefixes",
2763 0
2764 };
2765
2766 static void test_saxreader_features(void)
2767 {
2768 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2769 ISAXXMLReader *reader;
2770
2771 while (entry->guid)
2772 {
2773 VARIANT_BOOL value;
2774 const char **name;
2775 HRESULT hr;
2776
2777 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2778 if (hr != S_OK)
2779 {
2780 win_skip("can't create %s instance\n", entry->clsid);
2781 entry++;
2782 continue;
2783 }
2784
2785 name = feature_names;
2786 while (*name)
2787 {
2788 value = 0xc;
2789 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2790 EXPECT_HR(hr, S_OK);
2791 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2792
2793 value = 0xc;
2794 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2795 EXPECT_HR(hr, S_OK);
2796
2797 value = 0xd;
2798 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2799 EXPECT_HR(hr, S_OK);
2800 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2801
2802 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2803 EXPECT_HR(hr, S_OK);
2804 value = 0xd;
2805 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2806 EXPECT_HR(hr, S_OK);
2807 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2808
2809 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2810 EXPECT_HR(hr, S_OK);
2811 value = 0xd;
2812 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2813 EXPECT_HR(hr, S_OK);
2814 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2815
2816 name++;
2817 }
2818
2819 ISAXXMLReader_Release(reader);
2820
2821 entry++;
2822 }
2823 }
2824
2825 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2826 static const CHAR UTF8BOMTest[] =
2827 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2828 "<a></a>\n";
2829
2830 struct enc_test_entry_t {
2831 const GUID *guid;
2832 const char *clsid;
2833 const char *data;
2834 HRESULT hr;
2835 BOOL todo;
2836 };
2837
2838 static const struct enc_test_entry_t encoding_test_data[] = {
2839 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2840 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2841 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2842 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2843 { 0 }
2844 };
2845
2846 static void test_saxreader_encoding(void)
2847 {
2848 const struct enc_test_entry_t *entry = encoding_test_data;
2849 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2850 static const CHAR testXmlA[] = "test.xml";
2851
2852 while (entry->guid)
2853 {
2854 ISAXXMLReader *reader;
2855 VARIANT input;
2856 DWORD written;
2857 HANDLE file;
2858 HRESULT hr;
2859
2860 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2861 if (hr != S_OK)
2862 {
2863 win_skip("can't create %s instance\n", entry->clsid);
2864 entry++;
2865 continue;
2866 }
2867
2868 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2869 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2870 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2871 CloseHandle(file);
2872
2873 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2874 if (entry->todo)
2875 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2876 else
2877 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2878
2879 DeleteFileA(testXmlA);
2880
2881 /* try BSTR input with no BOM or '<?xml' instruction */
2882 V_VT(&input) = VT_BSTR;
2883 V_BSTR(&input) = _bstr_("<element></element>");
2884 hr = ISAXXMLReader_parse(reader, input);
2885 EXPECT_HR(hr, S_OK);
2886
2887 ISAXXMLReader_Release(reader);
2888
2889 free_bstrs();
2890 entry++;
2891 }
2892 }
2893
2894 static void test_mxwriter_handlers(void)
2895 {
2896 IMXWriter *writer;
2897 HRESULT hr;
2898 int i;
2899
2900 static const REFIID riids[] =
2901 {
2902 &IID_ISAXContentHandler,
2903 &IID_ISAXLexicalHandler,
2904 &IID_ISAXDeclHandler,
2905 &IID_ISAXDTDHandler,
2906 &IID_ISAXErrorHandler,
2907 &IID_IVBSAXDeclHandler,
2908 &IID_IVBSAXLexicalHandler,
2909 &IID_IVBSAXContentHandler,
2910 &IID_IVBSAXDTDHandler,
2911 &IID_IVBSAXErrorHandler
2912 };
2913
2914 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2915 &IID_IMXWriter, (void**)&writer);
2916 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2917
2918 EXPECT_REF(writer, 1);
2919
2920 for (i = 0; i < sizeof(riids)/sizeof(REFIID); i++)
2921 {
2922 IUnknown *handler;
2923 IMXWriter *writer2;
2924
2925 /* handler from IMXWriter */
2926 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2927 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2928 EXPECT_REF(writer, 2);
2929 EXPECT_REF(handler, 2);
2930
2931 /* IMXWriter from a handler */
2932 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2933 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2934 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2935 EXPECT_REF(writer, 3);
2936 EXPECT_REF(writer2, 3);
2937 IMXWriter_Release(writer2);
2938 IUnknown_Release(handler);
2939 }
2940
2941 IMXWriter_Release(writer);
2942 }
2943
2944 static struct msxmlsupported_data_t mxwriter_support_data[] =
2945 {
2946 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2947 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2948 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2949 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2950 { NULL }
2951 };
2952
2953 static struct msxmlsupported_data_t mxattributes_support_data[] =
2954 {
2955 { &CLSID_SAXAttributes, "SAXAttributes" },
2956 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2957 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2958 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2959 { NULL }
2960 };
2961
2962 struct mxwriter_props_t
2963 {
2964 const GUID *clsid;
2965 VARIANT_BOOL bom;
2966 VARIANT_BOOL disable_escape;
2967 VARIANT_BOOL indent;
2968 VARIANT_BOOL omitdecl;
2969 VARIANT_BOOL standalone;
2970 const char *encoding;
2971 };
2972
2973 static const struct mxwriter_props_t mxwriter_default_props[] =
2974 {
2975 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2976 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2977 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2978 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2979 { NULL }
2980 };
2981
2982 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2983 {
2984 int i = 0;
2985
2986 while (table->clsid)
2987 {
2988 IMXWriter *writer;
2989 VARIANT_BOOL b;
2990 BSTR encoding;
2991 HRESULT hr;
2992
2993 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2994 {
2995 table++;
2996 i++;
2997 continue;
2998 }
2999
3000 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3001 &IID_IMXWriter, (void**)&writer);
3002 EXPECT_HR(hr, S_OK);
3003
3004 b = !table->bom;
3005 hr = IMXWriter_get_byteOrderMark(writer, &b);
3006 EXPECT_HR(hr, S_OK);
3007 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3008
3009 b = !table->disable_escape;
3010 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3011 EXPECT_HR(hr, S_OK);
3012 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3013 table->disable_escape);
3014
3015 b = !table->indent;
3016 hr = IMXWriter_get_indent(writer, &b);
3017 EXPECT_HR(hr, S_OK);
3018 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3019
3020 b = !table->omitdecl;
3021 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3022 EXPECT_HR(hr, S_OK);
3023 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3024
3025 b = !table->standalone;
3026 hr = IMXWriter_get_standalone(writer, &b);
3027 EXPECT_HR(hr, S_OK);
3028 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3029
3030 hr = IMXWriter_get_encoding(writer, &encoding);
3031 EXPECT_HR(hr, S_OK);
3032 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3033 i, wine_dbgstr_w(encoding), table->encoding);
3034 SysFreeString(encoding);
3035
3036 IMXWriter_Release(writer);
3037
3038 table++;
3039 i++;
3040 }
3041 }
3042
3043 static void test_mxwriter_properties(void)
3044 {
3045 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3046 static const WCHAR testW[] = {'t','e','s','t',0};
3047 ISAXContentHandler *content;
3048 IMXWriter *writer;
3049 VARIANT_BOOL b;
3050 HRESULT hr;
3051 BSTR str, str2;
3052 VARIANT dest;
3053
3054 test_mxwriter_default_properties(mxwriter_default_props);
3055
3056 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3057 &IID_IMXWriter, (void**)&writer);
3058 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3059
3060 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3061 ok(hr == E_POINTER, "got %08x\n", hr);
3062
3063 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3064 ok(hr == E_POINTER, "got %08x\n", hr);
3065
3066 hr = IMXWriter_get_indent(writer, NULL);
3067 ok(hr == E_POINTER, "got %08x\n", hr);
3068
3069 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3070 ok(hr == E_POINTER, "got %08x\n", hr);
3071
3072 hr = IMXWriter_get_standalone(writer, NULL);
3073 ok(hr == E_POINTER, "got %08x\n", hr);
3074
3075 /* set and check */
3076 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3077 ok(hr == S_OK, "got %08x\n", hr);
3078
3079 b = VARIANT_FALSE;
3080 hr = IMXWriter_get_standalone(writer, &b);
3081 ok(hr == S_OK, "got %08x\n", hr);
3082 ok(b == VARIANT_TRUE, "got %d\n", b);
3083
3084 hr = IMXWriter_get_encoding(writer, NULL);
3085 EXPECT_HR(hr, E_POINTER);
3086
3087 /* UTF-16 is a default setting apparently */
3088 str = (void*)0xdeadbeef;
3089 hr = IMXWriter_get_encoding(writer, &str);
3090 EXPECT_HR(hr, S_OK);
3091 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3092
3093 str2 = (void*)0xdeadbeef;
3094 hr = IMXWriter_get_encoding(writer, &str2);
3095 ok(hr == S_OK, "got %08x\n", hr);
3096 ok(str != str2, "expected newly allocated, got same %p\n", str);
3097
3098 SysFreeString(str2);
3099 SysFreeString(str);
3100
3101 /* put empty string */
3102 str = SysAllocString(emptyW);
3103 hr = IMXWriter_put_encoding(writer, str);
3104 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3105 SysFreeString(str);
3106
3107 str = (void*)0xdeadbeef;
3108 hr = IMXWriter_get_encoding(writer, &str);
3109 EXPECT_HR(hr, S_OK);
3110 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3111 SysFreeString(str);
3112
3113 /* invalid encoding name */
3114 str = SysAllocString(testW);
3115 hr = IMXWriter_put_encoding(writer, str);
3116 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3117 SysFreeString(str);
3118
3119 /* test case sensivity */
3120 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3121 EXPECT_HR(hr, S_OK);
3122 str = (void*)0xdeadbeef;
3123 hr = IMXWriter_get_encoding(writer, &str);
3124 EXPECT_HR(hr, S_OK);
3125 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3126 SysFreeString(str);
3127
3128 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3129 EXPECT_HR(hr, S_OK);
3130 str = (void*)0xdeadbeef;
3131 hr = IMXWriter_get_encoding(writer, &str);
3132 EXPECT_HR(hr, S_OK);
3133 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3134 SysFreeString(str);
3135
3136 /* how it affects document creation */
3137 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3138 EXPECT_HR(hr, S_OK);
3139
3140 hr = ISAXContentHandler_startDocument(content);
3141 EXPECT_HR(hr, S_OK);
3142 hr = ISAXContentHandler_endDocument(content);
3143 EXPECT_HR(hr, S_OK);
3144
3145 V_VT(&dest) = VT_EMPTY;
3146 hr = IMXWriter_get_output(writer, &dest);
3147 EXPECT_HR(hr, S_OK);
3148 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3149 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3150 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3151 VariantClear(&dest);
3152 ISAXContentHandler_Release(content);
3153
3154 hr = IMXWriter_get_version(writer, NULL);
3155 ok(hr == E_POINTER, "got %08x\n", hr);
3156 /* default version is 'surprisingly' 1.0 */
3157 hr = IMXWriter_get_version(writer, &str);
3158 ok(hr == S_OK, "got %08x\n", hr);
3159 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3160 SysFreeString(str);
3161
3162 /* store version string as is */
3163 hr = IMXWriter_put_version(writer, NULL);
3164 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3165
3166 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3167 ok(hr == S_OK, "got %08x\n", hr);
3168
3169 hr = IMXWriter_put_version(writer, _bstr_(""));
3170 ok(hr == S_OK, "got %08x\n", hr);
3171 hr = IMXWriter_get_version(writer, &str);
3172 ok(hr == S_OK, "got %08x\n", hr);
3173 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3174 SysFreeString(str);
3175
3176 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3177 ok(hr == S_OK, "got %08x\n", hr);
3178 hr = IMXWriter_get_version(writer, &str);
3179 ok(hr == S_OK, "got %08x\n", hr);
3180 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3181 SysFreeString(str);
3182
3183 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3184 ok(hr == S_OK, "got %08x\n", hr);
3185 hr = IMXWriter_get_version(writer, &str);
3186 ok(hr == S_OK, "got %08x\n", hr);
3187 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3188 SysFreeString(str);
3189
3190 IMXWriter_Release(writer);
3191 free_bstrs();
3192 }
3193
3194 static void test_mxwriter_flush(void)
3195 {
3196 ISAXContentHandler *content;
3197 IMXWriter *writer;
3198 LARGE_INTEGER pos;
3199 ULARGE_INTEGER pos2;
3200 IStream *stream;
3201 VARIANT dest;
3202 HRESULT hr;
3203 char *buff;
3204 LONG ref;
3205 int len;
3206
3207 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3208 &IID_IMXWriter, (void**)&writer);
3209 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3210
3211 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3212 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3213 EXPECT_REF(stream, 1);
3214
3215 /* detach when nothing was attached */
3216 V_VT(&dest) = VT_EMPTY;
3217 hr = IMXWriter_put_output(writer, dest);
3218 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3219
3220 /* attach stream */
3221 V_VT(&dest) = VT_UNKNOWN;
3222 V_UNKNOWN(&dest) = (IUnknown*)stream;
3223 hr = IMXWriter_put_output(writer, dest);
3224 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3225 todo_wine EXPECT_REF(stream, 3);
3226
3227 /* detach setting VT_EMPTY destination */
3228 V_VT(&dest) = VT_EMPTY;
3229 hr = IMXWriter_put_output(writer, dest);
3230 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3231 EXPECT_REF(stream, 1);
3232
3233 V_VT(&dest) = VT_UNKNOWN;
3234 V_UNKNOWN(&dest) = (IUnknown*)stream;
3235 hr = IMXWriter_put_output(writer, dest);
3236 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3237
3238 /* flush() doesn't detach a stream */
3239 hr = IMXWriter_flush(writer);
3240 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3241 todo_wine EXPECT_REF(stream, 3);
3242
3243 pos.QuadPart = 0;
3244 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3245 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3246 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3247
3248 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3249 ok(hr == S_OK, "got %08x\n", hr);
3250
3251 hr = ISAXContentHandler_startDocument(content);
3252 ok(hr == S_OK, "got %08x\n", hr);
3253
3254 pos.QuadPart = 0;
3255 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3256 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3257 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3258
3259 /* already started */
3260 hr = ISAXContentHandler_startDocument(content);
3261 ok(hr == S_OK, "got %08x\n", hr);
3262
3263 hr = ISAXContentHandler_endDocument(content);
3264 ok(hr == S_OK, "got %08x\n", hr);
3265
3266 /* flushed on endDocument() */
3267 pos.QuadPart = 0;
3268 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3269 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3270 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3271
3272 IStream_Release(stream);
3273
3274 /* auto-flush feature */
3275 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3276 EXPECT_HR(hr, S_OK);
3277 EXPECT_REF(stream, 1);
3278
3279 V_VT(&dest) = VT_UNKNOWN;
3280 V_UNKNOWN(&dest) = (IUnknown*)stream;
3281 hr = IMXWriter_put_output(writer, dest);
3282 EXPECT_HR(hr, S_OK);
3283
3284 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3285 EXPECT_HR(hr, S_OK);
3286
3287 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3288 EXPECT_HR(hr, S_OK);
3289
3290 hr = ISAXContentHandler_startDocument(content);
3291 EXPECT_HR(hr, S_OK);
3292
3293 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3294 EXPECT_HR(hr, S_OK);
3295
3296 /* internal buffer is flushed automatically on certain threshold */
3297 pos.QuadPart = 0;
3298 pos2.QuadPart = 1;
3299 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3300 EXPECT_HR(hr, S_OK);
3301 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3302
3303 len = 2048;
3304 buff = HeapAlloc(GetProcessHeap(), 0, len);
3305 memset(buff, 'A', len);
3306 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3307 EXPECT_HR(hr, S_OK);
3308
3309 pos.QuadPart = 0;
3310 pos2.QuadPart = 0;
3311 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3312 EXPECT_HR(hr, S_OK);
3313 todo_wine
3314 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3315
3316 hr = IMXWriter_get_output(writer, NULL);
3317 EXPECT_HR(hr, E_POINTER);
3318
3319 ref = get_refcount(stream);
3320 V_VT(&dest) = VT_EMPTY;
3321 hr = IMXWriter_get_output(writer, &dest);
3322 EXPECT_HR(hr, S_OK);
3323 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3324 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3325 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3326 VariantClear(&dest);
3327
3328 hr = ISAXContentHandler_endDocument(content);
3329 EXPECT_HR(hr, S_OK);
3330
3331 IStream_Release(stream);
3332
3333 /* test char count lower than threshold */
3334 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3335 EXPECT_HR(hr, S_OK);
3336 EXPECT_REF(stream, 1);
3337
3338 hr = ISAXContentHandler_startDocument(content);
3339 EXPECT_HR(hr, S_OK);
3340
3341 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3342 EXPECT_HR(hr, S_OK);
3343
3344 pos.QuadPart = 0;
3345 pos2.QuadPart = 1;
3346 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3347 EXPECT_HR(hr, S_OK);
3348 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3349
3350 memset(buff, 'A', len);
3351 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3352 EXPECT_HR(hr, S_OK);
3353
3354 pos.QuadPart = 0;
3355 pos2.QuadPart = 1;
3356 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3357 EXPECT_HR(hr, S_OK);
3358 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3359
3360 hr = ISAXContentHandler_endDocument(content);
3361 EXPECT_HR(hr, S_OK);
3362
3363 /* test auto-flush function when stream is not set */
3364 V_VT(&dest) = VT_EMPTY;
3365 hr = IMXWriter_put_output(writer, dest);
3366 EXPECT_HR(hr, S_OK);
3367
3368 hr = ISAXContentHandler_startDocument(content);
3369 EXPECT_HR(hr, S_OK);
3370
3371 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3372 EXPECT_HR(hr, S_OK);
3373
3374 memset(buff, 'A', len);
3375 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3376 EXPECT_HR(hr, S_OK);
3377
3378 V_VT(&dest) = VT_EMPTY;
3379 hr = IMXWriter_get_output(writer, &dest);
3380 EXPECT_HR(hr, S_OK);
3381 len += strlen("<a>");
3382 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3383 VariantClear(&dest);
3384
3385 HeapFree(GetProcessHeap(), 0, buff);
3386 ISAXContentHandler_Release(content);
3387 IStream_Release(stream);
3388 IMXWriter_Release(writer);
3389 free_bstrs();
3390 }
3391
3392 static void test_mxwriter_startenddocument(void)
3393 {
3394 ISAXContentHandler *content;
3395 IMXWriter *writer;
3396 VARIANT dest;
3397 HRESULT hr;
3398
3399 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3400 &IID_IMXWriter, (void**)&writer);
3401 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3402
3403 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3404 ok(hr == S_OK, "got %08x\n", hr);
3405
3406 hr = ISAXContentHandler_startDocument(content);
3407 ok(hr == S_OK, "got %08x\n", hr);
3408
3409 hr = ISAXContentHandler_endDocument(content);
3410 ok(hr == S_OK, "got %08x\n", hr);
3411
3412 V_VT(&dest) = VT_EMPTY;
3413 hr = IMXWriter_get_output(writer, &dest);
3414 ok(hr == S_OK, "got %08x\n", hr);
3415 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3416 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3417 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3418 VariantClear(&dest);
3419
3420 /* now try another startDocument */
3421 hr = ISAXContentHandler_startDocument(content);
3422 ok(hr == S_OK, "got %08x\n", hr);
3423 /* and get duplicated prolog */
3424 V_VT(&dest) = VT_EMPTY;
3425 hr = IMXWriter_get_output(writer, &dest);
3426 ok(hr == S_OK, "got %08x\n", hr);
3427 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3428 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3429 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3430 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3431 VariantClear(&dest);
3432
3433 ISAXContentHandler_Release(content);
3434 IMXWriter_Release(writer);
3435
3436 /* now with omitted declaration */
3437 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3438 &IID_IMXWriter, (void**)&writer);
3439 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3440
3441 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3442 ok(hr == S_OK, "got %08x\n", hr);
3443
3444 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3445 ok(hr == S_OK, "got %08x\n", hr);
3446
3447 hr = ISAXContentHandler_startDocument(content);
3448 ok(hr == S_OK, "got %08x\n", hr);
3449
3450 hr = ISAXContentHandler_endDocument(content);
3451 ok(hr == S_OK, "got %08x\n", hr);
3452
3453 V_VT(&dest) = VT_EMPTY;
3454 hr = IMXWriter_get_output(writer, &dest);
3455 ok(hr == S_OK, "got %08x\n", hr);
3456 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3457 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3458 VariantClear(&dest);
3459
3460 ISAXContentHandler_Release(content);
3461 IMXWriter_Release(writer);
3462
3463 free_bstrs();
3464 }
3465
3466 enum startendtype
3467 {
3468 StartElement = 0x001,
3469 EndElement = 0x010,
3470 StartEndElement = 0x011,
3471 DisableEscaping = 0x100
3472 };
3473
3474 struct writer_startendelement_t {
3475 const GUID *clsid;
3476 enum startendtype type;
3477 const char *uri;
3478 const char *local_name;
3479 const char *qname;
3480 const char *output;
3481 HRESULT hr;
3482 ISAXAttributes *attr;
3483 };
3484
3485 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\">";
3486 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\"/>";
3487 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>";
3488
3489 static const struct writer_startendelement_t writer_startendelement[] = {
3490 /* 0 */
3491 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3492 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3493 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3494 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3495 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3496 /* 5 */
3497 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3498 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3499 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3500 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3501 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3502 /* 10 */
3503 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3504 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3505 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3506 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3507 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3508 /* 15 */
3509 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3510 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3511 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3512 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3513 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3514 /* 20 */
3515 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3516 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3517 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3518 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3519 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3520 /* 25 */
3521 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3522 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3523 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3524 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3525 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3526 /* 30 */
3527 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3528 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3529 /* endElement tests */
3530 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3531 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3532 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3533 /* 35 */
3534 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3535 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3536 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3537 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3538 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3539 /* 40 */
3540 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3541 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3542 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3543 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3544 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3545 /* 45 */
3546 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3547 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3548 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3549 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3550 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3551 /* 50 */
3552 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3553 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3554 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3555 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3556 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3557 /* 55 */
3558 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3559 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3560 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3561 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3562 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3563 /* 60 */
3564 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3565 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3566 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3567 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3568
3569 /* with attributes */
3570 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3571 /* 65 */
3572 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3573 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3574 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3575 /* empty elements */
3576 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3577 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3578 /* 70 */
3579 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3580 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3581 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3582 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3583 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3584 /* 75 */
3585 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3586
3587 /* with disabled output escaping */
3588 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3589 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3590 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3591 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3592
3593 { NULL }
3594 };
3595
3596 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3597 {
3598 while (table->clsid)
3599 {
3600 IUnknown *unk;
3601 HRESULT hr;
3602
3603 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3604 if (hr == S_OK) IUnknown_Release(unk);
3605
3606 table->supported = hr == S_OK;
3607 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3608
3609 table++;
3610 }
3611 }
3612
3613 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3614 {
3615 int i = 0;
3616
3617 while (table->clsid)
3618 {
3619 ISAXContentHandler *content;
3620 IMXWriter *writer;
3621 HRESULT hr;
3622
3623 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3624 {
3625 table++;
3626 i++;
3627 continue;
3628 }
3629
3630 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3631 &IID_IMXWriter, (void**)&writer);
3632 EXPECT_HR(hr, S_OK);
3633
3634 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3635 EXPECT_HR(hr, S_OK);
3636
3637 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3638 EXPECT_HR(hr, S_OK);
3639
3640 hr = ISAXContentHandler_startDocument(content);
3641 EXPECT_HR(hr, S_OK);
3642
3643 if (table->type & DisableEscaping)
3644 {
3645 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3646 EXPECT_HR(hr, S_OK);
3647 }
3648
3649 if (table->type & StartElement)
3650 {
3651 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3652 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3653 table->qname ? strlen(table->qname) : 0, table->attr);
3654 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3655 }
3656
3657 if (table->type & EndElement)
3658 {
3659 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3660 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3661 table->qname ? strlen(table->qname) : 0);
3662 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3663 }
3664
3665 /* test output */
3666 if (hr == S_OK)
3667 {
3668 VARIANT dest;
3669
3670 V_VT(&dest) = VT_EMPTY;
3671 hr = IMXWriter_get_output(writer, &dest);
3672 EXPECT_HR(hr, S_OK);
3673 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3674 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3675 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3676 VariantClear(&dest);
3677 }
3678
3679 ISAXContentHandler_Release(content);
3680 IMXWriter_Release(writer);
3681
3682 table++;
3683 i++;
3684 }
3685
3686 free_bstrs();
3687 }
3688
3689 /* point of these test is to start/end element with different names and name lengths */
3690 struct writer_startendelement2_t {
3691 const GUID *clsid;
3692 const char *qnamestart;
3693 int qnamestart_len;
3694 const char *qnameend;
3695 int qnameend_len;
3696 const char *output;
3697 HRESULT hr;
3698 };
3699
3700 static const struct writer_startendelement2_t writer_startendelement2[] = {
3701 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3702 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3703 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3704 /* -1 length is not allowed for version 6 */
3705 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3706
3707 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3708 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3709 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3710 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3711 { NULL }
3712 };
3713
3714 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3715 {
3716 int i = 0;
3717
3718 while (table->clsid)
3719 {
3720 ISAXContentHandler *content;
3721 IMXWriter *writer;
3722 HRESULT hr;
3723
3724 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3725 {
3726 table++;
3727 i++;
3728 continue;
3729 }
3730
3731 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3732 &IID_IMXWriter, (void**)&writer);
3733 EXPECT_HR(hr, S_OK);
3734
3735 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3736 EXPECT_HR(hr, S_OK);
3737
3738 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3739 EXPECT_HR(hr, S_OK);
3740
3741 hr = ISAXContentHandler_startDocument(content);
3742 EXPECT_HR(hr, S_OK);
3743
3744 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3745 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3746 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3747
3748 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3749 _bstr_(table->qnameend), table->qnameend_len);
3750 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3751
3752 /* test output */
3753 if (hr == S_OK)
3754 {
3755 VARIANT dest;
3756
3757 V_VT(&dest) = VT_EMPTY;
3758 hr = IMXWriter_get_output(writer, &dest);
3759 EXPECT_HR(hr, S_OK);
3760 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3761 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3762 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3763 VariantClear(&dest);
3764 }
3765
3766 ISAXContentHandler_Release(content);
3767 IMXWriter_Release(writer);
3768
3769 table++;
3770 i++;
3771
3772 free_bstrs();
3773 }
3774 }
3775
3776
3777 static void test_mxwriter_startendelement(void)
3778 {
3779 ISAXContentHandler *content;
3780 IMXWriter *writer;
3781 VARIANT dest;
3782 HRESULT hr;
3783
3784 test_mxwriter_startendelement_batch(writer_startendelement);
3785 test_mxwriter_startendelement_batch2(writer_startendelement2);
3786
3787 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3788 &IID_IMXWriter, (void**)&writer);
3789 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3790
3791 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3792 ok(hr == S_OK, "got %08x\n", hr);
3793
3794 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3795 ok(hr == S_OK, "got %08x\n", hr);
3796
3797 hr = ISAXContentHandler_startDocument(content);
3798 ok(hr == S_OK, "got %08x\n", hr);
3799
3800 /* all string pointers should be not null */
3801 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3802 ok(hr == S_OK, "got %08x\n", hr);
3803
3804 V_VT(&dest) = VT_EMPTY;
3805 hr = IMXWriter_get_output(writer, &dest);
3806 ok(hr == S_OK, "got %08x\n", hr);
3807 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3808 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3809 VariantClear(&dest);
3810
3811 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3812 ok(hr == S_OK, "got %08x\n", hr);
3813
3814 V_VT(&dest) = VT_EMPTY;
3815 hr = IMXWriter_get_output(writer, &dest);
3816 ok(hr == S_OK, "got %08x\n", hr);
3817 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3818 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3819 VariantClear(&dest);
3820
3821 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3822 EXPECT_HR(hr, E_INVALIDARG);
3823
3824 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3825 EXPECT_HR(hr, E_INVALIDARG);
3826
3827 /* only local name is an error too */
3828 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3829 EXPECT_HR(hr, E_INVALIDARG);
3830
3831 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3832 EXPECT_HR(hr, S_OK);
3833
3834 V_VT(&dest) = VT_EMPTY;
3835 hr = IMXWriter_get_output(writer, &dest);
3836 EXPECT_HR(hr, S_OK);
3837 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3838 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3839 VariantClear(&dest);
3840
3841 hr = ISAXContentHandler_endDocument(content);
3842 EXPECT_HR(hr, S_OK);
3843
3844 V_VT(&dest) = VT_EMPTY;
3845 hr = IMXWriter_put_output(writer, dest);
3846 EXPECT_HR(hr, S_OK);
3847
3848 V_VT(&dest) = VT_EMPTY;
3849 hr = IMXWriter_get_output(writer, &dest);
3850 EXPECT_HR(hr, S_OK);
3851 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3852 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3853 VariantClear(&dest);
3854
3855 hr = ISAXContentHandler_startDocument(content);
3856 EXPECT_HR(hr, S_OK);
3857
3858 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3859 EXPECT_HR(hr, S_OK);
3860
3861 V_VT(&dest) = VT_EMPTY;
3862 hr = IMXWriter_get_output(writer, &dest);
3863 EXPECT_HR(hr, S_OK);
3864 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3865 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3866 VariantClear(&dest);
3867
3868 hr = ISAXContentHandler_endDocument(content);
3869 EXPECT_HR(hr, S_OK);
3870 IMXWriter_flush(writer);
3871
3872 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3873 EXPECT_HR(hr, S_OK);
3874 V_VT(&dest) = VT_EMPTY;
3875 hr = IMXWriter_get_output(writer, &dest);
3876 EXPECT_HR(hr, S_OK);
3877 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3878 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3879 VariantClear(&dest);
3880
3881 V_VT(&dest) = VT_EMPTY;
3882 hr = IMXWriter_put_output(writer, dest);
3883 EXPECT_HR(hr, S_OK);
3884
3885 /* length -1 */
3886 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3887 EXPECT_HR(hr, S_OK);
3888 V_VT(&dest) = VT_EMPTY;
3889 hr = IMXWriter_get_output(writer, &dest);
3890 EXPECT_HR(hr, S_OK);
3891 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3892 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3893 VariantClear(&dest);
3894
3895 ISAXContentHandler_Release(content);
3896 IMXWriter_Release(writer);
3897 free_bstrs();
3898 }
3899
3900 struct writer_characters_t {
3901 const GUID *clsid;
3902 const char *data;
3903 const char *output;
3904 };
3905
3906 static const struct writer_characters_t writer_characters[] = {
3907 { &CLSID_MXXMLWriter, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3908 { &CLSID_MXXMLWriter30, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3909 { &CLSID_MXXMLWriter40, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3910 { &CLSID_MXXMLWriter60, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3911 { NULL }
3912 };
3913
3914 static void test_mxwriter_characters(void)
3915 {
3916 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3917 const struct writer_characters_t *table = writer_characters;
3918 ISAXContentHandler *content;
3919 IMXWriter *writer;
3920 VARIANT dest;
3921 HRESULT hr;
3922 int i = 0;
3923
3924 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3925 &IID_IMXWriter, (void**)&writer);
3926 EXPECT_HR(hr, S_OK);
3927
3928 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3929 EXPECT_HR(hr, S_OK);
3930
3931 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3932 EXPECT_HR(hr, S_OK);
3933
3934 hr = ISAXContentHandler_startDocument(content);
3935 EXPECT_HR(hr, S_OK);
3936
3937 hr = ISAXContentHandler_characters(content, NULL, 0);
3938 EXPECT_HR(hr, E_INVALIDARG);
3939
3940 hr = ISAXContentHandler_characters(content, chardataW, 0);
3941 EXPECT_HR(hr, S_OK);
3942
3943 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3944 EXPECT_HR(hr, S_OK);
3945
3946 V_VT(&dest) = VT_EMPTY;
3947 hr = IMXWriter_get_output(writer, &dest);
3948 EXPECT_HR(hr, S_OK);
3949 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3950 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3951 VariantClear(&dest);
3952
3953 hr = ISAXContentHandler_endDocument(content);
3954 EXPECT_HR(hr, S_OK);
3955
3956 ISAXContentHandler_Release(content);
3957 IMXWriter_Release(writer);
3958
3959 /* try empty characters data to see if element is closed */
3960 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3961 &IID_IMXWriter, (void**)&writer);
3962 EXPECT_HR(hr, S_OK);
3963
3964 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3965 EXPECT_HR(hr, S_OK);
3966
3967 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3968 EXPECT_HR(hr, S_OK);
3969
3970 hr = ISAXContentHandler_startDocument(content);
3971 EXPECT_HR(hr, S_OK);
3972
3973 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3974 EXPECT_HR(hr, S_OK);
3975
3976 hr = ISAXContentHandler_characters(content, chardataW, 0);
3977 EXPECT_HR(hr, S_OK);
3978
3979 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3980 EXPECT_HR(hr, S_OK);
3981
3982 V_VT(&dest) = VT_EMPTY;
3983 hr = IMXWriter_get_output(writer, &dest);
3984 EXPECT_HR(hr, S_OK);
3985 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3986 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3987 VariantClear(&dest);
3988
3989 ISAXContentHandler_Release(content);
3990 IMXWriter_Release(writer);
3991
3992 /* batch tests */
3993 while (table->clsid)
3994 {
3995 ISAXContentHandler *content;
3996 IMXWriter *writer;
3997 VARIANT dest;
3998 HRESULT hr;
3999
4000 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
4001 {
4002 table++;
4003 i++;
4004 continue;
4005 }
4006
4007 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4008 &IID_IMXWriter, (void**)&writer);
4009 EXPECT_HR(hr, S_OK);
4010
4011 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4012 EXPECT_HR(hr, S_OK);
4013
4014 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4015 EXPECT_HR(hr, S_OK);
4016
4017 hr = ISAXContentHandler_startDocument(content);
4018 EXPECT_HR(hr, S_OK);
4019
4020 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4021 EXPECT_HR(hr, S_OK);
4022
4023 /* test output */
4024 if (hr == S_OK)
4025 {
4026 V_VT(&dest) = VT_EMPTY;
4027 hr = IMXWriter_get_output(writer, &dest);
4028 EXPECT_HR(hr, S_OK);
4029 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4030 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
4031 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
4032 VariantClear(&dest);
4033 }
4034
4035 /* with disabled escaping */
4036 V_VT(&dest) = VT_EMPTY;
4037 hr = IMXWriter_put_output(writer, dest);
4038 EXPECT_HR(hr, S_OK);
4039
4040 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
4041 EXPECT_HR(hr, S_OK);
4042
4043 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4044 EXPECT_HR(hr, S_OK);
4045
4046 /* test output */
4047 if (hr == S_OK)
4048 {
4049 V_VT(&dest) = VT_EMPTY;
4050 hr = IMXWriter_get_output(writer, &dest);
4051 EXPECT_HR(hr, S_OK);
4052 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4053 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
4054 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
4055 VariantClear(&dest);
4056 }
4057
4058 ISAXContentHandler_Release(content);
4059 IMXWriter_Release(writer);
4060
4061 table++;
4062 i++;
4063 }
4064
4065 free_bstrs();
4066 }
4067
4068 static const mxwriter_stream_test mxwriter_stream_tests[] = {
4069 {
4070 VARIANT_TRUE,"UTF-16",
4071 {
4072 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4073 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4074 {TRUE}
4075 }
4076 },
4077 {
4078 VARIANT_FALSE,"UTF-16",
4079 {
4080 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4081 {TRUE}
4082 }
4083 },
4084 {
4085 VARIANT_TRUE,"UTF-8",
4086 {
4087 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
4088 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4089 * and the writer is released.
4090 */
4091 {FALSE,NULL,0},
4092 {TRUE}
4093 }
4094 },
4095 {
4096 VARIANT_TRUE,"utf-8",
4097 {
4098 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
4099 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4100 * and the writer is released.
4101 */
4102 {FALSE,NULL,0},
4103 {TRUE}
4104 }
4105 },
4106 {
4107 VARIANT_TRUE,"UTF-16",
4108 {
4109 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4110 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4111 {TRUE}
4112 }
4113 },
4114 {
4115 VARIANT_TRUE,"UTF-16",
4116 {
4117 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
4118 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4119 {TRUE}
4120 }
4121 }
4122 };
4123
4124 static void test_mxwriter_stream(void)
4125 {
4126 IMXWriter *writer;
4127 ISAXContentHandler *content;
4128 HRESULT hr;
4129 VARIANT dest;
4130 IStream *stream;
4131 LARGE_INTEGER pos;
4132 ULARGE_INTEGER pos2;
4133 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
4134
4135 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
4136 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
4137
4138 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4139 &IID_IMXWriter, (void**)&writer);
4140 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4141
4142 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4143 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4144
4145 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
4146 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
4147
4148 V_VT(&dest) = VT_UNKNOWN;
4149 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
4150 hr = IMXWriter_put_output(writer, dest);
4151 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
4152 VariantClear(&dest);
4153
4154 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4155 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4156
4157 current_write_test = test->expected_writes;
4158
4159 hr = ISAXContentHandler_startDocument(content);
4160 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4161
4162 hr = ISAXContentHandler_endDocument(content);
4163 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4164
4165 ISAXContentHandler_Release(content);
4166 IMXWriter_Release(writer);
4167
4168 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4169 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4170 }
4171
4172 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4173 &IID_IMXWriter, (void**)&writer);
4174 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4175
4176 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4177 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4178
4179 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4180 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4181
4182 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4183 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4184
4185 V_VT(&dest) = VT_UNKNOWN;
4186 V_UNKNOWN(&dest) = (IUnknown*)stream;
4187 hr = IMXWriter_put_output(writer, dest);
4188 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4189
4190 hr = ISAXContentHandler_startDocument(content);
4191 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4192
4193 /* Setting output of the mxwriter causes the current output to be flushed,
4194 * and the writer to start over.
4195 */
4196 V_VT(&dest) = VT_EMPTY;
4197 hr = IMXWriter_put_output(writer, dest);
4198 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4199
4200 pos.QuadPart = 0;
4201 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4202 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4203 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4204
4205 hr = ISAXContentHandler_startDocument(content);
4206 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4207
4208 hr = ISAXContentHandler_endDocument(content);
4209 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4210
4211 V_VT(&dest) = VT_EMPTY;
4212 hr = IMXWriter_get_output(writer, &dest);
4213 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4214 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4215 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4216 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4217 VariantClear(&dest);
4218
4219 /* test when BOM is written to output stream */
4220 V_VT(&dest) = VT_EMPTY;
4221 hr = IMXWriter_put_output(writer, dest);
4222 EXPECT_HR(hr, S_OK);
4223
4224 pos.QuadPart = 0;
4225 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4226 EXPECT_HR(hr, S_OK);
4227
4228 V_VT(&dest) = VT_UNKNOWN;
4229 V_UNKNOWN(&dest) = (IUnknown*)stream;
4230 hr = IMXWriter_put_output(writer, dest);
4231 EXPECT_HR(hr, S_OK);
4232
4233 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4234 EXPECT_HR(hr, S_OK);
4235
4236 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4237 EXPECT_HR(hr, S_OK);
4238
4239 hr = ISAXContentHandler_startDocument(content);
4240 EXPECT_HR(hr, S_OK);
4241
4242 pos.QuadPart = 0;
4243 pos2.QuadPart = 0;
4244 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4245 EXPECT_HR(hr, S_OK);
4246 ok(pos2.QuadPart == 2, "got wrong position\n");
4247
4248 ISAXContentHandler_Release(content);
4249 IMXWriter_Release(writer);
4250
4251 free_bstrs();
4252 }
4253
4254 static const char *encoding_names[] = {
4255 "iso-8859-1",
4256 "iso-8859-2",
4257 "iso-8859-3",
4258 "iso-8859-4",
4259 "iso-8859-5",
4260 "iso-8859-7",
4261 "iso-8859-9",
4262 "iso-8859-13",
4263 "iso-8859-15",
4264 NULL
4265 };
4266
4267 static void test_mxwriter_encoding(void)
4268 {
4269 ISAXContentHandler *content;
4270 IMXWriter *writer;
4271 IStream *stream;
4272 const char *enc;
4273 VARIANT dest;
4274 HRESULT hr;
4275 HGLOBAL g;
4276 char *ptr;
4277 BSTR s;
4278 int i;
4279
4280 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4281 &IID_IMXWriter, (void**)&writer);
4282 EXPECT_HR(hr, S_OK);
4283
4284 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4285 EXPECT_HR(hr, S_OK);
4286
4287 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4288 EXPECT_HR(hr, S_OK);
4289
4290 hr = ISAXContentHandler_startDocument(content);
4291 EXPECT_HR(hr, S_OK);
4292
4293 hr = ISAXContentHandler_endDocument(content);
4294 EXPECT_HR(hr, S_OK);
4295
4296 /* The content is always re-encoded to UTF-16 when the output is
4297 * retrieved as a BSTR.
4298 */
4299 V_VT(&dest) = VT_EMPTY;
4300 hr = IMXWriter_get_output(writer, &dest);
4301 EXPECT_HR(hr, S_OK);
4302 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4303 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4304 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4305 VariantClear(&dest);
4306
4307 /* switch encoding when something is written already */
4308 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4309 EXPECT_HR(hr, S_OK);
4310
4311 V_VT(&dest) = VT_UNKNOWN;
4312 V_UNKNOWN(&dest) = (IUnknown*)stream;
4313 hr = IMXWriter_put_output(writer, dest);
4314 EXPECT_HR(hr, S_OK);
4315
4316 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4317 EXPECT_HR(hr, S_OK);
4318
4319 /* write empty element */
4320 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4321 EXPECT_HR(hr, S_OK);
4322
4323 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4324 EXPECT_HR(hr, S_OK);
4325
4326 /* switch */
4327 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4328 EXPECT_HR(hr, S_OK);
4329
4330 hr = IMXWriter_flush(writer);
4331 EXPECT_HR(hr, S_OK);
4332
4333 hr = GetHGlobalFromStream(stream, &g);
4334 EXPECT_HR(hr, S_OK);
4335
4336 ptr = GlobalLock(g);
4337 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4338 GlobalUnlock(g);
4339
4340 /* so output is unaffected, encoding name is stored however */
4341 hr = IMXWriter_get_encoding(writer, &s);
4342 EXPECT_HR(hr, S_OK);
4343 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4344 SysFreeString(s);
4345
4346 IStream_Release(stream);
4347
4348 i = 0;
4349 enc = encoding_names[i];
4350 while (enc)
4351 {
4352 char expectedA[200];
4353
4354 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4355 EXPECT_HR(hr, S_OK);
4356
4357 V_VT(&dest) = VT_UNKNOWN;
4358 V_UNKNOWN(&dest) = (IUnknown*)stream;
4359 hr = IMXWriter_put_output(writer, dest);
4360 EXPECT_HR(hr, S_OK);
4361
4362 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4363 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4364 "%s: encoding not accepted\n", enc);
4365 if (hr != S_OK)
4366 {
4367 enc = encoding_names[++i];
4368 IStream_Release(stream);
4369 continue;
4370 }
4371
4372 hr = ISAXContentHandler_startDocument(content);
4373 EXPECT_HR(hr, S_OK);
4374
4375 hr = ISAXContentHandler_endDocument(content);
4376 EXPECT_HR(hr, S_OK);
4377
4378 hr = IMXWriter_flush(writer);
4379 EXPECT_HR(hr, S_OK);
4380
4381 /* prepare expected string */
4382 *expectedA = 0;
4383 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4384 strcat(expectedA, enc);
4385 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4386
4387 hr = GetHGlobalFromStream(stream, &g);
4388 EXPECT_HR(hr, S_OK);
4389
4390 ptr = GlobalLock(g);
4391 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4392 GlobalUnlock(g);
4393
4394 V_VT(&dest) = VT_EMPTY;
4395 hr = IMXWriter_put_output(writer, dest);
4396 EXPECT_HR(hr, S_OK);
4397
4398 IStream_Release(stream);
4399
4400 enc = encoding_names[++i];
4401 }
4402
4403 ISAXContentHandler_Release(content);
4404 IMXWriter_Release(writer);
4405
4406 free_bstrs();
4407 }
4408
4409 static void test_obj_dispex(IUnknown *obj)
4410 {
4411 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0};
4412 static const WCHAR starW[] = {'*',0};
4413 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4414 IDispatchEx *dispex;
4415 IUnknown *unk;
4416 DWORD props;
4417 UINT ticnt;
4418 HRESULT hr;
4419 BSTR name;
4420 DISPID did;
4421
4422 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4423 EXPECT_HR(hr, S_OK);
4424 if (FAILED(hr)) return;
4425
4426 ticnt = 0;
4427 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4428 EXPECT_HR(hr, S_OK);
4429 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4430
4431 name = SysAllocString(starW);
4432 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4433 EXPECT_HR(hr, E_NOTIMPL);
4434 SysFreeString(name);
4435
4436 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4437 EXPECT_HR(hr, E_NOTIMPL);
4438
4439 props = 0;
4440 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4441 EXPECT_HR(hr, E_NOTIMPL);
4442 ok(props == 0, "expected 0 got %d\n", props);
4443
4444 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4445 EXPECT_HR(hr, E_NOTIMPL);
4446 if (SUCCEEDED(hr)) SysFreeString(name);
4447
4448 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4449 EXPECT_HR(hr, E_NOTIMPL);
4450
4451 unk = (IUnknown*)0xdeadbeef;
4452 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4453 EXPECT_HR(hr, E_NOTIMPL);
4454 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
4455
4456 name = SysAllocString(testW);
4457 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
4458 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr);
4459 SysFreeString(name);
4460
4461 IDispatchEx_Release(dispex);
4462 }
4463
4464 static void test_saxreader_dispex(void)
4465 {
4466 IVBSAXXMLReader *vbreader;
4467 ISAXXMLReader *reader;
4468 DISPPARAMS dispparams;
4469 DISPID dispid;
4470 IUnknown *unk;
4471 VARIANT arg;
4472 HRESULT hr;
4473
4474 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4475 &IID_ISAXXMLReader, (void**)&reader);
4476 EXPECT_HR(hr, S_OK);
4477
4478 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4479 EXPECT_HR(hr, S_OK);
4480 test_obj_dispex(unk);
4481 IUnknown_Release(unk);
4482
4483 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4484 EXPECT_HR(hr, S_OK);
4485 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4486 EXPECT_HR(hr, S_OK);
4487 test_obj_dispex(unk);
4488 IUnknown_Release(unk);
4489
4490 dispid = DISPID_PROPERTYPUT;
4491 dispparams.cArgs = 1;
4492 dispparams.cNamedArgs = 1;
4493 dispparams.rgdispidNamedArgs = &dispid;
4494 dispparams.rgvarg = &arg;
4495
4496 V_VT(&arg) = VT_DISPATCH;
4497 V_DISPATCH(&arg) = NULL;
4498
4499 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */
4500 hr = IVBSAXXMLReader_Invoke(vbreader,
4501 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4502 &IID_NULL,
4503 0,
4504 DISPATCH_PROPERTYPUT,
4505 &dispparams,
4506 NULL,
4507 NULL,
4508 NULL);
4509 ok(hr == S_OK, "got 0x%08x\n", hr);
4510
4511 hr = IVBSAXXMLReader_Invoke(vbreader,
4512 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4513 &IID_NULL,
4514 0,
4515 DISPATCH_PROPERTYPUTREF,
4516 &dispparams,
4517 NULL,
4518 NULL,
4519 NULL);
4520 ok(hr == S_OK, "got 0x%08x\n", hr);
4521
4522 IVBSAXXMLReader_Release(vbreader);
4523 ISAXXMLReader_Release(reader);
4524
4525 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data))
4526 {
4527 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4528 ok(hr == S_OK, "got 0x%08x\n", hr);
4529 test_obj_dispex(unk);
4530 IUnknown_Release(unk);
4531 }
4532 }
4533
4534 static void test_mxwriter_dispex(void)
4535 {
4536 IDispatchEx *dispex;
4537 IMXWriter *writer;
4538 IUnknown *unk;
4539 HRESULT hr;
4540
4541 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4542 &IID_IMXWriter, (void**)&writer);
4543 EXPECT_HR(hr, S_OK);
4544
4545 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4546 EXPECT_HR(hr, S_OK);
4547 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4548 test_obj_dispex(unk);
4549 IUnknown_Release(unk);
4550 IDispatchEx_Release(dispex);
4551 IMXWriter_Release(writer);
4552
4553 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data))
4554 {
4555 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4556 ok(hr == S_OK, "got 0x%08x\n", hr);
4557 test_obj_dispex(unk);
4558 IUnknown_Release(unk);
4559 }
4560 }
4561
4562 static void test_mxwriter_comment(void)
4563 {
4564 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4565 IVBSAXLexicalHandler *vblexical;
4566 ISAXContentHandler *content;
4567 ISAXLexicalHandler *lexical;
4568 IMXWriter *writer;
4569 VARIANT dest;
4570 HRESULT hr;
4571
4572 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4573 &IID_IMXWriter, (void**)&writer);
4574 EXPECT_HR(hr, S_OK);
4575
4576 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4577 EXPECT_HR(hr, S_OK);
4578
4579 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4580 EXPECT_HR(hr, S_OK);
4581
4582 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4583 EXPECT_HR(hr, S_OK);
4584
4585 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4586 EXPECT_HR(hr, S_OK);
4587
4588 hr = ISAXContentHandler_startDocument(content);
4589 EXPECT_HR(hr, S_OK);
4590
4591 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4592 EXPECT_HR(hr, E_INVALIDARG);
4593
4594 hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
4595 EXPECT_HR(hr, E_POINTER);
4596
4597 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4598 EXPECT_HR(hr, S_OK);
4599
4600 V_VT(&dest) = VT_EMPTY;
4601 hr = IMXWriter_get_output(writer, &dest);
4602 EXPECT_HR(hr, S_OK);
4603 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4604 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4605 VariantClear(&dest);
4606
4607 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4608 EXPECT_HR(hr, S_OK);
4609
4610 V_VT(&dest) = VT_EMPTY;
4611 hr = IMXWriter_get_output(writer, &dest);
4612 EXPECT_HR(hr, S_OK);
4613 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4614 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4615 VariantClear(&dest);
4616
4617 ISAXContentHandler_Release(content);
4618 ISAXLexicalHandler_Release(lexical);
4619 IVBSAXLexicalHandler_Release(vblexical);
4620 IMXWriter_Release(writer);
4621 free_bstrs();
4622 }
4623
4624 static void test_mxwriter_cdata(void)
4625 {
4626 IVBSAXLexicalHandler *vblexical;
4627 ISAXContentHandler *content;
4628 ISAXLexicalHandler *lexical;
4629 IMXWriter *writer;
4630 VARIANT dest;
4631 HRESULT hr;
4632
4633 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4634 &IID_IMXWriter, (void**)&writer);
4635 EXPECT_HR(hr, S_OK);
4636
4637 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4638 EXPECT_HR(hr, S_OK);
4639
4640 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4641 EXPECT_HR(hr, S_OK);
4642
4643 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4644 EXPECT_HR(hr, S_OK);
4645
4646 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4647 EXPECT_HR(hr, S_OK);
4648
4649 hr = ISAXContentHandler_startDocument(content);
4650 EXPECT_HR(hr, S_OK);
4651
4652 hr = ISAXLexicalHandler_startCDATA(lexical);
4653 EXPECT_HR(hr, S_OK);
4654
4655 V_VT(&dest) = VT_EMPTY;
4656 hr = IMXWriter_get_output(writer, &dest);
4657 EXPECT_HR(hr, S_OK);
4658 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4659 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4660 VariantClear(&dest);
4661
4662 hr = IVBSAXLexicalHandler_startCDATA(vblexical);
4663 EXPECT_HR(hr, S_OK);
4664
4665 /* all these are escaped for text nodes */
4666 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4667 EXPECT_HR(hr, S_OK);
4668
4669 hr = ISAXLexicalHandler_endCDATA(lexical);
4670 EXPECT_HR(hr, S_OK);
4671
4672 V_VT(&dest) = VT_EMPTY;
4673 hr = IMXWriter_get_output(writer, &dest);
4674 EXPECT_HR(hr, S_OK);
4675 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4676 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4677 VariantClear(&dest);
4678
4679 ISAXContentHandler_Release(content);
4680 ISAXLexicalHandler_Release(lexical);
4681 IVBSAXLexicalHandler_Release(vblexical);
4682 IMXWriter_Release(writer);
4683 free_bstrs();
4684 }
4685
4686 static void test_mxwriter_pi(void)
4687 {
4688 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4689 static const WCHAR dataW[] = {'d','a','t','a',0};
4690 ISAXContentHandler *content;
4691 IMXWriter *writer;
4692 VARIANT dest;
4693 HRESULT hr;
4694
4695 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4696 &IID_IMXWriter, (void**)&writer);
4697 EXPECT_HR(hr, S_OK);
4698
4699 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4700 EXPECT_HR(hr, S_OK);
4701
4702 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4703 EXPECT_HR(hr, E_INVALIDARG);
4704
4705 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4706 EXPECT_HR(hr, S_OK);
4707
4708 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4709 EXPECT_HR(hr, S_OK);
4710
4711 V_VT(&dest) = VT_EMPTY;
4712 hr = IMXWriter_get_output(writer, &dest);
4713 EXPECT_HR(hr, S_OK);
4714 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4715 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4716 VariantClear(&dest);
4717
4718 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4719 EXPECT_HR(hr, S_OK);
4720
4721 V_VT(&dest) = VT_EMPTY;
4722 hr = IMXWriter_get_output(writer, &dest);
4723 EXPECT_HR(hr, S_OK);
4724 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4725 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n<?targ data?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4726 VariantClear(&dest);
4727
4728 V_VT(&dest) = VT_EMPTY;
4729 hr = IMXWriter_put_output(writer, dest);
4730 EXPECT_HR(hr, S_OK);
4731
4732 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4733 EXPECT_HR(hr, S_OK);
4734
4735 V_VT(&dest) = VT_EMPTY;
4736 hr = IMXWriter_get_output(writer, &dest);
4737 EXPECT_HR(hr, S_OK);
4738 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4739 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4740 VariantClear(&dest);
4741
4742
4743 ISAXContentHandler_Release(content);
4744 IMXWriter_Release(writer);
4745 }
4746
4747 static void test_mxwriter_ignorablespaces(void)
4748 {
4749 static const WCHAR dataW[] = {'d','a','t','a',0};
4750 ISAXContentHandler *content;
4751 IMXWriter *writer;
4752 VARIANT dest;
4753 HRESULT hr;
4754
4755 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4756 &IID_IMXWriter, (void**)&writer);
4757 EXPECT_HR(hr, S_OK);
4758
4759 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4760 EXPECT_HR(hr, S_OK);
4761
4762 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4763 EXPECT_HR(hr, E_INVALIDARG);
4764
4765 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4766 EXPECT_HR(hr, S_OK);
4767
4768 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4769 EXPECT_HR(hr, S_OK);
4770
4771 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4772 EXPECT_HR(hr, S_OK);
4773
4774 V_VT(&dest) = VT_EMPTY;
4775 hr = IMXWriter_get_output(writer, &dest);
4776 EXPECT_HR(hr, S_OK);
4777 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4778 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4779 VariantClear(&dest);
4780
4781 ISAXContentHandler_Release(content);
4782 IMXWriter_Release(writer);
4783 }
4784
4785 static void test_mxwriter_dtd(void)
4786 {
4787 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4788 static const WCHAR nameW[] = {'n','a','m','e'};
4789 static const WCHAR pubW[] = {'p','u','b'};
4790 static const WCHAR sysW[] = {'s','y','s'};
4791 IVBSAXLexicalHandler *vblexical;
4792 ISAXContentHandler *content;
4793 ISAXLexicalHandler *lexical;
4794 IVBSAXDeclHandler *vbdecl;
4795 ISAXDeclHandler *decl;
4796 IMXWriter *writer;
4797 VARIANT dest;
4798 HRESULT hr;
4799
4800 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4801 &IID_IMXWriter, (void**)&writer);
4802 EXPECT_HR(hr, S_OK);
4803
4804 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4805 EXPECT_HR(hr, S_OK);
4806
4807 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4808 EXPECT_HR(hr, S_OK);
4809
4810 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4811 EXPECT_HR(hr, S_OK);
4812
4813 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
4814 EXPECT_HR(hr, S_OK);
4815
4816 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4817 EXPECT_HR(hr, S_OK);
4818
4819 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4820 EXPECT_HR(hr, S_OK);
4821
4822 hr = ISAXContentHandler_startDocument(content);
4823 EXPECT_HR(hr, S_OK);
4824
4825 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4826 EXPECT_HR(hr, E_INVALIDARG);
4827
4828 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
4829 EXPECT_HR(hr, E_POINTER);
4830
4831 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4832 EXPECT_HR(hr, E_INVALIDARG);
4833
4834 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4835 EXPECT_HR(hr, E_INVALIDARG);
4836
4837 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4838 EXPECT_HR(hr, E_INVALIDARG);
4839
4840 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4841 EXPECT_HR(hr, S_OK);
4842
4843 V_VT(&dest) = VT_EMPTY;
4844 hr = IMXWriter_get_output(writer, &dest);
4845 EXPECT_HR(hr, S_OK);
4846 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4847 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4848 VariantClear(&dest);
4849
4850 /* system id is required if public is present */
4851 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4852 EXPECT_HR(hr, E_INVALIDARG);
4853
4854 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4855 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4856 EXPECT_HR(hr, S_OK);
4857
4858 V_VT(&dest) = VT_EMPTY;
4859 hr = IMXWriter_get_output(writer, &dest);
4860 EXPECT_HR(hr, S_OK);
4861 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4862 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4863 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4864 VariantClear(&dest);
4865
4866 hr = ISAXLexicalHandler_endDTD(lexical);
4867 EXPECT_HR(hr, S_OK);
4868
4869 hr = IVBSAXLexicalHandler_endDTD(vblexical);
4870 EXPECT_HR(hr, S_OK);
4871
4872 V_VT(&dest) = VT_EMPTY;
4873 hr = IMXWriter_get_output(writer, &dest);
4874 EXPECT_HR(hr, S_OK);
4875 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4876 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4877 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4878 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4879 VariantClear(&dest);
4880
4881 /* element declaration */
4882 V_VT(&dest) = VT_EMPTY;
4883 hr = IMXWriter_put_output(writer, dest);
4884 EXPECT_HR(hr, S_OK);
4885
4886 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4887 EXPECT_HR(hr, E_INVALIDARG);
4888
4889 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
4890 EXPECT_HR(hr, E_POINTER);
4891
4892 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4893 EXPECT_HR(hr, E_INVALIDARG);
4894
4895 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4896 EXPECT_HR(hr, S_OK);
4897
4898 V_VT(&dest) = VT_EMPTY;
4899 hr = IMXWriter_get_output(writer, &dest);
4900 EXPECT_HR(hr, S_OK);
4901 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4902 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4903 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4904 VariantClear(&dest);
4905
4906 V_VT(&dest) = VT_EMPTY;
4907 hr = IMXWriter_put_output(writer, dest);
4908 EXPECT_HR(hr, S_OK);
4909
4910 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4911 EXPECT_HR(hr, S_OK);
4912
4913 V_VT(&dest) = VT_EMPTY;
4914 hr = IMXWriter_get_output(writer, &dest);
4915 EXPECT_HR(hr, S_OK);
4916 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4917 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4918 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4919 VariantClear(&dest);
4920
4921 /* attribute declaration */
4922 V_VT(&dest) = VT_EMPTY;
4923 hr = IMXWriter_put_output(writer, dest);
4924 EXPECT_HR(hr, S_OK);
4925
4926 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4927 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4928 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4929 EXPECT_HR(hr, S_OK);
4930
4931 V_VT(&dest) = VT_EMPTY;
4932 hr = IMXWriter_get_output(writer, &dest);
4933 EXPECT_HR(hr, S_OK);
4934 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4935 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4936 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4937 VariantClear(&dest);
4938
4939 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4940 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4941 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4942 EXPECT_HR(hr, S_OK);
4943
4944 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4945 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4946 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4947 EXPECT_HR(hr, S_OK);
4948
4949 V_VT(&dest) = VT_EMPTY;
4950 hr = IMXWriter_get_output(writer, &dest);
4951 EXPECT_HR(hr, S_OK);
4952 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4953 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4954 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4955 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4956 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4957 VariantClear(&dest);
4958
4959 /* internal entities */
4960 V_VT(&dest) = VT_EMPTY;
4961 hr = IMXWriter_put_output(writer, dest);
4962 EXPECT_HR(hr, S_OK);
4963
4964 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4965 EXPECT_HR(hr, E_INVALIDARG);
4966
4967 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
4968 EXPECT_HR(hr, E_POINTER);
4969
4970 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4971 EXPECT_HR(hr, E_INVALIDARG);
4972
4973 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4974 EXPECT_HR(hr, S_OK);
4975
4976 V_VT(&dest) = VT_EMPTY;
4977 hr = IMXWriter_get_output(writer, &dest);
4978 EXPECT_HR(hr, S_OK);
4979 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4980 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4981 VariantClear(&dest);
4982
4983 /* external entities */
4984 V_VT(&dest) = VT_EMPTY;
4985 hr = IMXWriter_put_output(writer, dest);
4986 ok(hr == S_OK, "got 0x%08x\n", hr);
4987
4988 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
4989 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4990
4991 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
4992 ok(hr == E_POINTER, "got 0x%08x\n", hr);
4993
4994 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0);
4995 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4996
4997 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
4998 _bstr_("sysid"), strlen("sysid"));
4999 ok(hr == S_OK, "got 0x%08x\n", hr);
5000
5001 V_VT(&dest) = VT_EMPTY;
5002 hr = IMXWriter_get_output(writer, &dest);
5003 ok(hr == S_OK, "got 0x%08x\n", hr);
5004 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5005 ok(!lstrcmpW(_bstr_("<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5006 VariantClear(&dest);
5007
5008 ISAXContentHandler_Release(content);
5009 ISAXLexicalHandler_Release(lexical);
5010 IVBSAXLexicalHandler_Release(vblexical);
5011 IVBSAXDeclHandler_Release(vbdecl);
5012 ISAXDeclHandler_Release(decl);
5013 IMXWriter_Release(writer);
5014 free_bstrs();
5015 }
5016
5017 typedef struct {
5018 const CLSID *clsid;
5019 const char *uri;
5020 const char *local;
5021 const char *qname;
5022 const char *type;
5023 const char *value;
5024 HRESULT hr;
5025 } addattribute_test_t;
5026
5027 static const addattribute_test_t addattribute_data[] = {
5028 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5029 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5030 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5031 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
5032
5033 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5034 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5035 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5036 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
5037
5038 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5039 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5040 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5041 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
5042
5043 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
5044 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
5045 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
5046 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
5047
5048 { NULL }
5049 };
5050
5051 static void test_mxattr_addAttribute(void)
5052 {
5053 const addattribute_test_t *table = addattribute_data;
5054 int i = 0;
5055
5056 while (table->clsid)
5057 {
5058 ISAXAttributes *saxattr;
5059 IMXAttributes *mxattr;
5060 const WCHAR *value;
5061 int len, index;
5062 HRESULT hr;
5063
5064 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5065 {
5066 table++;
5067 i++;
5068 continue;
5069 }
5070
5071 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5072 &IID_IMXAttributes, (void**)&mxattr);
5073 EXPECT_HR(hr, S_OK);
5074
5075 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5076 EXPECT_HR(hr, S_OK);
5077
5078 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5079 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5080 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5081 {
5082 hr = ISAXAttributes_getLength(saxattr, NULL);
5083 EXPECT_HR(hr, E_POINTER);
5084 }
5085
5086 len = -1;
5087 hr = ISAXAttributes_getLength(saxattr, &len);
5088 EXPECT_HR(hr, S_OK);
5089 ok(len == 0, "got %d\n", len);
5090
5091 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5092 EXPECT_HR(hr, E_INVALIDARG);
5093
5094 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5095 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5096
5097 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5098 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5099
5100 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5101 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5102
5103 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5104 EXPECT_HR(hr, E_INVALIDARG);
5105
5106 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5107 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5108
5109 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5110 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5111
5112 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5113 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5114
5115 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
5116 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
5117 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
5118
5119 if (hr == S_OK)
5120 {
5121 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5122 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5123 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5124 {
5125 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5126 EXPECT_HR(hr, E_POINTER);
5127
5128 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5129 EXPECT_HR(hr, E_POINTER);
5130
5131 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5132 EXPECT_HR(hr, E_POINTER);
5133
5134 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5135 EXPECT_HR(hr, E_POINTER);
5136
5137 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5138 EXPECT_HR(hr, E_POINTER);
5139
5140 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5141 EXPECT_HR(hr, E_POINTER);
5142 }
5143
5144 len = -1;
5145 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5146 EXPECT_HR(hr, S_OK);
5147 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5148 table->value);
5149 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5150
5151 len = -1;
5152 value = (void*)0xdeadbeef;
5153 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5154 EXPECT_HR(hr, S_OK);
5155
5156 if (table->type)
5157 {
5158 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5159 table->type);
5160 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
5161 }
5162 else
5163 {
5164 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
5165 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
5166 }
5167
5168 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
5169 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5170 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5171 {
5172 EXPECT_HR(hr, E_POINTER);
5173 }
5174 else
5175 EXPECT_HR(hr, E_INVALIDARG);
5176
5177 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
5178 EXPECT_HR(hr, E_INVALIDARG);
5179
5180 index = -1;
5181 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
5182 EXPECT_HR(hr, E_INVALIDARG);
5183 ok(index == -1, "%d: got wrong index %d\n", i, index);
5184
5185 index = -1;
5186 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
5187 EXPECT_HR(hr, E_INVALIDARG);
5188 ok(index == -1, "%d: got wrong index %d\n", i, index);
5189
5190 index = -1;
5191 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
5192 EXPECT_HR(hr, S_OK);
5193 ok(index == 0, "%d: got wrong index %d\n", i, index);
5194
5195 index = -1;
5196 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
5197 EXPECT_HR(hr, E_INVALIDARG);
5198 ok(index == -1, "%d: got wrong index %d\n", i, index);
5199
5200 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
5201 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
5202 {
5203 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5204 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5205
5206 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5207 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5208
5209 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5210 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5211
5212 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5213 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5214
5215 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5216 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5217
5218 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5219 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5220 }
5221 else
5222 {
5223 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5224 EXPECT_HR(hr, E_POINTER);
5225
5226 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5227 EXPECT_HR(hr, E_POINTER);
5228
5229 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5230 EXPECT_HR(hr, E_POINTER);
5231
5232 /* versions 4 and 6 crash */
5233 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
5234 EXPECT_HR(hr, E_POINTER);
5235
5236 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
5237 EXPECT_HR(hr, E_POINTER);
5238
5239 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5240 EXPECT_HR(hr, E_POINTER);
5241
5242 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5243 EXPECT_HR(hr, E_POINTER);
5244
5245 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5246 EXPECT_HR(hr, E_POINTER);
5247
5248 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
5249 EXPECT_HR(hr, E_POINTER);
5250
5251 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
5252 EXPECT_HR(hr, E_POINTER);
5253
5254 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
5255 strlen(table->local), NULL, NULL);
5256 EXPECT_HR(hr, E_POINTER);
5257 }
5258
5259 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
5260 EXPECT_HR(hr, S_OK);
5261 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5262 table->value);
5263 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5264
5265 if (table->uri) {
5266 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
5267 _bstr_(table->local), strlen(table->local), &value, &len);
5268 EXPECT_HR(hr, S_OK);
5269 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5270 table->value);
5271 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5272 }
5273 }
5274
5275 len = -1;
5276 hr = ISAXAttributes_getLength(saxattr, &len);
5277 EXPECT_HR(hr, S_OK);
5278 if (table->hr == S_OK)
5279 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5280 else
5281 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5282
5283 ISAXAttributes_Release(saxattr);
5284 IMXAttributes_Release(mxattr);
5285
5286 table++;
5287 i++;
5288 }
5289
5290 free_bstrs();
5291 }
5292
5293 static void test_mxattr_clear(void)
5294 {
5295 ISAXAttributes *saxattr;
5296 IMXAttributes *mxattr;
5297 const WCHAR *ptr;
5298 HRESULT hr;
5299 int len;
5300
5301 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5302 &IID_IMXAttributes, (void**)&mxattr);
5303 EXPECT_HR(hr, S_OK);
5304
5305 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5306 EXPECT_HR(hr, S_OK);
5307
5308 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5309 EXPECT_HR(hr, E_INVALIDARG);
5310
5311 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5312 EXPECT_HR(hr, E_INVALIDARG);
5313
5314 hr = IMXAttributes_clear(mxattr);
5315 EXPECT_HR(hr, S_OK);
5316
5317 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5318 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5319 EXPECT_HR(hr, S_OK);
5320
5321 len = -1;
5322 hr = ISAXAttributes_getLength(saxattr, &len);
5323 EXPECT_HR(hr, S_OK);
5324 ok(len == 1, "got %d\n", len);
5325
5326 len = -1;
5327 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5328 EXPECT_HR(hr, E_POINTER);
5329 ok(len == -1, "got %d\n", len);
5330
5331 ptr = (void*)0xdeadbeef;
5332 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5333 EXPECT_HR(hr, E_POINTER);
5334 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5335
5336 len = 0;
5337 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5338 EXPECT_HR(hr, S_OK);
5339 ok(len == 5, "got %d\n", len);
5340 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5341
5342 hr = IMXAttributes_clear(mxattr);
5343 EXPECT_HR(hr, S_OK);
5344
5345 len = -1;
5346 hr = ISAXAttributes_getLength(saxattr, &len);
5347 EXPECT_HR(hr, S_OK);
5348 ok(len == 0, "got %d\n", len);
5349
5350 len = -1;
5351 ptr = (void*)0xdeadbeef;
5352 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5353 EXPECT_HR(hr, E_INVALIDARG);
5354 ok(len == -1, "got %d\n", len);
5355 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5356
5357 IMXAttributes_Release(mxattr);
5358 ISAXAttributes_Release(saxattr);
5359 free_bstrs();
5360 }
5361
5362 static void test_mxattr_dispex(void)
5363 {
5364 IMXAttributes *mxattr;
5365 IDispatchEx *dispex;
5366 IUnknown *unk;
5367 HRESULT hr;
5368
5369 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5370 &IID_IMXAttributes, (void**)&mxattr);
5371 EXPECT_HR(hr, S_OK);
5372
5373 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5374 EXPECT_HR(hr, S_OK);
5375 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5376 test_obj_dispex(unk);
5377 IUnknown_Release(unk);
5378 IDispatchEx_Release(dispex);
5379
5380 IMXAttributes_Release(mxattr);
5381 }
5382
5383 static void test_mxattr_qi(void)
5384 {
5385 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5386 ISAXAttributes *saxattr;
5387 IMXAttributes *mxattr;
5388 HRESULT hr;
5389
5390 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5391 &IID_IMXAttributes, (void**)&mxattr);
5392 EXPECT_HR(hr, S_OK);
5393
5394 EXPECT_REF(mxattr, 1);
5395 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5396 EXPECT_HR(hr, S_OK);
5397
5398 EXPECT_REF(mxattr, 2);
5399 EXPECT_REF(saxattr, 2);
5400
5401 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5402 EXPECT_HR(hr, S_OK);
5403
5404 EXPECT_REF(vbsaxattr, 3);
5405 EXPECT_REF(mxattr, 3);
5406 EXPECT_REF(saxattr, 3);
5407
5408 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5409 EXPECT_HR(hr, S_OK);
5410
5411 EXPECT_REF(vbsaxattr, 4);
5412 EXPECT_REF(mxattr, 4);
5413 EXPECT_REF(saxattr, 4);
5414
5415 IMXAttributes_Release(mxattr);
5416 ISAXAttributes_Release(saxattr);
5417 IVBSAXAttributes_Release(vbsaxattr);
5418 IVBSAXAttributes_Release(vbsaxattr2);
5419 }
5420
5421 static struct msxmlsupported_data_t saxattr_support_data[] =
5422 {
5423 { &CLSID_SAXAttributes, "SAXAttributes" },
5424 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5425 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5426 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5427 { NULL }
5428 };
5429
5430 static void test_mxattr_localname(void)
5431 {
5432 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5433 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5434 static const WCHAR uri1W[] = {'u','r','i','1',0};
5435 static const WCHAR uriW[] = {'u','r','i',0};
5436
5437 const struct msxmlsupported_data_t *table = saxattr_support_data;
5438
5439 while (table->clsid)
5440 {
5441 ISAXAttributes *saxattr;
5442 IMXAttributes *mxattr;
5443 HRESULT hr;
5444 int index;
5445
5446 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5447 {
5448 table++;
5449 continue;
5450 }
5451
5452 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5453 &IID_IMXAttributes, (void**)&mxattr);
5454 EXPECT_HR(hr, S_OK);
5455
5456 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5457 EXPECT_HR(hr, S_OK);
5458
5459 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5460 EXPECT_HR(hr, E_INVALIDARG);
5461
5462 /* add some ambiguos attribute names */
5463 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5464 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5465 EXPECT_HR(hr, S_OK);
5466 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5467 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5468 EXPECT_HR(hr, S_OK);
5469
5470 index = -1;
5471 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5472 EXPECT_HR(hr, S_OK);
5473 ok(index == 0, "%s: got index %d\n", table->name, index);
5474
5475 index = -1;
5476 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5477 EXPECT_HR(hr, E_INVALIDARG);
5478 ok(index == -1, "%s: got index %d\n", table->name, index);
5479
5480 index = -1;
5481 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5482 EXPECT_HR(hr, E_INVALIDARG);
5483 ok(index == -1, "%s: got index %d\n", table->name, index);
5484
5485 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5486 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5487 {
5488 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5489 EXPECT_HR(hr, E_POINTER);
5490
5491 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5492 EXPECT_HR(hr, E_POINTER);
5493 }
5494 else
5495 {
5496 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5497 EXPECT_HR(hr, E_INVALIDARG);
5498
5499 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5500 EXPECT_HR(hr, E_INVALIDARG);
5501 }
5502
5503 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5504 EXPECT_HR(hr, E_INVALIDARG);
5505
5506 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5507 EXPECT_HR(hr, E_INVALIDARG);
5508
5509 table++;
5510
5511 ISAXAttributes_Release(saxattr);
5512 IMXAttributes_Release(mxattr);
5513 }
5514 }
5515
5516 static void test_mxwriter_indent(void)
5517 {
5518 ISAXContentHandler *content;
5519 IMXWriter *writer;
5520 VARIANT dest;
5521 HRESULT hr;
5522
5523 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
5524 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5525
5526 hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
5527 ok(hr == S_OK, "got %08x\n", hr);
5528
5529 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
5530 ok(hr == S_OK, "got %08x\n", hr);
5531
5532 hr = ISAXContentHandler_startDocument(content);
5533 ok(hr == S_OK, "got %08x\n", hr);
5534
5535 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
5536 ok(hr == S_OK, "got %08x\n", hr);
5537
5538 hr = ISAXContentHandler_characters(content, _bstr_(""), 0);
5539 ok(hr == S_OK, "got %08x\n", hr);
5540
5541 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL);
5542 ok(hr == S_OK, "got %08x\n", hr);
5543
5544 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL);
5545 ok(hr == S_OK, "got %08x\n", hr);
5546
5547 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1);
5548 ok(hr == S_OK, "got %08x\n", hr);
5549
5550 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1);
5551 ok(hr == S_OK, "got %08x\n", hr);
5552
5553 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1);
5554 ok(hr == S_OK, "got %08x\n", hr);
5555
5556 hr = ISAXContentHandler_endDocument(content);
5557 ok(hr == S_OK, "got %08x\n", hr);
5558
5559 V_VT(&dest) = VT_EMPTY;
5560 hr = IMXWriter_get_output(writer, &dest);
5561 ok(hr == S_OK, "got %08x\n", hr);
5562 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5563 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>"), V_BSTR(&dest)),
5564 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5565 VariantClear(&dest);
5566
5567 ISAXContentHandler_Release(content);
5568 IMXWriter_Release(writer);
5569
5570 free_bstrs();
5571 }
5572
5573 START_TEST(saxreader)
5574 {
5575 ISAXXMLReader *reader;
5576 HRESULT hr;
5577
5578 hr = CoInitialize(NULL);
5579 ok(hr == S_OK, "failed to init com\n");
5580
5581 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5582 &IID_ISAXXMLReader, (void**)&reader);
5583
5584 if(FAILED(hr))
5585 {
5586 skip("Failed to create SAXXMLReader instance\n");
5587 CoUninitialize();
5588 return;
5589 }
5590 ISAXXMLReader_Release(reader);
5591
5592 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5593
5594 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5595
5596 test_saxreader();
5597 test_saxreader_properties();
5598 test_saxreader_features();
5599 test_saxreader_encoding();
5600 test_saxreader_dispex();
5601
5602 /* MXXMLWriter tests */
5603 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5604 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5605 {
5606 test_mxwriter_handlers();
5607 test_mxwriter_startenddocument();
5608 test_mxwriter_startendelement();
5609 test_mxwriter_characters();
5610 test_mxwriter_comment();
5611 test_mxwriter_cdata();
5612 test_mxwriter_pi();
5613 test_mxwriter_ignorablespaces();
5614 test_mxwriter_dtd();
5615 test_mxwriter_properties();
5616 test_mxwriter_flush();
5617 test_mxwriter_stream();
5618 test_mxwriter_encoding();
5619 test_mxwriter_dispex();
5620 test_mxwriter_indent();
5621 }
5622 else
5623 win_skip("MXXMLWriter not supported\n");
5624
5625 /* SAXAttributes tests */
5626 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5627 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5628 {
5629 test_mxattr_qi();
5630 test_mxattr_addAttribute();
5631 test_mxattr_clear();
5632 test_mxattr_localname();
5633 test_mxattr_dispex();
5634 }
5635 else
5636 skip("SAXAttributes not supported\n");
5637
5638 CoUninitialize();
5639 }