crypt32: Add additional path for Solaris 11 Express.
[wine] / dlls / msxml3 / tests / saxreader.c
1 /*
2  * XML test
3  *
4  * Copyright 2008 Piotr Caban
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #define CONST_VTABLE
23
24 #include <stdio.h>
25 #include <assert.h>
26
27 #include "windows.h"
28 #include "ole2.h"
29 #include "msxml2.h"
30 #include "ocidl.h"
31
32 #include "wine/test.h"
33
34 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
35 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
36 {
37     ULONG rc = IUnknown_AddRef(obj);
38     IUnknown_Release(obj);
39     ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
40 }
41
42 static BSTR alloc_str_from_narrow(const char *str)
43 {
44     int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
45     BSTR ret = SysAllocStringLen(NULL, len - 1);  /* NUL character added automatically */
46     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
47     return ret;
48 }
49
50 static BSTR alloced_bstrs[256];
51 static int alloced_bstrs_count;
52
53 static BSTR _bstr_(const char *str)
54 {
55     assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
56     alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
57     return alloced_bstrs[alloced_bstrs_count++];
58 }
59
60 static void free_bstrs(void)
61 {
62     int i;
63     for (i = 0; i < alloced_bstrs_count; i++)
64         SysFreeString(alloced_bstrs[i]);
65     alloced_bstrs_count = 0;
66 }
67
68 typedef enum _CH {
69     CH_ENDTEST,
70     CH_PUTDOCUMENTLOCATOR,
71     CH_STARTDOCUMENT,
72     CH_ENDDOCUMENT,
73     CH_STARTPREFIXMAPPING,
74     CH_ENDPREFIXMAPPING,
75     CH_STARTELEMENT,
76     CH_ENDELEMENT,
77     CH_CHARACTERS,
78     CH_IGNORABLEWHITESPACE,
79     CH_PROCESSINGINSTRUCTION,
80     CH_SKIPPEDENTITY
81 } CH;
82
83 static const WCHAR szSimpleXML[] = {
84 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
85 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
86 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
87 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
88 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
89 };
90
91 static const WCHAR szCarriageRetTest[] = {
92 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
93 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
94 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
95 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
96 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\0'
97 };
98
99 static const CHAR szTestXML[] =
100 "<?xml version=\"1.0\" ?>\n"
101 "<BankAccount>\n"
102 "   <Number>1234</Number>\n"
103 "   <Name>Captain Ahab</Name>\n"
104 "</BankAccount>\n";
105
106 typedef struct _contenthandlercheck {
107     CH id;
108     int line;
109     int column;
110     const char *arg1;
111     const char *arg2;
112     const char *arg3;
113 } content_handler_test;
114
115 static content_handler_test contentHandlerTest1[] = {
116     { CH_PUTDOCUMENTLOCATOR, 0, 0 },
117     { CH_STARTDOCUMENT, 0, 0 },
118     { CH_STARTELEMENT, 2, 14, "", "BankAccount", "BankAccount" },
119     { CH_CHARACTERS, 2, 14, "\n   " },
120     { CH_STARTELEMENT, 3, 12, "", "Number", "Number" },
121     { CH_CHARACTERS, 3, 12, "1234" },
122     { CH_ENDELEMENT, 3, 18, "", "Number", "Number" },
123     { CH_CHARACTERS, 3, 25, "\n   " },
124     { CH_STARTELEMENT, 4, 10, "", "Name", "Name" },
125     { CH_CHARACTERS, 4, 10, "Captain Ahab" },
126     { CH_ENDELEMENT, 4, 24, "", "Name", "Name" },
127     { CH_CHARACTERS, 4, 29, "\n" },
128     { CH_ENDELEMENT, 5, 3, "", "BankAccount", "BankAccount" },
129     { CH_ENDDOCUMENT, 0, 0 },
130     { CH_ENDTEST }
131 };
132
133 static content_handler_test contentHandlerTest2[] = {
134     { CH_PUTDOCUMENTLOCATOR, 0, 0 },
135     { CH_STARTDOCUMENT, 0, 0 },
136     { CH_STARTELEMENT, 2, 14, "", "BankAccount", "BankAccount" },
137     { CH_CHARACTERS, 2, 14, "\n" },
138     { CH_CHARACTERS, 2, 16, "\t" },
139     { CH_STARTELEMENT, 3, 10, "", "Number", "Number" },
140     { CH_CHARACTERS, 3, 10, "1234" },
141     { CH_ENDELEMENT, 3, 16, "", "Number", "Number" },
142     { CH_CHARACTERS, 3, 23, "\n" },
143     { CH_CHARACTERS, 3, 25, "\t" },
144     { CH_STARTELEMENT, 4, 8, "", "Name", "Name" },
145     { CH_CHARACTERS, 4, 8, "Captain Ahab" },
146     { CH_ENDELEMENT, 4, 22, "", "Name", "Name" },
147     { CH_CHARACTERS, 4, 27, "\n" },
148     { CH_ENDELEMENT, 5, 3, "", "BankAccount", "BankAccount" },
149     { CH_ENDDOCUMENT, 0, 0 },
150     { CH_ENDTEST }
151 };
152
153 static content_handler_test *expectCall;
154 static ISAXLocator *locator;
155
156 static void test_saxstr(unsigned line, const WCHAR *szStr, int nStr, const char *szTest)
157 {
158     WCHAR buf[1024];
159     int len;
160
161     if(!szTest) {
162         ok_(__FILE__,line) (szStr == NULL, "szStr != NULL\n");
163         ok_(__FILE__,line) (nStr == 0, "nStr = %d, expected 0\n", nStr);
164         return;
165     }
166
167     len = strlen(szTest);
168     ok_(__FILE__,line) (len == nStr, "nStr = %d, expected %d (%s)\n", nStr, len, szTest);
169     if(len != nStr)
170         return;
171
172     MultiByteToWideChar(CP_ACP, 0, szTest, -1, buf, sizeof(buf)/sizeof(WCHAR));
173     ok_(__FILE__,line) (!memcmp(szStr, buf, len*sizeof(WCHAR)), "unexpected szStr %s, expected %s\n",
174                         wine_dbgstr_wn(szStr, nStr), szTest);
175 }
176
177 static BOOL test_expect_call(CH id)
178 {
179     ok(expectCall->id == id, "unexpected call %d, expected %d\n", id, expectCall->id);
180     return expectCall->id == id;
181 }
182
183 static void test_locator(unsigned line, int loc_line, int loc_column)
184 {
185     int rcolumn, rline;
186     ISAXLocator_getLineNumber(locator, &rline);
187     ISAXLocator_getColumnNumber(locator, &rcolumn);
188
189     ok_(__FILE__,line) (rline == loc_line,
190             "unexpected line %d, expected %d\n", rline, loc_line);
191     ok_(__FILE__,line) (rcolumn == loc_column,
192             "unexpected column %d, expected %d\n", rcolumn, loc_column);
193 }
194
195 static HRESULT WINAPI contentHandler_QueryInterface(
196         ISAXContentHandler* iface,
197         REFIID riid,
198         void **ppvObject)
199 {
200     *ppvObject = NULL;
201
202     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
203     {
204         *ppvObject = iface;
205     }
206     else
207     {
208         return E_NOINTERFACE;
209     }
210
211     return S_OK;
212 }
213
214 static ULONG WINAPI contentHandler_AddRef(
215         ISAXContentHandler* iface)
216 {
217     return 2;
218 }
219
220 static ULONG WINAPI contentHandler_Release(
221         ISAXContentHandler* iface)
222 {
223     return 1;
224 }
225
226 static HRESULT WINAPI contentHandler_putDocumentLocator(
227         ISAXContentHandler* iface,
228         ISAXLocator *pLocator)
229 {
230     if(!test_expect_call(CH_PUTDOCUMENTLOCATOR))
231         return E_FAIL;
232
233     locator = pLocator;
234     test_locator(__LINE__, expectCall->line, expectCall->column);
235
236     expectCall++;
237     return S_OK;
238 }
239
240 static HRESULT WINAPI contentHandler_startDocument(
241         ISAXContentHandler* iface)
242 {
243     if(!test_expect_call(CH_STARTDOCUMENT))
244         return E_FAIL;
245
246     test_locator(__LINE__, expectCall->line, expectCall->column);
247
248     expectCall++;
249     return S_OK;
250 }
251
252 static HRESULT WINAPI contentHandler_endDocument(
253         ISAXContentHandler* iface)
254 {
255     if(!test_expect_call(CH_ENDDOCUMENT))
256         return E_FAIL;
257
258     test_locator(__LINE__, expectCall->line, expectCall->column);
259
260     expectCall++;
261     return S_OK;
262 }
263
264 static HRESULT WINAPI contentHandler_startPrefixMapping(
265         ISAXContentHandler* iface,
266         const WCHAR *pPrefix,
267         int nPrefix,
268         const WCHAR *pUri,
269         int nUri)
270 {
271     if(!test_expect_call(CH_ENDDOCUMENT))
272         return E_FAIL;
273
274     test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1);
275     test_saxstr(__LINE__, pUri, nUri, expectCall->arg2);
276     test_locator(__LINE__, expectCall->line, expectCall->column);
277
278     expectCall++;
279     return S_OK;
280 }
281
282 static HRESULT WINAPI contentHandler_endPrefixMapping(
283         ISAXContentHandler* iface,
284         const WCHAR *pPrefix,
285         int nPrefix)
286 {
287     if(!test_expect_call(CH_ENDPREFIXMAPPING))
288         return E_FAIL;
289
290     test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1);
291     test_locator(__LINE__, expectCall->line, expectCall->column);
292
293     expectCall++;
294     return S_OK;
295 }
296
297 static HRESULT WINAPI contentHandler_startElement(
298         ISAXContentHandler* iface,
299         const WCHAR *pNamespaceUri,
300         int nNamespaceUri,
301         const WCHAR *pLocalName,
302         int nLocalName,
303         const WCHAR *pQName,
304         int nQName,
305         ISAXAttributes *pAttr)
306 {
307     if(!test_expect_call(CH_STARTELEMENT))
308         return E_FAIL;
309
310     test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1);
311     test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2);
312     test_saxstr(__LINE__, pQName, nQName, expectCall->arg3);
313     test_locator(__LINE__, expectCall->line, expectCall->column);
314
315     expectCall++;
316     return S_OK;
317 }
318
319 static HRESULT WINAPI contentHandler_endElement(
320         ISAXContentHandler* iface,
321         const WCHAR *pNamespaceUri,
322         int nNamespaceUri,
323         const WCHAR *pLocalName,
324         int nLocalName,
325         const WCHAR *pQName,
326         int nQName)
327 {
328     if(!test_expect_call(CH_ENDELEMENT))
329         return E_FAIL;
330
331     test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1);
332     test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2);
333     test_saxstr(__LINE__, pQName, nQName, expectCall->arg3);
334     test_locator(__LINE__, expectCall->line, expectCall->column);
335
336     expectCall++;
337     return S_OK;
338 }
339
340 static HRESULT WINAPI contentHandler_characters(
341         ISAXContentHandler* iface,
342         const WCHAR *pChars,
343         int nChars)
344 {
345     if(!test_expect_call(CH_CHARACTERS))
346         return E_FAIL;
347
348     test_saxstr(__LINE__, pChars, nChars, expectCall->arg1);
349     test_locator(__LINE__, expectCall->line, expectCall->column);
350
351     expectCall++;
352     return S_OK;
353 }
354
355 static HRESULT WINAPI contentHandler_ignorableWhitespace(
356         ISAXContentHandler* iface,
357         const WCHAR *pChars,
358         int nChars)
359 {
360     if(!test_expect_call(CH_IGNORABLEWHITESPACE))
361         return E_FAIL;
362
363     test_saxstr(__LINE__, pChars, nChars, expectCall->arg1);
364     test_locator(__LINE__, expectCall->line, expectCall->column);
365
366     expectCall++;
367     return S_OK;
368 }
369
370 static HRESULT WINAPI contentHandler_processingInstruction(
371         ISAXContentHandler* iface,
372         const WCHAR *pTarget,
373         int nTarget,
374         const WCHAR *pData,
375         int nData)
376 {
377     if(!test_expect_call(CH_PROCESSINGINSTRUCTION))
378         return E_FAIL;
379
380     test_saxstr(__LINE__, pTarget, nTarget, expectCall->arg1);
381     test_saxstr(__LINE__, pData, nData, expectCall->arg2);
382     test_locator(__LINE__, expectCall->line, expectCall->column);
383
384     expectCall++;
385     return S_OK;
386 }
387
388 static HRESULT WINAPI contentHandler_skippedEntity(
389         ISAXContentHandler* iface,
390         const WCHAR *pName,
391         int nName)
392 {
393     if(!test_expect_call(CH_SKIPPEDENTITY))
394         return E_FAIL;
395
396     test_saxstr(__LINE__, pName, nName, expectCall->arg1);
397     test_locator(__LINE__, expectCall->line, expectCall->column);
398
399     expectCall++;
400     return S_OK;
401 }
402
403
404 static const ISAXContentHandlerVtbl contentHandlerVtbl =
405 {
406     contentHandler_QueryInterface,
407     contentHandler_AddRef,
408     contentHandler_Release,
409     contentHandler_putDocumentLocator,
410     contentHandler_startDocument,
411     contentHandler_endDocument,
412     contentHandler_startPrefixMapping,
413     contentHandler_endPrefixMapping,
414     contentHandler_startElement,
415     contentHandler_endElement,
416     contentHandler_characters,
417     contentHandler_ignorableWhitespace,
418     contentHandler_processingInstruction,
419     contentHandler_skippedEntity
420 };
421
422 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
423
424 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
425         ISAXErrorHandler* iface,
426         REFIID riid,
427         void **ppvObject)
428 {
429     *ppvObject = NULL;
430
431     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
432     {
433         *ppvObject = iface;
434     }
435     else
436     {
437         return E_NOINTERFACE;
438     }
439
440     return S_OK;
441 }
442
443 static ULONG WINAPI isaxerrorHandler_AddRef(
444         ISAXErrorHandler* iface)
445 {
446     return 2;
447 }
448
449 static ULONG WINAPI isaxerrorHandler_Release(
450         ISAXErrorHandler* iface)
451 {
452     return 1;
453 }
454
455 static HRESULT WINAPI isaxerrorHandler_error(
456         ISAXErrorHandler* iface,
457         ISAXLocator *pLocator,
458         const WCHAR *pErrorMessage,
459         HRESULT hrErrorCode)
460 {
461     return S_OK;
462 }
463
464 static HRESULT WINAPI isaxerrorHandler_fatalError(
465         ISAXErrorHandler* iface,
466         ISAXLocator *pLocator,
467         const WCHAR *pErrorMessage,
468         HRESULT hrErrorCode)
469 {
470     return S_OK;
471 }
472
473 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
474         ISAXErrorHandler* iface,
475         ISAXLocator *pLocator,
476         const WCHAR *pErrorMessage,
477         HRESULT hrErrorCode)
478 {
479     return S_OK;
480 }
481
482 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
483 {
484     isaxerrorHandler_QueryInterface,
485     isaxerrorHandler_AddRef,
486     isaxerrorHandler_Release,
487     isaxerrorHandler_error,
488     isaxerrorHandler_fatalError,
489     isaxerrorHanddler_ignorableWarning
490 };
491
492 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
493
494 static HRESULT WINAPI isaxattributes_QueryInterface(
495         ISAXAttributes* iface,
496         REFIID riid,
497         void **ppvObject)
498 {
499     *ppvObject = NULL;
500
501     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
502     {
503         *ppvObject = iface;
504     }
505     else
506     {
507         return E_NOINTERFACE;
508     }
509
510     return S_OK;
511 }
512
513 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
514 {
515     return 2;
516 }
517
518 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
519 {
520     return 1;
521 }
522
523 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
524 {
525     *length = 2;
526     return S_OK;
527 }
528
529 static HRESULT WINAPI isaxattributes_getURI(
530     ISAXAttributes* iface,
531     int nIndex,
532     const WCHAR **pUrl,
533     int *pUriSize)
534 {
535     ok(0, "unexpected call\n");
536     return E_NOTIMPL;
537 }
538
539 static HRESULT WINAPI isaxattributes_getLocalName(
540     ISAXAttributes* iface,
541     int nIndex,
542     const WCHAR **pLocalName,
543     int *pLocalNameLength)
544 {
545     ok(0, "unexpected call\n");
546     return E_NOTIMPL;
547 }
548
549 static HRESULT WINAPI isaxattributes_getQName(
550     ISAXAttributes* iface,
551     int nIndex,
552     const WCHAR **pQName,
553     int *pQNameLength)
554 {
555     static const WCHAR attr1W[] = {'a',':','a','t','t','r','1',0};
556     static const WCHAR attr2W[] = {'a','t','t','r','2',0};
557
558     ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
559
560     *pQName = (nIndex == 0) ? attr1W : attr2W;
561     *pQNameLength = lstrlenW(*pQName);
562
563     return S_OK;
564 }
565
566 static HRESULT WINAPI isaxattributes_getName(
567     ISAXAttributes* iface,
568     int nIndex,
569     const WCHAR **pUri,
570     int * pUriLength,
571     const WCHAR ** pLocalName,
572     int * pLocalNameSize,
573     const WCHAR ** pQName,
574     int * pQNameLength)
575 {
576     ok(0, "unexpected call\n");
577     return E_NOTIMPL;
578 }
579
580 static HRESULT WINAPI isaxattributes_getIndexFromName(
581     ISAXAttributes* iface,
582     const WCHAR * pUri,
583     int cUriLength,
584     const WCHAR * pLocalName,
585     int cocalNameLength,
586     int * index)
587 {
588     ok(0, "unexpected call\n");
589     return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI isaxattributes_getIndexFromQName(
593     ISAXAttributes* iface,
594     const WCHAR * pQName,
595     int nQNameLength,
596     int * index)
597 {
598     ok(0, "unexpected call\n");
599     return E_NOTIMPL;
600 }
601
602 static HRESULT WINAPI isaxattributes_getType(
603     ISAXAttributes* iface,
604     int nIndex,
605     const WCHAR ** pType,
606     int * pTypeLength)
607 {
608     ok(0, "unexpected call\n");
609     return E_NOTIMPL;
610 }
611
612 static HRESULT WINAPI isaxattributes_getTypeFromName(
613     ISAXAttributes* iface,
614     const WCHAR * pUri,
615     int nUri,
616     const WCHAR * pLocalName,
617     int nLocalName,
618     const WCHAR ** pType,
619     int * nType)
620 {
621     ok(0, "unexpected call\n");
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI isaxattributes_getTypeFromQName(
626     ISAXAttributes* iface,
627     const WCHAR * pQName,
628     int nQName,
629     const WCHAR ** pType,
630     int * nType)
631 {
632     ok(0, "unexpected call\n");
633     return E_NOTIMPL;
634 }
635
636 static HRESULT WINAPI isaxattributes_getValue(
637     ISAXAttributes* iface,
638     int nIndex,
639     const WCHAR ** pValue,
640     int * nValue)
641 {
642     static const WCHAR attrval1W[] = {'a','1',0};
643     static const WCHAR attrval2W[] = {'a','2',0};
644
645     ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
646
647     *pValue = (nIndex == 0) ? attrval1W : attrval2W;
648     *nValue = lstrlenW(*pValue);
649
650     return S_OK;
651 }
652
653 static HRESULT WINAPI isaxattributes_getValueFromName(
654     ISAXAttributes* iface,
655     const WCHAR * pUri,
656     int nUri,
657     const WCHAR * pLocalName,
658     int nLocalName,
659     const WCHAR ** pValue,
660     int * nValue)
661 {
662     ok(0, "unexpected call\n");
663     return E_NOTIMPL;
664 }
665
666 static HRESULT WINAPI isaxattributes_getValueFromQName(
667     ISAXAttributes* iface,
668     const WCHAR * pQName,
669     int nQName,
670     const WCHAR ** pValue,
671     int * nValue)
672 {
673     ok(0, "unexpected call\n");
674     return E_NOTIMPL;
675 }
676
677 static const ISAXAttributesVtbl SAXAttributesVtbl =
678 {
679     isaxattributes_QueryInterface,
680     isaxattributes_AddRef,
681     isaxattributes_Release,
682     isaxattributes_getLength,
683     isaxattributes_getURI,
684     isaxattributes_getLocalName,
685     isaxattributes_getQName,
686     isaxattributes_getName,
687     isaxattributes_getIndexFromName,
688     isaxattributes_getIndexFromQName,
689     isaxattributes_getType,
690     isaxattributes_getTypeFromName,
691     isaxattributes_getTypeFromQName,
692     isaxattributes_getValue,
693     isaxattributes_getValueFromName,
694     isaxattributes_getValueFromQName
695 };
696
697 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
698
699 static void test_saxreader(void)
700 {
701     HRESULT hr;
702     ISAXXMLReader *reader = NULL;
703     VARIANT var;
704     ISAXContentHandler *lpContentHandler;
705     ISAXErrorHandler *lpErrorHandler;
706     SAFEARRAY *pSA;
707     SAFEARRAYBOUND SADim[1];
708     char *pSAData = NULL;
709     IStream *iStream;
710     ULARGE_INTEGER liSize;
711     LARGE_INTEGER liPos;
712     ULONG bytesWritten;
713     HANDLE file;
714     static const CHAR testXmlA[] = "test.xml";
715     static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
716     IXMLDOMDocument *domDocument;
717     BSTR bstrData;
718     VARIANT_BOOL vBool;
719
720     hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
721             &IID_ISAXXMLReader, (LPVOID*)&reader);
722     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
723
724     hr = ISAXXMLReader_getContentHandler(reader, NULL);
725     ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr);
726
727     hr = ISAXXMLReader_getErrorHandler(reader, NULL);
728     ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr);
729
730     hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler);
731     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
732     ok(lpContentHandler == NULL, "Expected %p, got %p\n", NULL, lpContentHandler);
733
734     hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
735     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
736     ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
737
738     hr = ISAXXMLReader_putContentHandler(reader, NULL);
739     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
740
741     hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
742     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
743
744     hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
745     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
746
747     hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler);
748     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
749     ok(lpContentHandler == &contentHandler, "Expected %p, got %p\n", &contentHandler, lpContentHandler);
750
751     V_VT(&var) = VT_BSTR;
752     V_BSTR(&var) = SysAllocString(szSimpleXML);
753
754     expectCall = contentHandlerTest1;
755     hr = ISAXXMLReader_parse(reader, var);
756     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
757     test_expect_call(CH_ENDTEST);
758
759     VariantClear(&var);
760
761     SADim[0].lLbound= 0;
762     SADim[0].cElements= sizeof(szTestXML)-1;
763     pSA = SafeArrayCreate(VT_UI1, 1, SADim);
764     SafeArrayAccessData(pSA, (void**)&pSAData);
765     memcpy(pSAData, szTestXML, sizeof(szTestXML)-1);
766     SafeArrayUnaccessData(pSA);
767     V_VT(&var) = VT_ARRAY|VT_UI1;
768     V_ARRAY(&var) = pSA;
769
770     expectCall = contentHandlerTest1;
771     hr = ISAXXMLReader_parse(reader, var);
772     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
773     test_expect_call(CH_ENDTEST);
774
775     SafeArrayDestroy(pSA);
776
777     CreateStreamOnHGlobal(NULL, TRUE, &iStream);
778     liSize.QuadPart = strlen(szTestXML);
779     IStream_SetSize(iStream, liSize);
780     IStream_Write(iStream, szTestXML, strlen(szTestXML), &bytesWritten);
781     liPos.QuadPart = 0;
782     IStream_Seek(iStream, liPos, STREAM_SEEK_SET, NULL);
783     V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
784     V_UNKNOWN(&var) = (IUnknown*)iStream;
785
786     expectCall = contentHandlerTest1;
787     hr = ISAXXMLReader_parse(reader, var);
788     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
789     test_expect_call(CH_ENDTEST);
790
791     IStream_Release(iStream);
792
793     V_VT(&var) = VT_BSTR;
794     V_BSTR(&var) = SysAllocString(szCarriageRetTest);
795
796     expectCall = contentHandlerTest2;
797     hr = ISAXXMLReader_parse(reader, var);
798     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
799     test_expect_call(CH_ENDTEST);
800
801     VariantClear(&var);
802
803     file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
804     ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
805     WriteFile(file, szTestXML, sizeof(szTestXML)-1, &bytesWritten, NULL);
806     CloseHandle(file);
807
808     expectCall = contentHandlerTest1;
809     hr = ISAXXMLReader_parseURL(reader, testXmlW);
810     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
811     test_expect_call(CH_ENDTEST);
812
813     DeleteFileA(testXmlA);
814
815     hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
816             &IID_IXMLDOMDocument, (LPVOID*)&domDocument);
817     if(FAILED(hr))
818     {
819         skip("Failed to create DOMDocument instance\n");
820         return;
821     }
822     bstrData = SysAllocString(szSimpleXML);
823     hr = IXMLDOMDocument_loadXML(domDocument, bstrData, &vBool);
824     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
825     V_VT(&var) = VT_UNKNOWN;
826     V_UNKNOWN(&var) = (IUnknown*)domDocument;
827
828     expectCall = contentHandlerTest2;
829     hr = ISAXXMLReader_parse(reader, var);
830     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
831     test_expect_call(CH_ENDTEST);
832     IXMLDOMDocument_Release(domDocument);
833
834     ISAXXMLReader_Release(reader);
835     SysFreeString(bstrData);
836 }
837
838 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
839 static const CHAR UTF8BOMTest[] =
840 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
841 "<a></a>\n";
842
843 struct enc_test_entry_t {
844     const GUID *guid;
845     const char *clsid;
846     const char *data;
847     HRESULT hr;
848     int todo;
849 };
850
851 static const struct enc_test_entry_t encoding_test_data[] = {
852     { &CLSID_SAXXMLReader,   "CLSID_SAXXMLReader",   UTF8BOMTest, 0xc00ce56f, 1 },
853     { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
854     { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
855     { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
856     { 0 }
857 };
858
859 static void test_encoding(void)
860 {
861     const struct enc_test_entry_t *entry = encoding_test_data;
862     static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
863     static const CHAR testXmlA[] = "test.xml";
864     ISAXXMLReader *reader;
865     DWORD written;
866     HANDLE file;
867     HRESULT hr;
868
869     while (entry->guid)
870     {
871         hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
872         if (hr != S_OK)
873         {
874             win_skip("can't create %s instance\n", entry->clsid);
875             entry++;
876             continue;
877         }
878
879         file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
880         ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
881         WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
882         CloseHandle(file);
883
884         hr = ISAXXMLReader_parseURL(reader, testXmlW);
885         if (entry->todo)
886             todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
887         else
888             ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
889
890         DeleteFileA(testXmlA);
891         ISAXXMLReader_Release(reader);
892
893         entry++;
894     }
895 }
896
897 static void test_mxwriter_contenthandler(void)
898 {
899     ISAXContentHandler *handler;
900     IMXWriter *writer, *writer2;
901     HRESULT hr;
902
903     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
904             &IID_IMXWriter, (void**)&writer);
905     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
906
907     EXPECT_REF(writer, 1);
908
909     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
910     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
911     EXPECT_REF(writer, 2);
912     EXPECT_REF(handler, 2);
913
914     hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
915     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
916     ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
917     EXPECT_REF(writer, 3);
918     EXPECT_REF(writer2, 3);
919     IMXWriter_Release(writer2);
920
921     ISAXContentHandler_Release(handler);
922     IMXWriter_Release(writer);
923 }
924
925 static void test_mxwriter_properties(void)
926 {
927     static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
928     static const WCHAR emptyW[] = {0};
929     static const WCHAR testW[] = {'t','e','s','t',0};
930     IMXWriter *writer;
931     VARIANT_BOOL b;
932     HRESULT hr;
933     BSTR str, str2;
934
935     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
936             &IID_IMXWriter, (void**)&writer);
937     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
938
939     hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
940     ok(hr == E_POINTER, "got %08x\n", hr);
941
942     b = VARIANT_TRUE;
943     hr = IMXWriter_get_disableOutputEscaping(writer, &b);
944     ok(hr == S_OK, "got %08x\n", hr);
945     ok(b == VARIANT_FALSE, "got %d\n", b);
946
947     hr = IMXWriter_get_byteOrderMark(writer, NULL);
948     ok(hr == E_POINTER, "got %08x\n", hr);
949
950     b = VARIANT_FALSE;
951     hr = IMXWriter_get_byteOrderMark(writer, &b);
952     ok(hr == S_OK, "got %08x\n", hr);
953     ok(b == VARIANT_TRUE, "got %d\n", b);
954
955     hr = IMXWriter_get_indent(writer, NULL);
956     ok(hr == E_POINTER, "got %08x\n", hr);
957
958     b = VARIANT_TRUE;
959     hr = IMXWriter_get_indent(writer, &b);
960     ok(hr == S_OK, "got %08x\n", hr);
961     ok(b == VARIANT_FALSE, "got %d\n", b);
962
963     hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
964     ok(hr == E_POINTER, "got %08x\n", hr);
965
966     b = VARIANT_TRUE;
967     hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
968     ok(hr == S_OK, "got %08x\n", hr);
969     ok(b == VARIANT_FALSE, "got %d\n", b);
970
971     hr = IMXWriter_get_standalone(writer, NULL);
972     ok(hr == E_POINTER, "got %08x\n", hr);
973
974     b = VARIANT_TRUE;
975     hr = IMXWriter_get_standalone(writer, &b);
976     ok(hr == S_OK, "got %08x\n", hr);
977     ok(b == VARIANT_FALSE, "got %d\n", b);
978
979     /* set and check */
980     hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
981     ok(hr == S_OK, "got %08x\n", hr);
982
983     b = VARIANT_FALSE;
984     hr = IMXWriter_get_standalone(writer, &b);
985     ok(hr == S_OK, "got %08x\n", hr);
986     ok(b == VARIANT_TRUE, "got %d\n", b);
987
988     hr = IMXWriter_get_encoding(writer, NULL);
989     ok(hr == E_POINTER, "got %08x\n", hr);
990
991     /* UTF-16 is a default setting apparently */
992     str = (void*)0xdeadbeef;
993     hr = IMXWriter_get_encoding(writer, &str);
994     ok(hr == S_OK, "got %08x\n", hr);
995     ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
996
997     str2 = (void*)0xdeadbeef;
998     hr = IMXWriter_get_encoding(writer, &str2);
999     ok(hr == S_OK, "got %08x\n", hr);
1000     ok(str != str2, "expected newly allocated, got same %p\n", str);
1001
1002     SysFreeString(str2);
1003     SysFreeString(str);
1004
1005     /* put empty string */
1006     str = SysAllocString(emptyW);
1007     hr = IMXWriter_put_encoding(writer, str);
1008     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1009     SysFreeString(str);
1010
1011     str = (void*)0xdeadbeef;
1012     hr = IMXWriter_get_encoding(writer, &str);
1013     ok(hr == S_OK, "got %08x\n", hr);
1014     ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
1015     SysFreeString(str);
1016
1017     /* invalid encoding name */
1018     str = SysAllocString(testW);
1019     hr = IMXWriter_put_encoding(writer, str);
1020     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1021     SysFreeString(str);
1022
1023     hr = IMXWriter_get_version(writer, NULL);
1024     ok(hr == E_POINTER, "got %08x\n", hr);
1025     /* default version is 'surprisingly' 1.0 */
1026     hr = IMXWriter_get_version(writer, &str);
1027     ok(hr == S_OK, "got %08x\n", hr);
1028     ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
1029     SysFreeString(str);
1030
1031     IMXWriter_Release(writer);
1032     free_bstrs();
1033 }
1034
1035 static void test_mxwriter_flush(void)
1036 {
1037     ISAXContentHandler *content;
1038     IMXWriter *writer;
1039     LARGE_INTEGER pos;
1040     ULARGE_INTEGER pos2;
1041     IStream *stream;
1042     VARIANT dest;
1043     HRESULT hr;
1044
1045     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1046             &IID_IMXWriter, (void**)&writer);
1047     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1048
1049     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1050     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1051     EXPECT_REF(stream, 1);
1052
1053     /* detach whe nothing was attached */
1054     V_VT(&dest) = VT_EMPTY;
1055     hr = IMXWriter_put_output(writer, dest);
1056     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1057
1058     /* attach stream */
1059     V_VT(&dest) = VT_UNKNOWN;
1060     V_UNKNOWN(&dest) = (IUnknown*)stream;
1061     hr = IMXWriter_put_output(writer, dest);
1062     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1063     todo_wine EXPECT_REF(stream, 3);
1064
1065     /* detach setting VT_EMPTY destination */
1066     V_VT(&dest) = VT_EMPTY;
1067     hr = IMXWriter_put_output(writer, dest);
1068     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1069     EXPECT_REF(stream, 1);
1070
1071     V_VT(&dest) = VT_UNKNOWN;
1072     V_UNKNOWN(&dest) = (IUnknown*)stream;
1073     hr = IMXWriter_put_output(writer, dest);
1074     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1075
1076     /* flush() doesn't detach a stream */
1077     hr = IMXWriter_flush(writer);
1078 todo_wine {
1079     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1080     EXPECT_REF(stream, 3);
1081 }
1082
1083     pos.QuadPart = 0;
1084     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1085     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1086     ok(pos2.QuadPart == 0, "expected stream beginning\n");
1087
1088     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1089     ok(hr == S_OK, "got %08x\n", hr);
1090
1091     hr = ISAXContentHandler_startDocument(content);
1092     ok(hr == S_OK, "got %08x\n", hr);
1093
1094     pos.QuadPart = 0;
1095     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1096     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1097     todo_wine ok(pos2.QuadPart != 0, "expected stream beginning\n");
1098
1099     /* already started */
1100     hr = ISAXContentHandler_startDocument(content);
1101     ok(hr == S_OK, "got %08x\n", hr);
1102
1103     hr = ISAXContentHandler_endDocument(content);
1104     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1105
1106     /* flushed on endDocument() */
1107     pos.QuadPart = 0;
1108     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1109     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1110     todo_wine ok(pos2.QuadPart != 0, "expected stream position moved\n");
1111
1112     ISAXContentHandler_Release(content);
1113     IStream_Release(stream);
1114     IMXWriter_Release(writer);
1115 }
1116
1117 static void test_mxwriter_startenddocument(void)
1118 {
1119     ISAXContentHandler *content;
1120     IMXWriter *writer;
1121     VARIANT dest;
1122     HRESULT hr;
1123
1124     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1125             &IID_IMXWriter, (void**)&writer);
1126     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1127
1128     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1129     ok(hr == S_OK, "got %08x\n", hr);
1130
1131     hr = ISAXContentHandler_startDocument(content);
1132     ok(hr == S_OK, "got %08x\n", hr);
1133
1134     hr = ISAXContentHandler_endDocument(content);
1135     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1136
1137     V_VT(&dest) = VT_EMPTY;
1138     hr = IMXWriter_get_output(writer, &dest);
1139     ok(hr == S_OK, "got %08x\n", hr);
1140     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1141     ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1142         "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1143     VariantClear(&dest);
1144
1145     /* now try another startDocument */
1146     hr = ISAXContentHandler_startDocument(content);
1147     ok(hr == S_OK, "got %08x\n", hr);
1148     /* and get duplcated prolog */
1149     V_VT(&dest) = VT_EMPTY;
1150     hr = IMXWriter_get_output(writer, &dest);
1151     ok(hr == S_OK, "got %08x\n", hr);
1152     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1153     ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
1154                         "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1155         "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1156     VariantClear(&dest);
1157
1158     ISAXContentHandler_Release(content);
1159     IMXWriter_Release(writer);
1160
1161     /* now with omitted declaration */
1162     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1163             &IID_IMXWriter, (void**)&writer);
1164     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1165
1166     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1167     ok(hr == S_OK, "got %08x\n", hr);
1168
1169     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1170     ok(hr == S_OK, "got %08x\n", hr);
1171
1172     hr = ISAXContentHandler_startDocument(content);
1173     ok(hr == S_OK, "got %08x\n", hr);
1174
1175     hr = ISAXContentHandler_endDocument(content);
1176     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1177
1178     V_VT(&dest) = VT_EMPTY;
1179     hr = IMXWriter_get_output(writer, &dest);
1180     ok(hr == S_OK, "got %08x\n", hr);
1181     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1182     ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1183     VariantClear(&dest);
1184
1185     ISAXContentHandler_Release(content);
1186     IMXWriter_Release(writer);
1187
1188     free_bstrs();
1189 }
1190
1191 static void test_mxwriter_startendelement(void)
1192 {
1193     static const char winehqA[] = "http://winehq.org";
1194     ISAXContentHandler *content;
1195     IMXWriter *writer;
1196     VARIANT dest;
1197     HRESULT hr;
1198
1199     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1200             &IID_IMXWriter, (void**)&writer);
1201     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1202
1203     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1204     ok(hr == S_OK, "got %08x\n", hr);
1205
1206     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1207     ok(hr == S_OK, "got %08x\n", hr);
1208
1209     hr = ISAXContentHandler_startDocument(content);
1210     ok(hr == S_OK, "got %08x\n", hr);
1211
1212     /* qualified name without defined namespace */
1213     hr = ISAXContentHandler_startElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3, NULL);
1214     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1215
1216     hr = ISAXContentHandler_startElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3, NULL);
1217     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1218
1219     /* only local name is an error too */
1220     hr = ISAXContentHandler_startElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0, NULL);
1221     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1222
1223     /* only local name is an error too */
1224     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, NULL, 0, NULL);
1225     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1226
1227     /* all string pointers should be not null */
1228     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
1229     ok(hr == S_OK, "got %08x\n", hr);
1230
1231     V_VT(&dest) = VT_EMPTY;
1232     hr = IMXWriter_get_output(writer, &dest);
1233     ok(hr == S_OK, "got %08x\n", hr);
1234     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1235     ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1236     VariantClear(&dest);
1237
1238     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
1239     ok(hr == S_OK, "got %08x\n", hr);
1240
1241     V_VT(&dest) = VT_EMPTY;
1242     hr = IMXWriter_get_output(writer, &dest);
1243     ok(hr == S_OK, "got %08x\n", hr);
1244     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1245     ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1246     VariantClear(&dest);
1247
1248     hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
1249     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1250
1251     hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
1252     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1253
1254     /* only local name is an error too */
1255     hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
1256     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1257
1258     hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
1259     ok(hr == S_OK, "got %08x\n", hr);
1260
1261     V_VT(&dest) = VT_EMPTY;
1262     hr = IMXWriter_get_output(writer, &dest);
1263     ok(hr == S_OK, "got %08x\n", hr);
1264     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1265     ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1266     VariantClear(&dest);
1267
1268     /* some with namespace URI */
1269     hr = ISAXContentHandler_startElement(content, _bstr_(winehqA), sizeof(winehqA), _bstr_(""), 0, _bstr_("nspace:c"), 8, NULL);
1270     ok(hr == S_OK, "got %08x\n", hr);
1271
1272     hr = ISAXContentHandler_endElement(content, _bstr_(winehqA), sizeof(winehqA), _bstr_(""), 0, _bstr_("nspace:c"), 8);
1273     ok(hr == S_OK, "got %08x\n", hr);
1274
1275     V_VT(&dest) = VT_EMPTY;
1276     hr = IMXWriter_get_output(writer, &dest);
1277     ok(hr == S_OK, "got %08x\n", hr);
1278     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1279     todo_wine ok(!lstrcmpW(_bstr_("<><b></b><nspace:c/>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1280     VariantClear(&dest);
1281
1282     /* try to end element that wasn't open */
1283     hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
1284     ok(hr == S_OK, "got %08x\n", hr);
1285
1286     V_VT(&dest) = VT_EMPTY;
1287     hr = IMXWriter_get_output(writer, &dest);
1288     ok(hr == S_OK, "got %08x\n", hr);
1289     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1290     todo_wine ok(!lstrcmpW(_bstr_("<><b></b><nspace:c/></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1291     VariantClear(&dest);
1292
1293     /* try with attributes */
1294     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, &saxattributes);
1295     ok(hr == S_OK, "got %08x\n", hr);
1296
1297     hr = ISAXContentHandler_endDocument(content);
1298     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1299
1300     ISAXContentHandler_Release(content);
1301     IMXWriter_Release(writer);
1302
1303     free_bstrs();
1304 }
1305
1306 static void test_mxwriter_characters(void)
1307 {
1308     static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
1309     ISAXContentHandler *content;
1310     IMXWriter *writer;
1311     VARIANT dest;
1312     HRESULT hr;
1313
1314     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1315             &IID_IMXWriter, (void**)&writer);
1316     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1317
1318     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1319     ok(hr == S_OK, "got %08x\n", hr);
1320
1321     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1322     ok(hr == S_OK, "got %08x\n", hr);
1323
1324     hr = ISAXContentHandler_startDocument(content);
1325     ok(hr == S_OK, "got %08x\n", hr);
1326
1327     hr = ISAXContentHandler_characters(content, NULL, 0);
1328     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1329
1330     hr = ISAXContentHandler_characters(content, chardataW, 0);
1331     ok(hr == S_OK, "got %08x\n", hr);
1332
1333     hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
1334     ok(hr == S_OK, "got %08x\n", hr);
1335
1336     V_VT(&dest) = VT_EMPTY;
1337     hr = IMXWriter_get_output(writer, &dest);
1338     ok(hr == S_OK, "got %08x\n", hr);
1339     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1340     ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1341     VariantClear(&dest);
1342
1343     hr = ISAXContentHandler_endDocument(content);
1344     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1345
1346     ISAXContentHandler_Release(content);
1347     IMXWriter_Release(writer);
1348
1349     free_bstrs();
1350 }
1351
1352 START_TEST(saxreader)
1353 {
1354     ISAXXMLReader *reader;
1355     IMXWriter *writer;
1356     HRESULT hr;
1357
1358     hr = CoInitialize(NULL);
1359     ok(hr == S_OK, "failed to init com\n");
1360
1361     hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
1362             &IID_ISAXXMLReader, (void**)&reader);
1363
1364     if(FAILED(hr))
1365     {
1366         skip("Failed to create SAXXMLReader instance\n");
1367         CoUninitialize();
1368         return;
1369     }
1370     ISAXXMLReader_Release(reader);
1371
1372     test_saxreader();
1373     test_encoding();
1374
1375     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1376             &IID_IMXWriter, (void**)&writer);
1377     if (hr == S_OK)
1378     {
1379         IMXWriter_Release(writer);
1380
1381         test_mxwriter_contenthandler();
1382         test_mxwriter_startenddocument();
1383         test_mxwriter_startendelement();
1384         test_mxwriter_characters();
1385         test_mxwriter_properties();
1386         test_mxwriter_flush();
1387     }
1388     else
1389         win_skip("MXXMLWriter not supported\n");
1390
1391     CoUninitialize();
1392 }