Reactos
1/*
2 * Copyright 2008 Piotr Caban
3 * Copyright 2011 Thomas Mullaly
4 * Copyright 2012 Nikolay Sivov
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 "msxml6.h"
30#include "msxml6did.h"
31#include "ocidl.h"
32#include "initguid.h"
33#include "dispex.h"
34
35#include "wine/test.h"
36
37struct class_support
38{
39 const GUID *clsid;
40 const char *name;
41 const IID *iid;
42 BOOL supported;
43};
44
45static struct class_support class_support[] =
46{
47 { &CLSID_MXXMLWriter60, "MXXMLWriter60", &IID_IMXWriter },
48 { &CLSID_SAXAttributes60, "SAXAttributes60", &IID_IMXAttributes },
49 { NULL }
50};
51
52static void get_class_support_data(void)
53{
54 struct class_support *table = class_support;
55
56 while (table->clsid)
57 {
58 IUnknown *unk;
59 HRESULT hr;
60
61 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, table->iid, (void **)&unk);
62 if (hr == S_OK) IUnknown_Release(unk);
63
64 table->supported = hr == S_OK;
65 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
66
67 table++;
68 }
69}
70
71static BOOL is_class_supported(const CLSID *clsid)
72{
73 struct class_support *table = class_support;
74
75 while (table->clsid)
76 {
77 if (table->clsid == clsid) return table->supported;
78 table++;
79 }
80 return FALSE;
81}
82
83#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
84static void _expect_ref(IUnknown* obj, ULONG ref, int line)
85{
86 ULONG rc;
87 IUnknown_AddRef(obj);
88 rc = IUnknown_Release(obj);
89 ok_(__FILE__, line)(rc == ref, "expected refcount %ld, got %ld.\n", ref, rc);
90}
91
92#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
93static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
94{
95 IUnknown *iface = iface_ptr;
96 HRESULT hr, expected_hr;
97 IUnknown *unk;
98
99 expected_hr = supported ? S_OK : E_NOINTERFACE;
100
101 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
102 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
103 if (SUCCEEDED(hr))
104 IUnknown_Release(unk);
105}
106
107static LONG get_refcount(void *iface)
108{
109 IUnknown *unk = iface;
110 LONG ref;
111
112 ref = IUnknown_AddRef(unk);
113 IUnknown_Release(unk);
114 return ref-1;
115}
116
117static BSTR alloc_str_from_narrow(const char *str)
118{
119 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
120 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
121 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
122 return ret;
123}
124
125static BSTR alloced_bstrs[512];
126static int alloced_bstrs_count;
127
128static BSTR _bstr_(const char *str)
129{
130 assert(alloced_bstrs_count < ARRAY_SIZE(alloced_bstrs));
131 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
132 return alloced_bstrs[alloced_bstrs_count++];
133}
134
135static void free_bstrs(void)
136{
137 int i;
138 for (i = 0; i < alloced_bstrs_count; i++)
139 SysFreeString(alloced_bstrs[i]);
140 alloced_bstrs_count = 0;
141}
142
143static HRESULT WINAPI isaxattributes_QueryInterface(
144 ISAXAttributes* iface,
145 REFIID riid,
146 void **ppvObject)
147{
148 *ppvObject = NULL;
149
150 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
151 {
152 *ppvObject = iface;
153 }
154 else
155 {
156 return E_NOINTERFACE;
157 }
158
159 return S_OK;
160}
161
162static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
163{
164 return 2;
165}
166
167static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
168{
169 return 1;
170}
171
172static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
173{
174 *length = 3;
175 return S_OK;
176}
177
178static HRESULT WINAPI isaxattributes_getURI(
179 ISAXAttributes* iface,
180 int nIndex,
181 const WCHAR **pUrl,
182 int *pUriSize)
183{
184 ok(0, "unexpected call\n");
185 return E_NOTIMPL;
186}
187
188static HRESULT WINAPI isaxattributes_getLocalName(
189 ISAXAttributes* iface,
190 int nIndex,
191 const WCHAR **pLocalName,
192 int *pLocalNameLength)
193{
194 ok(0, "unexpected call\n");
195 return E_NOTIMPL;
196}
197
198static HRESULT WINAPI isaxattributes_getQName(
199 ISAXAttributes* iface,
200 int index,
201 const WCHAR **QName,
202 int *QNameLength)
203{
204 static const WCHAR attrqnamesW[][15] = {L"a:attr1junk",
205 L"attr2junk",
206 L"attr3"};
207 static const int attrqnamelen[] = {7, 5, 5};
208
209 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
210
211 if (index >= 0 && index <= 2) {
212 *QName = attrqnamesW[index];
213 *QNameLength = attrqnamelen[index];
214 } else {
215 *QName = NULL;
216 *QNameLength = 0;
217 }
218
219 return S_OK;
220}
221
222static HRESULT WINAPI isaxattributes_getName(
223 ISAXAttributes* iface,
224 int nIndex,
225 const WCHAR **pUri,
226 int * pUriLength,
227 const WCHAR ** pLocalName,
228 int * pLocalNameSize,
229 const WCHAR ** pQName,
230 int * pQNameLength)
231{
232 ok(0, "unexpected call\n");
233 return E_NOTIMPL;
234}
235
236static HRESULT WINAPI isaxattributes_getIndexFromName(
237 ISAXAttributes* iface,
238 const WCHAR * pUri,
239 int cUriLength,
240 const WCHAR * pLocalName,
241 int cocalNameLength,
242 int * index)
243{
244 ok(0, "unexpected call\n");
245 return E_NOTIMPL;
246}
247
248static HRESULT WINAPI isaxattributes_getIndexFromQName(
249 ISAXAttributes* iface,
250 const WCHAR * pQName,
251 int nQNameLength,
252 int * index)
253{
254 ok(0, "unexpected call\n");
255 return E_NOTIMPL;
256}
257
258static HRESULT WINAPI isaxattributes_getType(
259 ISAXAttributes* iface,
260 int nIndex,
261 const WCHAR ** pType,
262 int * pTypeLength)
263{
264 ok(0, "unexpected call\n");
265 return E_NOTIMPL;
266}
267
268static HRESULT WINAPI isaxattributes_getTypeFromName(
269 ISAXAttributes* iface,
270 const WCHAR * pUri,
271 int nUri,
272 const WCHAR * pLocalName,
273 int nLocalName,
274 const WCHAR ** pType,
275 int * nType)
276{
277 ok(0, "unexpected call\n");
278 return E_NOTIMPL;
279}
280
281static HRESULT WINAPI isaxattributes_getTypeFromQName(
282 ISAXAttributes* iface,
283 const WCHAR * pQName,
284 int nQName,
285 const WCHAR ** pType,
286 int * nType)
287{
288 ok(0, "unexpected call\n");
289 return E_NOTIMPL;
290}
291
292static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
293 const WCHAR **value, int *nValue)
294{
295 static const WCHAR attrvaluesW[][10] = {L"a1junk",
296 L"a2junk",
297 L"<&\">'"};
298 static const int attrvalueslen[] = {2, 2, 5};
299
300 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
301
302 if (index >= 0 && index <= 2) {
303 *value = attrvaluesW[index];
304 *nValue = attrvalueslen[index];
305 } else {
306 *value = NULL;
307 *nValue = 0;
308 }
309
310 return S_OK;
311}
312
313static HRESULT WINAPI isaxattributes_getValueFromName(
314 ISAXAttributes* iface,
315 const WCHAR * pUri,
316 int nUri,
317 const WCHAR * pLocalName,
318 int nLocalName,
319 const WCHAR ** pValue,
320 int * nValue)
321{
322 ok(0, "unexpected call\n");
323 return E_NOTIMPL;
324}
325
326static HRESULT WINAPI isaxattributes_getValueFromQName(
327 ISAXAttributes* iface,
328 const WCHAR * pQName,
329 int nQName,
330 const WCHAR ** pValue,
331 int * nValue)
332{
333 ok(0, "unexpected call\n");
334 return E_NOTIMPL;
335}
336
337static const ISAXAttributesVtbl SAXAttributesVtbl =
338{
339 isaxattributes_QueryInterface,
340 isaxattributes_AddRef,
341 isaxattributes_Release,
342 isaxattributes_getLength,
343 isaxattributes_getURI,
344 isaxattributes_getLocalName,
345 isaxattributes_getQName,
346 isaxattributes_getName,
347 isaxattributes_getIndexFromName,
348 isaxattributes_getIndexFromQName,
349 isaxattributes_getType,
350 isaxattributes_getTypeFromName,
351 isaxattributes_getTypeFromQName,
352 isaxattributes_getValue,
353 isaxattributes_getValueFromName,
354 isaxattributes_getValueFromQName
355};
356
357static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
358
359static void test_mxwriter_handlers(void)
360{
361 IMXWriter *writer;
362 HRESULT hr;
363 int i;
364
365 static const IID *riids[] =
366 {
367 &IID_ISAXContentHandler,
368 &IID_ISAXLexicalHandler,
369 &IID_ISAXDeclHandler,
370 &IID_ISAXDTDHandler,
371 &IID_ISAXErrorHandler,
372 &IID_IVBSAXDeclHandler,
373 &IID_IVBSAXLexicalHandler,
374 &IID_IVBSAXContentHandler,
375 &IID_IVBSAXDTDHandler,
376 &IID_IVBSAXErrorHandler
377 };
378
379 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
380 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
381
382 EXPECT_REF(writer, 1);
383
384 for (i = 0; i < ARRAY_SIZE(riids); i++)
385 {
386 IUnknown *handler;
387 IMXWriter *writer2;
388
389 /* handler from IMXWriter */
390 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
391 ok(hr == S_OK, "%s, unexpected hr %#lx.\n", wine_dbgstr_guid(riids[i]), hr);
392 EXPECT_REF(writer, 2);
393
394 /* IMXWriter from a handler */
395 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
396 ok(hr == S_OK, "%s, unexpected hr %#lx.\n", wine_dbgstr_guid(riids[i]), hr);
397 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
398 EXPECT_REF(writer, 3);
399 IMXWriter_Release(writer2);
400 IUnknown_Release(handler);
401 }
402
403 IMXWriter_Release(writer);
404}
405
406static void test_mxwriter_default_properties(void)
407{
408 IMXWriter *writer;
409 VARIANT_BOOL b;
410 BSTR encoding;
411 HRESULT hr;
412
413 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
414 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
415
416 b = VARIANT_FALSE;
417 hr = IMXWriter_get_byteOrderMark(writer, &b);
418 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
419 ok(b == VARIANT_TRUE, "Unexpected value %d.\n", b);
420
421 b = VARIANT_TRUE;
422 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
423 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
424 ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
425
426 b = VARIANT_TRUE;
427 hr = IMXWriter_get_indent(writer, &b);
428 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
429 ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
430
431 b = VARIANT_TRUE;
432 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
433 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
434 ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
435
436 b = VARIANT_TRUE;
437 hr = IMXWriter_get_standalone(writer, &b);
438 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
439 ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
440
441 hr = IMXWriter_get_encoding(writer, &encoding);
442 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
443 ok(!lstrcmpW(encoding, L"UTF-16"), "Unexpected value %s.\n", wine_dbgstr_w(encoding));
444 SysFreeString(encoding);
445
446 IMXWriter_Release(writer);
447}
448
449static void test_mxwriter_properties(void)
450{
451 ISAXContentHandler *content;
452 IMXWriter *writer;
453 VARIANT_BOOL b;
454 HRESULT hr;
455 BSTR str, str2;
456 VARIANT dest;
457
458 test_mxwriter_default_properties();
459
460 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
461 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
462
463 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
464 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
465
466 hr = IMXWriter_get_byteOrderMark(writer, NULL);
467 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
468
469 hr = IMXWriter_get_indent(writer, NULL);
470 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
471
472 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
473 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
474
475 hr = IMXWriter_get_standalone(writer, NULL);
476 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
477
478 /* set and check */
479 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
480 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
481
482 b = VARIANT_FALSE;
483 hr = IMXWriter_get_standalone(writer, &b);
484 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
485 ok(b == VARIANT_TRUE, "got %d\n", b);
486
487 hr = IMXWriter_get_encoding(writer, NULL);
488 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
489
490 str = (void*)0xdeadbeef;
491 hr = IMXWriter_get_encoding(writer, &str);
492 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
493 ok(!lstrcmpW(str, L"UTF-16"), "Unexpected string %s.\n", wine_dbgstr_w(str));
494
495 str2 = (void*)0xdeadbeef;
496 hr = IMXWriter_get_encoding(writer, &str2);
497 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
498 ok(str != str2, "expected newly allocated, got same %p\n", str);
499
500 SysFreeString(str2);
501 SysFreeString(str);
502
503 /* put empty string */
504 str = SysAllocString(L"");
505 hr = IMXWriter_put_encoding(writer, str);
506 todo_wine
507 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
508 SysFreeString(str);
509
510 str = (void*)0xdeadbeef;
511 hr = IMXWriter_get_encoding(writer, &str);
512 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
513 ok(!lstrcmpW(str, L"UTF-16"), "got %s\n", wine_dbgstr_w(str));
514 SysFreeString(str);
515
516 /* invalid encoding name */
517 str = SysAllocString(L"test");
518 hr = IMXWriter_put_encoding(writer, str);
519 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
520 SysFreeString(str);
521
522 /* test case sensitivity */
523 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
524 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
525 str = (void*)0xdeadbeef;
526 hr = IMXWriter_get_encoding(writer, &str);
527 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
528 ok(!lstrcmpW(str, L"utf-8"), "got %s\n", wine_dbgstr_w(str));
529 SysFreeString(str);
530
531 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
532 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
533 str = (void*)0xdeadbeef;
534 hr = IMXWriter_get_encoding(writer, &str);
535 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
536 ok(!lstrcmpW(str, L"uTf-16"), "got %s\n", wine_dbgstr_w(str));
537 SysFreeString(str);
538
539 /* how it affects document creation */
540 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
541 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
542
543 hr = ISAXContentHandler_startDocument(content);
544 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
545 hr = ISAXContentHandler_endDocument(content);
546 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
547
548 V_VT(&dest) = VT_EMPTY;
549 hr = IMXWriter_get_output(writer, &dest);
550 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
551 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
552 todo_wine
553 ok(!lstrcmpW(L"<?xml version=\"1.0\" standalone=\"yes\"?>\r\n",
554 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
555 VariantClear(&dest);
556 ISAXContentHandler_Release(content);
557
558 hr = IMXWriter_get_version(writer, NULL);
559 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
560 /* default version is 'surprisingly' 1.0 */
561 hr = IMXWriter_get_version(writer, &str);
562 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
563 ok(!lstrcmpW(str, L"1.0"), "got %s\n", wine_dbgstr_w(str));
564 SysFreeString(str);
565
566 /* store version string as is */
567 hr = IMXWriter_put_version(writer, NULL);
568 todo_wine
569 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
570
571 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
572 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
573
574 hr = IMXWriter_put_version(writer, _bstr_(""));
575 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
576 hr = IMXWriter_get_version(writer, &str);
577 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
578 todo_wine
579 ok(!lstrcmpW(str, L"1.0"), "got %s\n", wine_dbgstr_w(str));
580 SysFreeString(str);
581
582 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
583 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
584 hr = IMXWriter_get_version(writer, &str);
585 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
586 ok(!lstrcmpW(str, L"a.b"), "got %s\n", wine_dbgstr_w(str));
587 SysFreeString(str);
588
589 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
590 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
591 hr = IMXWriter_get_version(writer, &str);
592 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
593 ok(!lstrcmpW(str, L"2.0"), "got %s\n", wine_dbgstr_w(str));
594 SysFreeString(str);
595
596 IMXWriter_Release(writer);
597 free_bstrs();
598}
599
600static void test_mxwriter_flush(void)
601{
602 ISAXContentHandler *content;
603 IMXWriter *writer;
604 LARGE_INTEGER pos;
605 ULARGE_INTEGER pos2;
606 IStream *stream;
607 VARIANT dest;
608 HRESULT hr;
609 char *buff;
610 LONG ref;
611 int len;
612
613 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
614 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
615
616 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
617 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
618 EXPECT_REF(stream, 1);
619
620 /* detach when nothing was attached */
621 V_VT(&dest) = VT_EMPTY;
622 hr = IMXWriter_put_output(writer, dest);
623 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
624
625 /* attach stream */
626 V_VT(&dest) = VT_UNKNOWN;
627 V_UNKNOWN(&dest) = (IUnknown*)stream;
628 hr = IMXWriter_put_output(writer, dest);
629 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
630 todo_wine EXPECT_REF(stream, 3);
631
632 /* detach setting VT_EMPTY destination */
633 V_VT(&dest) = VT_EMPTY;
634 hr = IMXWriter_put_output(writer, dest);
635 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
636 EXPECT_REF(stream, 1);
637
638 V_VT(&dest) = VT_UNKNOWN;
639 V_UNKNOWN(&dest) = (IUnknown*)stream;
640 hr = IMXWriter_put_output(writer, dest);
641 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
642
643 /* flush() doesn't detach a stream */
644 hr = IMXWriter_flush(writer);
645 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
646 todo_wine EXPECT_REF(stream, 3);
647
648 pos.QuadPart = 0;
649 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
650 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
651 ok(pos2.QuadPart == 0, "expected stream beginning\n");
652
653 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
654 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
655
656 hr = ISAXContentHandler_startDocument(content);
657 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
658
659 pos.QuadPart = 0;
660 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
661 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
662 ok(pos2.QuadPart != 0, "expected stream beginning\n");
663
664 /* already started */
665 hr = ISAXContentHandler_startDocument(content);
666 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
667
668 hr = ISAXContentHandler_endDocument(content);
669 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
670
671 /* flushed on endDocument() */
672 pos.QuadPart = 0;
673 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
674 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
675 ok(pos2.QuadPart != 0, "expected stream position moved\n");
676
677 IStream_Release(stream);
678
679 /* auto-flush feature */
680 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
681 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
682 EXPECT_REF(stream, 1);
683
684 V_VT(&dest) = VT_UNKNOWN;
685 V_UNKNOWN(&dest) = (IUnknown*)stream;
686 hr = IMXWriter_put_output(writer, dest);
687 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
688
689 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
690 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
691
692 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
693 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
694
695 hr = ISAXContentHandler_startDocument(content);
696 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
697
698 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("a"), 1, NULL);
699 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
700
701 /* internal buffer is flushed automatically on certain threshold */
702 pos.QuadPart = 0;
703 pos2.QuadPart = 1;
704 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
705 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
706 ok(pos2.QuadPart == 0, "expected stream beginning\n");
707
708 len = 2048;
709 buff = malloc(len + 1);
710 memset(buff, 'A', len);
711 buff[len] = 0;
712 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
713 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
714
715 pos.QuadPart = 0;
716 pos2.QuadPart = 0;
717 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
718 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
719 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
720
721 hr = IMXWriter_get_output(writer, NULL);
722 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
723
724 ref = get_refcount(stream);
725 V_VT(&dest) = VT_EMPTY;
726 hr = IMXWriter_get_output(writer, &dest);
727 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
728 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
729 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
730 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
731 VariantClear(&dest);
732
733 hr = ISAXContentHandler_endDocument(content);
734 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
735
736 IStream_Release(stream);
737
738 /* test char count lower than threshold */
739 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
740 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
741 EXPECT_REF(stream, 1);
742
743 hr = ISAXContentHandler_startDocument(content);
744 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
745
746 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("a"), 1, NULL);
747 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
748
749 pos.QuadPart = 0;
750 pos2.QuadPart = 1;
751 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
752 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
753 ok(pos2.QuadPart == 0, "expected stream beginning\n");
754
755 memset(buff, 'A', len);
756 buff[len] = 0;
757 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
758 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
759
760 pos.QuadPart = 0;
761 pos2.QuadPart = 1;
762 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
763 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
764 ok(pos2.QuadPart == 0, "expected stream beginning\n");
765
766 hr = ISAXContentHandler_endDocument(content);
767 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
768
769 /* test auto-flush function when stream is not set */
770 V_VT(&dest) = VT_EMPTY;
771 hr = IMXWriter_put_output(writer, dest);
772 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
773
774 hr = ISAXContentHandler_startDocument(content);
775 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
776
777 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("a"), 1, NULL);
778 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
779
780 memset(buff, 'A', len);
781 buff[len] = 0;
782 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
783 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
784
785 V_VT(&dest) = VT_EMPTY;
786 hr = IMXWriter_get_output(writer, &dest);
787 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
788 len += strlen("<a>");
789 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
790 VariantClear(&dest);
791
792 free(buff);
793 ISAXContentHandler_Release(content);
794 IStream_Release(stream);
795 IMXWriter_Release(writer);
796 free_bstrs();
797}
798
799static void test_mxwriter_startenddocument(void)
800{
801 ISAXContentHandler *content;
802 IMXWriter *writer;
803 VARIANT dest;
804 HRESULT hr;
805
806 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
807 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
808
809 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
810 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
811
812 hr = ISAXContentHandler_startDocument(content);
813 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
814
815 hr = ISAXContentHandler_endDocument(content);
816 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
817
818 V_VT(&dest) = VT_EMPTY;
819 hr = IMXWriter_get_output(writer, &dest);
820 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
821 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
822 ok(!lstrcmpW(L"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
823 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
824 VariantClear(&dest);
825
826 /* now try another startDocument */
827 hr = ISAXContentHandler_startDocument(content);
828 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
829 /* and get duplicated prolog */
830 V_VT(&dest) = VT_EMPTY;
831 hr = IMXWriter_get_output(writer, &dest);
832 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
833 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
834 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
835 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
836 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
837 VariantClear(&dest);
838
839 ISAXContentHandler_Release(content);
840 IMXWriter_Release(writer);
841
842 /* now with omitted declaration */
843 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
844 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
845
846 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
847 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
848
849 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
850 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
851
852 hr = ISAXContentHandler_startDocument(content);
853 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
854
855 hr = ISAXContentHandler_endDocument(content);
856 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
857
858 V_VT(&dest) = VT_EMPTY;
859 hr = IMXWriter_get_output(writer, &dest);
860 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
861 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
862 ok(!lstrcmpW(L"", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
863 VariantClear(&dest);
864
865 ISAXContentHandler_Release(content);
866 IMXWriter_Release(writer);
867
868 free_bstrs();
869}
870
871enum startendtype
872{
873 StartElement = 0x001,
874 EndElement = 0x010,
875 StartEndElement = 0x011,
876 DisableEscaping = 0x100
877};
878
879struct writer_startendelement_t
880{
881 enum startendtype type;
882 const char *uri;
883 const char *local_name;
884 const char *qname;
885 const char *output;
886 HRESULT hr;
887 ISAXAttributes *attr;
888};
889
890static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\">";
891static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\"/>";
892
893static const struct writer_startendelement_t writer_startendelement[] =
894{
895 { StartElement, NULL, NULL, NULL, "<>", S_OK },
896 { StartElement, "uri", NULL, NULL, "<>", S_OK },
897 { StartElement, NULL, "local", NULL, "<>", S_OK },
898 { StartElement, NULL, NULL, "qname", "<qname>", S_OK },
899 { StartElement, "uri", "local", "qname", "<qname>", S_OK },
900 { StartElement, "uri", "local", NULL, "<>", S_OK },
901 { StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
902 { StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
903 { EndElement, NULL, NULL, NULL, "</>", S_OK },
904 { EndElement, "uri", NULL, NULL, "</>", S_OK },
905 { EndElement, NULL, "local", NULL, "</>", S_OK },
906 { EndElement, NULL, NULL, "qname", "</qname>", S_OK },
907 { EndElement, "uri", "local", "qname", "</qname>", S_OK },
908 { EndElement, "uri", "local", NULL, "</>", S_OK },
909 { EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
910 { EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
911 { StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
912 { StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
913 { StartEndElement, "", "", "", "</>", S_OK },
914 { StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
915};
916
917static void test_mxwriter_startendelement_batch(void)
918{
919 unsigned int i;
920
921 for (i = 0; i < ARRAY_SIZE(writer_startendelement); ++i)
922 {
923 const struct writer_startendelement_t *table = &writer_startendelement[i];
924 ISAXContentHandler *content;
925 IMXWriter *writer;
926 HRESULT hr;
927
928 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
929 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
930
931 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
933
934 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
935 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
936
937 hr = ISAXContentHandler_startDocument(content);
938 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
939
940 if (table->type & DisableEscaping)
941 {
942 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
943 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
944 }
945
946 if (table->type & StartElement)
947 {
948 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
949 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
950 table->qname ? strlen(table->qname) : 0, table->attr);
951 ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
952 }
953
954 if (table->type & EndElement)
955 {
956 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
957 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
958 table->qname ? strlen(table->qname) : 0);
959 ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
960 }
961
962 /* test output */
963 if (hr == S_OK)
964 {
965 VARIANT dest;
966
967 V_VT(&dest) = VT_EMPTY;
968 hr = IMXWriter_get_output(writer, &dest);
969 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
970 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
971 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
972 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
973 VariantClear(&dest);
974 }
975
976 ISAXContentHandler_Release(content);
977 IMXWriter_Release(writer);
978 }
979
980 free_bstrs();
981}
982
983/* point of these test is to start/end element with different names and name lengths */
984struct writer_startendelement2_t
985{
986 const char *qnamestart;
987 int qnamestart_len;
988 const char *qnameend;
989 int qnameend_len;
990 const char *output;
991 HRESULT hr;
992};
993
994static const struct writer_startendelement2_t writer_startendelement2[] =
995{
996 { "a", -1, "b", -1, "<a/>", E_INVALIDARG },
997 { "a", 1, "b", 1, "<a/>", S_OK },
998};
999
1000static void test_mxwriter_startendelement_batch2(void)
1001{
1002 unsigned int i;
1003
1004 for (i = 0; i < ARRAY_SIZE(writer_startendelement2); ++i)
1005 {
1006 const struct writer_startendelement2_t *table = &writer_startendelement2[i];
1007 ISAXContentHandler *content;
1008 IMXWriter *writer;
1009 HRESULT hr;
1010
1011 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1012 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1013
1014 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1015 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1016
1017 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1018 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1019
1020 hr = ISAXContentHandler_startDocument(content);
1021 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1022
1023 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
1024 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
1025 ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
1026
1027 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
1028 _bstr_(table->qnameend), table->qnameend_len);
1029 ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
1030
1031 /* test output */
1032 if (hr == S_OK)
1033 {
1034 VARIANT dest;
1035
1036 V_VT(&dest) = VT_EMPTY;
1037 hr = IMXWriter_get_output(writer, &dest);
1038 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1039 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1040 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
1041 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
1042 VariantClear(&dest);
1043 }
1044
1045 ISAXContentHandler_Release(content);
1046 IMXWriter_Release(writer);
1047
1048 free_bstrs();
1049 }
1050}
1051
1052static void test_mxwriter_startendelement(void)
1053{
1054 ISAXContentHandler *content;
1055 IVBSAXContentHandler *vb_content;
1056 IMXWriter *writer;
1057 VARIANT dest;
1058 BSTR bstr_null = NULL, bstr_empty, bstr_a, bstr_b, bstr_ab;
1059 HRESULT hr;
1060
1061 test_mxwriter_startendelement_batch();
1062 test_mxwriter_startendelement_batch2();
1063
1064 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1065 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1066
1067 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1068 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1069
1070 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content);
1071 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1072
1073 hr = IVBSAXContentHandler_startDocument(vb_content);
1074 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1075
1076 bstr_empty = SysAllocString(L"");
1077 bstr_a = SysAllocString(L"a");
1078 bstr_b = SysAllocString(L"b");
1079 bstr_ab = SysAllocString(L"a:b");
1080
1081 hr = IVBSAXContentHandler_startElement(vb_content, &bstr_null, &bstr_empty, &bstr_b, NULL);
1082 todo_wine
1083 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1084
1085 hr = IVBSAXContentHandler_startElement(vb_content, &bstr_empty, &bstr_b, &bstr_empty, NULL);
1086 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1087
1088 V_VT(&dest) = VT_EMPTY;
1089 hr = IMXWriter_get_output(writer, &dest);
1090 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1091 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1092 todo_wine
1093 ok(!lstrcmpW(L"<b><>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1094 VariantClear(&dest);
1095
1096 hr = IVBSAXContentHandler_startElement(vb_content, &bstr_empty, &bstr_empty, &bstr_b, NULL);
1097 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1098
1099 V_VT(&dest) = VT_EMPTY;
1100 hr = IMXWriter_get_output(writer, &dest);
1101 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1102 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1103 todo_wine
1104 ok(!lstrcmpW(L"<b><><b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1105 VariantClear(&dest);
1106
1107 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_null, &bstr_null, &bstr_b);
1108 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1109
1110 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_null, &bstr_a, &bstr_b);
1111 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1112
1113 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_a, &bstr_b, &bstr_null);
1114 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1115
1116 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_null, &bstr_b);
1117 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1118
1119 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_b, &bstr_null);
1120 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1121
1122 hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_empty, &bstr_b);
1123 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1124
1125 V_VT(&dest) = VT_EMPTY;
1126 hr = IMXWriter_get_output(writer, &dest);
1127 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1128 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1129 todo_wine
1130 ok(!lstrcmpW(L"<b><><b></b></b></></b></></b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1131 VariantClear(&dest);
1132
1133 SysFreeString(bstr_empty);
1134 SysFreeString(bstr_a);
1135 SysFreeString(bstr_b);
1136 SysFreeString(bstr_ab);
1137
1138 hr = IVBSAXContentHandler_endDocument(vb_content);
1139 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1140
1141 IVBSAXContentHandler_Release(vb_content);
1142 IMXWriter_Release(writer);
1143
1144 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1145 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1146
1147 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1148 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1149
1150 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1151 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1152
1153 hr = ISAXContentHandler_startDocument(content);
1154 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1155
1156 /* all string pointers should be not null */
1157 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
1158 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1159
1160 V_VT(&dest) = VT_EMPTY;
1161 hr = IMXWriter_get_output(writer, &dest);
1162 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1163 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1164 ok(!lstrcmpW(L"<>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1165 VariantClear(&dest);
1166
1167 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
1168 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1169
1170 V_VT(&dest) = VT_EMPTY;
1171 hr = IMXWriter_get_output(writer, &dest);
1172 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1173 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1174 ok(!lstrcmpW(L"<><b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1175 VariantClear(&dest);
1176
1177 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
1178 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1179
1180 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
1181 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1182
1183 /* only local name is an error too */
1184 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
1185 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1186
1187 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
1188 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1189
1190 V_VT(&dest) = VT_EMPTY;
1191 hr = IMXWriter_get_output(writer, &dest);
1192 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1193 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1194 ok(!lstrcmpW(L"<><b></a:b></a:b></></b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1195 VariantClear(&dest);
1196
1197 hr = ISAXContentHandler_endDocument(content);
1198 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1199
1200 V_VT(&dest) = VT_EMPTY;
1201 hr = IMXWriter_put_output(writer, dest);
1202 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1203
1204 V_VT(&dest) = VT_EMPTY;
1205 hr = IMXWriter_get_output(writer, &dest);
1206 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1207 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1208 ok(!lstrcmpW(L"", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1209 VariantClear(&dest);
1210
1211 hr = ISAXContentHandler_startDocument(content);
1212 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1213
1214 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
1215 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1216
1217 V_VT(&dest) = VT_EMPTY;
1218 hr = IMXWriter_get_output(writer, &dest);
1219 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1220 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1221 ok(!lstrcmpW(L"<abc>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1222 VariantClear(&dest);
1223
1224 hr = ISAXContentHandler_endDocument(content);
1225 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1226 IMXWriter_flush(writer);
1227
1228 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
1229 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1230 V_VT(&dest) = VT_EMPTY;
1231 hr = IMXWriter_get_output(writer, &dest);
1232 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1233 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1234 ok(!lstrcmpW(L"<abc></abd>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1235 VariantClear(&dest);
1236
1237 V_VT(&dest) = VT_EMPTY;
1238 hr = IMXWriter_put_output(writer, dest);
1239 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1240
1241 /* length -1 */
1242 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
1243 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1244
1245 ISAXContentHandler_Release(content);
1246 IMXWriter_Release(writer);
1247 free_bstrs();
1248}
1249
1250struct writer_characters_t
1251{
1252 const char *data;
1253 const char *output;
1254};
1255
1256static const struct writer_characters_t writer_characters[] =
1257{
1258 { "< > & \" \'", "< > & \" \'" },
1259};
1260
1261static void test_mxwriter_characters(void)
1262{
1263 static const WCHAR embedded_nullbytes[] = L"a\0b\0\0\0c";
1264 IVBSAXContentHandler *vb_content;
1265 ISAXContentHandler *content;
1266 IMXWriter *writer;
1267 VARIANT dest;
1268 BSTR str;
1269 HRESULT hr;
1270 int i = 0;
1271
1272 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1273 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1274
1275 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1276 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1277
1278 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content);
1279 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1280
1281 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1282 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1283
1284 hr = ISAXContentHandler_startDocument(content);
1285 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1286
1287 hr = ISAXContentHandler_characters(content, NULL, 0);
1288 todo_wine
1289 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1290
1291 hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 0);
1292 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1293
1294 str = _bstr_("VbChars");
1295 hr = IVBSAXContentHandler_characters(vb_content, &str);
1296 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1297
1298 hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 14);
1299 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1300
1301 V_VT(&dest) = VT_EMPTY;
1302 hr = IMXWriter_get_output(writer, &dest);
1303 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1304 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1305 ok(!lstrcmpW(L"VbCharsTESTCHARDATA .", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1306 VariantClear(&dest);
1307
1308 hr = ISAXContentHandler_endDocument(content);
1309 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1310
1311 ISAXContentHandler_Release(content);
1312 IVBSAXContentHandler_Release(vb_content);
1313 IMXWriter_Release(writer);
1314
1315 /* try empty characters data to see if element is closed */
1316 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1317 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1318
1319 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1320 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1321
1322 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1323 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1324
1325 hr = ISAXContentHandler_startDocument(content);
1326 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1327
1328 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
1329 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1330
1331 hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 0);
1332 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1333
1334 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
1335 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1336
1337 V_VT(&dest) = VT_EMPTY;
1338 hr = IMXWriter_get_output(writer, &dest);
1339 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1340 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1341 ok(!lstrcmpW(L"<a></a>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1342 VariantClear(&dest);
1343
1344 ISAXContentHandler_Release(content);
1345 IMXWriter_Release(writer);
1346
1347 /* test embedded null bytes */
1348 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1349 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1350
1351 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1352 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1353
1354 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1355 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1356
1357 hr = ISAXContentHandler_startDocument(content);
1358 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1359
1360 hr = ISAXContentHandler_characters(content, embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes));
1361 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1362
1363 V_VT(&dest) = VT_EMPTY;
1364 hr = IMXWriter_get_output(writer, &dest);
1365 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1366 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1367 ok(SysStringLen(V_BSTR(&dest)) == ARRAY_SIZE(embedded_nullbytes), "unexpected len %d\n", SysStringLen(V_BSTR(&dest)));
1368 ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)),
1369 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1370 VariantClear(&dest);
1371
1372 ISAXContentHandler_Release(content);
1373 IMXWriter_Release(writer);
1374
1375 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1376 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1377
1378 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content);
1379 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1380
1381 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1382 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1383
1384 hr = IVBSAXContentHandler_startDocument(vb_content);
1385 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1386
1387 str = SysAllocStringLen(embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes));
1388 hr = IVBSAXContentHandler_characters(vb_content, &str);
1389 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1390 SysFreeString(str);
1391
1392 V_VT(&dest) = VT_EMPTY;
1393 hr = IMXWriter_get_output(writer, &dest);
1394 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1395 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1396 todo_wine
1397 ok(SysStringLen(V_BSTR(&dest)) == 1, "Unexpected length %d.\n", SysStringLen(V_BSTR(&dest)));
1398 ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)),
1399 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1400 VariantClear(&dest);
1401
1402 IVBSAXContentHandler_Release(vb_content);
1403 IMXWriter_Release(writer);
1404
1405 /* batch tests */
1406 for (i = 0; i < ARRAY_SIZE(writer_characters); ++i)
1407 {
1408 const struct writer_characters_t *table = &writer_characters[i];
1409 ISAXContentHandler *content;
1410 IMXWriter *writer;
1411 VARIANT dest;
1412 HRESULT hr;
1413
1414 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1415 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1416
1417 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1418 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1419
1420 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1421 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1422
1423 hr = ISAXContentHandler_startDocument(content);
1424 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1425
1426 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
1427 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1428
1429 /* test output */
1430 if (hr == S_OK)
1431 {
1432 V_VT(&dest) = VT_EMPTY;
1433 hr = IMXWriter_get_output(writer, &dest);
1434 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1435 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1436 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
1437 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
1438 VariantClear(&dest);
1439 }
1440
1441 /* with disabled escaping */
1442 V_VT(&dest) = VT_EMPTY;
1443 hr = IMXWriter_put_output(writer, dest);
1444 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1445
1446 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
1447 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1448
1449 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
1450 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1451
1452 /* test output */
1453 if (hr == S_OK)
1454 {
1455 V_VT(&dest) = VT_EMPTY;
1456 hr = IMXWriter_get_output(writer, &dest);
1457 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1458 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1459 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
1460 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
1461 VariantClear(&dest);
1462 }
1463
1464 ISAXContentHandler_Release(content);
1465 IMXWriter_Release(writer);
1466 }
1467
1468 free_bstrs();
1469}
1470
1471static void test_mxwriter_domdoc(void)
1472{
1473 ISAXContentHandler *content;
1474 IXMLDOMDocument *domdoc;
1475 IMXWriter *writer;
1476 HRESULT hr;
1477 VARIANT dest;
1478 IXMLDOMElement *root = NULL;
1479 IXMLDOMNodeList *node_list = NULL;
1480 IXMLDOMNode *node = NULL;
1481 LONG list_length = 0;
1482 BSTR str;
1483
1484 /* Create writer and attach DOMDocument output */
1485 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
1486 ok(hr == S_OK, "Failed to create a writer, hr %#lx.\n", hr);
1487
1488 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1489 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1490
1491 hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&domdoc);
1492 ok(hr == S_OK, "Failed to create a document, hr %#lx.\n", hr);
1493
1494 V_VT(&dest) = VT_DISPATCH;
1495 V_DISPATCH(&dest) = (IDispatch *)domdoc;
1496
1497 hr = IMXWriter_put_output(writer, dest);
1498 todo_wine
1499 ok(hr == S_OK, "Failed to set writer output, hr %#lx.\n", hr);
1500 if (FAILED(hr))
1501 {
1502 IXMLDOMDocument_Release(domdoc);
1503 IMXWriter_Release(writer);
1504 return;
1505 }
1506
1507 /* Add root element to document. */
1508 hr = IXMLDOMDocument_createElement(domdoc, _bstr_("TestElement"), &root);
1509 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1510 hr = IXMLDOMDocument_appendChild(domdoc, (IXMLDOMNode *)root, NULL);
1511 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1512 IXMLDOMElement_Release(root);
1513
1514 hr = IXMLDOMDocument_get_documentElement(domdoc, &root);
1515 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1516 ok(root != NULL, "Unexpected document root.\n");
1517 IXMLDOMElement_Release(root);
1518
1519 /* startDocument clears root element and disables methods. */
1520 hr = ISAXContentHandler_startDocument(content);
1521 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1522
1523 hr = IXMLDOMDocument_get_documentElement(domdoc, &root);
1524 todo_wine
1525 ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
1526
1527 hr = IXMLDOMDocument_createElement(domdoc, _bstr_("TestElement"), &root);
1528 todo_wine
1529 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1530
1531 /* startElement allows document root node to be accessed. */
1532 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"BankAccount", 11, NULL);
1533 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1534
1535 hr = IXMLDOMDocument_get_documentElement(domdoc, &root);
1536 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1537 ok(root != NULL, "Unexpected document root.\n");
1538
1539 hr = IXMLDOMElement_get_nodeName(root, &str);
1540 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1541 todo_wine
1542 ok(!lstrcmpW(L"BankAccount", str), "Unexpected name %s.\n", wine_dbgstr_w(str));
1543 SysFreeString(str);
1544
1545 /* startElement immediately updates previous node. */
1546 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"Number", 6, NULL);
1547 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1548
1549 hr = IXMLDOMElement_get_childNodes(root, &node_list);
1550 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1551
1552 hr = IXMLDOMNodeList_get_length(node_list, &list_length);
1553 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1554 todo_wine
1555 ok(list_length == 1, "list length %ld, expected 1\n", list_length);
1556
1557 hr = IXMLDOMNodeList_get_item(node_list, 0, &node);
1558 todo_wine
1559 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1560
1561 hr = IXMLDOMNode_get_nodeName(node, &str);
1562todo_wine {
1563 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1564 ok(!lstrcmpW(L"Number", str), "got %s\n", wine_dbgstr_w(str));
1565}
1566 SysFreeString(str);
1567
1568 /* characters not immediately visible. */
1569 hr = ISAXContentHandler_characters(content, L"12345", 5);
1570 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1571
1572 hr = IXMLDOMNode_get_text(node, &str);
1573todo_wine {
1574 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1575 ok(!lstrcmpW(L"", str), "got %s\n", wine_dbgstr_w(str));
1576}
1577 SysFreeString(str);
1578
1579 /* characters visible after endElement. */
1580 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"Number", 6);
1581 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1582
1583 hr = IXMLDOMNode_get_text(node, &str);
1584todo_wine {
1585 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1586 ok(!lstrcmpW(L"12345", str), "got %s\n", wine_dbgstr_w(str));
1587}
1588 SysFreeString(str);
1589
1590 IXMLDOMNode_Release(node);
1591
1592 /* second startElement updates the existing node list. */
1593
1594 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"Name", 4, NULL);
1595 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1596
1597 hr = ISAXContentHandler_characters(content, L"Captain Ahab", 12);
1598 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1599
1600 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"Name", 4);
1601 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1602
1603 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"BankAccount", 11);
1604 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1605
1606 hr = IXMLDOMNodeList_get_length(node_list, &list_length);
1607todo_wine {
1608 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1609 ok(2 == list_length, "list length %ld, expected 2\n", list_length);
1610}
1611 hr = IXMLDOMNodeList_get_item(node_list, 1, &node);
1612 todo_wine
1613 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1614
1615 hr = IXMLDOMNode_get_nodeName(node, &str);
1616todo_wine {
1617 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1618 ok(!lstrcmpW(L"Name", str), "got %s\n", wine_dbgstr_w(str));
1619}
1620 SysFreeString(str);
1621
1622 hr = IXMLDOMNode_get_text(node, &str);
1623 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1624todo_wine {
1625 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1626 ok(!lstrcmpW(L"Captain Ahab", str), "got %s\n", wine_dbgstr_w(str));
1627}
1628 SysFreeString(str);
1629
1630 IXMLDOMNode_Release(node);
1631 IXMLDOMNodeList_Release(node_list);
1632 IXMLDOMElement_Release(root);
1633
1634 /* endDocument makes document modifiable again. */
1635
1636 hr = ISAXContentHandler_endDocument(content);
1637 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1638
1639 hr = IXMLDOMDocument_createElement(domdoc, _bstr_("TestElement"), &root);
1640 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1641 IXMLDOMElement_Release(root);
1642
1643 /* finally check doc output */
1644 hr = IXMLDOMDocument_get_xml(domdoc, &str);
1645todo_wine {
1646 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1647 ok(!lstrcmpW(
1648 L"<BankAccount>"
1649 "<Number>12345</Number>"
1650 "<Name>Captain Ahab</Name>"
1651 "</BankAccount>\r\n",
1652 str),
1653 "got %s\n", wine_dbgstr_w(str));
1654}
1655 SysFreeString(str);
1656
1657 IXMLDOMDocument_Release(domdoc);
1658 ISAXContentHandler_Release(content);
1659 IMXWriter_Release(writer);
1660
1661 free_bstrs();
1662}
1663
1664static const char *encoding_names[] = {
1665 "iso-8859-1",
1666 "iso-8859-2",
1667 "iso-8859-3",
1668 "iso-8859-4",
1669 "iso-8859-5",
1670 "iso-8859-7",
1671 "iso-8859-9",
1672 "iso-8859-13",
1673 "iso-8859-15",
1674 NULL
1675};
1676
1677static void test_mxwriter_encoding(void)
1678{
1679 ISAXContentHandler *content;
1680 IMXWriter *writer;
1681 IStream *stream;
1682 const char *enc;
1683 VARIANT dest;
1684 HRESULT hr;
1685 HGLOBAL g;
1686 char *ptr;
1687 BSTR s;
1688 int i;
1689
1690 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1691 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1692
1693 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1694 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1695
1696 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
1697 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1698
1699 hr = ISAXContentHandler_startDocument(content);
1700 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1701
1702 hr = ISAXContentHandler_endDocument(content);
1703 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1704
1705 /* The content is always re-encoded to UTF-16 when the output is
1706 * retrieved as a BSTR.
1707 */
1708 V_VT(&dest) = VT_EMPTY;
1709 hr = IMXWriter_get_output(writer, &dest);
1710 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1711 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
1712 todo_wine
1713 ok(!lstrcmpW(L"<?xml version=\"1.0\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
1714 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1715 VariantClear(&dest);
1716
1717 /* switch encoding when something is written already */
1718 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1719 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1720
1721 V_VT(&dest) = VT_UNKNOWN;
1722 V_UNKNOWN(&dest) = (IUnknown*)stream;
1723 hr = IMXWriter_put_output(writer, dest);
1724 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1725
1726 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
1727 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1728
1729 /* write empty element */
1730 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
1731 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1732
1733 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
1734 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1735
1736 /* switch */
1737 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
1738 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1739
1740 hr = IMXWriter_flush(writer);
1741 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1742
1743 hr = GetHGlobalFromStream(stream, &g);
1744 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1745
1746 ptr = GlobalLock(g);
1747 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
1748 GlobalUnlock(g);
1749
1750 /* so output is unaffected, encoding name is stored however */
1751 hr = IMXWriter_get_encoding(writer, &s);
1752 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1753 ok(!lstrcmpW(s, L"UTF-16"), "got %s\n", wine_dbgstr_w(s));
1754 SysFreeString(s);
1755
1756 IStream_Release(stream);
1757
1758 i = 0;
1759 enc = encoding_names[i];
1760 while (enc)
1761 {
1762 char expectedA[200];
1763
1764 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1765 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1766
1767 V_VT(&dest) = VT_UNKNOWN;
1768 V_UNKNOWN(&dest) = (IUnknown*)stream;
1769 hr = IMXWriter_put_output(writer, dest);
1770 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1771
1772 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
1773 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
1774 "%s: encoding not accepted\n", enc);
1775 if (hr != S_OK)
1776 {
1777 enc = encoding_names[++i];
1778 IStream_Release(stream);
1779 continue;
1780 }
1781
1782 hr = ISAXContentHandler_startDocument(content);
1783 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1784
1785 hr = ISAXContentHandler_endDocument(content);
1786 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1787
1788 hr = IMXWriter_flush(writer);
1789 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1790
1791 /* prepare expected string */
1792 *expectedA = 0;
1793 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
1794 strcat(expectedA, enc);
1795 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
1796
1797 hr = GetHGlobalFromStream(stream, &g);
1798 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1799
1800 ptr = GlobalLock(g);
1801 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
1802 GlobalUnlock(g);
1803
1804 V_VT(&dest) = VT_EMPTY;
1805 hr = IMXWriter_put_output(writer, dest);
1806 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1807
1808 IStream_Release(stream);
1809
1810 enc = encoding_names[++i];
1811 }
1812
1813 ISAXContentHandler_Release(content);
1814 IMXWriter_Release(writer);
1815
1816 free_bstrs();
1817}
1818
1819static void test_obj_dispex(IUnknown *obj)
1820{
1821 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
1822 IDispatchEx *dispex;
1823 IUnknown *unk;
1824 DWORD props;
1825 UINT ticnt;
1826 HRESULT hr;
1827 BSTR name;
1828 DISPID did;
1829
1830 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
1831 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1832 if (FAILED(hr)) return;
1833
1834 ticnt = 0;
1835 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
1836 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1837 ok(ticnt == 1, "ticnt=%u\n", ticnt);
1838
1839 name = SysAllocString(L"*");
1840 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
1841 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1842 SysFreeString(name);
1843
1844 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
1845 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1846
1847 props = 0;
1848 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
1849 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1850 ok(props == 0, "Unexpected value %ld.\n", props);
1851
1852 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
1853 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1854 if (SUCCEEDED(hr)) SysFreeString(name);
1855
1856 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
1857 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1858
1859 unk = (IUnknown*)0xdeadbeef;
1860 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
1861 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1862 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
1863
1864 name = SysAllocString(L"testprop");
1865 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
1866 ok(hr == DISP_E_UNKNOWNNAME, "Unexpected hr %#lx.\n", hr);
1867 SysFreeString(name);
1868
1869 IDispatchEx_Release(dispex);
1870}
1871
1872static void test_mxwriter_dispex(void)
1873{
1874 IDispatchEx *dispex;
1875 IMXWriter *writer;
1876 IUnknown *unk;
1877 HRESULT hr;
1878
1879 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1880 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1881
1882 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
1883 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1884 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
1885 test_obj_dispex(unk);
1886 IUnknown_Release(unk);
1887 IDispatchEx_Release(dispex);
1888 IMXWriter_Release(writer);
1889
1890 if (is_class_supported(&CLSID_MXXMLWriter60))
1891 {
1892 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
1893 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1894 test_obj_dispex(unk);
1895 IUnknown_Release(unk);
1896 }
1897}
1898
1899static void test_mxwriter_comment(void)
1900{
1901 IVBSAXLexicalHandler *vblexical;
1902 ISAXContentHandler *content;
1903 ISAXLexicalHandler *lexical;
1904 IMXWriter *writer;
1905 VARIANT dest;
1906 HRESULT hr;
1907
1908 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1909 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1910
1911 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1912 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1913
1914 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
1915 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1916
1917 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
1918 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1919
1920 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1921 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1922
1923 hr = ISAXContentHandler_startDocument(content);
1924 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1925
1926 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
1927 todo_wine
1928 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1929
1930 hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
1931 todo_wine
1932 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1933
1934 hr = ISAXLexicalHandler_comment(lexical, L"comment", 0);
1935 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1936
1937 V_VT(&dest) = VT_EMPTY;
1938 hr = IMXWriter_get_output(writer, &dest);
1939 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1940 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1941 todo_wine
1942 ok(!lstrcmpW(L"<!---->\r\n<!---->\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1943 VariantClear(&dest);
1944
1945 hr = ISAXLexicalHandler_comment(lexical, L"comment", 7);
1946 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1947
1948 V_VT(&dest) = VT_EMPTY;
1949 hr = IMXWriter_get_output(writer, &dest);
1950 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1951 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1952 todo_wine
1953 ok(!lstrcmpW(L"<!---->\r\n<!---->\r\n<!--comment-->\r\n", V_BSTR(&dest)), "Unexpected content %s.\n",
1954 wine_dbgstr_w(V_BSTR(&dest)));
1955 VariantClear(&dest);
1956
1957 ISAXContentHandler_Release(content);
1958 ISAXLexicalHandler_Release(lexical);
1959 IVBSAXLexicalHandler_Release(vblexical);
1960 IMXWriter_Release(writer);
1961 free_bstrs();
1962}
1963
1964static void test_mxwriter_cdata(void)
1965{
1966 IVBSAXLexicalHandler *vblexical;
1967 ISAXContentHandler *content;
1968 ISAXLexicalHandler *lexical;
1969 IMXWriter *writer;
1970 VARIANT dest;
1971 HRESULT hr;
1972
1973 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
1974 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1975
1976 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1977 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1978
1979 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
1980 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1981
1982 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
1983 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1984
1985 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
1986 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1987
1988 hr = ISAXContentHandler_startDocument(content);
1989 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1990
1991 hr = ISAXLexicalHandler_startCDATA(lexical);
1992 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1993
1994 V_VT(&dest) = VT_EMPTY;
1995 hr = IMXWriter_get_output(writer, &dest);
1996 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1997 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1998 ok(!lstrcmpW(L"<![CDATA[", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1999 VariantClear(&dest);
2000
2001 hr = IVBSAXLexicalHandler_startCDATA(vblexical);
2002 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2003
2004 /* all these are escaped for text nodes */
2005 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
2006 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2007
2008 hr = ISAXLexicalHandler_endCDATA(lexical);
2009 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2010
2011 V_VT(&dest) = VT_EMPTY;
2012 hr = IMXWriter_get_output(writer, &dest);
2013 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2014 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2015 ok(!lstrcmpW(L"<![CDATA[<![CDATA[< > & \"]]>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2016 VariantClear(&dest);
2017
2018 ISAXContentHandler_Release(content);
2019 ISAXLexicalHandler_Release(lexical);
2020 IVBSAXLexicalHandler_Release(vblexical);
2021 IMXWriter_Release(writer);
2022 free_bstrs();
2023}
2024
2025static void test_mxwriter_pi(void)
2026{
2027 ISAXContentHandler *content;
2028 IMXWriter *writer;
2029 VARIANT dest;
2030 HRESULT hr;
2031
2032 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
2033 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2034
2035 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2036 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2037
2038 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
2039 todo_wine
2040 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2041
2042 hr = ISAXContentHandler_processingInstruction(content, L"target", 0, NULL, 0);
2043 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2044
2045 hr = ISAXContentHandler_processingInstruction(content, L"target", 6, NULL, 0);
2046 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2047
2048 V_VT(&dest) = VT_EMPTY;
2049 hr = IMXWriter_get_output(writer, &dest);
2050 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2051 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2052 todo_wine
2053 ok(!lstrcmpW(L"<?\?>\r\n<?\?>\r\n<?target?>\r\n", V_BSTR(&dest)), "Unexpected content %s.\n", wine_dbgstr_w(V_BSTR(&dest)));
2054 VariantClear(&dest);
2055
2056 hr = ISAXContentHandler_processingInstruction(content, L"target", 4, L"data", 4);
2057 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2058
2059 V_VT(&dest) = VT_EMPTY;
2060 hr = IMXWriter_get_output(writer, &dest);
2061 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2062 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2063 todo_wine
2064 ok(!lstrcmpW(L"<?\?>\r\n<?\?>\r\n<?target?>\r\n<?targ data?>\r\n", V_BSTR(&dest)), "Unexpected content %s.\n", wine_dbgstr_w(V_BSTR(&dest)));
2065 VariantClear(&dest);
2066
2067 V_VT(&dest) = VT_EMPTY;
2068 hr = IMXWriter_put_output(writer, dest);
2069 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2070
2071 hr = ISAXContentHandler_processingInstruction(content, L"target", 6, L"data", 0);
2072 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2073
2074 V_VT(&dest) = VT_EMPTY;
2075 hr = IMXWriter_get_output(writer, &dest);
2076 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2077 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2078 ok(!lstrcmpW(L"<?target?>\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2079 VariantClear(&dest);
2080
2081
2082 ISAXContentHandler_Release(content);
2083 IMXWriter_Release(writer);
2084}
2085
2086static void test_mxwriter_ignorablespaces(void)
2087{
2088 ISAXContentHandler *content;
2089 IMXWriter *writer;
2090 VARIANT dest;
2091 HRESULT hr;
2092
2093 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
2094 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2095
2096 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2097 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2098
2099 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
2100 todo_wine
2101 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2102
2103 hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 0);
2104 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2105
2106 hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 4);
2107 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2108
2109 hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 1);
2110 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2111
2112 V_VT(&dest) = VT_EMPTY;
2113 hr = IMXWriter_get_output(writer, &dest);
2114 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2115 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2116 ok(!lstrcmpW(L"datad", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2117 VariantClear(&dest);
2118
2119 ISAXContentHandler_Release(content);
2120 IMXWriter_Release(writer);
2121}
2122
2123static void test_mxwriter_dtd(void)
2124{
2125 IVBSAXLexicalHandler *vblexical;
2126 ISAXContentHandler *content;
2127 ISAXLexicalHandler *lexical;
2128 IVBSAXDeclHandler *vbdecl;
2129 ISAXDeclHandler *decl;
2130 ISAXDTDHandler *dtd;
2131 IMXWriter *writer;
2132 VARIANT dest;
2133 HRESULT hr;
2134
2135 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
2136 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2137
2138 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2139 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2140
2141 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
2142 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2143
2144 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2145 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2146
2147 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
2148 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2149
2150 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
2151 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2152
2153 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2154 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2155
2156 hr = ISAXContentHandler_startDocument(content);
2157 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2158
2159 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
2160 todo_wine
2161 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2162
2163 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
2164 todo_wine
2165 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2166
2167 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, L"pub", 3, NULL, 0);
2168 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2169
2170 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, L"sys", 3);
2171 todo_wine
2172 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2173
2174 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, L"pub", 3, L"sys", 3);
2175 todo_wine
2176 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2177
2178 hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, NULL, 0, NULL, 0);
2179 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2180
2181 V_VT(&dest) = VT_EMPTY;
2182 hr = IMXWriter_get_output(writer, &dest);
2183 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2184 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2185 todo_wine
2186 ok(!lstrcmpW(L"<!DOCTYPE [\r\n<!DOCTYPE PUBLIC \"pub\"<!DOCTYPE SYSTEM \"sys\" [\r\n"
2187 "<!DOCTYPE PUBLIC \"pub\" \"sys\" [\r\n<!DOCTYPE name [\r\n", V_BSTR(&dest)), "Unexpected content %s.\n", wine_dbgstr_w(V_BSTR(&dest)));
2188 VariantClear(&dest);
2189
2190 /* system id is required if public is present */
2191 hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, L"pub", 3, NULL, 0);
2192 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2193
2194 hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, L"pub", 3, L"sys", 3);
2195 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2196
2197 V_VT(&dest) = VT_EMPTY;
2198 hr = IMXWriter_get_output(writer, &dest);
2199 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2200 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2201 todo_wine
2202 ok(!lstrcmpW(L"<!DOCTYPE [\r\n<!DOCTYPE PUBLIC \"pub\"<!DOCTYPE SYSTEM \"sys\" [\r\n"
2203 "<!DOCTYPE PUBLIC \"pub\" \"sys\" [\r\n<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n",
2204 V_BSTR(&dest)), "Unexpected content %s.\n", debugstr_w(V_BSTR(&dest)));
2205 VariantClear(&dest);
2206
2207 hr = ISAXLexicalHandler_endDTD(lexical);
2208 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2209
2210 hr = IVBSAXLexicalHandler_endDTD(vblexical);
2211 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2212
2213 V_VT(&dest) = VT_EMPTY;
2214 hr = IMXWriter_get_output(writer, &dest);
2215 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2216 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2217 todo_wine
2218 ok(!lstrcmpW(L"<!DOCTYPE [\r\n<!DOCTYPE PUBLIC \"pub\"<!DOCTYPE SYSTEM \"sys\" [\r\n"
2219 "<!DOCTYPE PUBLIC \"pub\" \"sys\" [\r\n<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n",
2220 V_BSTR(&dest)), "Unexpected content %s.\n", debugstr_w(V_BSTR(&dest)));
2221 VariantClear(&dest);
2222
2223 /* element declaration */
2224 V_VT(&dest) = VT_EMPTY;
2225 hr = IMXWriter_put_output(writer, dest);
2226 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2227
2228 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
2229 todo_wine
2230 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2231
2232 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
2233 todo_wine
2234 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2235
2236 hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, NULL, 0);
2237 todo_wine
2238 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2239
2240 hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, L"content", 7);
2241 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2242
2243 V_VT(&dest) = VT_EMPTY;
2244 hr = IMXWriter_get_output(writer, &dest);
2245 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2246 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2247 todo_wine
2248 ok(!lstrcmpW(L"<!ELEMENT >\r\n<!ELEMENT name >\r\n<!ELEMENT name content>\r\n",
2249 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2250 VariantClear(&dest);
2251
2252 V_VT(&dest) = VT_EMPTY;
2253 hr = IMXWriter_put_output(writer, dest);
2254 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2255
2256 hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, L"content", 0);
2257 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2258
2259 V_VT(&dest) = VT_EMPTY;
2260 hr = IMXWriter_get_output(writer, &dest);
2261 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2262 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2263 ok(!lstrcmpW(L"<!ELEMENT name >\r\n",
2264 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2265 VariantClear(&dest);
2266
2267 /* attribute declaration */
2268 V_VT(&dest) = VT_EMPTY;
2269 hr = IMXWriter_put_output(writer, dest);
2270 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2271
2272 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
2273 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
2274 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
2275 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2276
2277 V_VT(&dest) = VT_EMPTY;
2278 hr = IMXWriter_get_output(writer, &dest);
2279 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2280 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2281 todo_wine
2282 ok(!lstrcmpW(L"<!ATTLIST element attribute CDATA #REQUIRED>\r\n",
2283 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2284 VariantClear(&dest);
2285
2286 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
2287 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
2288 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
2289 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2290
2291 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
2292 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
2293 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
2294 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2295
2296 V_VT(&dest) = VT_EMPTY;
2297 hr = IMXWriter_get_output(writer, &dest);
2298 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2299 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2300 todo_wine
2301 ok(!lstrcmpW(L"<!ATTLIST element attribute CDATA #REQUIRED>\r\n"
2302 "<!ATTLIST element attribute2 CDATA #REQUIRED>\r\n<!ATTLIST element2 attribute3 CDATA #REQUIRED>\r\n",
2303 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2304 VariantClear(&dest);
2305
2306 /* internal entities */
2307 V_VT(&dest) = VT_EMPTY;
2308 hr = IMXWriter_put_output(writer, dest);
2309 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2310
2311 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
2312 todo_wine
2313 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2314
2315 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
2316 todo_wine
2317 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2318
2319 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
2320 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2321
2322 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
2323 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2324
2325 V_VT(&dest) = VT_EMPTY;
2326 hr = IMXWriter_get_output(writer, &dest);
2327 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2328 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2329 todo_wine
2330 ok(!lstrcmpW(L"<!ENTITY \"\">\r\n<!ENTITY name \"value\">\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2331 VariantClear(&dest);
2332
2333 /* external entities */
2334 V_VT(&dest) = VT_EMPTY;
2335 hr = IMXWriter_put_output(writer, dest);
2336 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2337
2338 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
2339 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2340
2341 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
2342 todo_wine
2343 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2344
2345 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), 0, NULL, 0, NULL, 0);
2346 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2347
2348 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0);
2349 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2350
2351 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
2352 _bstr_("sysid"), strlen("sysid"));
2353 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2354
2355 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid"));
2356 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2357
2358 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
2359 NULL, 0);
2360 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2361
2362 V_VT(&dest) = VT_EMPTY;
2363 hr = IMXWriter_get_output(writer, &dest);
2364 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2365 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2366 todo_wine
2367 ok(!lstrcmpW(L"<!ENTITY <!ENTITY <!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n"
2368 "<!ENTITY name SYSTEM \"sysid\">\r\n<!ENTITY name PUBLIC \"pubid\"",
2369 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2370
2371 VariantClear(&dest);
2372
2373 /* notation declaration */
2374 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDTDHandler, (void**)&dtd);
2375 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2376
2377 V_VT(&dest) = VT_EMPTY;
2378 hr = IMXWriter_put_output(writer, dest);
2379 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2380
2381 hr = ISAXDTDHandler_notationDecl(dtd, NULL, 0, NULL, 0, NULL, 0);
2382 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2383
2384 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, NULL, 0);
2385 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2386
2387 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), NULL, 0);
2388 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2389
2390 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), _bstr_("sysid"), strlen("sysid"));
2391 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2392
2393 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid"));
2394 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2395
2396 hr = IMXWriter_get_output(writer, &dest);
2397 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2398 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2399 todo_wine
2400 ok(!lstrcmpW(L"<!NOTATION <!NOTATION name<!NOTATION name PUBLIC \"pubid\">\r\n"
2401 "<!NOTATION name PUBLIC \"pubid\" \"sysid\">\r\n"
2402 "<!NOTATION name SYSTEM \"sysid\">\r\n",
2403 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2404
2405 VariantClear(&dest);
2406
2407 ISAXDTDHandler_Release(dtd);
2408
2409 ISAXContentHandler_Release(content);
2410 ISAXLexicalHandler_Release(lexical);
2411 IVBSAXLexicalHandler_Release(vblexical);
2412 IVBSAXDeclHandler_Release(vbdecl);
2413 ISAXDeclHandler_Release(decl);
2414 IMXWriter_Release(writer);
2415 free_bstrs();
2416}
2417
2418typedef struct
2419{
2420 const char *uri;
2421 const char *local;
2422 const char *qname;
2423 const char *type;
2424 const char *value;
2425 HRESULT hr;
2426} addattribute_test_t;
2427
2428static const addattribute_test_t addattribute_data[] =
2429{
2430 { NULL, NULL, "ns:qname", NULL, "value", S_OK },
2431 { NULL, "qname", "ns:qname", NULL, "value", S_OK },
2432 { "uri", "qname", "ns:qname", NULL, "value", S_OK },
2433 { "uri", "qname", "ns:qname", "type", "value", S_OK },
2434};
2435
2436static void test_mxattr_addAttribute(void)
2437{
2438 int i = 0;
2439
2440 for (i = 0; i < ARRAY_SIZE(addattribute_data); ++i)
2441 {
2442 const addattribute_test_t *table = &addattribute_data[i];
2443 ISAXAttributes *saxattr;
2444 IMXAttributes *mxattr;
2445 const WCHAR *value;
2446 int len, index;
2447 HRESULT hr;
2448
2449 hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
2450 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2451
2452 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
2453 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2454
2455 len = -1;
2456 hr = ISAXAttributes_getLength(saxattr, &len);
2457 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2458 ok(len == 0, "got %d\n", len);
2459
2460 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
2461 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2462
2463 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
2464 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2465
2466 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
2467 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2468
2469 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
2470 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2471
2472 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
2473 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2474
2475 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
2476 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2477
2478 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
2479 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2480
2481 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
2482 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2483
2484 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
2485 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
2486 ok(hr == table->hr, "%d: got %#lx, expected %#lx.\n", i, hr, table->hr);
2487
2488 if (hr == S_OK)
2489 {
2490 /* Crashes. */
2491 if (0)
2492 {
2493 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
2494 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2495
2496 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
2497 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2498
2499 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
2500 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2501
2502 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
2503 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2504
2505 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
2506 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2507
2508 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
2509 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2510 }
2511
2512 len = -1;
2513 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
2514 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2515 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
2516 table->value);
2517 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
2518
2519 len = -1;
2520 value = (void*)0xdeadbeef;
2521 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
2522 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2523
2524 if (table->type)
2525 {
2526 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
2527 table->type);
2528 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
2529 }
2530 else
2531 {
2532 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
2533 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
2534 }
2535
2536 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
2537 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2538
2539 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
2540 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2541
2542 index = -1;
2543 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
2544 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2545 ok(index == -1, "%d: got wrong index %d\n", i, index);
2546
2547 index = -1;
2548 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
2549 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2550 ok(index == -1, "%d: got wrong index %d\n", i, index);
2551
2552 index = -1;
2553 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
2554 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2555 ok(index == 0, "%d: got wrong index %d\n", i, index);
2556
2557 index = -1;
2558 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
2559 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2560 ok(index == -1, "%d: got wrong index %d\n", i, index);
2561
2562 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
2563 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2564
2565 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
2566 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2567
2568 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
2569 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2570
2571 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
2572 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2573
2574 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
2575 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2576
2577 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
2578 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2579
2580 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
2581 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2582 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
2583 table->value);
2584 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
2585
2586 if (table->uri) {
2587 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
2588 _bstr_(table->local), strlen(table->local), &value, &len);
2589 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2590 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
2591 table->value);
2592 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
2593 }
2594 }
2595
2596 len = -1;
2597 hr = ISAXAttributes_getLength(saxattr, &len);
2598 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2599 if (table->hr == S_OK)
2600 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
2601 else
2602 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
2603
2604 ISAXAttributes_Release(saxattr);
2605 IMXAttributes_Release(mxattr);
2606 }
2607
2608 free_bstrs();
2609}
2610
2611static void test_mxattr_clear(void)
2612{
2613 ISAXAttributes *saxattr;
2614 IMXAttributes *mxattr;
2615 const WCHAR *ptr;
2616 HRESULT hr;
2617 int len;
2618
2619 hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
2620 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2621
2622 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
2623 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2624
2625 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
2626 todo_wine
2627 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2628
2629 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
2630 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2631
2632 hr = IMXAttributes_clear(mxattr);
2633 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2634
2635 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
2636 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
2637 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2638
2639 len = -1;
2640 hr = ISAXAttributes_getLength(saxattr, &len);
2641 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2642 ok(len == 1, "got %d\n", len);
2643
2644 len = -1;
2645 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
2646 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2647 ok(len == -1, "got %d\n", len);
2648
2649 ptr = (void*)0xdeadbeef;
2650 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
2651 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
2652 todo_wine
2653 ok(!ptr, "Unexpected pointer %p.\n", ptr);
2654
2655 len = 0;
2656 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
2657 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2658 ok(len == 5, "got %d\n", len);
2659 ok(!lstrcmpW(ptr, L"qname"), "got %s\n", wine_dbgstr_w(ptr));
2660
2661 hr = IMXAttributes_clear(mxattr);
2662 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2663
2664 len = -1;
2665 hr = ISAXAttributes_getLength(saxattr, &len);
2666 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2667 ok(len == 0, "got %d\n", len);
2668
2669 len = -1;
2670 ptr = (void*)0xdeadbeef;
2671 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
2672 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2673 todo_wine
2674 ok(!len, "Unexpected length %d.\n", len);
2675 todo_wine
2676 ok(!ptr, "Unexpected pointer %p.\n", ptr);
2677
2678 IMXAttributes_Release(mxattr);
2679 ISAXAttributes_Release(saxattr);
2680 free_bstrs();
2681}
2682
2683static void test_mxattr_dispex(void)
2684{
2685 IMXAttributes *mxattr;
2686 IDispatchEx *dispex;
2687 IUnknown *unk;
2688 HRESULT hr;
2689
2690 hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
2691 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2692
2693 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
2694 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2695 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
2696 test_obj_dispex(unk);
2697 IUnknown_Release(unk);
2698 IDispatchEx_Release(dispex);
2699
2700 IMXAttributes_Release(mxattr);
2701}
2702
2703static void test_mxattr_qi(void)
2704{
2705 IMXAttributes *mxattr;
2706 HRESULT hr;
2707
2708 hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
2709 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2710
2711 check_interface(mxattr, &IID_IMXAttributes, TRUE);
2712 check_interface(mxattr, &IID_ISAXAttributes, TRUE);
2713 check_interface(mxattr, &IID_IVBSAXAttributes, TRUE);
2714 check_interface(mxattr, &IID_IDispatch, TRUE);
2715 check_interface(mxattr, &IID_IDispatchEx, TRUE);
2716
2717 IMXAttributes_Release(mxattr);
2718}
2719
2720static void test_mxattr_localname(void)
2721{
2722 ISAXAttributes *saxattr;
2723 IMXAttributes *mxattr;
2724 HRESULT hr;
2725 int index;
2726
2727 hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
2728 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2729
2730 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
2731 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2732
2733 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
2734 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2735
2736 /* add some ambiguous attribute names */
2737 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
2738 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
2739 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2740 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
2741 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
2742 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2743
2744 index = -1;
2745 hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname", 9, &index);
2746 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2747 ok(!index, "Got index %d.\n", index);
2748
2749 index = -1;
2750 hr = ISAXAttributes_getIndexFromName(saxattr, L"uri1", 4, L"localname", 9, &index);
2751 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2752 ok(index == -1, "Got index %d.\n", index);
2753
2754 index = -1;
2755 hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname1", 10, &index);
2756 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2757 ok(index == -1, "Got index %d.\n", index);
2758
2759 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
2760 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2761
2762 hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname1", 10, NULL);
2763 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2764
2765 hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, NULL, 0, &index);
2766 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2767
2768 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, L"localname1", 10, &index);
2769 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2770
2771 ISAXAttributes_Release(saxattr);
2772 IMXAttributes_Release(mxattr);
2773 free_bstrs();
2774}
2775
2776static void test_mxwriter_indent(void)
2777{
2778 ISAXContentHandler *content;
2779 IMXWriter *writer;
2780 VARIANT dest;
2781 HRESULT hr;
2782
2783 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
2784 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2785
2786 hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
2787 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2788
2789 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2790 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2791
2792 hr = ISAXContentHandler_startDocument(content);
2793 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2794
2795 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("a"), 1, NULL);
2796 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2797
2798 hr = ISAXContentHandler_characters(content, _bstr_(""), 0);
2799 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2800
2801 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("b"), 1, NULL);
2802 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2803
2804 hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, _bstr_("c"), 1, NULL);
2805 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2806
2807 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, _bstr_("c"), 1);
2808 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2809
2810 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, _bstr_("b"), 1);
2811 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2812
2813 hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, _bstr_("a"), 1);
2814 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2815
2816 hr = ISAXContentHandler_endDocument(content);
2817 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2818
2819 V_VT(&dest) = VT_EMPTY;
2820 hr = IMXWriter_get_output(writer, &dest);
2821 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2822 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2823 ok(!lstrcmpW(L"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>", V_BSTR(&dest)),
2824 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2825 VariantClear(&dest);
2826
2827 ISAXContentHandler_Release(content);
2828 IMXWriter_Release(writer);
2829
2830 free_bstrs();
2831}
2832
2833START_TEST(saxreader)
2834{
2835 HRESULT hr;
2836
2837 hr = CoInitialize(NULL);
2838 ok(hr == S_OK, "Failed to initialize COM, hr %#lx.\n", hr);
2839
2840 get_class_support_data();
2841
2842 if (is_class_supported(&CLSID_MXXMLWriter60))
2843 {
2844 test_mxwriter_handlers();
2845 test_mxwriter_startenddocument();
2846 test_mxwriter_startendelement();
2847 test_mxwriter_characters();
2848 test_mxwriter_comment();
2849 test_mxwriter_cdata();
2850 test_mxwriter_pi();
2851 test_mxwriter_ignorablespaces();
2852 test_mxwriter_dtd();
2853 test_mxwriter_properties();
2854 test_mxwriter_flush();
2855 test_mxwriter_domdoc();
2856 test_mxwriter_encoding();
2857 test_mxwriter_dispex();
2858 test_mxwriter_indent();
2859 }
2860
2861 if (is_class_supported(&CLSID_SAXAttributes60))
2862 {
2863 test_mxattr_qi();
2864 test_mxattr_addAttribute();
2865 test_mxattr_clear();
2866 test_mxattr_localname();
2867 test_mxattr_dispex();
2868 }
2869
2870 CoUninitialize();
2871}