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