ReactOS  0.4.14-dev-337-gf981a68
saxreader.c
Go to the documentation of this file.
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__)
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 
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 
64 {
65  const GUID *clsid;
66  const char *name;
68 };
69 
71 {
72  while (table->clsid)
73  {
74  if (table->clsid == clsid) return table->supported;
75  table++;
76  }
77  return FALSE;
78 }
79 
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 */
85  return ret;
86 }
87 
88 static BSTR alloced_bstrs[512];
90 
91 static BSTR _bstr_(const char *str)
92 {
96 }
97 
98 static void free_bstrs(void)
99 {
100  int i;
101  for (i = 0; i < alloced_bstrs_count; i++)
104 }
105 
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 
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",
156  }
157  else
158  ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
160 }
161 
162 typedef enum _CH {
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 
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 */
214 };
215 
216 struct call_entry {
218  int line;
219  int column;
221  const char *arg1;
222  const char *arg2;
223  const char *arg3;
224 
225  /* allocated once at startElement callback */
228 
229  /* used for actual call data only, null for expected call data */
233 };
234 
236 {
237  int count;
238  int size;
240 };
241 
242 #define CONTENT_HANDLER_INDEX 0
243 #define NUM_CALL_SEQUENCES 1
245 
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 
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 
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 
315 static const char *get_event_name(CH event)
316 {
317  return event_names[event];
318 }
319 
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 
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  {
419  case CH_STARTDOCUMENT:
420  case CH_ENDDOCUMENT:
421  case LH_STARTCDATA:
422  case LH_ENDCDATA:
423  break;
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:
445  /* char data */
446  test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
447  break;
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",
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",
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",
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",
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 
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 
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 */
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 
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 
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 
672  { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
673  { EH_FATALERROR, 0, 0, E_FAIL },
674  { CH_ENDTEST }
675 };
676 
678  { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
679  { EH_FATALERROR, 1, 0, E_FAIL },
680  { CH_ENDTEST }
681 };
682 
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 
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 
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 
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 
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 */
769  { "", "", "xmlns:test", "prefix_test" },
770  { "", "", "xmlns", "prefix" },
771  { "", "", "test:arg1", "arg1" },
772  { "", "", "arg2", "arg2" },
773  { "", "", "test:ar3", "arg3" },
774  { NULL }
775 };
776 
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 
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 
799  { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
800  { NULL }
801 };
802 
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 */
823  { "prefix_test", "arg1", "test:arg1", "arg1" },
824  { "", "arg2", "arg2", "arg2" },
825  { "prefix_test", "ar3", "test:ar3", "arg3" },
826  { NULL }
827 };
828 
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 
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 
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 &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
894 
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 
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;
1040 
1042 {
1043  expectCall = expected;
1044 }
1045 
1046 /* to be called once on each tested callback return */
1048 {
1049  HRESULT hr = expectCall->ret;
1050  if (expectCall->id != CH_ENDTEST) expectCall++;
1051  return hr;
1052 }
1053 
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 
1074  ISAXContentHandler* iface)
1075 {
1076  return 2;
1077 }
1078 
1080  ISAXContentHandler* iface)
1081 {
1082  return 1;
1083 }
1084 
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;
1098 
1099  hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
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);
1117 
1118  hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1120 
1121  hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1123 
1124  ISAXAttributes_Release(attr);
1125  ISAXAttributes_Release(attr1);
1126  }
1127 
1128  return get_expected_ret();
1129 }
1130 
1131 static ISAXAttributes *test_attr_ptr;
1133  ISAXContentHandler* iface)
1134 {
1135  struct call_entry call;
1136 
1137  init_call_entry(locator, &call);
1138  call.id = CH_STARTDOCUMENT;
1140 
1141  test_attr_ptr = NULL;
1142 
1143  return get_expected_ret();
1144 }
1145 
1147  ISAXContentHandler* iface)
1148 {
1149  struct call_entry call;
1150 
1151  init_call_entry(locator, &call);
1152  call.id = CH_ENDDOCUMENT;
1154 
1155  return get_expected_ret();
1156 }
1157 
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);
1173 
1174  return get_expected_ret();
1175 }
1176 
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);
1189 
1190  return get_expected_ret();
1191 }
1192 
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);
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 
1272 
1273  return get_expected_ret();
1274 }
1275 
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);
1294 
1295  return get_expected_ret();
1296 }
1297 
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);
1311 
1312  return get_expected_ret();
1313 }
1314 
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);
1327 
1328  return get_expected_ret();
1329 }
1330 
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);
1343  call.arg1W = SysAllocStringLen(target, target_len);
1344  call.arg2W = SysAllocStringLen(data, data_len);
1346 
1347  return get_expected_ret();
1348 }
1349 
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);
1362 
1363  return get_expected_ret();
1364 }
1365 
1366 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1367 {
1382 };
1383 
1384 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1385 
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 
1406  ISAXErrorHandler* iface)
1407 {
1408  return 2;
1409 }
1410 
1412  ISAXErrorHandler* iface)
1413 {
1414  return 1;
1415 }
1416 
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 
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 
1440 
1441  get_expected_ret();
1442  return S_OK;
1443 }
1444 
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 {
1463 };
1464 
1465 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1466 
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 
1486 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1487 {
1488  return 2;
1489 }
1490 
1491 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1492 {
1493  return 1;
1494 }
1495 
1496 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1497 {
1498  *length = 3;
1499  return S_OK;
1500 }
1501 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 {
1679 };
1680 
1681 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1682 
1684 {
1685  ISAXLexicalHandler ISAXLexicalHandler_iface;
1687 
1688  HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1689 };
1690 
1691 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1692 {
1694 }
1695 
1696 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1697 {
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 
1721 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1722 {
1724  return InterlockedIncrement(&handler->ref);
1725 }
1726 
1727 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1728 {
1730  return InterlockedDecrement(&handler->ref);
1731 }
1732 
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 
1741 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1742 {
1743  ok(0, "call not expected\n");
1744  return E_NOTIMPL;
1745 }
1746 
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 
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 
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;
1768 
1769  return get_expected_ret();
1770 }
1771 
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;
1779 
1780  return get_expected_ret();
1781 }
1782 
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 {
1802 };
1803 
1805 {
1806  handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1807  handler->ref = 1;
1808  handler->qi_hr = hr;
1809 }
1810 
1812 {
1813  ISAXDeclHandler ISAXDeclHandler_iface;
1815 
1816  HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1817 };
1818 
1819 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1820 {
1822 }
1823 
1824 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1825 {
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 
1849 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1850 {
1852  return InterlockedIncrement(&handler->ref);
1853 }
1854 
1855 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1856 {
1858  return InterlockedDecrement(&handler->ref);
1859 }
1860 
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 
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 
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 
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 {
1901 };
1902 
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 {
1912  const BYTE *data;
1917 
1918 typedef struct mxwriter_stream_test_t {
1920  const char *encoding;
1923 
1926 
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 
1942 {
1943  return 2;
1944 }
1945 
1947 {
1948  return 1;
1949 }
1950 
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 
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 
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 
1971 {
1972  ok(0, "unexpected call\n");
1973  return E_NOTIMPL;
1974 }
1975 
1977  ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1978 {
1979  ok(0, "unexpected call\n");
1980  return E_NOTIMPL;
1981 }
1982 
1983 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1984 {
1985  ok(0, "unexpected call\n");
1986  return E_NOTIMPL;
1987 }
1988 
1990 {
1991  ok(0, "unexpected call\n");
1992  return E_NOTIMPL;
1993 }
1994 
1996  ULARGE_INTEGER cb, DWORD dwLockType)
1997 {
1998  ok(0, "unexpected call\n");
1999  return E_NOTIMPL;
2000 }
2001 
2003  ULARGE_INTEGER cb, DWORD dwLockType)
2004 {
2005  ok(0, "unexpected call\n");
2006  return E_NOTIMPL;
2007 }
2008 
2009 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
2010 {
2011  return E_NOTIMPL;
2012 }
2013 
2014 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
2015 {
2016  ok(0, "unexpected call\n");
2017  return E_NOTIMPL;
2018 }
2019 
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 
2032 
2033  ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
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 
2042 
2043  if(pcbWritten)
2044  *pcbWritten = cb;
2045 
2046  return fail ? E_FAIL : S_OK;
2047 }
2048 
2049 static const IStreamVtbl mxstreamVtbl = {
2053  istream_Read,
2055  istream_Seek,
2062  istream_Stat,
2064 };
2065 
2067 
2068 static int read_cnt;
2069 
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 = {
2093  instream_Read,
2094  istream_Write,
2095  istream_Seek,
2102  istream_Stat,
2104 };
2105 
2107 
2109 {
2110  { &CLSID_SAXXMLReader, "SAXReader" },
2111  { &CLSID_SAXXMLReader30, "SAXReader30" },
2112  { &CLSID_SAXXMLReader40, "SAXReader40" },
2113  { &CLSID_SAXXMLReader60, "SAXReader60" },
2114  { NULL }
2115 };
2116 
2119 
2120 static IStream *create_test_stream(const char *data, int len)
2121 {
2124  IStream *stream;
2125  ULONG written;
2126 
2127  if (len == -1) len = strlen(data);
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 
2138 static void test_saxreader(void)
2139 {
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 
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);
2187 
2188  hr = ISAXXMLReader_getErrorHandler(reader, NULL);
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;
2215 
2216  if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2217  IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
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);
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 
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 
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 
2266  V_VT(&var) = VT_UNKNOWN;
2267  V_UNKNOWN(&var) = (IUnknown*)stream;
2268 
2269  if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2271  else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2273  else
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;
2301 
2302  if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2303  IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
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 */
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))
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))
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  {
2347  set_expected_seq(test_seq);
2348  hr = ISAXXMLReader_parseURL(reader, testXmlW);
2349  EXPECT_HR(hr, S_OK);
2350  }
2351  else
2352  {
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 
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))
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 
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  {
2422  }
2423  else
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 
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  {
2446  }
2447  else
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 */
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 */
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 
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 */
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 */
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 
2558 {
2559  const char *prop_name;
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 
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);
2583 
2584  while (ptr->prop_name)
2585  {
2586  VARIANT varref;
2587  LONG ref;
2588 
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);
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 
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);
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 
2775  const GUID *guid;
2776  const char *clsid;
2778  VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2779 };
2780 
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 
2795 static void test_saxreader_features(void)
2796 {
2798  ISAXXMLReader *reader;
2799 
2800  while (entry->guid)
2801  {
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 
2890  const GUID *guid;
2891  const char *clsid;
2892  const char *data;
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 
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 
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 
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 
3001 {
3002  { &CLSID_MXXMLWriter, "MXXMLWriter" },
3003  { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
3004  { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
3005  { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
3006  { NULL }
3007 };
3008 
3010 {
3011  { &CLSID_SAXAttributes, "SAXAttributes" },
3012  { &CLSID_SAXAttributes30, "SAXAttributes30" },
3013  { &CLSID_SAXAttributes40, "SAXAttributes40" },
3014  { &CLSID_SAXAttributes60, "SAXAttributes60" },
3015  { NULL }
3016 };
3017 
3019 {
3020  const GUID *clsid;
3026  const char *encoding;
3027 };
3028 
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 
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 
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);
3091 
3092  IMXWriter_Release(writer);
3093 
3094  table++;
3095  i++;
3096  }
3097 }
3098 
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 
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);
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 */
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 */
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 
3250 static void test_mxwriter_flush(void)
3251 {
3252  ISAXContentHandler *content;
3253  IMXWriter *writer;
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 
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);
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);
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 */
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);
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 */
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 
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 
3525 {
3526  StartElement = 0x001,
3527  EndElement = 0x010,
3530 };
3531 
3533  const GUID *clsid;
3535  const char *uri;
3536  const char *local_name;
3537  const char *qname;
3538  const char *output;
3540  ISAXAttributes *attr;
3541 };
3542