d3d9: Implement IDirect3DVertexBuffer9 private data handling on top of wined3d_resource.
[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
1016     /* invalid encoding name */
1017     str = SysAllocString(testW);
1018     hr = IMXWriter_put_encoding(writer, str);
1019     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1020     SysFreeString(str);
1021
1022     hr = IMXWriter_get_version(writer, NULL);
1023     ok(hr == E_POINTER, "got %08x\n", hr);
1024     /* default version is 'surprisingly' 1.0 */
1025     hr = IMXWriter_get_version(writer, &str);
1026     ok(hr == S_OK, "got %08x\n", hr);
1027     ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
1028
1029     IMXWriter_Release(writer);
1030     free_bstrs();
1031 }
1032
1033 static void test_mxwriter_flush(void)
1034 {
1035     ISAXContentHandler *content;
1036     IMXWriter *writer;
1037     LARGE_INTEGER pos;
1038     ULARGE_INTEGER pos2;
1039     IStream *stream;
1040     VARIANT dest;
1041     HRESULT hr;
1042
1043     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1044             &IID_IMXWriter, (void**)&writer);
1045     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1046
1047     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1048     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1049     EXPECT_REF(stream, 1);
1050
1051     /* detach whe nothing was attached */
1052     V_VT(&dest) = VT_EMPTY;
1053     hr = IMXWriter_put_output(writer, dest);
1054     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1055
1056     /* attach stream */
1057     V_VT(&dest) = VT_UNKNOWN;
1058     V_UNKNOWN(&dest) = (IUnknown*)stream;
1059     hr = IMXWriter_put_output(writer, dest);
1060     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1061     todo_wine EXPECT_REF(stream, 3);
1062
1063     /* detach setting VT_EMPTY destination */
1064     V_VT(&dest) = VT_EMPTY;
1065     hr = IMXWriter_put_output(writer, dest);
1066     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1067     EXPECT_REF(stream, 1);
1068
1069     V_VT(&dest) = VT_UNKNOWN;
1070     V_UNKNOWN(&dest) = (IUnknown*)stream;
1071     hr = IMXWriter_put_output(writer, dest);
1072     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1073
1074     /* flush() doesn't detach a stream */
1075     hr = IMXWriter_flush(writer);
1076 todo_wine {
1077     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1078     EXPECT_REF(stream, 3);
1079 }
1080
1081     pos.QuadPart = 0;
1082     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1083     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1084     ok(pos2.QuadPart == 0, "expected stream beginning\n");
1085
1086     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1087     ok(hr == S_OK, "got %08x\n", hr);
1088
1089     hr = ISAXContentHandler_startDocument(content);
1090     ok(hr == S_OK, "got %08x\n", hr);
1091
1092     pos.QuadPart = 0;
1093     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1094     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1095     todo_wine ok(pos2.QuadPart != 0, "expected stream beginning\n");
1096
1097     /* already started */
1098     hr = ISAXContentHandler_startDocument(content);
1099     ok(hr == S_OK, "got %08x\n", hr);
1100
1101     hr = ISAXContentHandler_endDocument(content);
1102     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1103
1104     /* flushed on endDocument() */
1105     pos.QuadPart = 0;
1106     hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1107     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1108     todo_wine ok(pos2.QuadPart != 0, "expected stream position moved\n");
1109
1110     ISAXContentHandler_Release(content);
1111     IStream_Release(stream);
1112     IMXWriter_Release(writer);
1113 }
1114
1115 static void test_mxwriter_startenddocument(void)
1116 {
1117     ISAXContentHandler *content;
1118     IMXWriter *writer;
1119     VARIANT dest;
1120     HRESULT hr;
1121
1122     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1123             &IID_IMXWriter, (void**)&writer);
1124     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1125
1126     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1127     ok(hr == S_OK, "got %08x\n", hr);
1128
1129     hr = ISAXContentHandler_startDocument(content);
1130     ok(hr == S_OK, "got %08x\n", hr);
1131
1132     hr = ISAXContentHandler_endDocument(content);
1133     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1134
1135     V_VT(&dest) = VT_EMPTY;
1136     hr = IMXWriter_get_output(writer, &dest);
1137     ok(hr == S_OK, "got %08x\n", hr);
1138     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1139     ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1140         "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1141     VariantClear(&dest);
1142
1143     /* now try another startDocument */
1144     hr = ISAXContentHandler_startDocument(content);
1145     ok(hr == S_OK, "got %08x\n", hr);
1146     /* and get duplcated prolog */
1147     V_VT(&dest) = VT_EMPTY;
1148     hr = IMXWriter_get_output(writer, &dest);
1149     ok(hr == S_OK, "got %08x\n", hr);
1150     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1151     ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
1152                         "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1153         "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1154     VariantClear(&dest);
1155
1156     ISAXContentHandler_Release(content);
1157     IMXWriter_Release(writer);
1158
1159     /* now with omitted declaration */
1160     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1161             &IID_IMXWriter, (void**)&writer);
1162     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1163
1164     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1165     ok(hr == S_OK, "got %08x\n", hr);
1166
1167     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1168     ok(hr == S_OK, "got %08x\n", hr);
1169
1170     hr = ISAXContentHandler_startDocument(content);
1171     ok(hr == S_OK, "got %08x\n", hr);
1172
1173     hr = ISAXContentHandler_endDocument(content);
1174     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1175
1176     V_VT(&dest) = VT_EMPTY;
1177     hr = IMXWriter_get_output(writer, &dest);
1178     ok(hr == S_OK, "got %08x\n", hr);
1179     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1180     ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1181     VariantClear(&dest);
1182
1183     ISAXContentHandler_Release(content);
1184     IMXWriter_Release(writer);
1185
1186     free_bstrs();
1187 }
1188
1189 static void test_mxwriter_startendelement(void)
1190 {
1191     static const char winehqA[] = "http://winehq.org";
1192     ISAXContentHandler *content;
1193     IMXWriter *writer;
1194     VARIANT dest;
1195     HRESULT hr;
1196
1197     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1198             &IID_IMXWriter, (void**)&writer);
1199     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1200
1201     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1202     ok(hr == S_OK, "got %08x\n", hr);
1203
1204     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1205     ok(hr == S_OK, "got %08x\n", hr);
1206
1207     hr = ISAXContentHandler_startDocument(content);
1208     ok(hr == S_OK, "got %08x\n", hr);
1209
1210     /* qualified name without defined namespace */
1211     hr = ISAXContentHandler_startElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3, NULL);
1212     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1213
1214     hr = ISAXContentHandler_startElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3, NULL);
1215     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1216
1217     /* only local name is an error too */
1218     hr = ISAXContentHandler_startElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0, NULL);
1219     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1220
1221     /* only local name is an error too */
1222     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, NULL, 0, NULL);
1223     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1224
1225     /* all string pointers should be not null */
1226     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
1227     ok(hr == S_OK, "got %08x\n", hr);
1228
1229     V_VT(&dest) = VT_EMPTY;
1230     hr = IMXWriter_get_output(writer, &dest);
1231     ok(hr == S_OK, "got %08x\n", hr);
1232     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1233     ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1234     VariantClear(&dest);
1235
1236     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
1237     ok(hr == S_OK, "got %08x\n", hr);
1238
1239     V_VT(&dest) = VT_EMPTY;
1240     hr = IMXWriter_get_output(writer, &dest);
1241     ok(hr == S_OK, "got %08x\n", hr);
1242     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1243     ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1244     VariantClear(&dest);
1245
1246     hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
1247     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1248
1249     hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
1250     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1251
1252     /* only local name is an error too */
1253     hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
1254     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1255
1256     hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
1257     ok(hr == S_OK, "got %08x\n", hr);
1258
1259     V_VT(&dest) = VT_EMPTY;
1260     hr = IMXWriter_get_output(writer, &dest);
1261     ok(hr == S_OK, "got %08x\n", hr);
1262     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1263     ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1264     VariantClear(&dest);
1265
1266     /* some with namespace URI */
1267     hr = ISAXContentHandler_startElement(content, _bstr_(winehqA), sizeof(winehqA), _bstr_(""), 0, _bstr_("nspace:c"), 8, NULL);
1268     ok(hr == S_OK, "got %08x\n", hr);
1269
1270     hr = ISAXContentHandler_endElement(content, _bstr_(winehqA), sizeof(winehqA), _bstr_(""), 0, _bstr_("nspace:c"), 8);
1271     ok(hr == S_OK, "got %08x\n", hr);
1272
1273     V_VT(&dest) = VT_EMPTY;
1274     hr = IMXWriter_get_output(writer, &dest);
1275     ok(hr == S_OK, "got %08x\n", hr);
1276     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1277     todo_wine ok(!lstrcmpW(_bstr_("<><b></b><nspace:c/>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1278     VariantClear(&dest);
1279
1280     /* try to end element that wasn't open */
1281     hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
1282     ok(hr == S_OK, "got %08x\n", hr);
1283
1284     V_VT(&dest) = VT_EMPTY;
1285     hr = IMXWriter_get_output(writer, &dest);
1286     ok(hr == S_OK, "got %08x\n", hr);
1287     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1288     todo_wine ok(!lstrcmpW(_bstr_("<><b></b><nspace:c/></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1289     VariantClear(&dest);
1290
1291     /* try with attributes */
1292     hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, &saxattributes);
1293     ok(hr == S_OK, "got %08x\n", hr);
1294
1295     hr = ISAXContentHandler_endDocument(content);
1296     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1297
1298     ISAXContentHandler_Release(content);
1299     IMXWriter_Release(writer);
1300
1301     free_bstrs();
1302 }
1303
1304 static void test_mxwriter_characters(void)
1305 {
1306     static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
1307     ISAXContentHandler *content;
1308     IMXWriter *writer;
1309     VARIANT dest;
1310     HRESULT hr;
1311
1312     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1313             &IID_IMXWriter, (void**)&writer);
1314     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1315
1316     hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1317     ok(hr == S_OK, "got %08x\n", hr);
1318
1319     hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1320     ok(hr == S_OK, "got %08x\n", hr);
1321
1322     hr = ISAXContentHandler_startDocument(content);
1323     ok(hr == S_OK, "got %08x\n", hr);
1324
1325     hr = ISAXContentHandler_characters(content, NULL, 0);
1326     ok(hr == E_INVALIDARG, "got %08x\n", hr);
1327
1328     hr = ISAXContentHandler_characters(content, chardataW, 0);
1329     ok(hr == S_OK, "got %08x\n", hr);
1330
1331     hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
1332     ok(hr == S_OK, "got %08x\n", hr);
1333
1334     V_VT(&dest) = VT_EMPTY;
1335     hr = IMXWriter_get_output(writer, &dest);
1336     ok(hr == S_OK, "got %08x\n", hr);
1337     ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1338     ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1339     VariantClear(&dest);
1340
1341     hr = ISAXContentHandler_endDocument(content);
1342     todo_wine ok(hr == S_OK, "got %08x\n", hr);
1343
1344     ISAXContentHandler_Release(content);
1345     IMXWriter_Release(writer);
1346
1347     free_bstrs();
1348 }
1349
1350 START_TEST(saxreader)
1351 {
1352     ISAXXMLReader *reader;
1353     IMXWriter *writer;
1354     HRESULT hr;
1355
1356     hr = CoInitialize(NULL);
1357     ok(hr == S_OK, "failed to init com\n");
1358
1359     hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
1360             &IID_ISAXXMLReader, (void**)&reader);
1361
1362     if(FAILED(hr))
1363     {
1364         skip("Failed to create SAXXMLReader instance\n");
1365         CoUninitialize();
1366         return;
1367     }
1368     ISAXXMLReader_Release(reader);
1369
1370     test_saxreader();
1371     test_encoding();
1372
1373     hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1374             &IID_IMXWriter, (void**)&writer);
1375     if (hr == S_OK)
1376     {
1377         IMXWriter_Release(writer);
1378
1379         test_mxwriter_contenthandler();
1380         test_mxwriter_startenddocument();
1381         test_mxwriter_startendelement();
1382         test_mxwriter_characters();
1383         test_mxwriter_properties();
1384         test_mxwriter_flush();
1385     }
1386     else
1387         win_skip("MXXMLWriter not supported\n");
1388
1389     CoUninitialize();
1390 }