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