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