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