makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / webservices / tests / writer.c
blob1d76918901484c136b2156df99d5224a7373a96a
1 /*
2 * Copyright 2015 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include <math.h>
21 #include <float.h>
22 #include "windows.h"
23 #include "rpc.h"
24 #include "webservices.h"
25 #include "wine/test.h"
27 static HRESULT set_output( WS_XML_WRITER *writer )
29 WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
30 WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
31 return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
34 static void test_WsCreateWriter(void)
36 HRESULT hr;
37 WS_XML_WRITER *writer;
38 WS_XML_WRITER_PROPERTY prop;
39 ULONG size, max_depth, max_attrs, indent, trim_size, max_size, max_ns;
40 BOOL allow_fragment, write_decl, in_attr;
41 WS_CHARSET charset;
42 WS_BUFFERS buffers;
43 WS_BYTES bytes;
45 hr = WsCreateWriter( NULL, 0, NULL, NULL );
46 ok( hr == E_INVALIDARG, "got %08x\n", hr );
48 writer = NULL;
49 hr = WsCreateWriter( NULL, 0, &writer, NULL );
50 ok( hr == S_OK, "got %08x\n", hr );
51 ok( writer != NULL, "writer not set\n" );
53 /* can't retrieve properties before output is set */
54 max_depth = 0xdeadbeef;
55 size = sizeof(max_depth);
56 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
57 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
58 ok( max_depth == 0xdeadbeef, "max_depth set\n" );
60 hr = set_output( writer );
61 ok( hr == S_OK, "got %08x\n", hr );
63 /* check some defaults */
64 max_depth = 0xdeadbeef;
65 size = sizeof(max_depth);
66 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
67 ok( hr == S_OK, "got %08x\n", hr );
68 ok( max_depth == 32, "got %u\n", max_depth );
70 allow_fragment = TRUE;
71 size = sizeof(allow_fragment);
72 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT, &allow_fragment, size, NULL );
73 ok( hr == S_OK, "got %08x\n", hr );
74 ok( !allow_fragment, "got %d\n", allow_fragment );
76 max_attrs = 0xdeadbeef;
77 size = sizeof(max_attrs);
78 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, size, NULL );
79 ok( hr == S_OK, "got %08x\n", hr );
80 ok( max_attrs == 128, "got %u\n", max_attrs );
82 write_decl = TRUE;
83 size = sizeof(write_decl);
84 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_WRITE_DECLARATION, &write_decl, size, NULL );
85 ok( hr == S_OK, "got %08x\n", hr );
86 ok( !write_decl, "got %d\n", write_decl );
88 indent = 0xdeadbeef;
89 size = sizeof(indent);
90 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INDENT, &indent, size, NULL );
91 ok( hr == S_OK, "got %08x\n", hr );
92 ok( !indent, "got %u\n", indent );
94 trim_size = 0xdeadbeef;
95 size = sizeof(trim_size);
96 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, size, NULL );
97 ok( hr == S_OK, "got %08x\n", hr );
98 ok( trim_size == 4096, "got %u\n", trim_size );
100 charset = 0xdeadbeef;
101 size = sizeof(charset);
102 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_CHARSET, &charset, size, NULL );
103 ok( hr == S_OK, "got %08x\n", hr );
104 ok( charset == WS_CHARSET_UTF8, "got %u\n", charset );
106 buffers.bufferCount = 0xdeadbeef;
107 buffers.buffers = (WS_BYTES *)0xdeadbeef;
108 size = sizeof(buffers);
109 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFERS, &buffers, size, NULL );
110 ok( hr == S_OK, "got %08x\n", hr );
111 ok( !buffers.bufferCount, "got %u\n", buffers.bufferCount );
112 ok( !buffers.buffers, "got %p\n", buffers.buffers );
114 max_size = 0xdeadbeef;
115 size = sizeof(max_size);
116 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, size, NULL );
117 ok( hr == S_OK, "got %08x\n", hr );
118 ok( max_size == 65536, "got %u\n", max_size );
120 bytes.length = 0xdeadbeef;
121 bytes.bytes = (BYTE *)0xdeadbeef;
122 size = sizeof(bytes);
123 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
124 ok( hr == S_OK, "got %08x\n", hr );
125 ok( !bytes.length, "got %u\n", bytes.length );
126 ok( bytes.bytes != NULL, "got %p\n", bytes.bytes );
128 max_size = 0xdeadbeef;
129 size = sizeof(max_size);
130 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, size, NULL );
131 ok( hr == S_OK, "got %08x\n", hr );
132 ok( max_size == 65536, "got %u\n", max_size );
134 bytes.length = 0xdeadbeef;
135 bytes.bytes = (BYTE *)0xdeadbeef;
136 size = sizeof(bytes);
137 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_INITIAL_BUFFER, &bytes, size, NULL );
138 ok( hr == S_OK, "got %08x\n", hr );
139 ok( !bytes.length, "got %u\n", bytes.length );
140 ok( !bytes.bytes, "got %p\n", bytes.bytes );
142 max_ns = 0xdeadbeef;
143 size = sizeof(max_ns);
144 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, size, NULL );
145 ok( hr == S_OK, "got %08x\n", hr );
146 ok( max_ns == 32, "got %u\n", max_ns );
147 WsFreeWriter( writer );
149 /* change a property */
150 max_depth = 16;
151 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
152 prop.value = &max_depth;
153 prop.valueSize = sizeof(max_depth);
154 hr = WsCreateWriter( &prop, 1, &writer, NULL );
155 ok( hr == S_OK, "got %08x\n", hr );
157 hr = set_output( writer );
158 ok( hr == S_OK, "got %08x\n", hr );
160 max_depth = 0xdeadbeef;
161 size = sizeof(max_depth);
162 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
163 ok( hr == S_OK, "got %08x\n", hr );
164 ok( max_depth == 16, "got %u\n", max_depth );
165 WsFreeWriter( writer );
167 /* show that some properties are read-only */
168 in_attr = TRUE;
169 prop.id = WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE;
170 prop.value = &in_attr;
171 prop.valueSize = sizeof(in_attr);
172 hr = WsCreateWriter( &prop, 1, &writer, NULL );
173 ok( hr == E_INVALIDARG, "got %08x\n", hr );
175 size = 1;
176 prop.id = WS_XML_WRITER_PROPERTY_BYTES_WRITTEN;
177 prop.value = &size;
178 prop.valueSize = sizeof(size);
179 hr = WsCreateWriter( &prop, 1, &writer, NULL );
180 ok( hr == E_INVALIDARG, "got %08x\n", hr );
182 size = 1;
183 prop.id = WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE;
184 prop.value = &size;
185 prop.valueSize = sizeof(size);
186 hr = WsCreateWriter( &prop, 1, &writer, NULL );
187 ok( hr == E_INVALIDARG, "got %08x\n", hr );
190 static void test_WsCreateXmlBuffer(void)
192 HRESULT hr;
193 WS_HEAP *heap;
194 WS_XML_WRITER *writer;
195 WS_XML_BUFFER *buffer;
196 WS_BYTES bytes;
197 ULONG size;
199 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
200 ok( hr == E_INVALIDARG, "got %08x\n", hr );
202 hr = WsCreateXmlBuffer( NULL, NULL, 0, &buffer, NULL );
203 ok( hr == E_INVALIDARG, "got %08x\n", hr );
205 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
206 ok( hr == S_OK, "got %08x\n", hr );
208 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
209 ok( hr == E_INVALIDARG, "got %08x\n", hr );
211 buffer = NULL;
212 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
213 ok( hr == S_OK, "got %08x\n", hr );
214 ok( buffer != NULL, "buffer not set\n" );
216 hr = WsCreateWriter( NULL, 0, &writer, NULL );
217 ok( hr == S_OK, "got %08x\n", hr );
219 size = sizeof(bytes);
220 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
221 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
223 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
224 ok( hr == S_OK, "got %08x\n", hr );
226 size = sizeof(bytes);
227 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
228 todo_wine ok( hr == E_INVALIDARG, "got %08x\n", hr );
230 WsFreeWriter( writer );
231 WsFreeHeap( heap );
234 static void test_WsSetOutput(void)
236 HRESULT hr;
237 WS_XML_WRITER *writer;
238 WS_XML_WRITER_PROPERTY prop;
239 WS_XML_WRITER_TEXT_ENCODING encoding;
240 WS_XML_WRITER_BUFFER_OUTPUT output;
241 ULONG size, max_depth;
243 hr = WsCreateWriter( NULL, 0, &writer, NULL );
244 ok( hr == S_OK, "got %08x\n", hr );
246 hr = WsSetOutput( NULL, NULL, NULL, NULL, 0, NULL );
247 ok( hr == E_INVALIDARG, "got %08x\n", hr );
249 encoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_TEXT;
250 encoding.charSet = WS_CHARSET_UTF8;
252 output.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
254 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
255 ok( hr == S_OK, "got %08x\n", hr );
257 /* multiple calls are allowed */
258 hr = WsSetOutput( writer, &encoding.encoding, &output.output, NULL, 0, NULL );
259 ok( hr == S_OK, "got %08x\n", hr );
261 /* writer properties can be set with WsSetOutput */
262 max_depth = 16;
263 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
264 prop.value = &max_depth;
265 prop.valueSize = sizeof(max_depth);
266 hr = WsSetOutput( writer, &encoding.encoding, &output.output, &prop, 1, NULL );
267 ok( hr == S_OK, "got %08x\n", hr );
269 max_depth = 0xdeadbeef;
270 size = sizeof(max_depth);
271 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
272 ok( hr == S_OK, "got %08x\n", hr );
273 ok( max_depth == 16, "got %u\n", max_depth );
274 WsFreeWriter( writer );
277 static void test_WsSetOutputToBuffer(void)
279 HRESULT hr;
280 WS_HEAP *heap;
281 WS_XML_BUFFER *buffer;
282 WS_XML_WRITER *writer;
283 WS_XML_WRITER_PROPERTY prop;
284 ULONG size, max_depth;
286 hr = WsSetOutputToBuffer( NULL, NULL, NULL, 0, NULL );
287 ok( hr == E_INVALIDARG, "got %08x\n", hr );
289 hr = WsCreateWriter( NULL, 0, &writer, NULL );
290 ok( hr == S_OK, "got %08x\n", hr );
292 hr = WsSetOutputToBuffer( writer, NULL, NULL, 0, NULL );
293 ok( hr == E_INVALIDARG, "got %08x\n", hr );
295 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
296 ok( hr == S_OK, "got %08x\n", hr );
298 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
299 ok( hr == S_OK, "got %08x\n", hr );
301 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
302 ok( hr == S_OK, "got %08x\n", hr );
304 /* multiple calls are allowed */
305 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
306 ok( hr == S_OK, "got %08x\n", hr );
308 /* writer properties can be set with WsSetOutputToBuffer */
309 max_depth = 16;
310 prop.id = WS_XML_WRITER_PROPERTY_MAX_DEPTH;
311 prop.value = &max_depth;
312 prop.valueSize = sizeof(max_depth);
313 hr = WsSetOutputToBuffer( writer, buffer, &prop, 1, NULL );
314 ok( hr == S_OK, "got %08x\n", hr );
316 max_depth = 0xdeadbeef;
317 size = sizeof(max_depth);
318 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, size, NULL );
319 ok( hr == S_OK, "got %08x\n", hr );
320 ok( max_depth == 16, "got %u\n", max_depth );
322 WsFreeWriter( writer );
323 WsFreeHeap( heap );
326 static char strbuf[512];
327 static const char *debugstr_bytes( const BYTE *bytes, ULONG len )
329 const BYTE *src = bytes;
330 char *dst = strbuf;
332 while (len)
334 BYTE c = *src++;
335 if (dst - strbuf > sizeof(strbuf) - 7) break;
336 switch (c)
338 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
339 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
340 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
341 default:
342 if (c >= ' ' && c < 127) *dst++ = c;
343 else
345 sprintf( dst, "\\%02x", c );
346 dst += 3;
349 len--;
351 if (len)
353 *dst++ = '.';
354 *dst++ = '.';
355 *dst++ = '.';
357 *dst = 0;
358 return strbuf;
361 static void check_output( WS_XML_WRITER *writer, const char *expected, unsigned int line )
363 WS_BYTES bytes;
364 ULONG size = sizeof(bytes);
365 int len = strlen( expected );
366 HRESULT hr;
368 memset( &bytes, 0, sizeof(bytes) );
369 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
370 ok( hr == S_OK, "%u: got %08x\n", line, hr );
371 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
372 if (bytes.length != len) return;
373 ok( !memcmp( bytes.bytes, expected, len ),
374 "%u: got %s expected %s\n", line, debugstr_bytes(bytes.bytes, bytes.length), expected );
377 static void test_WsWriteStartElement(void)
379 HRESULT hr;
380 WS_XML_WRITER *writer;
381 WS_XML_STRING prefix = {1, (BYTE *)"p"}, ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
382 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"}, empty = {0, NULL};
384 hr = WsCreateWriter( NULL, 0, &writer, NULL );
385 ok( hr == S_OK, "got %08x\n", hr );
387 hr = set_output( writer );
388 ok( hr == S_OK, "got %08x\n", hr );
390 hr = WsWriteStartElement( NULL, &prefix, &localname, &ns, NULL );
391 ok( hr == E_INVALIDARG, "got %08x\n", hr );
393 /* first call to WsWriteStartElement doesn't output anything */
394 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
395 ok( hr == S_OK, "got %08x\n", hr );
396 check_output( writer, "", __LINE__ );
398 /* two ways to close an element */
399 hr = WsWriteEndStartElement( writer, NULL );
400 ok( hr == S_OK, "got %08x\n", hr );
401 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
403 hr = WsWriteEndElement( writer, NULL );
404 ok( hr == S_OK, "got %08x\n", hr );
405 check_output( writer, "<p:a xmlns:p=\"ns\"></p:a>", __LINE__ );
407 hr = set_output( writer );
408 ok( hr == S_OK, "got %08x\n", hr );
410 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
411 ok( hr == S_OK, "got %08x\n", hr );
413 hr = WsWriteEndElement( writer, NULL );
414 ok( hr == S_OK, "got %08x\n", hr );
415 check_output( writer, "<p:a xmlns:p=\"ns\"/>", __LINE__ );
417 /* nested elements */
418 hr = set_output( writer );
419 ok( hr == S_OK, "got %08x\n", hr );
421 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
422 ok( hr == S_OK, "got %08x\n", hr );
423 check_output( writer, "", __LINE__ );
425 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
426 ok( hr == S_OK, "got %08x\n", hr );
427 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
429 hr = WsWriteEndElement( writer, NULL );
430 ok( hr == S_OK, "got %08x\n", hr );
431 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/>", __LINE__ );
433 hr = WsWriteEndElement( writer, NULL );
434 ok( hr == S_OK, "got %08x\n", hr );
435 check_output( writer, "<p:a xmlns:p=\"ns\"><p:b/></p:a>", __LINE__ );
437 hr = set_output( writer );
438 ok( hr == S_OK, "got %08x\n", hr );
440 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
441 ok( hr == S_OK, "got %08x\n", hr );
442 check_output( writer, "", __LINE__ );
444 hr = WsWriteStartElement( writer, NULL, &localname2, &ns2, NULL );
445 ok( hr == S_OK, "got %08x\n", hr );
446 check_output( writer, "<p:a xmlns:p=\"ns\">", __LINE__ );
448 hr = WsWriteEndElement( writer, NULL );
449 ok( hr == S_OK, "got %08x\n", hr );
450 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/>", __LINE__ );
452 hr = WsWriteEndElement( writer, NULL );
453 ok( hr == S_OK, "got %08x\n", hr );
454 check_output( writer, "<p:a xmlns:p=\"ns\"><b xmlns=\"ns2\"/></p:a>", __LINE__ );
456 hr = set_output( writer );
457 ok( hr == S_OK, "got %08x\n", hr );
459 hr = WsWriteStartElement( writer, &empty, &localname, &empty, NULL );
460 ok( hr == S_OK, "got %08x\n", hr );
461 hr = WsWriteEndStartElement( writer, NULL );
462 ok( hr == S_OK, "got %08x\n", hr );
463 hr = WsWriteEndElement( writer, NULL );
464 ok( hr == S_OK, "got %08x\n", hr );
465 check_output( writer, "<a></a>", __LINE__ );
467 WsFreeWriter( writer );
470 static void test_WsWriteStartAttribute(void)
472 HRESULT hr;
473 WS_XML_WRITER *writer;
474 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {3, (BYTE *)"str"};
475 WS_XML_STRING localname2 = {3, (BYTE *)"len"}, ns = {2, (BYTE *)"ns"}, empty = {0, NULL};
476 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
478 hr = WsCreateWriter( NULL, 0, &writer, NULL );
479 ok( hr == S_OK, "got %08x\n", hr );
481 hr = set_output( writer );
482 ok( hr == S_OK, "got %08x\n", hr );
484 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
485 ok( hr == S_OK, "got %08x\n", hr );
487 hr = WsWriteStartAttribute( NULL, &prefix, &localname, &ns, FALSE, NULL );
488 ok( hr == E_INVALIDARG, "got %08x\n", hr );
490 /* WsWriteStartAttribute doesn't output anything */
491 hr = WsWriteStartAttribute( writer, &prefix, &localname2, &ns, FALSE, NULL );
492 ok( hr == S_OK, "got %08x\n", hr );
493 check_output( writer, "", __LINE__ );
495 text.value.length = 1;
496 text.value.bytes = (BYTE *)"0";
497 hr = WsWriteText( writer, &text.text, NULL );
498 ok( hr == S_OK, "got %08x\n", hr );
499 check_output( writer, "", __LINE__ );
501 /* WsWriteEndAttribute doesn't output anything */
502 hr = WsWriteEndAttribute( writer, NULL );
503 ok( hr == S_OK, "got %08x\n", hr );
504 check_output( writer, "", __LINE__ );
506 hr = WsWriteEndElement( writer, NULL );
507 ok( hr == S_OK, "got %08x\n", hr );
508 check_output( writer, "<p:str p:len=\"0\" xmlns:p=\"ns\"/>", __LINE__ );
510 hr = set_output( writer );
511 ok( hr == S_OK, "got %08x\n", hr );
513 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
514 ok( hr == S_OK, "got %08x\n", hr );
516 hr = WsWriteStartAttribute( writer, &empty, &localname2, &empty, FALSE, NULL );
517 ok( hr == S_OK, "got %08x\n", hr );
518 hr = WsWriteEndAttribute( writer, NULL );
519 ok( hr == S_OK, "got %08x\n", hr );
521 hr = WsWriteEndElement( writer, NULL );
522 ok( hr == S_OK, "got %08x\n", hr );
523 check_output( writer, "<p:str len=\"\" xmlns:p=\"ns\"/>", __LINE__ );
525 hr = set_output( writer );
526 ok( hr == S_OK, "got %08x\n", hr );
528 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
529 ok( hr == S_OK, "got %08x\n", hr );
531 hr = WsWriteStartAttribute( writer, NULL, &localname2, &empty, FALSE, NULL );
532 ok( hr == S_OK, "got %08x\n", hr );
534 hr = WsWriteEndAttribute( writer, NULL );
535 ok( hr == S_OK, "got %08x\n", hr );
537 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
538 ok( hr == S_OK, "got %08x\n", hr );
540 hr = WsWriteEndAttribute( writer, NULL );
541 ok( hr == S_OK, "got %08x\n", hr );
543 hr = WsWriteEndElement( writer, NULL );
544 ok( hr == S_OK, "got %08x\n", hr );
545 check_output( writer, "<p:str len=\"\" p:str=\"\" xmlns:p=\"ns\"/>", __LINE__ );
547 WsFreeWriter( writer );
550 static void test_WsWriteType(void)
552 HRESULT hr;
553 WS_XML_WRITER *writer;
554 WS_XML_STRING prefix = {1, (BYTE*)"p"}, localname = {3, (BYTE *)"str"}, ns = {2, (BYTE *)"ns"};
555 const WCHAR *val_str;
556 enum {ONE = 1, TWO = 2};
557 WS_XML_STRING one = {3, (BYTE *)"ONE" }, two = {3, (BYTE *)"TWO"};
558 WS_ENUM_VALUE enum_values[] = {{ONE, &one}, {TWO, &two}};
559 WS_ENUM_DESCRIPTION enum_desc;
560 int val_enum;
562 hr = WsCreateWriter( NULL, 0, &writer, NULL );
563 ok( hr == S_OK, "got %08x\n", hr );
565 hr = set_output( writer );
566 ok( hr == S_OK, "got %08x\n", hr );
568 val_str = L"test";
569 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
570 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
571 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
573 hr = set_output( writer );
574 ok( hr == S_OK, "got %08x\n", hr );
576 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
577 ok( hr == S_OK, "got %08x\n", hr );
579 /* required value */
580 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
581 WS_WRITE_REQUIRED_VALUE, NULL, sizeof(L"test"), NULL );
582 ok( hr == E_INVALIDARG, "got %08x\n", hr );
584 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
585 WS_WRITE_REQUIRED_VALUE, L"test", sizeof(L"test"), NULL );
586 ok( hr == E_INVALIDARG, "got %08x\n", hr );
588 /* required pointer */
589 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
590 WS_WRITE_REQUIRED_POINTER, NULL, sizeof(val_str), NULL );
591 ok( hr == E_INVALIDARG, "got %08x\n", hr );
593 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
594 WS_WRITE_REQUIRED_VALUE, L"test", sizeof(L"test"), NULL );
595 ok( hr == E_INVALIDARG, "got %08x\n", hr );
597 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
598 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(WCHAR **), NULL );
599 ok( hr == S_OK, "got %08x\n", hr );
600 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
602 hr = WsWriteEndElement( writer, NULL );
603 ok( hr == S_OK, "got %08x\n", hr );
604 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
606 hr = set_output( writer );
607 ok( hr == S_OK, "got %08x\n", hr );
609 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
610 ok( hr == S_OK, "got %08x\n", hr );
612 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
613 ok( hr == S_OK, "got %08x\n", hr );
615 val_str = L"test";
616 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
617 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
618 ok( hr == S_OK, "got %08x\n", hr );
619 check_output( writer, "", __LINE__ );
621 hr = WsWriteEndAttribute( writer, NULL );
622 ok( hr == S_OK, "got %08x\n", hr );
623 check_output( writer, "", __LINE__ );
625 hr = WsWriteEndElement( writer, NULL );
626 ok( hr == S_OK, "got %08x\n", hr );
627 check_output( writer, "<p:str p:str=\"test\" xmlns:p=\"ns\"/>", __LINE__ );
629 hr = set_output( writer );
630 ok( hr == S_OK, "got %08x\n", hr );
632 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
633 ok( hr == S_OK, "got %08x\n", hr );
635 val_str = L"test";
636 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL,
637 WS_WRITE_REQUIRED_POINTER, &val_str, sizeof(val_str), NULL );
638 ok( hr == S_OK, "got %08x\n", hr );
639 check_output( writer, "<p:str xmlns:p=\"ns\">test", __LINE__ );
641 hr = WsWriteEndElement( writer, NULL );
642 ok( hr == S_OK, "got %08x\n", hr );
643 check_output( writer, "<p:str xmlns:p=\"ns\">test</p:str>", __LINE__ );
645 hr = set_output( writer );
646 ok( hr == S_OK, "got %08x\n", hr );
648 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
649 ok( hr == S_OK, "got %08x\n", hr );
651 enum_desc.values = enum_values;
652 enum_desc.valueCount = ARRAY_SIZE(enum_values);
653 enum_desc.maxByteCount = 3;
654 enum_desc.nameIndices = NULL;
656 val_enum = 0;
657 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_ENUM_TYPE, &enum_desc,
658 WS_WRITE_REQUIRED_VALUE, &val_enum, sizeof(val_enum), NULL );
659 ok( hr == E_INVALIDARG, "got %08x\n", hr );
661 val_enum = 3;
662 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_ENUM_TYPE, &enum_desc,
663 WS_WRITE_REQUIRED_VALUE, &val_enum, sizeof(val_enum), NULL );
664 ok( hr == E_INVALIDARG, "got %08x\n", hr );
666 val_enum = ONE;
667 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_ENUM_TYPE, &enum_desc,
668 WS_WRITE_REQUIRED_VALUE, &val_enum, sizeof(val_enum), NULL );
669 ok( hr == S_OK, "got %08x\n", hr );
671 hr = WsWriteEndElement( writer, NULL );
672 ok( hr == S_OK, "got %08x\n", hr );
673 check_output( writer, "<p:str xmlns:p=\"ns\">ONE</p:str>", __LINE__ );
675 WsFreeWriter( writer );
678 static void prepare_basic_type_test( WS_XML_WRITER *writer )
680 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
681 HRESULT hr;
683 hr = set_output( writer );
684 ok( hr == S_OK, "got %08x\n", hr );
685 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
686 ok( hr == S_OK, "got %08x\n", hr );
689 static void test_basic_type(void)
691 HRESULT hr;
692 WS_XML_WRITER *writer;
693 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, xmlstr;
694 GUID guid;
695 const WCHAR *str;
696 WS_STRING string;
697 WS_BYTES bytes;
698 WS_UNIQUE_ID id;
699 ULONG i;
700 static const struct
702 WS_TYPE type;
703 INT64 val;
704 ULONG size;
705 const char *result;
706 const char *result2;
708 tests[] =
710 { WS_BOOL_TYPE, TRUE, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
711 { WS_BOOL_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
712 { WS_INT8_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
713 { WS_INT16_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
714 { WS_INT32_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
715 "<t t=\"-2147483648\"/>" },
716 { WS_INT64_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
717 "<t t=\"-9223372036854775808\"/>" },
718 { WS_UINT8_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
719 { WS_UINT16_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
720 { WS_UINT32_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
721 { WS_UINT64_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
722 "<t t=\"18446744073709551615\"/>" },
725 hr = WsCreateWriter( NULL, 0, &writer, NULL );
726 ok( hr == S_OK, "got %08x\n", hr );
728 /* element content type mapping */
729 for (i = 0; i < ARRAY_SIZE( tests ); i++)
731 prepare_basic_type_test( writer );
732 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, tests[i].type, NULL,
733 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
734 ok( hr == S_OK, "%u: got %08x\n", i, hr );
736 hr = WsWriteEndElement( writer, NULL );
737 ok( hr == S_OK, "got %08x\n", hr );
738 check_output( writer, tests[i].result, __LINE__ );
741 /* element type mapping is the same as element content type mapping for basic types */
742 for (i = 0; i < ARRAY_SIZE( tests ); i++)
744 const INT64 *ptr = &tests[i].val;
746 prepare_basic_type_test( writer );
747 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL,
748 WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL );
749 ok( hr == S_OK, "%u: got %08x\n", i, hr );
751 hr = WsWriteEndElement( writer, NULL );
752 ok( hr == S_OK, "got %08x\n", hr );
753 check_output( writer, tests[i].result, __LINE__ );
756 /* attribute type mapping */
757 for (i = 0; i < ARRAY_SIZE( tests ); i++)
759 prepare_basic_type_test( writer );
760 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
761 ok( hr == S_OK, "got %08x\n", hr );
763 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, tests[i].type, NULL,
764 WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL );
765 ok( hr == S_OK, "%u: got %08x\n", i, hr );
767 hr = WsWriteEndAttribute( writer, NULL );
768 ok( hr == S_OK, "got %08x\n", hr );
770 hr = WsWriteEndElement( writer, NULL );
771 ok( hr == S_OK, "got %08x\n", hr );
772 check_output( writer, tests[i].result2, __LINE__ );
775 prepare_basic_type_test( writer );
776 memset( &guid, 0, sizeof(guid) );
777 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_GUID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
778 &guid, sizeof(guid), NULL );
779 ok( hr == S_OK, "got %08x\n", hr );
780 hr = WsWriteEndElement( writer, NULL );
781 ok( hr == S_OK, "got %08x\n", hr );
782 check_output( writer, "<t>00000000-0000-0000-0000-000000000000</t>", __LINE__ );
784 prepare_basic_type_test( writer );
785 string.chars = (WCHAR *)L"test";
786 string.length = 4;
787 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
788 &string, sizeof(string), NULL );
789 ok( hr == S_OK, "got %08x\n", hr );
790 hr = WsWriteEndElement( writer, NULL );
791 ok( hr == S_OK, "got %08x\n", hr );
792 check_output( writer, "<t>test</t>", __LINE__ );
794 prepare_basic_type_test( writer );
795 str = L"test";
796 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL, WS_WRITE_REQUIRED_POINTER,
797 &str, sizeof(str), NULL );
798 ok( hr == S_OK, "got %08x\n", hr );
799 hr = WsWriteEndElement( writer, NULL );
800 ok( hr == S_OK, "got %08x\n", hr );
801 check_output( writer, "<t>test</t>", __LINE__ );
803 prepare_basic_type_test( writer );
804 xmlstr.bytes = (BYTE *)"test";
805 xmlstr.length = 4;
806 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
807 &xmlstr, sizeof(xmlstr), NULL );
808 ok( hr == S_OK, "got %08x\n", hr );
809 hr = WsWriteEndElement( writer, NULL );
810 ok( hr == S_OK, "got %08x\n", hr );
811 check_output( writer, "<t>test</t>", __LINE__ );
813 prepare_basic_type_test( writer );
814 bytes.bytes = (BYTE *)"test";
815 bytes.length = 4;
816 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
817 &bytes, sizeof(bytes), NULL );
818 ok( hr == S_OK, "got %08x\n", hr );
819 hr = WsWriteEndElement( writer, NULL );
820 ok( hr == S_OK, "got %08x\n", hr );
821 check_output( writer, "<t>dGVzdA==</t>", __LINE__ );
823 prepare_basic_type_test( writer );
824 bytes.length = 0;
825 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
826 &bytes, sizeof(bytes), NULL );
827 ok( hr == S_OK, "got %08x\n", hr );
828 hr = WsWriteEndElement( writer, NULL );
829 ok( hr == S_OK, "got %08x\n", hr );
830 check_output( writer, "<t/>", __LINE__ );
832 prepare_basic_type_test( writer );
833 bytes.bytes = NULL;
834 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
835 &bytes, sizeof(bytes), NULL );
836 ok( hr == S_OK, "got %08x\n", hr );
837 hr = WsWriteEndElement( writer, NULL );
838 ok( hr == S_OK, "got %08x\n", hr );
839 check_output( writer, "<t/>", __LINE__ );
841 prepare_basic_type_test( writer );
842 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_NILLABLE_VALUE,
843 &bytes, sizeof(bytes), NULL );
844 ok( hr == S_OK, "got %08x\n", hr );
845 hr = WsWriteEndElement( writer, NULL );
846 ok( hr == S_OK, "got %08x\n", hr );
847 check_output( writer, "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>",
848 __LINE__ );
850 prepare_basic_type_test( writer );
851 memset( &id, 0, sizeof(id) );
852 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_UNIQUE_ID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
853 &id, sizeof(id), NULL );
854 ok( hr == S_OK, "got %08x\n", hr );
855 hr = WsWriteEndElement( writer, NULL );
856 ok( hr == S_OK, "got %08x\n", hr );
857 check_output( writer, "<t>urn:uuid:00000000-0000-0000-0000-000000000000</t>", __LINE__ );
859 prepare_basic_type_test( writer );
860 id.uri.length = 4;
861 id.uri.chars = (WCHAR *)L"test";
862 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_UNIQUE_ID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
863 &id, sizeof(id), NULL );
864 ok( hr == S_OK, "got %08x\n", hr );
865 hr = WsWriteEndElement( writer, NULL );
866 ok( hr == S_OK, "got %08x\n", hr );
867 check_output( writer, "<t>test</t>", __LINE__ );
869 WsFreeWriter( writer );
872 static void test_simple_struct_type(void)
874 HRESULT hr;
875 WS_XML_WRITER *writer;
876 WS_STRUCT_DESCRIPTION s;
877 WS_FIELD_DESCRIPTION f, *fields[1];
878 WS_XML_STRING localname = {6, (BYTE *)"struct"}, ns = {0, NULL};
879 struct test
881 const WCHAR *field;
882 } *test;
884 hr = WsCreateWriter( NULL, 0, &writer, NULL );
885 ok( hr == S_OK, "got %08x\n", hr );
887 hr = set_output( writer );
888 ok( hr == S_OK, "got %08x\n", hr );
890 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
891 ok( hr == S_OK, "got %08x\n", hr );
893 memset( &f, 0, sizeof(f) );
894 f.mapping = WS_TEXT_FIELD_MAPPING;
895 f.type = WS_WSZ_TYPE;
896 fields[0] = &f;
898 memset( &s, 0, sizeof(s) );
899 s.size = sizeof(struct test);
900 s.alignment = TYPE_ALIGNMENT(struct test);
901 s.fields = fields;
902 s.fieldCount = 1;
904 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
905 test->field = L"value";
906 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
907 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
908 ok( hr == E_INVALIDARG, "got %08x\n", hr );
910 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, NULL,
911 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
912 ok( hr == E_INVALIDARG, "got %08x\n", hr );
914 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
915 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
916 ok( hr == S_OK, "got %08x\n", hr );
918 hr = WsWriteEndElement( writer, NULL );
919 ok( hr == S_OK, "got %08x\n", hr );
920 check_output( writer, "<struct>value</struct>", __LINE__ );
922 /* required value */
923 hr = set_output( writer );
924 ok( hr == S_OK, "got %08x\n", hr );
926 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
927 ok( hr == S_OK, "got %08x\n", hr );
929 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
930 WS_WRITE_REQUIRED_VALUE, test, sizeof(*test), NULL );
931 ok( hr == S_OK, "got %08x\n", hr );
933 hr = WsWriteEndElement( writer, NULL );
934 ok( hr == S_OK, "got %08x\n", hr );
935 check_output( writer, "<struct>value</struct>", __LINE__ );
937 hr = set_output( writer );
938 ok( hr == S_OK, "got %08x\n", hr );
940 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
941 ok( hr == S_OK, "got %08x\n", hr );
943 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
944 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
945 ok( hr == S_OK, "got %08x\n", hr );
947 hr = WsWriteEndElement( writer, NULL );
948 ok( hr == S_OK, "got %08x\n", hr );
949 check_output( writer, "<struct>value</struct>", __LINE__ );
951 hr = set_output( writer );
952 ok( hr == S_OK, "got %08x\n", hr );
954 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
955 ok( hr == S_OK, "got %08x\n", hr );
957 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
958 ok( hr == S_OK, "got %08x\n", hr );
960 hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
961 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
962 ok( hr == S_OK, "got %08x\n", hr );
964 hr = WsWriteEndAttribute( writer, NULL );
965 ok( hr == S_OK, "got %08x\n", hr );
967 hr = WsWriteEndElement( writer, NULL );
968 ok( hr == S_OK, "got %08x\n", hr );
969 check_output( writer, "<struct struct=\"value\"/>", __LINE__ );
971 HeapFree( GetProcessHeap(), 0, test );
972 WsFreeWriter( writer );
975 static void test_WsWriteElement(void)
977 HRESULT hr;
978 WS_XML_WRITER *writer;
979 WS_STRUCT_DESCRIPTION s;
980 WS_FIELD_DESCRIPTION f, *fields[1];
981 WS_ELEMENT_DESCRIPTION desc;
982 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
983 struct test { const WCHAR *str; } *test;
985 hr = WsCreateWriter( NULL, 0, &writer, NULL );
986 ok( hr == S_OK, "got %08x\n", hr );
988 hr = set_output( writer );
989 ok( hr == S_OK, "got %08x\n", hr );
991 /* text field mapping */
992 memset( &f, 0, sizeof(f) );
993 f.mapping = WS_TEXT_FIELD_MAPPING;
994 f.type = WS_WSZ_TYPE;
995 fields[0] = &f;
997 memset( &s, 0, sizeof(s) );
998 s.size = sizeof(struct test);
999 s.alignment = TYPE_ALIGNMENT(struct test);
1000 s.fields = fields;
1001 s.fieldCount = 1;
1003 desc.elementLocalName = &localname;
1004 desc.elementNs = &ns;
1005 desc.type = WS_STRUCT_TYPE;
1006 desc.typeDescription = &s;
1008 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
1009 test->str = L"test";
1010 hr = WsWriteElement( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1011 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1013 hr = WsWriteElement( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1014 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1016 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
1017 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1019 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1020 ok( hr == S_OK, "got %08x\n", hr );
1021 check_output( writer, "<str>test</str>", __LINE__ );
1023 hr = set_output( writer );
1024 ok( hr == S_OK, "got %08x\n", hr );
1026 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1027 ok( hr == S_OK, "got %08x\n", hr );
1029 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1030 ok( hr == S_OK, "got %08x\n", hr );
1031 check_output( writer, "<str><str>test</str>", __LINE__ );
1033 hr = set_output( writer );
1034 ok( hr == S_OK, "got %08x\n", hr );
1036 /* attribute field mapping */
1037 f.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
1039 /* requires localName and ns to be set */
1040 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1041 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1043 hr = set_output( writer );
1044 ok( hr == S_OK, "got %08x\n", hr );
1046 f.localName = &localname;
1047 f.ns = &ns;
1048 hr = WsWriteElement( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1049 ok( hr == S_OK, "got %08x\n", hr );
1050 check_output( writer, "<str str=\"test\"/>", __LINE__ );
1052 HeapFree( GetProcessHeap(), 0, test );
1053 WsFreeWriter( writer );
1056 static void test_WsWriteValue(void)
1058 HRESULT hr;
1059 WS_XML_WRITER *writer;
1060 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1061 ULONG i;
1062 static const struct
1064 WS_VALUE_TYPE type;
1065 INT64 val;
1066 ULONG size;
1067 const char *result;
1068 const char *result2;
1070 tests[] =
1072 { WS_BOOL_VALUE_TYPE, ~0, sizeof(BOOL), "<t>true</t>", "<t t=\"true\"/>" },
1073 { WS_BOOL_VALUE_TYPE, FALSE, sizeof(BOOL), "<t>false</t>", "<t t=\"false\"/>" },
1074 { WS_INT8_VALUE_TYPE, -128, sizeof(INT8), "<t>-128</t>", "<t t=\"-128\"/>" },
1075 { WS_INT16_VALUE_TYPE, -32768, sizeof(INT16), "<t>-32768</t>", "<t t=\"-32768\"/>" },
1076 { WS_INT32_VALUE_TYPE, -2147483647 - 1, sizeof(INT32), "<t>-2147483648</t>",
1077 "<t t=\"-2147483648\"/>" },
1078 { WS_INT64_VALUE_TYPE, -9223372036854775807 - 1, sizeof(INT64), "<t>-9223372036854775808</t>",
1079 "<t t=\"-9223372036854775808\"/>" },
1080 { WS_UINT8_VALUE_TYPE, 255, sizeof(UINT8), "<t>255</t>", "<t t=\"255\"/>" },
1081 { WS_UINT16_VALUE_TYPE, 65535, sizeof(UINT16), "<t>65535</t>", "<t t=\"65535\"/>" },
1082 { WS_UINT32_VALUE_TYPE, ~0u, sizeof(UINT32), "<t>4294967295</t>", "<t t=\"4294967295\"/>" },
1083 { WS_UINT64_VALUE_TYPE, ~0, sizeof(UINT64), "<t>18446744073709551615</t>",
1084 "<t t=\"18446744073709551615\"/>" },
1087 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1088 ok( hr == S_OK, "got %08x\n", hr );
1090 hr = set_output( writer );
1091 ok( hr == S_OK, "got %08x\n", hr );
1093 hr = WsWriteValue( NULL, tests[0].type, &tests[0].val, tests[0].size, NULL );
1094 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1096 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, tests[0].size, NULL );
1097 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1099 hr = set_output( writer );
1100 ok( hr == S_OK, "got %08x\n", hr );
1102 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1103 ok( hr == S_OK, "got %08x\n", hr );
1105 /* zero size */
1106 hr = WsWriteValue( writer, tests[0].type, &tests[0].val, 0, NULL );
1107 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1109 hr = set_output( writer );
1110 ok( hr == S_OK, "got %08x\n", hr );
1112 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1113 ok( hr == S_OK, "got %08x\n", hr );
1115 /* NULL value */
1116 hr = WsWriteValue( writer, tests[0].type, NULL, 0, NULL );
1117 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1119 /* element type mapping */
1120 for (i = 0; i < ARRAY_SIZE( tests ); i++)
1122 hr = set_output( writer );
1123 ok( hr == S_OK, "got %08x\n", hr );
1125 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1126 ok( hr == S_OK, "got %08x\n", hr );
1128 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1129 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1131 hr = WsWriteEndElement( writer, NULL );
1132 ok( hr == S_OK, "got %08x\n", hr );
1133 check_output( writer, tests[i].result, __LINE__ );
1136 /* attribute type mapping */
1137 for (i = 0; i < ARRAY_SIZE( tests ); i++)
1139 hr = set_output( writer );
1140 ok( hr == S_OK, "got %08x\n", hr );
1142 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1143 ok( hr == S_OK, "got %08x\n", hr );
1145 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL );
1146 ok( hr == S_OK, "got %08x\n", hr );
1148 hr = WsWriteValue( writer, tests[i].type, &tests[i].val, tests[i].size, NULL );
1149 ok( hr == S_OK, "%u: got %08x\n", i, hr );
1151 hr = WsWriteEndAttribute( writer, NULL );
1152 ok( hr == S_OK, "got %08x\n", hr );
1154 hr = WsWriteEndElement( writer, NULL );
1155 ok( hr == S_OK, "got %08x\n", hr );
1156 check_output( writer, tests[i].result2, __LINE__ );
1159 WsFreeWriter( writer );
1162 static void test_WsWriteAttribute(void)
1164 HRESULT hr;
1165 WS_XML_WRITER *writer;
1166 WS_STRUCT_DESCRIPTION s;
1167 WS_FIELD_DESCRIPTION f, *fields[1];
1168 WS_ATTRIBUTE_DESCRIPTION desc;
1169 WS_XML_STRING localname = {3, (BYTE *)"str"}, ns = {0, NULL};
1170 struct test { const WCHAR *str; } *test;
1172 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1173 ok( hr == S_OK, "got %08x\n", hr );
1175 hr = set_output( writer );
1176 ok( hr == S_OK, "got %08x\n", hr );
1178 /* text field mapping */
1179 memset( &f, 0, sizeof(f) );
1180 f.mapping = WS_TEXT_FIELD_MAPPING;
1181 f.type = WS_WSZ_TYPE;
1182 fields[0] = &f;
1184 memset( &s, 0, sizeof(s) );
1185 s.size = sizeof(struct test);
1186 s.alignment = TYPE_ALIGNMENT(struct test);
1187 s.fields = fields;
1188 s.fieldCount = 1;
1190 desc.attributeLocalName = &localname;
1191 desc.attributeNs = &ns;
1192 desc.type = WS_STRUCT_TYPE;
1193 desc.typeDescription = &s;
1195 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) );
1196 test->str = L"test";
1197 hr = WsWriteAttribute( NULL, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1198 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1200 hr = WsWriteAttribute( writer, NULL, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1201 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1203 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, NULL, 0, NULL );
1204 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1206 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1207 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1209 hr = set_output( writer );
1210 ok( hr == S_OK, "got %08x\n", hr );
1212 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1213 ok( hr == S_OK, "got %08x\n", hr );
1215 hr = WsWriteAttribute( writer, &desc, WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1216 ok( hr == S_OK, "got %08x\n", hr );
1218 hr = WsWriteEndElement( writer, NULL );
1219 ok( hr == S_OK, "got %08x\n", hr );
1220 check_output( writer, "<str str=\"test\"/>", __LINE__ );
1222 HeapFree( GetProcessHeap(), 0, test );
1223 WsFreeWriter( writer );
1226 static void test_WsWriteStartCData(void)
1228 HRESULT hr;
1229 WS_XML_WRITER *writer;
1230 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1231 WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
1233 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1234 ok( hr == S_OK, "got %08x\n", hr );
1236 hr = set_output( writer );
1237 ok( hr == S_OK, "got %08x\n", hr );
1239 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1240 ok( hr == S_OK, "got %08x\n", hr );
1242 hr = WsWriteEndCData( writer, NULL );
1243 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1245 hr = set_output( writer );
1246 ok( hr == S_OK, "got %08x\n", hr );
1248 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1249 ok( hr == S_OK, "got %08x\n", hr );
1250 check_output( writer, "", __LINE__ );
1252 hr = WsWriteStartCData( writer, NULL );
1253 ok( hr == S_OK, "got %08x\n", hr );
1254 check_output( writer, "<t><![CDATA[", __LINE__ );
1256 text.value.bytes = (BYTE *)"<data>";
1257 text.value.length = 6;
1258 hr = WsWriteText( writer, &text.text, NULL );
1259 ok( hr == S_OK, "got %08x\n", hr );
1260 check_output( writer, "<t><![CDATA[<data>", __LINE__ );
1262 hr = WsWriteEndCData( writer, NULL );
1263 ok( hr == S_OK, "got %08x\n", hr );
1264 check_output( writer, "<t><![CDATA[<data>]]>", __LINE__ );
1266 hr = WsWriteEndElement( writer, NULL );
1267 ok( hr == S_OK, "got %08x\n", hr );
1268 check_output( writer, "<t><![CDATA[<data>]]></t>", __LINE__ );
1270 WsFreeWriter( writer );
1273 static void check_output_buffer( WS_XML_BUFFER *buffer, const char *expected, unsigned int line )
1275 WS_XML_WRITER *writer;
1276 WS_BYTES bytes;
1277 ULONG size = sizeof(bytes);
1278 int len = strlen(expected);
1279 HRESULT hr;
1281 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1282 ok( hr == S_OK, "got %08x\n", hr );
1284 hr = set_output( writer );
1285 ok( hr == S_OK, "got %08x\n", hr );
1287 hr = WsWriteXmlBuffer( writer, buffer, NULL );
1288 ok( hr == S_OK, "got %08x\n", hr );
1290 memset( &bytes, 0, sizeof(bytes) );
1291 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
1292 ok( hr == S_OK, "%u: got %08x\n", line, hr );
1293 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
1294 if (bytes.length != len) return;
1295 ok( !memcmp( bytes.bytes, expected, len ), "%u: got %s expected %s\n", line, bytes.bytes, expected );
1297 WsFreeWriter( writer );
1300 static void prepare_xmlns_test( WS_XML_WRITER *writer, WS_HEAP **heap, WS_XML_BUFFER **buffer )
1302 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1303 HRESULT hr;
1305 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, heap, NULL );
1306 ok( hr == S_OK, "got %08x\n", hr );
1308 hr = WsCreateXmlBuffer( *heap, NULL, 0, buffer, NULL );
1309 ok( hr == S_OK, "got %08x\n", hr );
1311 hr = WsSetOutputToBuffer( writer, *buffer, NULL, 0, NULL );
1312 ok( hr == S_OK, "got %08x\n", hr );
1314 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
1315 ok( hr == S_OK, "got %08x\n", hr );
1318 static void test_WsWriteXmlnsAttribute(void)
1320 WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1321 WS_XML_STRING prefix = {6, (BYTE *)"prefix"}, prefix2 = {7, (BYTE *)"prefix2"};
1322 WS_XML_STRING xmlns = {6, (BYTE *)"xmlns"}, attr = {4, (BYTE *)"attr"};
1323 WS_XML_STRING localname = {1, (BYTE *)"u"};
1324 WS_HEAP *heap;
1325 WS_XML_BUFFER *buffer;
1326 WS_XML_WRITER *writer;
1327 HRESULT hr;
1329 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1330 ok( hr == S_OK, "got %08x\n", hr );
1332 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1333 ok( hr == S_OK, "got %08x\n", hr );
1335 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1336 ok( hr == S_OK, "got %08x\n", hr );
1338 hr = WsWriteXmlnsAttribute( NULL, NULL, NULL, FALSE, NULL );
1339 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1340 WsFreeHeap( heap );
1342 prepare_xmlns_test( writer, &heap, &buffer );
1343 hr = WsWriteXmlnsAttribute( writer, NULL, NULL, FALSE, NULL );
1344 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1345 WsFreeHeap( heap );
1347 prepare_xmlns_test( writer, &heap, &buffer );
1348 hr = WsWriteXmlnsAttribute( writer, &prefix2, NULL, FALSE, NULL );
1349 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1351 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1352 ok( hr == S_OK, "got %08x\n", hr );
1353 hr = WsWriteXmlnsAttribute( writer, NULL, &ns, FALSE, NULL );
1354 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1355 WsFreeHeap( heap );
1357 /* no prefix */
1358 prepare_xmlns_test( writer, &heap, &buffer );
1359 hr = WsWriteXmlnsAttribute( writer, NULL, &ns2, FALSE, NULL );
1360 ok( hr == S_OK, "got %08x\n", hr );
1361 hr = WsWriteEndElement( writer, NULL );
1362 ok( hr == S_OK, "got %08x\n", hr );
1363 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\" xmlns=\"ns2\"/>", __LINE__ );
1364 WsFreeHeap( heap );
1366 /* prefix */
1367 prepare_xmlns_test( writer, &heap, &buffer );
1368 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1369 ok( hr == S_OK, "got %08x\n", hr );
1370 hr = WsWriteEndElement( writer, NULL );
1371 ok( hr == S_OK, "got %08x\n", hr );
1372 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns2\" xmlns:prefix=\"ns\"/>", __LINE__ );
1373 WsFreeHeap( heap );
1375 /* implicitly set element prefix namespace */
1376 prepare_xmlns_test( writer, &heap, &buffer );
1377 hr = WsWriteEndElement( writer, NULL );
1378 ok( hr == S_OK, "got %08x\n", hr );
1379 check_output_buffer( buffer, "<prefix:t xmlns:prefix=\"ns\"/>", __LINE__ );
1380 WsFreeHeap( heap );
1382 /* explicitly set element prefix namespace */
1383 prepare_xmlns_test( writer, &heap, &buffer );
1384 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1385 ok( hr == S_OK, "got %08x\n", hr );
1386 hr = WsWriteEndElement( writer, NULL );
1387 ok( hr == S_OK, "got %08x\n", hr );
1388 check_output_buffer( buffer, "<prefix:t xmlns:prefix='ns'/>", __LINE__ );
1389 WsFreeHeap( heap );
1391 /* repeated calls, same namespace */
1392 prepare_xmlns_test( writer, &heap, &buffer );
1393 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1394 ok( hr == S_OK, "got %08x\n", hr );
1395 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1396 ok( hr == S_OK, "got %08x\n", hr );
1397 hr = WsWriteEndElement( writer, NULL );
1398 ok( hr == S_OK, "got %08x\n", hr );
1399 check_output_buffer( buffer, "<prefix:t xmlns:prefix2=\"ns\" xmlns:prefix=\"ns\"/>", __LINE__ );
1400 WsFreeHeap( heap );
1402 /* repeated calls, different namespace */
1403 prepare_xmlns_test( writer, &heap, &buffer );
1404 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, FALSE, NULL );
1405 ok( hr == S_OK, "got %08x\n", hr );
1406 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, FALSE, NULL );
1407 ok( hr == S_OK, "got %08x\n", hr );
1408 hr = WsWriteEndElement( writer, NULL );
1409 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1410 WsFreeHeap( heap );
1412 /* single quotes */
1413 prepare_xmlns_test( writer, &heap, &buffer );
1414 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns, TRUE, NULL );
1415 ok( hr == S_OK, "got %08x\n", hr );
1416 hr = WsWriteEndElement( writer, NULL );
1417 ok( hr == S_OK, "got %08x\n", hr );
1418 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns' xmlns:prefix=\"ns\"/>", __LINE__ );
1419 WsFreeHeap( heap );
1421 /* different namespace, different prefix */
1422 prepare_xmlns_test( writer, &heap, &buffer );
1423 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1424 ok( hr == S_OK, "got %08x\n", hr );
1425 hr = WsWriteEndElement( writer, NULL );
1426 ok( hr == S_OK, "got %08x\n", hr );
1427 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"/>", __LINE__ );
1428 WsFreeHeap( heap );
1430 /* different namespace, same prefix */
1431 prepare_xmlns_test( writer, &heap, &buffer );
1432 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns2, TRUE, NULL );
1433 ok( hr == S_OK, "got %08x\n", hr );
1434 hr = WsWriteEndElement( writer, NULL );
1435 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1436 WsFreeHeap( heap );
1438 /* regular attribute */
1439 prepare_xmlns_test( writer, &heap, &buffer );
1440 hr = WsWriteStartAttribute( writer, &xmlns, &prefix2, &ns2, TRUE, NULL );
1441 ok( hr == S_OK, "got %08x\n", hr );
1442 hr = WsWriteEndAttribute( writer, NULL );
1443 ok( hr == S_OK, "got %08x\n", hr );
1444 hr = WsWriteEndElement( writer, NULL );
1445 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1446 WsFreeHeap( heap );
1448 /* attribute order */
1449 prepare_xmlns_test( writer, &heap, &buffer );
1450 hr = WsWriteXmlnsAttribute( writer, &prefix, &ns, TRUE, NULL );
1451 ok( hr == S_OK, "got %08x\n", hr );
1452 hr = WsWriteStartAttribute( writer, &prefix, &attr, &ns, TRUE, NULL );
1453 ok( hr == S_OK, "got %08x\n", hr );
1454 hr = WsWriteEndAttribute( writer, NULL );
1455 ok( hr == S_OK, "got %08x\n", hr );
1456 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1457 ok( hr == S_OK, "got %08x\n", hr );
1458 hr = WsWriteEndElement( writer, NULL );
1459 ok( hr == S_OK, "got %08x\n", hr );
1460 check_output_buffer( buffer, "<prefix:t prefix:attr='' xmlns:prefix='ns' xmlns:prefix2='ns2'/>", __LINE__ );
1461 WsFreeHeap( heap );
1463 /* scope */
1464 prepare_xmlns_test( writer, &heap, &buffer );
1465 hr = WsWriteXmlnsAttribute( writer, &prefix2, &ns2, TRUE, NULL );
1466 ok( hr == S_OK, "got %08x\n", hr );
1467 hr = WsWriteStartElement( writer, &prefix2, &localname, &ns2, NULL );
1468 ok( hr == S_OK, "got %08x\n", hr );
1469 hr = WsWriteEndElement( writer, NULL );
1470 ok( hr == S_OK, "got %08x\n", hr );
1471 hr = WsWriteEndElement( writer, NULL );
1472 ok( hr == S_OK, "got %08x\n", hr );
1473 check_output_buffer( buffer, "<prefix:t xmlns:prefix2='ns2' xmlns:prefix=\"ns\"><prefix2:u/></prefix:t>",
1474 __LINE__ );
1475 WsFreeHeap( heap );
1477 WsFreeWriter( writer );
1480 static void prepare_prefix_test( WS_XML_WRITER *writer )
1482 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
1483 HRESULT hr;
1485 hr = set_output( writer );
1486 ok( hr == S_OK, "got %08x\n", hr );
1487 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1488 ok( hr == S_OK, "got %08x\n", hr );
1489 hr = WsWriteEndStartElement( writer, NULL );
1490 ok( hr == S_OK, "got %08x\n", hr );
1493 static void test_WsGetPrefixFromNamespace(void)
1495 const WS_XML_STRING p = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, *prefix;
1496 const WS_XML_STRING ns = {2, (BYTE *)"ns"}, ns2 = {3, (BYTE *)"ns2"};
1497 WS_XML_WRITER *writer;
1498 HRESULT hr;
1500 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1501 ok( hr == S_OK, "got %08x\n", hr );
1503 hr = set_output( writer );
1504 ok( hr == S_OK, "got %08x\n", hr );
1505 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1506 ok( hr == S_OK, "got %08x\n", hr );
1508 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, NULL, NULL );
1509 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1511 hr = WsGetPrefixFromNamespace( NULL, NULL, FALSE, &prefix, NULL );
1512 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1514 hr = WsGetPrefixFromNamespace( writer, NULL, FALSE, &prefix, NULL );
1515 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1517 /* element must be committed */
1518 hr = set_output( writer );
1519 ok( hr == S_OK, "got %08x\n", hr );
1520 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1521 ok( hr == S_OK, "got %08x\n", hr );
1522 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1523 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1525 /* but writer can't be positioned on end element node */
1526 hr = set_output( writer );
1527 ok( hr == S_OK, "got %08x\n", hr );
1528 hr = WsWriteStartElement( writer, &p, &localname, &ns, NULL );
1529 ok( hr == S_OK, "got %08x\n", hr );
1530 hr = WsWriteEndElement( writer, NULL );
1531 ok( hr == S_OK, "got %08x\n", hr );
1532 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1533 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1535 /* required = TRUE */
1536 prefix = NULL;
1537 prepare_prefix_test( writer );
1538 hr = WsGetPrefixFromNamespace( writer, &ns, TRUE, &prefix, NULL );
1539 ok( hr == S_OK, "got %08x\n", hr );
1540 ok( prefix != NULL, "prefix not set\n" );
1541 if (prefix)
1543 ok( prefix->length == 1, "got %u\n", prefix->length );
1544 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1547 prefix = (const WS_XML_STRING *)0xdeadbeef;
1548 hr = WsGetPrefixFromNamespace( writer, &ns2, TRUE, &prefix, NULL );
1549 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1550 ok( prefix == (const WS_XML_STRING *)0xdeadbeef, "prefix set\n" );
1552 /* required = FALSE */
1553 prefix = NULL;
1554 prepare_prefix_test( writer );
1555 hr = WsGetPrefixFromNamespace( writer, &ns, FALSE, &prefix, NULL );
1556 ok( hr == S_OK, "got %08x\n", hr );
1557 ok( prefix != NULL, "prefix not set\n" );
1558 if (prefix)
1560 ok( prefix->length == 1, "got %u\n", prefix->length );
1561 ok( !memcmp( prefix->bytes, "p", 1 ), "wrong prefix\n" );
1564 prefix = (const WS_XML_STRING *)0xdeadbeef;
1565 hr = WsGetPrefixFromNamespace( writer, &ns2, FALSE, &prefix, NULL );
1566 ok( hr == S_FALSE, "got %08x\n", hr );
1567 ok( prefix == NULL, "prefix not set\n" );
1569 WsFreeWriter( writer );
1572 static void test_complex_struct_type(void)
1574 static const char expected[] =
1575 "<o:OfficeConfig xmlns:o=\"urn:schemas-microsoft-com:office:office\">"
1576 "<o:services o:GenerationTime=\"2015-09-03T18:47:54\"/>"
1577 "</o:OfficeConfig>";
1578 WS_XML_STRING str_officeconfig = {12, (BYTE *)"OfficeConfig"};
1579 WS_XML_STRING str_services = {8, (BYTE *)"services"};
1580 WS_XML_STRING str_generationtime = {14, (BYTE *)"GenerationTime"};
1581 WS_XML_STRING ns = {39, (BYTE *)"urn:schemas-microsoft-com:office:office"};
1582 WS_XML_STRING prefix = {1, (BYTE *)"o"};
1583 DWORD size;
1584 HRESULT hr;
1585 WS_HEAP *heap;
1586 WS_XML_BUFFER *buffer;
1587 WS_XML_WRITER *writer;
1588 WS_STRUCT_DESCRIPTION s, s2;
1589 WS_FIELD_DESCRIPTION f, f2, f3, *fields[1], *fields2[2];
1590 struct services
1592 const WCHAR *generationtime;
1593 BYTE dummy[12];
1595 struct officeconfig
1597 struct services *services;
1598 } *test;
1600 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1601 ok( hr == S_OK, "got %08x\n", hr );
1603 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1604 ok( hr == S_OK, "got %08x\n", hr );
1606 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1607 ok( hr == S_OK, "got %08x\n", hr );
1609 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1610 ok( hr == S_OK, "got %08x\n", hr );
1612 hr = WsWriteStartElement( writer, &prefix, &str_officeconfig, &ns, NULL );
1613 ok( hr == S_OK, "got %08x\n", hr );
1615 memset( &f2, 0, sizeof(f2) );
1616 f2.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
1617 f2.localName = &str_generationtime;
1618 f2.ns = &ns;
1619 f2.type = WS_WSZ_TYPE;
1620 f2.options = WS_FIELD_OPTIONAL;
1621 fields2[0] = &f2;
1623 memset( &f3, 0, sizeof(f3) );
1624 f3.mapping = WS_ANY_ATTRIBUTES_FIELD_MAPPING;
1625 f3.type = WS_ANY_ATTRIBUTES_TYPE;
1626 f3.offset = FIELD_OFFSET(struct services, dummy);
1627 fields2[1] = &f3;
1629 memset( &s2, 0, sizeof(s2) );
1630 s2.size = sizeof(*test->services);
1631 s2.alignment = 4;
1632 s2.fields = fields2;
1633 s2.fieldCount = 2;
1634 s2.typeLocalName = &str_services;
1635 s2.typeNs = &ns;
1637 memset( &f, 0, sizeof(f) );
1638 f.mapping = WS_ELEMENT_FIELD_MAPPING;
1639 f.localName = &str_services;
1640 f.ns = &ns;
1641 f.type = WS_STRUCT_TYPE;
1642 f.typeDescription = &s2;
1643 f.options = WS_FIELD_POINTER;
1644 fields[0] = &f;
1646 memset( &s, 0, sizeof(s) );
1647 s.size = sizeof(*test);
1648 s.alignment = 4;
1649 s.fields = fields;
1650 s.fieldCount = 1;
1651 s.typeLocalName = &str_officeconfig;
1652 s.typeNs = &ns;
1654 size = sizeof(struct officeconfig) + sizeof(struct services);
1655 test = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
1656 test->services = (struct services *)(test + 1);
1657 test->services->generationtime = L"2015-09-03T18:47:54";
1658 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
1659 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
1660 ok( hr == S_OK, "got %08x\n", hr );
1662 hr = WsWriteEndElement( writer, NULL );
1663 ok( hr == S_OK, "got %08x\n", hr );
1664 check_output_buffer( buffer, expected, __LINE__ );
1666 HeapFree( GetProcessHeap(), 0, test );
1667 WsFreeWriter( writer );
1668 WsFreeHeap( heap );
1671 static void test_WsMoveWriter(void)
1673 WS_XML_STRING localname = {1, (BYTE *)"a"}, localname2 = {1, (BYTE *)"b"}, ns = {0, NULL};
1674 WS_HEAP *heap;
1675 WS_XML_WRITER *writer;
1676 WS_XML_BUFFER *buffer;
1677 HRESULT hr;
1679 hr = WsMoveWriter( NULL, WS_MOVE_TO_EOF, NULL, NULL );
1680 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1682 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1683 ok( hr == S_OK, "got %08x\n", hr );
1685 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1686 ok( hr == S_OK, "got %08x\n", hr );
1688 hr = set_output( writer );
1689 ok( hr == S_OK, "got %08x\n", hr );
1691 /* writer must be set to an XML buffer */
1692 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1693 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1695 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1696 ok( hr == S_OK, "got %08x\n", hr );
1698 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1699 ok( hr == S_OK, "got %08x\n", hr );
1701 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1702 ok( hr == S_OK, "got %08x\n", hr );
1704 /* <a><b/></a> */
1705 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1706 ok( hr == S_OK, "got %08x\n", hr );
1708 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
1709 ok( hr == S_OK, "got %08x\n", hr );
1711 hr = WsWriteEndElement( writer, NULL );
1712 ok( hr == S_OK, "got %08x\n", hr );
1714 hr = WsWriteEndElement( writer, NULL );
1715 ok( hr == S_OK, "got %08x\n", hr );
1717 hr = WsMoveWriter( writer, WS_MOVE_TO_EOF, NULL, NULL );
1718 ok( hr == S_OK, "got %08x\n", hr );
1720 hr = WsMoveWriter( writer, WS_MOVE_TO_ROOT_ELEMENT, NULL, NULL );
1721 ok( hr == S_OK, "got %08x\n", hr );
1723 hr = WsMoveWriter( writer, WS_MOVE_TO_CHILD_ELEMENT, NULL, NULL );
1724 ok( hr == S_OK, "got %08x\n", hr );
1726 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1727 ok( hr == S_OK, "got %08x\n", hr );
1729 hr = WsMoveWriter( writer, WS_MOVE_TO_PARENT_ELEMENT, NULL, NULL );
1730 ok( hr == S_OK, "got %08x\n", hr );
1732 hr = WsMoveWriter( writer, WS_MOVE_TO_END_ELEMENT, NULL, NULL );
1733 ok( hr == S_OK, "got %08x\n", hr );
1735 hr = WsMoveWriter( writer, WS_MOVE_TO_BOF, NULL, NULL );
1736 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1738 WsFreeWriter( writer );
1739 WsFreeHeap( heap );
1742 static void test_WsGetWriterPosition(void)
1744 WS_HEAP *heap;
1745 WS_XML_WRITER *writer;
1746 WS_XML_BUFFER *buffer;
1747 WS_XML_NODE_POSITION pos;
1748 HRESULT hr;
1750 hr = WsGetWriterPosition( NULL, NULL, NULL );
1751 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1753 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1754 ok( hr == S_OK, "got %08x\n", hr );
1756 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1757 ok( hr == S_OK, "got %08x\n", hr );
1759 hr = WsGetWriterPosition( writer, &pos, NULL );
1760 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1762 hr = set_output( writer );
1763 ok( hr == S_OK, "got %08x\n", hr );
1765 /* writer must be set to an XML buffer */
1766 hr = WsGetWriterPosition( writer, &pos, NULL );
1767 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1769 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1770 ok( hr == S_OK, "got %08x\n", hr );
1772 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1773 ok( hr == S_OK, "got %08x\n", hr );
1775 hr = WsGetWriterPosition( writer, NULL, NULL );
1776 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1778 pos.buffer = pos.node = NULL;
1779 hr = WsGetWriterPosition( writer, &pos, NULL );
1780 ok( hr == S_OK, "got %08x\n", hr );
1781 ok( pos.buffer != NULL, "buffer not set\n" );
1782 ok( pos.node != NULL, "node not set\n" );
1784 WsFreeWriter( writer );
1785 WsFreeHeap( heap );
1788 static void test_WsSetWriterPosition(void)
1790 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1791 WS_HEAP *heap;
1792 WS_XML_WRITER *writer;
1793 WS_XML_BUFFER *buf1, *buf2;
1794 WS_XML_NODE_POSITION pos;
1795 HRESULT hr;
1797 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1798 ok( hr == S_OK, "got %08x\n", hr );
1800 hr = WsSetWriterPosition( NULL, NULL, NULL );
1801 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1803 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1804 ok( hr == S_OK, "got %08x\n", hr );
1806 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf1, NULL );
1807 ok( hr == S_OK, "got %08x\n", hr );
1809 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1810 ok( hr == S_OK, "got %08x\n", hr );
1812 hr = WsSetWriterPosition( writer, NULL, NULL );
1813 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1815 pos.buffer = pos.node = NULL;
1816 hr = WsGetWriterPosition( writer, &pos, NULL );
1817 ok( hr == S_OK, "got %08x\n", hr );
1818 ok( pos.buffer == buf1, "wrong buffer\n" );
1819 ok( pos.node != NULL, "node not set\n" );
1821 hr = WsSetWriterPosition( writer, &pos, NULL );
1822 ok( hr == S_OK, "got %08x\n", hr );
1824 /* different buffer */
1825 hr = WsCreateXmlBuffer( heap, NULL, 0, &buf2, NULL );
1826 ok( hr == S_OK, "got %08x\n", hr );
1828 pos.buffer = buf2;
1829 hr = WsSetWriterPosition( writer, &pos, NULL );
1830 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1832 hr = WsSetOutputToBuffer( writer, buf1, NULL, 0, NULL );
1833 ok( hr == S_OK, "got %08x\n", hr );
1835 /* try to write at non-final position */
1836 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1837 ok( hr == S_OK, "got %08x\n", hr );
1839 pos.buffer = pos.node = NULL;
1840 hr = WsGetWriterPosition( writer, &pos, NULL );
1841 ok( hr == S_OK, "got %08x\n", hr );
1842 ok( pos.buffer == buf1, "wrong buffer\n" );
1843 ok( pos.node != NULL, "node not set\n" );
1845 hr = WsWriteEndElement( writer, NULL );
1846 ok( hr == S_OK, "got %08x\n", hr );
1847 check_output_buffer( buf1, "<t/>", __LINE__ );
1849 hr = WsSetWriterPosition( writer, &pos, NULL );
1850 ok( hr == S_OK, "got %08x\n", hr );
1852 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
1853 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1855 WsFreeWriter( writer );
1856 WsFreeHeap( heap );
1859 static void test_WsWriteXmlBuffer(void)
1861 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
1862 WS_XML_WRITER *writer1, *writer2;
1863 WS_XML_BUFFER *buffer1, *buffer2;
1864 WS_HEAP *heap;
1865 HRESULT hr;
1867 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1868 ok( hr == S_OK, "got %08x\n", hr );
1870 hr = WsCreateXmlBuffer( NULL, NULL, 0, NULL, NULL );
1871 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1873 hr = WsCreateWriter( NULL, 0, &writer1, NULL );
1874 ok( hr == S_OK, "got %08x\n", hr );
1876 hr = WsCreateXmlBuffer( heap, NULL, 0, NULL, NULL );
1877 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1879 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer1, NULL );
1880 ok( hr == S_OK, "got %08x\n", hr );
1882 hr = WsSetOutputToBuffer( writer1, buffer1, NULL, 0, NULL );
1883 ok( hr == S_OK, "got %08x\n", hr );
1885 hr = WsWriteStartElement( writer1, NULL, &localname, &ns, NULL );
1886 ok( hr == S_OK, "got %08x\n", hr );
1888 hr = WsWriteEndElement( writer1, NULL );
1889 ok( hr == S_OK, "got %08x\n", hr );
1890 check_output_buffer( buffer1, "<t/>", __LINE__ );
1892 hr = WsCreateWriter( NULL, 0, &writer2, NULL );
1893 ok( hr == S_OK, "got %08x\n", hr );
1895 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer2, NULL );
1896 ok( hr == S_OK, "got %08x\n", hr );
1898 hr = WsSetOutputToBuffer( writer2, buffer2, NULL, 0, NULL );
1899 ok( hr == S_OK, "got %08x\n", hr );
1901 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1902 ok( hr == S_OK, "got %08x\n", hr );
1903 check_output_buffer( buffer2, "<t/>", __LINE__ );
1905 hr = WsMoveWriter( writer2, WS_MOVE_TO_PREVIOUS_ELEMENT, NULL, NULL );
1906 todo_wine ok( hr == S_OK, "got %08x\n", hr );
1908 hr = WsWriteXmlBuffer( writer2, buffer1, NULL );
1909 todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
1911 WsFreeWriter( writer1 );
1912 WsFreeWriter( writer2 );
1913 WsFreeHeap( heap );
1916 static void test_WsWriteNode(void)
1918 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {4, (BYTE *)"attr"}, ns = {0, NULL};
1919 WS_XML_WRITER *writer;
1920 WS_XML_BUFFER *buffer;
1921 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
1922 WS_XML_ATTRIBUTE attr, *attrs[1];
1923 WS_XML_ELEMENT_NODE elem;
1924 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
1925 WS_XML_NODE node;
1926 WS_XML_TEXT_NODE text = {{WS_XML_NODE_TYPE_TEXT}};
1927 WS_HEAP *heap;
1928 HRESULT hr;
1930 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
1931 ok( hr == S_OK, "got %08x\n", hr );
1933 hr = WsWriteNode( NULL, NULL, NULL );
1934 ok( hr == E_INVALIDARG, "got %08x\n", hr );
1936 hr = WsCreateWriter( NULL, 0, &writer, NULL );
1937 ok( hr == S_OK, "got %08x\n", hr );
1939 hr = WsWriteNode( writer, NULL, NULL );
1940 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
1942 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
1943 ok( hr == S_OK, "got %08x\n", hr );
1945 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
1946 ok( hr == S_OK, "got %08x\n", hr );
1948 utf8.value.bytes = (BYTE *)"value";
1949 utf8.value.length = sizeof("value") - 1;
1951 attr.singleQuote = TRUE;
1952 attr.isXmlNs = FALSE;
1953 attr.prefix = NULL;
1954 attr.localName = &localname2;
1955 attr.ns = &ns;
1956 attr.value = &utf8.text;
1957 attrs[0] = &attr;
1959 elem.node.nodeType = WS_XML_NODE_TYPE_ELEMENT;
1960 elem.prefix = NULL;
1961 elem.localName = &localname;
1962 elem.ns = &ns;
1963 elem.attributeCount = 1;
1964 elem.attributes = attrs;
1965 elem.isEmpty = FALSE;
1966 hr = WsWriteNode( writer, &elem.node, NULL );
1967 ok( hr == S_OK, "got %08x\n", hr );
1969 comment.value.bytes = (BYTE *)"comment";
1970 comment.value.length = sizeof("comment") - 1;
1971 hr = WsWriteNode( writer, &comment.node, NULL );
1972 ok( hr == S_OK, "got %08x\n", hr );
1974 node.nodeType = WS_XML_NODE_TYPE_EOF;
1975 hr = WsWriteNode( writer, &node, NULL );
1976 ok( hr == S_OK, "got %08x\n", hr );
1978 node.nodeType = WS_XML_NODE_TYPE_BOF;
1979 hr = WsWriteNode( writer, &node, NULL );
1980 ok( hr == S_OK, "got %08x\n", hr );
1982 node.nodeType = WS_XML_NODE_TYPE_CDATA;
1983 hr = WsWriteNode( writer, &node, NULL );
1984 ok( hr == S_OK, "got %08x\n", hr );
1986 utf8.value.bytes = (BYTE *)"cdata";
1987 utf8.value.length = sizeof("cdata") - 1;
1988 text.text = &utf8.text;
1989 hr = WsWriteNode( writer, &text.node, NULL );
1990 ok( hr == S_OK, "got %08x\n", hr );
1992 node.nodeType = WS_XML_NODE_TYPE_END_CDATA;
1993 hr = WsWriteNode( writer, &node, NULL );
1994 ok( hr == S_OK, "got %08x\n", hr );
1996 utf8.value.bytes = (BYTE *)"text";
1997 utf8.value.length = sizeof("text") - 1;
1998 hr = WsWriteNode( writer, &text.node, NULL );
1999 ok( hr == S_OK, "got %08x\n", hr );
2001 node.nodeType = WS_XML_NODE_TYPE_END_ELEMENT;
2002 hr = WsWriteNode( writer, &node, NULL );
2003 ok( hr == S_OK, "got %08x\n", hr );
2004 check_output_buffer( buffer, "<t attr='value'><!--comment--><![CDATA[cdata]]>text</t>", __LINE__ );
2006 WsFreeWriter( writer );
2007 WsFreeHeap( heap );
2010 static HRESULT set_input( WS_XML_READER *reader, const char *data, ULONG size )
2012 WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_AUTO};
2013 WS_XML_READER_BUFFER_INPUT buf = {{WS_XML_READER_INPUT_TYPE_BUFFER}, (void *)data, size};
2014 return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
2017 static void test_WsCopyNode(void)
2019 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"}, ns = {0, NULL};
2020 WS_XML_NODE_POSITION pos, pos2;
2021 const WS_XML_NODE *node;
2022 WS_XML_WRITER *writer;
2023 WS_XML_READER *reader;
2024 WS_XML_BUFFER *buffer;
2025 WS_BUFFERS bufs;
2026 WS_HEAP *heap;
2027 HRESULT hr;
2029 hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
2030 ok( hr == S_OK, "got %08x\n", hr );
2032 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2033 ok( hr == S_OK, "got %08x\n", hr );
2035 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
2036 ok( hr == S_OK, "got %08x\n", hr );
2038 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
2039 ok( hr == S_OK, "got %08x\n", hr );
2041 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2042 ok( hr == S_OK, "got %08x\n", hr );
2044 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
2045 ok( hr == S_OK, "got %08x\n", hr );
2047 hr = WsWriteEndElement( writer, NULL );
2048 ok( hr == S_OK, "got %08x\n", hr );
2050 hr = WsGetWriterPosition( writer, &pos, NULL );
2051 ok( hr == S_OK, "got %08x\n", hr );
2053 hr = WsWriteEndElement( writer, NULL );
2054 ok( hr == S_OK, "got %08x\n", hr );
2055 check_output_buffer( buffer, "<t><u/></t>", __LINE__ );
2057 hr = WsCreateReader( NULL, 0, &reader, NULL );
2058 ok( hr == S_OK, "got %08x\n", hr );
2060 hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
2061 ok( hr == S_OK, "got %08x\n", hr );
2063 hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
2064 ok( hr == S_OK, "got %08x\n", hr );
2066 hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
2067 ok( hr == S_OK, "got %08x\n", hr );
2069 hr = WsSetWriterPosition( writer, &pos, NULL );
2070 ok( hr == S_OK, "got %08x\n", hr );
2072 hr = WsCopyNode( writer, reader, NULL );
2073 ok( hr == S_OK, "got %08x\n", hr );
2074 check_output_buffer( buffer, "<t><u/><v/></t>", __LINE__ );
2076 hr = WsGetWriterPosition( writer, &pos2, NULL );
2077 ok( hr == S_OK, "got %08x\n", hr );
2078 ok( pos2.buffer == pos.buffer, "wrong buffer\n" );
2079 ok( pos2.node == pos.node, "wrong node\n" );
2081 hr = WsGetReaderNode( reader, &node, NULL );
2082 ok( hr == S_OK, "got %08x\n", hr );
2083 ok( node->nodeType == WS_XML_NODE_TYPE_EOF, "got %u\n", node->nodeType );
2085 /* reader positioned at EOF */
2086 hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
2087 ok( hr == S_OK, "got %08x\n", hr );
2089 hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
2090 ok( hr == S_OK, "got %08x\n", hr );
2092 hr = WsCopyNode( writer, reader, NULL );
2093 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2095 /* reader positioned at BOF */
2096 hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
2097 ok( hr == S_OK, "got %08x\n", hr );
2099 hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
2100 ok( hr == S_OK, "got %08x\n", hr );
2102 hr = WsGetReaderNode( reader, &node, NULL );
2103 ok( hr == S_OK, "got %08x\n", hr );
2104 ok( node->nodeType == WS_XML_NODE_TYPE_BOF, "got %u\n", node->nodeType );
2106 hr = set_output( writer );
2107 ok( hr == S_OK, "got %08x\n", hr );
2109 hr = WsCopyNode( writer, reader, NULL );
2110 ok( hr == S_OK, "got %08x\n", hr );
2111 check_output( writer, "<v/>", __LINE__ );
2113 hr = WsGetReaderNode( reader, &node, NULL );
2114 ok( hr == S_OK, "got %08x\n", hr );
2115 ok( node->nodeType == WS_XML_NODE_TYPE_EOF, "got %u\n", node->nodeType );
2117 memset( &bufs, 0, sizeof(bufs) );
2118 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BUFFERS, &bufs, sizeof(bufs), NULL );
2119 ok( hr == S_OK, "got %08x\n", hr );
2120 ok( bufs.bufferCount == 1, "got %u\n", bufs.bufferCount );
2121 ok( bufs.buffers != NULL, "buffers not set\n" );
2123 /* reader positioned at BOF, single text node */
2124 hr = set_input( reader, "text", sizeof("text") - 1 );
2125 ok( hr == S_OK, "got %08x\n", hr );
2127 hr = WsGetReaderNode( reader, &node, NULL );
2128 ok( hr == S_OK, "got %08x\n", hr );
2129 ok( node->nodeType == WS_XML_NODE_TYPE_BOF, "got %u\n", node->nodeType );
2131 hr = set_output( writer );
2132 ok( hr == S_OK, "got %08x\n", hr );
2134 hr = WsCopyNode( writer, reader, NULL );
2135 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
2137 WsFreeReader( reader );
2138 WsFreeWriter( writer );
2139 WsFreeHeap( heap );
2142 static void test_text_types(void)
2144 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"};
2145 WS_XML_STRING ns = {0, NULL}, ns2 = {2, (BYTE *)"ns"};
2146 WS_XML_WRITER *writer;
2147 static const WS_XML_UTF8_TEXT val_utf8 = { {WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"utf8"} };
2148 static WS_XML_UTF16_TEXT val_utf16 = { {WS_XML_TEXT_TYPE_UTF16} };
2149 static WS_XML_QNAME_TEXT val_qname = { {WS_XML_TEXT_TYPE_QNAME} };
2150 static const WS_XML_GUID_TEXT val_guid = { {WS_XML_TEXT_TYPE_GUID} };
2151 static const WS_XML_UNIQUE_ID_TEXT val_urn = { {WS_XML_TEXT_TYPE_UNIQUE_ID} };
2152 static const WS_XML_BOOL_TEXT val_bool = { {WS_XML_TEXT_TYPE_BOOL}, TRUE };
2153 static const WS_XML_INT32_TEXT val_int32 = { {WS_XML_TEXT_TYPE_INT32}, -2147483647 - 1 };
2154 static const WS_XML_INT64_TEXT val_int64 = { {WS_XML_TEXT_TYPE_INT64}, -9223372036854775807 - 1 };
2155 static const WS_XML_UINT64_TEXT val_uint64 = { {WS_XML_TEXT_TYPE_UINT64}, ~0 };
2156 static const WS_XML_DATETIME_TEXT val_datetime = { {WS_XML_TEXT_TYPE_DATETIME}, {0, WS_DATETIME_FORMAT_UTC} };
2157 static const WS_XML_DOUBLE_TEXT val_double = { {WS_XML_TEXT_TYPE_DOUBLE}, 1.1 };
2158 static const WS_XML_BASE64_TEXT val_base64 = { {WS_XML_TEXT_TYPE_BASE64}, (BYTE *)"test", 4 };
2159 static const struct
2161 const WS_XML_TEXT *text;
2162 const char *result;
2164 tests[] =
2166 { &val_utf8.text, "<t>utf8</t>" },
2167 { &val_utf16.text, "<t>utf16</t>" },
2168 { &val_guid.text, "<t>00000000-0000-0000-0000-000000000000</t>" },
2169 { &val_urn.text, "<t>urn:uuid:00000000-0000-0000-0000-000000000000</t>" },
2170 { &val_bool.text, "<t>true</t>" },
2171 { &val_int32.text, "<t>-2147483648</t>" },
2172 { &val_int64.text, "<t>-9223372036854775808</t>" },
2173 { &val_uint64.text, "<t>18446744073709551615</t>" },
2174 { &val_datetime.text, "<t>0001-01-01T00:00:00Z</t>" },
2175 { &val_double.text, "<t>1.1</t>" },
2176 { &val_base64.text, "<t>dGVzdA==</t>" },
2177 { &val_qname.text, "<t>u</t>" },
2179 HRESULT hr;
2180 ULONG i;
2182 val_utf16.bytes = (BYTE *)L"utf16";
2183 val_utf16.byteCount = 10;
2184 val_qname.localName = &localname2;
2185 val_qname.ns = &ns;
2187 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2188 ok( hr == S_OK, "got %08x\n", hr );
2190 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2192 hr = set_output( writer );
2193 ok( hr == S_OK, "got %08x\n", hr );
2194 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2195 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2197 hr = WsWriteText( writer, tests[i].text, NULL );
2198 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2200 hr = WsWriteEndElement( writer, NULL );
2201 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2202 check_output( writer, tests[i].result, __LINE__ );
2205 hr = set_output( writer );
2206 ok( hr == S_OK, "got %08x\n", hr );
2207 hr = WsWriteStartElement( writer, &prefix, &localname, &ns2, NULL );
2208 ok( hr == S_OK, "got %08x\n", hr );
2210 val_qname.prefix = &prefix;
2211 val_qname.localName = &localname2;
2212 val_qname.ns = &ns2;
2213 hr = WsWriteText( writer, &val_qname.text, NULL );
2214 ok( hr == S_OK, "got %08x\n", hr );
2216 hr = WsWriteEndElement( writer, NULL );
2217 ok( hr == S_OK, "got %08x\n", hr );
2218 check_output( writer, "<p:t xmlns:p=\"ns\">p:u</p:t>", __LINE__ );
2220 WsFreeWriter( writer );
2223 static void test_double(void)
2225 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2226 unsigned int fpword, fpword_orig;
2227 static const struct
2229 double val;
2230 const char *result;
2232 tests[] =
2234 {0.0, "<t>0</t>"},
2235 {1.0, "<t>1</t>"},
2236 {-1.0, "<t>-1</t>"},
2237 {1.0000000000000001, "<t>1</t>"},
2238 {1.0000000000000002, "<t>1.0000000000000002</t>"},
2239 {1.0000000000000003, "<t>1.0000000000000002</t>"},
2240 {1.0000000000000004, "<t>1.0000000000000004</t>"},
2241 {100000000000000, "<t>100000000000000</t>"},
2242 {1000000000000000, "<t>1E+15</t>"},
2243 {0.1, "<t>0.1</t>"},
2244 {0.01, "<t>1E-2</t>"},
2245 {-0.1, "<t>-0.1</t>"},
2246 {-0.01, "<t>-1E-2</t>"},
2247 {1.7976931348623158e308, "<t>1.7976931348623157E+308</t>"},
2248 {-1.7976931348623158e308, "<t>-1.7976931348623157E+308</t>"},
2250 HRESULT hr;
2251 WS_XML_WRITER *writer;
2252 WS_XML_DOUBLE_TEXT text;
2253 ULONG i;
2255 hr = WsCreateWriter( NULL, 0, &writer, NULL ) ;
2256 ok( hr == S_OK, "got %08x\n", hr );
2258 text.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
2259 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2261 hr = set_output( writer );
2262 ok( hr == S_OK, "got %08x\n", hr );
2263 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2264 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2266 text.value = tests[i].val;
2267 hr = WsWriteText( writer, &text.text, NULL );
2268 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2270 hr = WsWriteEndElement( writer, NULL );
2271 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2272 check_output( writer, tests[i].result, __LINE__ );
2275 hr = set_output( writer );
2276 ok( hr == S_OK, "got %08x\n", hr );
2277 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2278 ok( hr == S_OK, "got %08x\n", hr );
2280 text.value = NAN;
2281 hr = WsWriteText( writer, &text.text, NULL );
2282 ok( hr == S_OK, "got %08x\n", hr );
2284 hr = WsWriteEndElement( writer, NULL );
2285 ok( hr == S_OK, "got %08x\n", hr );
2286 check_output( writer, "<t>NaN</t>", __LINE__ );
2288 hr = set_output( writer );
2289 ok( hr == S_OK, "got %08x\n", hr );
2290 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2291 ok( hr == S_OK, "got %08x\n", hr );
2293 text.value = INFINITY;
2294 hr = WsWriteText( writer, &text.text, NULL );
2295 ok( hr == S_OK, "got %08x\n", hr );
2297 hr = WsWriteEndElement( writer, NULL );
2298 ok( hr == S_OK, "got %08x\n", hr );
2299 check_output( writer, "<t>INF</t>", __LINE__ );
2301 hr = set_output( writer );
2302 ok( hr == S_OK, "got %08x\n", hr );
2303 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2304 ok( hr == S_OK, "got %08x\n", hr );
2306 text.value = -INFINITY;
2307 hr = WsWriteText( writer, &text.text, NULL );
2308 ok( hr == S_OK, "got %08x\n", hr );
2310 hr = WsWriteEndElement( writer, NULL );
2311 ok( hr == S_OK, "got %08x\n", hr );
2312 check_output( writer, "<t>-INF</t>", __LINE__ );
2314 fpword_orig = _control87( 0, 0 );
2315 fpword = _control87( _MCW_EM | _RC_CHOP | _PC_64, _MCW_EM | _MCW_RC | _MCW_PC );
2316 ok( fpword == (_MCW_EM | _RC_CHOP | _PC_64), "got %08x\n", fpword );
2318 hr = set_output( writer );
2319 ok( hr == S_OK, "got %08x\n", hr );
2320 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2321 ok( hr == S_OK, "got %08x\n", hr );
2323 text.value = 100000000000000;
2324 hr = WsWriteText( writer, &text.text, NULL );
2325 ok( hr == S_OK, "got %08x\n", hr );
2327 hr = WsWriteEndElement( writer, NULL );
2328 ok( hr == S_OK, "got %08x\n", hr );
2329 check_output( writer, "<t>100000000000000</t>", __LINE__ );
2331 fpword = _control87( 0, 0 );
2332 ok( fpword == (_MCW_EM | _RC_CHOP | _PC_64), "got %08x\n", fpword );
2333 _control87( fpword_orig, _MCW_EM | _MCW_RC | _MCW_PC );
2335 WsFreeWriter( writer );
2338 static void test_field_options(void)
2340 static const char expected[] =
2341 "<t><bool a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/><int32>-1</int32>"
2342 "<xmlstr a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/></t>";
2343 HRESULT hr;
2344 WS_XML_WRITER *writer;
2345 WS_STRUCT_DESCRIPTION s;
2346 WS_FIELD_DESCRIPTION f, f2, f3, f4, f5, *fields[5];
2347 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}, str_guid = {4, (BYTE *)"guid"};
2348 WS_XML_STRING str_int32 = {5, (BYTE *)"int32"}, str_bool = {4, (BYTE *)"bool"};
2349 WS_XML_STRING str_xmlstr = {6, (BYTE *)"xmlstr"}, str_str = {3, (BYTE *)"str"};
2350 INT32 val = -1;
2351 struct test
2353 GUID guid;
2354 BOOL *bool_ptr;
2355 INT32 *int32_ptr;
2356 WS_XML_STRING xmlstr;
2357 WCHAR *str;
2358 } test;
2360 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2361 ok( hr == S_OK, "got %08x\n", hr );
2363 hr = set_output( writer );
2364 ok( hr == S_OK, "got %08x\n", hr );
2366 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2367 ok( hr == S_OK, "got %08x\n", hr );
2369 memset( &f, 0, sizeof(f) );
2370 f.mapping = WS_ELEMENT_FIELD_MAPPING;
2371 f.localName = &str_guid;
2372 f.ns = &ns;
2373 f.type = WS_GUID_TYPE;
2374 f.options = WS_FIELD_OPTIONAL;
2375 fields[0] = &f;
2377 memset( &f2, 0, sizeof(f2) );
2378 f2.mapping = WS_ELEMENT_FIELD_MAPPING;
2379 f2.localName = &str_bool;
2380 f2.offset = FIELD_OFFSET(struct test, bool_ptr);
2381 f2.ns = &ns;
2382 f2.type = WS_BOOL_TYPE;
2383 f2.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2384 fields[1] = &f2;
2386 memset( &f3, 0, sizeof(f3) );
2387 f3.mapping = WS_ELEMENT_FIELD_MAPPING;
2388 f3.localName = &str_int32;
2389 f3.offset = FIELD_OFFSET(struct test, int32_ptr);
2390 f3.ns = &ns;
2391 f3.type = WS_INT32_TYPE;
2392 f3.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE;
2393 fields[2] = &f3;
2395 memset( &f4, 0, sizeof(f4) );
2396 f4.mapping = WS_ELEMENT_FIELD_MAPPING;
2397 f4.localName = &str_xmlstr;
2398 f4.offset = FIELD_OFFSET(struct test, xmlstr);
2399 f4.ns = &ns;
2400 f4.type = WS_XML_STRING_TYPE;
2401 f4.options = WS_FIELD_NILLABLE;
2402 fields[3] = &f4;
2404 memset( &f5, 0, sizeof(f5) );
2405 f5.mapping = WS_ELEMENT_FIELD_MAPPING;
2406 f5.localName = &str_str;
2407 f5.offset = FIELD_OFFSET(struct test, str);
2408 f5.ns = &ns;
2409 f5.type = WS_WSZ_TYPE;
2410 f5.options = WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE;
2411 fields[4] = &f5;
2413 memset( &s, 0, sizeof(s) );
2414 s.size = sizeof(struct test);
2415 s.alignment = TYPE_ALIGNMENT(struct test);
2416 s.fields = fields;
2417 s.fieldCount = 5;
2419 memset( &test, 0, sizeof(test) );
2420 test.int32_ptr = &val;
2421 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
2422 &test, sizeof(test), NULL );
2423 ok( hr == S_OK, "got %08x\n", hr );
2425 hr = WsWriteEndElement( writer, NULL );
2426 ok( hr == S_OK, "got %08x\n", hr );
2427 check_output( writer, expected, __LINE__ );
2429 WsFreeWriter( writer );
2432 static void test_WsWriteText(void)
2434 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
2435 HRESULT hr;
2436 WS_XML_WRITER *writer;
2437 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2438 WS_XML_UTF16_TEXT utf16 = {{WS_XML_TEXT_TYPE_UTF16}};
2439 WS_XML_GUID_TEXT guid = {{WS_XML_TEXT_TYPE_GUID}};
2441 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2442 ok( hr == S_OK, "got %08x\n", hr );
2444 hr = set_output( writer );
2445 ok( hr == S_OK, "got %08x\n", hr );
2447 utf8.value.bytes = (BYTE *)"test";
2448 utf8.value.length = 4;
2449 hr = WsWriteText( writer, &utf8.text, NULL );
2450 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
2452 hr = set_output( writer );
2453 ok( hr == S_OK, "got %08x\n", hr );
2455 /* element, utf8 */
2456 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2457 ok( hr == S_OK, "got %08x\n", hr );
2459 hr = WsWriteText( writer, &utf8.text, NULL );
2460 ok( hr == S_OK, "got %08x\n", hr );
2461 check_output( writer, "<t>test", __LINE__ );
2463 utf8.value.bytes = (BYTE *)"tset";
2464 hr = WsWriteText( writer, &utf8.text, NULL );
2465 ok( hr == S_OK, "got %08x\n", hr );
2466 check_output( writer, "<t>testtset", __LINE__ );
2468 hr = WsWriteEndElement( writer, NULL );
2469 ok( hr == S_OK, "got %08x\n", hr );
2470 check_output( writer, "<t>testtset</t>", __LINE__ );
2472 hr = set_output( writer );
2473 ok( hr == S_OK, "got %08x\n", hr );
2475 /* attribute, utf8 */
2476 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2477 ok( hr == S_OK, "got %08x\n", hr );
2479 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2480 ok( hr == S_OK, "got %08x\n", hr );
2482 hr = WsWriteText( writer, &utf8.text, NULL );
2483 ok( hr == S_OK, "got %08x\n", hr );
2484 check_output( writer, "", __LINE__ );
2486 utf8.value.bytes = (BYTE *)"test";
2487 hr = WsWriteText( writer, &utf8.text, NULL );
2488 ok( hr == S_OK, "got %08x\n", hr );
2489 check_output( writer, "", __LINE__ );
2491 hr = WsWriteEndAttribute( writer, NULL );
2492 ok( hr == S_OK, "got %08x\n", hr );
2494 hr = WsWriteEndElement( writer, NULL );
2495 ok( hr == S_OK, "got %08x\n", hr );
2496 check_output( writer, "<t a=\"tsettest\"/>", __LINE__ );
2498 hr = set_output( writer );
2499 ok( hr == S_OK, "got %08x\n", hr );
2501 /* element, utf16 */
2502 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2503 ok( hr == S_OK, "got %08x\n", hr );
2505 utf16.bytes = (BYTE *)L"test";
2506 utf16.byteCount = 8;
2507 hr = WsWriteText( writer, &utf16.text, NULL );
2508 ok( hr == S_OK, "got %08x\n", hr );
2509 check_output( writer, "<t>test", __LINE__ );
2511 hr = WsWriteText( writer, &utf16.text, NULL );
2512 ok( hr == S_OK, "got %08x\n", hr );
2513 check_output( writer, "<t>testtest", __LINE__ );
2515 hr = WsWriteEndElement( writer, NULL );
2516 ok( hr == S_OK, "got %08x\n", hr );
2517 check_output( writer, "<t>testtest</t>", __LINE__ );
2519 hr = set_output( writer );
2520 ok( hr == S_OK, "got %08x\n", hr );
2522 /* attribute, utf16 */
2523 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2524 ok( hr == S_OK, "got %08x\n", hr );
2526 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2527 ok( hr == S_OK, "got %08x\n", hr );
2529 hr = WsWriteText( writer, &utf16.text, NULL );
2530 ok( hr == S_OK, "got %08x\n", hr );
2531 check_output( writer, "", __LINE__ );
2533 hr = WsWriteText( writer, &utf16.text, NULL );
2534 ok( hr == S_OK, "got %08x\n", hr );
2535 check_output( writer, "", __LINE__ );
2537 hr = WsWriteEndAttribute( writer, NULL );
2538 ok( hr == S_OK, "got %08x\n", hr );
2540 hr = WsWriteEndElement( writer, NULL );
2541 ok( hr == S_OK, "got %08x\n", hr );
2542 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
2544 hr = set_output( writer );
2545 ok( hr == S_OK, "got %08x\n", hr );
2547 /* element, guid */
2548 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2549 ok( hr == S_OK, "got %08x\n", hr );
2551 hr = WsWriteText( writer, &guid.text, NULL );
2552 ok( hr == S_OK, "got %08x\n", hr );
2553 check_output( writer, "<t>00000000-0000-0000-0000-000000000000", __LINE__ );
2555 hr = WsWriteText( writer, &guid.text, NULL );
2556 ok( hr == S_OK, "got %08x\n", hr );
2557 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000",
2558 __LINE__ );
2560 /* continue with different text type */
2561 hr = WsWriteText( writer, &utf8.text, NULL );
2562 ok( hr == S_OK, "got %08x\n", hr );
2563 check_output( writer, "<t>00000000-0000-0000-0000-00000000000000000000-0000-0000-0000-000000000000test",
2564 __LINE__ );
2566 hr = WsWriteEndElement( writer, NULL );
2567 ok( hr == S_OK, "got %08x\n", hr );
2569 hr = set_output( writer );
2570 ok( hr == S_OK, "got %08x\n", hr );
2572 /* attribute, guid */
2573 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2574 ok( hr == S_OK, "got %08x\n", hr );
2576 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2577 ok( hr == S_OK, "got %08x\n", hr );
2579 hr = WsWriteText( writer, &guid.text, NULL );
2580 ok( hr == S_OK, "got %08x\n", hr );
2581 check_output( writer, "", __LINE__ );
2583 hr = WsWriteText( writer, &guid.text, NULL );
2584 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2586 hr = set_output( writer );
2587 ok( hr == S_OK, "got %08x\n", hr );
2589 /* attribute, mix allowed text types */
2590 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2591 ok( hr == S_OK, "got %08x\n", hr );
2593 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
2594 ok( hr == S_OK, "got %08x\n", hr );
2596 hr = WsWriteText( writer, &utf8.text, NULL );
2597 ok( hr == S_OK, "got %08x\n", hr );
2599 hr = WsWriteText( writer, &utf16.text, NULL );
2600 todo_wine ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2602 hr = set_output( writer );
2603 ok( hr == S_OK, "got %08x\n", hr );
2605 /* cdata */
2606 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2607 ok( hr == S_OK, "got %08x\n", hr );
2608 hr = WsWriteStartCData( writer, NULL );
2609 ok( hr == S_OK, "got %08x\n", hr );
2611 hr = WsWriteText( writer, &utf8.text, NULL );
2612 ok( hr == S_OK, "got %08x\n", hr );
2614 hr = WsWriteText( writer, &guid.text, NULL );
2615 ok( hr == S_OK, "got %08x\n", hr );
2617 hr = WsWriteEndCData( writer, NULL );
2618 ok( hr == S_OK, "got %08x\n", hr );
2619 hr = WsWriteEndElement( writer, NULL );
2620 ok( hr == S_OK, "got %08x\n", hr );
2621 check_output( writer, "<t><![CDATA[test00000000-0000-0000-0000-000000000000]]></t>", __LINE__ );
2623 WsFreeWriter( writer );
2626 static void test_WsWriteArray(void)
2628 static const WS_XML_STRING localname = {4, (BYTE *)"item"}, localname2 = {5, (BYTE *)"array"};
2629 static const WS_XML_STRING ns = {0, NULL};
2630 WS_XML_WRITER *writer;
2631 BOOL array_bool[2];
2632 HRESULT hr;
2634 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2635 ok( hr == S_OK, "got %08x\n", hr );
2637 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2638 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
2640 hr = set_output( writer );
2641 ok( hr == S_OK, "got %08x\n", hr );
2642 hr = WsWriteArray( writer, NULL, NULL, 0, NULL, 0, 0, 0, NULL );
2643 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2645 hr = set_output( writer );
2646 ok( hr == S_OK, "got %08x\n", hr );
2647 hr = WsWriteArray( writer, &localname, NULL, 0, NULL, 0, 0, 0, NULL );
2648 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2650 hr = set_output( writer );
2651 ok( hr == S_OK, "got %08x\n", hr );
2652 hr = WsWriteArray( writer, &localname, &ns, 0, NULL, 0, 0, 0, NULL );
2653 ok( hr == S_OK, "got %08x\n", hr );
2654 check_output( writer, "", __LINE__ );
2656 hr = WsWriteArray( writer, &localname, &ns, ~0u, NULL, 0, 0, 0, NULL );
2657 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2659 hr = set_output( writer );
2660 ok( hr == S_OK, "got %08x\n", hr );
2661 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, 0, 0, 0, NULL );
2662 ok( hr == S_OK, "got %08x\n", hr );
2663 check_output( writer, "", __LINE__ );
2665 array_bool[0] = FALSE;
2666 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, 0, 0, 0, NULL );
2667 ok( hr == S_OK, "got %08x\n", hr );
2668 check_output( writer, "", __LINE__ );
2670 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 0, NULL );
2671 ok( hr == S_OK, "got %08x\n", hr );
2672 check_output( writer, "", __LINE__ );
2674 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 0, NULL );
2675 ok( hr == S_OK, "got %08x\n", hr );
2676 check_output( writer, "", __LINE__ );
2678 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, NULL, sizeof(array_bool), 0, 1, NULL );
2679 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2681 hr = set_output( writer );
2682 ok( hr == S_OK, "got %08x\n", hr );
2683 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 1, NULL );
2684 ok( hr == S_OK, "got %08x\n", hr );
2685 check_output( writer, "<item>false</item>", __LINE__ );
2687 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool) - 1, 0, 2, NULL );
2688 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2690 hr = set_output( writer );
2691 ok( hr == S_OK, "got %08x\n", hr );
2692 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 3, NULL );
2693 ok( hr == E_INVALIDARG, "got %08x\n", hr );
2695 hr = set_output( writer );
2696 ok( hr == S_OK, "got %08x\n", hr );
2698 hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
2699 ok( hr == S_OK, "got %08x\n", hr );
2701 array_bool[1] = TRUE;
2702 hr = WsWriteArray( writer, &localname, &ns, WS_BOOL_VALUE_TYPE, array_bool, sizeof(array_bool), 0, 2, NULL );
2703 ok( hr == S_OK, "got %08x\n", hr );
2705 hr = WsWriteEndElement( writer, NULL );
2706 ok( hr == S_OK, "got %08x\n", hr );
2707 check_output( writer, "<array><item>false</item><item>true</item></array>", __LINE__ );
2709 WsFreeWriter( writer );
2712 static void test_escapes(void)
2714 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2715 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
2716 WS_XML_WRITER *writer;
2717 struct test
2719 const char *text;
2720 const char *result;
2721 BOOL single;
2723 static const struct test tests_elem[] =
2725 { "<", "<t>&lt;</t>" },
2726 { ">", "<t>&gt;</t>" },
2727 { "\"", "<t>\"</t>" },
2728 { "&", "<t>&amp;</t>" },
2729 { "&&", "<t>&amp;&amp;</t>" },
2730 { "'", "<t>'</t>" },
2732 static const struct test tests_attr[] =
2734 { "<", "<t t=\"&lt;\"/>" },
2735 { ">", "<t t=\">\"/>" },
2736 { "\"", "<t t=\"&quot;\"/>" },
2737 { "&", "<t t=\"&amp;\"/>" },
2738 { "'", "<t t=\"'\"/>" },
2739 { "\"", "<t t='\"'/>", TRUE },
2740 { "'", "<t t='&apos;'/>", TRUE },
2742 static const struct test tests_cdata[] =
2744 { "<", "<t><![CDATA[<]]></t>" },
2745 { ">", "<t><![CDATA[>]]></t>" },
2746 { "\"", "<t><![CDATA[\"]]></t>" },
2747 { "&", "<t><![CDATA[&]]></t>" },
2748 { "[", "<t><![CDATA[[]]></t>" },
2749 { "]", "<t><![CDATA[]]]></t>" },
2750 { "'", "<t><![CDATA[']]></t>" },
2752 static const struct test tests_comment[] =
2754 { "<", "<t><!--<--></t>" },
2755 { ">", "<t><!-->--></t>" },
2756 { "\"", "<t><!--\"--></t>" },
2757 { "&", "<t><!--&--></t>" },
2758 { "'", "<t><!--'--></t>" },
2760 HRESULT hr;
2761 ULONG i;
2763 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2764 ok( hr == S_OK, "got %08x\n", hr );
2766 for (i = 0; i < ARRAY_SIZE( tests_elem ); i++)
2768 hr = set_output( writer );
2769 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2770 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2771 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2773 utf8.value.bytes = (BYTE *)tests_elem[i].text;
2774 utf8.value.length = strlen( tests_elem[i].text );
2775 hr = WsWriteText( writer, &utf8.text, NULL );
2776 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2778 hr = WsWriteEndElement( writer, NULL );
2779 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2780 check_output( writer, tests_elem[i].result, __LINE__ );
2783 for (i = 0; i < ARRAY_SIZE( tests_attr ); i++)
2785 hr = set_output( writer );
2786 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2787 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2788 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2790 hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, tests_attr[i].single, NULL );
2791 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2793 utf8.value.bytes = (BYTE *)tests_attr[i].text;
2794 utf8.value.length = strlen( tests_attr[i].text );
2795 hr = WsWriteText( writer, &utf8.text, NULL );
2796 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2798 hr = WsWriteEndAttribute( writer, NULL );
2799 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2801 hr = WsWriteEndElement( writer, NULL );
2802 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2803 check_output( writer, tests_attr[i].result, __LINE__ );
2806 for (i = 0; i < ARRAY_SIZE( tests_cdata ); i++)
2808 hr = set_output( writer );
2809 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2810 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2811 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2813 hr = WsWriteStartCData( writer, NULL );
2814 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2816 utf8.value.bytes = (BYTE *)tests_cdata[i].text;
2817 utf8.value.length = strlen( tests_cdata[i].text );
2818 hr = WsWriteText( writer, &utf8.text, NULL );
2819 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2821 hr = WsWriteEndCData( writer, NULL );
2822 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2824 hr = WsWriteEndElement( writer, NULL );
2825 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2826 check_output( writer, tests_cdata[i].result, __LINE__ );
2829 for (i = 0; i < ARRAY_SIZE( tests_comment ); i++)
2831 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
2833 hr = set_output( writer );
2834 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2835 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2836 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2838 comment.value.bytes = (BYTE *)tests_comment[i].text;
2839 comment.value.length = strlen( tests_comment[i].text );
2840 hr = WsWriteNode( writer, &comment.node, NULL );
2841 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2843 hr = WsWriteEndElement( writer, NULL );
2844 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2845 check_output( writer, tests_comment[i].result, __LINE__ );
2848 WsFreeWriter( writer );
2851 static void test_write_option(void)
2853 static const WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2854 WS_XML_WRITER *writer;
2855 int val_int = -1, val_int_zero = 0, *ptr_int = &val_int, *ptr_int_null = NULL;
2856 const WCHAR *ptr_wsz = L"s", *ptr_wsz_null = NULL;
2857 static const WS_XML_STRING val_xmlstr = {1, (BYTE *)"x"}, val_xmlstr_zero = {0, NULL};
2858 const WS_XML_STRING *ptr_xmlstr = &val_xmlstr, *ptr_xmlstr_null = NULL;
2859 struct
2861 WS_TYPE type;
2862 WS_WRITE_OPTION option;
2863 const void *value;
2864 ULONG size;
2865 HRESULT hr;
2866 const char *result;
2868 tests[] =
2870 { WS_INT32_TYPE, 0, NULL, 0, E_INVALIDARG },
2871 { WS_INT32_TYPE, 0, "str", 0, E_INVALIDARG },
2872 { WS_INT32_TYPE, 0, NULL, sizeof(val_int), E_INVALIDARG },
2873 { WS_INT32_TYPE, 0, &val_int, sizeof(val_int), E_INVALIDARG },
2874 { WS_INT32_TYPE, 0, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2875 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2876 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, 0, E_INVALIDARG },
2877 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2878 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, sizeof(val_int), S_OK, "<t>-1</t>" },
2879 { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int_zero, sizeof(val_int_zero), S_OK, "<t>0</t>" },
2880 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, 0, E_INVALIDARG },
2881 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, 0, E_INVALIDARG },
2882 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(val_int), E_INVALIDARG },
2883 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, sizeof(val_int), E_INVALIDARG },
2884 { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG },
2885 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2886 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, 0, E_INVALIDARG },
2887 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2888 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2889 { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int_null, sizeof(ptr_int_null), E_INVALIDARG },
2890 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2891 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, 0, E_INVALIDARG },
2892 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG },
2893 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "<t>-1</t>" },
2894 { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int_null, sizeof(ptr_int_null), S_OK,
2895 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2896 { WS_XML_STRING_TYPE, 0, NULL, 0, E_INVALIDARG },
2897 { WS_XML_STRING_TYPE, 0, &val_xmlstr, 0, E_INVALIDARG },
2898 { WS_XML_STRING_TYPE, 0, NULL, sizeof(val_xmlstr), E_INVALIDARG },
2899 { WS_XML_STRING_TYPE, 0, &val_xmlstr, sizeof(val_xmlstr), E_INVALIDARG },
2900 { WS_XML_STRING_TYPE, 0, &val_xmlstr_zero, sizeof(val_xmlstr_zero), E_INVALIDARG },
2901 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG },
2902 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2903 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2904 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, sizeof(val_xmlstr), S_OK, "<t>x</t>" },
2905 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, "<t/>" },
2906 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, 0, E_INVALIDARG },
2907 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG },
2908 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, sizeof(&val_xmlstr), E_INVALIDARG },
2909 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK,
2910 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2911 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2912 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2913 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2914 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2915 { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), E_INVALIDARG },
2916 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2917 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, 0, E_INVALIDARG },
2918 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG },
2919 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "<t>x</t>" },
2920 { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), S_OK,
2921 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2922 { WS_WSZ_TYPE, 0, NULL, 0, E_INVALIDARG },
2923 { WS_WSZ_TYPE, 0, &ptr_wsz, 0, E_INVALIDARG },
2924 { WS_WSZ_TYPE, 0, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2925 { WS_WSZ_TYPE, 0, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2926 { WS_WSZ_TYPE, 0, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2927 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2928 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG },
2929 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG },
2930 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2931 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2932 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2933 { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG },
2934 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG },
2935 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, 0, E_INVALIDARG },
2936 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG },
2937 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "<t>s</t>" },
2938 { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), S_OK,
2939 "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
2941 HRESULT hr;
2942 ULONG i;
2944 hr = WsCreateWriter( NULL, 0, &writer, NULL );
2945 ok( hr == S_OK, "got %08x\n", hr );
2947 for (i = 0; i < ARRAY_SIZE( tests ); i++)
2949 hr = set_output( writer );
2950 ok( hr == S_OK, "%u: got %08x\n", i, hr );
2951 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
2952 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL, tests[i].option, tests[i].value,
2953 tests[i].size, NULL );
2954 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
2955 WsWriteEndElement( writer, NULL );
2956 if (hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
2959 WsFreeWriter( writer );
2962 static BOOL check_result( WS_XML_WRITER *writer, const char *expected )
2964 WS_BYTES bytes;
2965 ULONG size = sizeof(bytes);
2966 int len = strlen( expected );
2968 memset( &bytes, 0, sizeof(bytes) );
2969 WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
2970 if (bytes.length != len) return FALSE;
2971 return !memcmp( bytes.bytes, expected, len );
2974 static void test_datetime(void)
2976 WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
2977 static const struct
2979 unsigned __int64 ticks;
2980 WS_DATETIME_FORMAT format;
2981 HRESULT hr;
2982 const char *result;
2983 const char *result2;
2984 HRESULT hr_broken;
2986 tests[] =
2988 { 0, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00Z</t>" },
2989 { 0, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00+00:00</t>" },
2990 { 0, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00</t>" },
2991 { 1, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0001-01-01T00:00:00.0000001Z</t>" },
2992 { 1, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:00:00.0000001+00:00</t>" },
2993 { 1, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.0000001</t>" },
2994 { 10, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.000001</t>" },
2995 { 1000000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:00.1</t>" },
2996 { 0x23c34600, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T00:01:00+00:00</t>" },
2997 { 0x861c46800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T01:00:00+00:00</t>" },
2998 { 0x430e234000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T08:00:00+00:00</t>" },
2999 { 0x4b6fe7a800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>0001-01-01T09:00:00+00:00</t>" },
3000 { 0x989680, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:00:01</t>" },
3001 { 0x23c34600, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T00:01:00</t>" },
3002 { 0x861c46800, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-01T01:00:00</t>" },
3003 { 0xc92a69c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0001-01-02T00:00:00</t>" },
3004 { 0x11ed178c6c000, WS_DATETIME_FORMAT_NONE, S_OK, "<t>0002-01-01T00:00:00</t>" },
3005 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_UTC, S_OK, "<t>9999-12-31T23:59:59.9999999Z</t>" },
3006 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>9999-12-31T15:59:59.9999999-08:00</t>",
3007 "<t>9999-12-31T17:59:59.9999999-06:00</t>" /* win7 */, WS_E_INVALID_FORMAT },
3008 { 0x2bca2875f4373fff, WS_DATETIME_FORMAT_NONE, S_OK, "<t>9999-12-31T23:59:59.9999999</t>" },
3009 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_UTC, WS_E_INVALID_FORMAT },
3010 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_LOCAL, WS_E_INVALID_FORMAT },
3011 { 0x2bca2875f4374000, WS_DATETIME_FORMAT_NONE, WS_E_INVALID_FORMAT },
3012 { 0x8d3123e7df74000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>2015-12-31T16:00:00-08:00</t>",
3013 "<t>2015-12-31T18:00:00-06:00</t>" /* win7 */ },
3014 { 0x701ce1722770000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00+00:00</t>" },
3015 { 0x701ce5a309a4000, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:00:00-08:00</t>",
3016 "<t>1601-01-01T02:00:00-06:00</t>" /* win7 */ },
3017 { 0x701ce5e617c7400, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T00:30:00-08:00</t>",
3018 "<t>1601-01-01T02:30:00-06:00</t>" /* win7 */ },
3019 { 0x701ce51ced5d800, WS_DATETIME_FORMAT_LOCAL, S_OK, "<t>1601-01-01T07:00:00+00:00</t>",
3020 "<t>1601-01-01T01:00:00-06:00</t>" /* win7 */ },
3021 { 0, WS_DATETIME_FORMAT_NONE + 1, WS_E_INVALID_FORMAT },
3022 { 0x38a080649c000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-28T00:00:00Z</t>" },
3023 { 0x38ad130b38000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>0004-02-29T00:00:00Z</t>" },
3024 { 0x8c1505f0e438000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2000-02-29T00:00:00Z</t>" },
3025 { 0x8d46035e7870000, WS_DATETIME_FORMAT_UTC, S_OK, "<t>2017-03-01T00:00:00Z</t>" },
3027 HRESULT hr;
3028 WS_XML_WRITER *writer;
3029 WS_DATETIME date;
3030 ULONG i;
3032 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3033 ok( hr == S_OK, "got %08x\n", hr );
3034 for (i = 0; i < ARRAY_SIZE( tests ); i++)
3036 hr = set_output( writer );
3037 ok( hr == S_OK, "got %08x\n", hr );
3039 date.ticks = tests[i].ticks;
3040 date.format = tests[i].format;
3041 WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3042 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_DATETIME_TYPE, NULL, WS_WRITE_REQUIRED_VALUE,
3043 &date, sizeof(date), NULL );
3044 WsWriteEndElement( writer, NULL );
3045 ok( hr == tests[i].hr || broken(hr == tests[i].hr_broken), "%u: got %08x\n", i, hr );
3046 if (hr != tests[i].hr && hr == tests[i].hr_broken) break;
3047 if (hr == S_OK)
3049 ok( check_result( writer, tests[i].result ) ||
3050 (tests[i].result2 && broken(check_result( writer, tests[i].result2 ))),
3051 "%u: wrong result\n", i );
3055 WsFreeWriter( writer );
3058 static void test_repeating_element(void)
3060 WS_XML_STRING localname = {4, (BYTE *)"test"}, ns = {0, NULL}, data = {4, (BYTE *)"data"};
3061 WS_XML_STRING val = {3, (BYTE *)"val"}, wrapper = {7, (BYTE *)"wrapper"}, structval = {9, (BYTE *)"structval"};
3062 HRESULT hr;
3063 WS_XML_WRITER *writer;
3064 WS_STRUCT_DESCRIPTION s, s2;
3065 WS_FIELD_DESCRIPTION f, f2, *fields[1], *fields2[1];
3066 WS_ITEM_RANGE range;
3067 struct test
3069 const WCHAR **val;
3070 ULONG count;
3071 } *test;
3072 struct test2
3074 INT32 *val;
3075 ULONG count;
3076 } *test2;
3077 struct value
3079 INT32 data;
3080 } value;
3081 struct test3
3083 const struct value **val;
3084 ULONG count;
3085 } *test3;
3087 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3088 ok( hr == S_OK, "got %08x\n", hr );
3090 /* array of strings, wrapper */
3091 hr = set_output( writer );
3092 ok( hr == S_OK, "got %08x\n", hr );
3093 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3094 ok( hr == S_OK, "got %08x\n", hr );
3096 memset( &f, 0, sizeof(f) );
3097 f.mapping = WS_REPEATING_ELEMENT_FIELD_MAPPING;
3098 f.localName = &wrapper;
3099 f.ns = &ns;
3100 f.type = WS_WSZ_TYPE;
3101 f.countOffset = FIELD_OFFSET(struct test, count);
3102 f.itemLocalName = &val;
3103 f.itemNs = &ns;
3104 fields[0] = &f;
3106 memset( &s, 0, sizeof(s) );
3107 s.size = sizeof(struct test);
3108 s.alignment = TYPE_ALIGNMENT(struct test);
3109 s.typeLocalName = &localname;
3110 s.typeNs = &ns;
3111 s.fields = fields;
3112 s.fieldCount = 1;
3114 hr = set_output( writer );
3115 ok( hr == S_OK, "got %08x\n", hr );
3116 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3117 ok( hr == S_OK, "got %08x\n", hr );
3119 test = HeapAlloc( GetProcessHeap(), 0, sizeof(*test) + 2 * sizeof(const WCHAR *) );
3120 test->val = (const WCHAR **)(test + 1);
3121 test->val[0] = L"1";
3122 test->val[1] = L"2";
3123 test->count = 2;
3124 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3125 WS_WRITE_REQUIRED_POINTER, &test, sizeof(test), NULL );
3126 ok( hr == S_OK, "got %08x\n", hr );
3127 hr = WsWriteEndElement( writer, NULL );
3128 ok( hr == S_OK, "got %08x\n", hr );
3129 check_output( writer, "<test><wrapper><val>1</val><val>2</val></wrapper></test>", __LINE__ );
3130 HeapFree( GetProcessHeap(), 0, test );
3132 /* array of integers, no wrapper */
3133 hr = set_output( writer );
3134 ok( hr == S_OK, "got %08x\n", hr );
3135 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3136 ok( hr == S_OK, "got %08x\n", hr );
3138 f.type = WS_INT32_TYPE;
3139 f.localName = NULL;
3140 f.ns = NULL;
3142 test2 = HeapAlloc( GetProcessHeap(), 0, sizeof(*test2) + 2 * sizeof(INT32) );
3143 test2->val = (INT32 *)(test2 + 1);
3144 test2->val[0] = 1;
3145 test2->val[1] = 2;
3146 test2->count = 2;
3147 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3148 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3149 ok( hr == S_OK, "got %08x\n", hr );
3150 hr = WsWriteEndElement( writer, NULL );
3151 ok( hr == S_OK, "got %08x\n", hr );
3152 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3154 /* item range has no effect */
3155 hr = set_output( writer );
3156 ok( hr == S_OK, "got %08x\n", hr );
3157 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3158 ok( hr == S_OK, "got %08x\n", hr );
3160 range.minItemCount = 0;
3161 range.maxItemCount = 0;
3162 f.itemRange = &range;
3164 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3165 WS_WRITE_REQUIRED_POINTER, &test2, sizeof(test2), NULL );
3166 ok( hr == S_OK, "got %08x\n", hr );
3167 hr = WsWriteEndElement( writer, NULL );
3168 ok( hr == S_OK, "got %08x\n", hr );
3169 check_output( writer, "<test><val>1</val><val>2</val></test>", __LINE__ );
3170 HeapFree( GetProcessHeap(), 0, test2 );
3172 /* nillable item */
3173 hr = set_output( writer );
3174 ok( hr == S_OK, "got %08x\n", hr );
3175 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3176 ok( hr == S_OK, "got %08x\n", hr );
3178 memset( &f2, 0, sizeof(f2) );
3179 f2.mapping = WS_ELEMENT_FIELD_MAPPING;
3180 f2.localName = &data;
3181 f2.ns = &ns;
3182 f2.type = WS_INT32_TYPE;
3183 fields2[0] = &f2;
3185 memset( &s2, 0, sizeof(s2) );
3186 s2.size = sizeof(struct test3);
3187 s2.alignment = TYPE_ALIGNMENT(struct test3);
3188 s2.typeLocalName = &structval;
3189 s2.typeNs = &ns;
3190 s2.fields = fields2;
3191 s2.fieldCount = 1;
3193 f.type = WS_STRUCT_TYPE;
3194 f.typeDescription = &s2;
3195 f.localName = &wrapper;
3196 f.ns = &ns;
3197 f.itemRange = NULL;
3198 f.options = WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM;
3200 value.data = -1;
3201 test3 = HeapAlloc( GetProcessHeap(), 0, sizeof(*test3) + 2 * sizeof(const struct value *) );
3202 test3->val = (const struct value **)(test3 + 1);
3203 test3->val[0] = &value;
3204 test3->val[1] = NULL;
3205 test3->count = 2;
3207 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
3208 WS_WRITE_REQUIRED_POINTER, &test3, sizeof(test3), NULL );
3209 ok( hr == S_OK, "got %08x\n", hr );
3210 hr = WsWriteEndElement( writer, NULL );
3211 ok( hr == S_OK, "got %08x\n", hr );
3212 check_output( writer, "<test><wrapper><val><data>-1</data></val><val a:nil=\"true\" "
3213 "xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/></wrapper></test>", __LINE__ );
3214 HeapFree( GetProcessHeap(), 0, test3 );
3216 WsFreeWriter( writer );
3219 static const WS_XML_STRING *init_xmlstring( const char *src, WS_XML_STRING *str )
3221 if (!src) return NULL;
3222 str->length = strlen( src );
3223 str->bytes = (BYTE *)src;
3224 str->dictionary = NULL;
3225 str->id = 0;
3226 return str;
3229 static void test_WsWriteQualifiedName(void)
3231 WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {1, (BYTE *)"t"}, ns = {2, (BYTE *)"ns"};
3232 WS_XML_WRITER *writer;
3233 HRESULT hr;
3234 ULONG i;
3235 static const struct
3237 const char *prefix;
3238 const char *localname;
3239 const char *ns;
3240 HRESULT hr;
3241 const char *result;
3242 } tests[] =
3244 { NULL, NULL, NULL, E_INVALIDARG, NULL },
3245 { NULL, "t2", NULL, E_INVALIDARG, NULL },
3246 { "p2", "t2", NULL, S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3247 { NULL, "t2", "ns2", WS_E_INVALID_FORMAT, NULL },
3248 { NULL, "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t2" },
3249 { "p2", "t2", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3250 { "p2", "t2", "ns", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3251 { "p", "t", NULL, S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3252 { NULL, "t", "ns", S_OK, "<p:t xmlns:p=\"ns\">p:t" },
3253 { "p2", "", "", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3254 { "p2", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">p2:" },
3255 { "p2", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">p2:t2" },
3256 { "", "t2", "", S_OK, "<p:t xmlns:p=\"ns\">t2" },
3257 { "", "", "ns2", S_OK, "<p:t xmlns:p=\"ns\">" },
3258 { "", "", "", S_OK, "<p:t xmlns:p=\"ns\">" },
3261 hr = WsWriteQualifiedName( NULL, NULL, NULL, NULL, NULL );
3262 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3264 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3265 ok( hr == S_OK, "got %08x\n", hr );
3267 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3268 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3270 hr = set_output( writer );
3271 ok( hr == S_OK, "got %08x\n", hr );
3273 hr = WsWriteQualifiedName( writer, NULL, NULL, NULL, NULL );
3274 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3276 for (i = 0; i < ARRAY_SIZE( tests ); i++)
3278 WS_XML_STRING prefix2, localname2, ns2;
3279 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3281 hr = set_output( writer );
3282 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3284 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
3285 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3287 prefix_ptr = init_xmlstring( tests[i].prefix, &prefix2 );
3288 localname_ptr = init_xmlstring( tests[i].localname, &localname2 );
3289 ns_ptr = init_xmlstring( tests[i].ns, &ns2 );
3291 hr = WsWriteQualifiedName( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3292 ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
3293 if (tests[i].hr == S_OK && hr == S_OK) check_output( writer, tests[i].result, __LINE__ );
3296 WsFreeWriter( writer );
3299 static void test_WsWriteBytes(void)
3301 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3302 WS_XML_WRITER *writer;
3303 HRESULT hr;
3305 hr = WsWriteBytes( NULL, NULL, 0, NULL );
3306 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3308 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3309 ok( hr == S_OK, "got %08x\n", hr );
3311 hr = WsWriteBytes( writer, NULL, 0, NULL );
3312 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3314 hr = WsWriteBytes( writer, "test", 0, NULL );
3315 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3317 hr = WsWriteBytes( writer, NULL, 1, NULL );
3318 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3320 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3321 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3323 hr = set_output( writer );
3324 ok( hr == S_OK, "got %08x\n", hr );
3326 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3327 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3329 hr = set_output( writer );
3330 ok( hr == S_OK, "got %08x\n", hr );
3332 /* element */
3333 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3334 ok( hr == S_OK, "got %08x\n", hr );
3336 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3337 ok( hr == S_OK, "got %08x\n", hr );
3339 hr = WsWriteEndElement( writer, NULL );
3340 ok( hr == S_OK, "got %08x\n", hr );
3341 check_output( writer, "<t>dGVzdAA=</t>", __LINE__ );
3343 hr = set_output( writer );
3344 ok( hr == S_OK, "got %08x\n", hr );
3346 /* attribute */
3347 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3348 ok( hr == S_OK, "got %08x\n", hr );
3350 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3351 ok( hr == S_OK, "got %08x\n", hr );
3353 hr = WsWriteBytes( writer, "test", sizeof("test"), NULL );
3354 ok( hr == S_OK, "got %08x\n", hr );
3356 hr = WsWriteEndAttribute( writer, NULL );
3357 ok( hr == S_OK, "got %08x\n", hr );
3359 hr = WsWriteEndElement( writer, NULL );
3360 ok( hr == S_OK, "got %08x\n", hr );
3361 check_output( writer, "<t a=\"dGVzdAA=\"/>", __LINE__ );
3363 WsFreeWriter( writer );
3366 static void test_WsWriteChars(void)
3368 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3369 WS_XML_WRITER *writer;
3370 HRESULT hr;
3372 hr = WsWriteChars( NULL, NULL, 0, NULL );
3373 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3375 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3376 ok( hr == S_OK, "got %08x\n", hr );
3378 hr = WsWriteChars( writer, NULL, 0, NULL );
3379 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3381 hr = WsWriteChars( writer, L"test", 0, NULL );
3382 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3384 hr = WsWriteChars( writer, NULL, 1, NULL );
3385 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3387 hr = WsWriteChars( writer, L"test", 4, NULL );
3388 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3390 hr = set_output( writer );
3391 ok( hr == S_OK, "got %08x\n", hr );
3393 hr = WsWriteChars( writer, L"test", 4, NULL );
3394 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3396 hr = set_output( writer );
3397 ok( hr == S_OK, "got %08x\n", hr );
3399 /* element */
3400 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3401 ok( hr == S_OK, "got %08x\n", hr );
3403 hr = WsWriteChars( writer, L"test", 4, NULL );
3404 ok( hr == S_OK, "got %08x\n", hr );
3406 hr = WsWriteChars( writer, L"test", 4, NULL );
3407 ok( hr == S_OK, "got %08x\n", hr );
3409 hr = WsWriteEndElement( writer, NULL );
3410 ok( hr == S_OK, "got %08x\n", hr );
3411 check_output( writer, "<t>testtest</t>", __LINE__ );
3413 hr = set_output( writer );
3414 ok( hr == S_OK, "got %08x\n", hr );
3416 /* attribute */
3417 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3418 ok( hr == S_OK, "got %08x\n", hr );
3420 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3421 ok( hr == S_OK, "got %08x\n", hr );
3423 hr = WsWriteChars( writer, L"test", 4, NULL );
3424 ok( hr == S_OK, "got %08x\n", hr );
3426 hr = WsWriteChars( writer, L"test", 4, NULL );
3427 ok( hr == S_OK, "got %08x\n", hr );
3429 hr = WsWriteEndAttribute( writer, NULL );
3430 ok( hr == S_OK, "got %08x\n", hr );
3432 hr = WsWriteEndElement( writer, NULL );
3433 ok( hr == S_OK, "got %08x\n", hr );
3434 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3436 WsFreeWriter( writer );
3439 static void test_WsWriteCharsUtf8(void)
3441 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"}, ns = {0, NULL};
3442 static const BYTE test[] = {'t','e','s','t'};
3443 WS_XML_WRITER *writer;
3444 HRESULT hr;
3446 hr = WsWriteCharsUtf8( NULL, NULL, 0, NULL );
3447 ok( hr == E_INVALIDARG, "got %08x\n", hr );
3449 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3450 ok( hr == S_OK, "got %08x\n", hr );
3452 hr = WsWriteCharsUtf8( writer, NULL, 0, NULL );
3453 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3455 hr = WsWriteCharsUtf8( writer, test, 0, NULL );
3456 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3458 hr = WsWriteCharsUtf8( writer, NULL, 1, NULL );
3459 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3461 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3462 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
3464 hr = set_output( writer );
3465 ok( hr == S_OK, "got %08x\n", hr );
3467 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3468 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
3470 hr = set_output( writer );
3471 ok( hr == S_OK, "got %08x\n", hr );
3473 /* element */
3474 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3475 ok( hr == S_OK, "got %08x\n", hr );
3477 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3478 ok( hr == S_OK, "got %08x\n", hr );
3480 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3481 ok( hr == S_OK, "got %08x\n", hr );
3483 hr = WsWriteEndElement( writer, NULL );
3484 ok( hr == S_OK, "got %08x\n", hr );
3485 check_output( writer, "<t>testtest</t>", __LINE__ );
3487 hr = set_output( writer );
3488 ok( hr == S_OK, "got %08x\n", hr );
3490 /* attribute */
3491 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3492 ok( hr == S_OK, "got %08x\n", hr );
3494 hr = WsWriteStartAttribute( writer, NULL, &localname2, &ns, FALSE, NULL );
3495 ok( hr == S_OK, "got %08x\n", hr );
3497 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3498 ok( hr == S_OK, "got %08x\n", hr );
3500 hr = WsWriteCharsUtf8( writer, test, sizeof(test), NULL );
3501 ok( hr == S_OK, "got %08x\n", hr );
3503 hr = WsWriteEndAttribute( writer, NULL );
3504 ok( hr == S_OK, "got %08x\n", hr );
3506 hr = WsWriteEndElement( writer, NULL );
3507 ok( hr == S_OK, "got %08x\n", hr );
3508 check_output( writer, "<t a=\"testtest\"/>", __LINE__ );
3510 WsFreeWriter( writer );
3513 static void check_output_bin( WS_XML_WRITER *writer, const char *expected, int len, unsigned int line )
3515 WS_BYTES bytes;
3516 ULONG size = sizeof(bytes);
3517 HRESULT hr;
3519 memset( &bytes, 0, sizeof(bytes) );
3520 hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
3521 ok( hr == S_OK, "%u: got %08x\n", line, hr );
3522 ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
3523 if (bytes.length != len) return;
3524 ok( !memcmp( bytes.bytes, expected, bytes.length ), "%u: got %s expected %s\n", line,
3525 debugstr_bytes(bytes.bytes, bytes.length), debugstr_bytes((const BYTE *)expected, len) );
3528 static void test_binary_encoding(void)
3530 static const char res[] =
3531 {0x40,0x01,'t',0x01};
3532 static const char res2[] =
3533 {0x6d,0x01,'t',0x09,0x01,'p',0x02,'n','s',0x01};
3534 static const char res3[] =
3535 {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x01};
3536 static const char res4[] =
3537 {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x99,0x04,'t','e','s','t'};
3538 static const char res100[] =
3539 {0x40,0x01,'t',0x04,0x01,'t',0x98,0x00,0x01};
3540 static const char res101[] =
3541 {0x40,0x01,'t',0x35,0x01,'t',0x98,0x00,0x09,0x01,'p',0x02,'n','s',0x01};
3542 static const char res102[] =
3543 {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x00,0x09,0x02,'p','2',0x02,'n','s',0x01};
3544 static const char res103[] =
3545 {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x04,'t','e','s','t',0x09,0x02,'p','2',0x02,'n','s',0x01};
3546 static const char res200[] =
3547 {0x02,0x07,'c','o','m','m','e','n','t'};
3548 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
3549 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
3550 static const char prefix[] = "p", prefix2[] = "p2";
3551 static const char localname[] = "t", ns[] = "ns";
3552 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3553 WS_XML_STRING str, str2, str3, localname2 = {1, (BYTE *)"t"}, empty = {0, NULL};
3554 WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
3555 WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
3556 WS_XML_WRITER *writer;
3557 HRESULT hr;
3558 ULONG i;
3559 static const struct
3561 const char *prefix;
3562 const char *localname;
3563 const char *ns;
3564 const char *text;
3565 const char *result;
3566 int len_result;
3568 elem_tests[] =
3570 { NULL, localname, "", NULL, res, sizeof(res) }, /* short element */
3571 { prefix, localname, ns, NULL, res2, sizeof(res2) }, /* one character prefix element */
3572 { prefix2, localname, ns, NULL, res3, sizeof(res3) }, /* element */
3573 { prefix2, localname, ns, "test", res4, sizeof(res4) }, /* element with text */
3575 static const struct
3577 const char *prefix;
3578 const char *localname;
3579 const char *ns;
3580 const char *value;
3581 const char *result;
3582 int len_result;
3584 attr_tests[] =
3586 { NULL, localname, "", NULL, res100, sizeof(res100) }, /* short attribute */
3587 { prefix, localname, ns, NULL, res101, sizeof(res101) }, /* one character prefix attribute */
3588 { prefix2, localname, ns, NULL, res102, sizeof(res102) }, /* attribute */
3589 { prefix2, localname, ns, "test", res103, sizeof(res103) }, /* attribute with value */
3592 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3593 ok( hr == S_OK, "got %08x\n", hr );
3595 for (i = 0; i < ARRAY_SIZE( elem_tests ); i++)
3597 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3598 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3600 prefix_ptr = init_xmlstring( elem_tests[i].prefix, &str );
3601 localname_ptr = init_xmlstring( elem_tests[i].localname, &str2 );
3602 ns_ptr = init_xmlstring( elem_tests[i].ns, &str3 );
3604 hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3605 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3606 if (elem_tests[i].text)
3608 utf8.value.length = strlen( elem_tests[i].text );
3609 utf8.value.bytes = (BYTE *)elem_tests[i].text;
3610 hr = WsWriteText( writer, &utf8.text, NULL );
3611 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3613 hr = WsWriteEndElement( writer, NULL );
3614 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3615 if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
3618 for (i = 0; i < ARRAY_SIZE( attr_tests ); i++)
3620 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3621 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3623 prefix_ptr = init_xmlstring( attr_tests[i].prefix, &str );
3624 localname_ptr = init_xmlstring( attr_tests[i].localname, &str2 );
3625 ns_ptr = init_xmlstring( elem_tests[i].ns, &str3 );
3627 hr = WsWriteStartElement( writer, NULL, &localname2, &empty, NULL );
3628 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3629 hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
3630 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3631 if (attr_tests[i].value)
3633 utf8.value.length = strlen( attr_tests[i].value );
3634 utf8.value.bytes = (BYTE *)attr_tests[i].value;
3635 hr = WsWriteText( writer, &utf8.text, NULL );
3636 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3638 hr = WsWriteEndAttribute( writer, NULL );
3639 ok( hr == S_OK, "got %08x\n", hr );
3640 hr = WsWriteEndElement( writer, NULL );
3641 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3642 if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
3645 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3646 ok( hr == S_OK, "got %08x\n", hr );
3648 comment.value.bytes = (BYTE *)"comment";
3649 comment.value.length = sizeof("comment") - 1;
3650 hr = WsWriteNode( writer, &comment.node, NULL );
3651 ok( hr == S_OK, "got %08x\n", hr );
3652 if (hr == S_OK) check_output_bin( writer, res200, sizeof(res200), __LINE__ );
3654 WsFreeWriter( writer );
3657 static void test_namespaces(void)
3659 WS_XML_STRING prefix = {1, (BYTE *)"p"}, prefix2 = {1, (BYTE *)"q"};
3660 WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"a"};
3661 WS_XML_STRING ns = {1, (BYTE *)"n"}, ns2 = {1, (BYTE *)"o"};
3662 WS_XML_WRITER *writer;
3663 HRESULT hr;
3665 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3666 ok( hr == S_OK, "got %08x\n", hr );
3668 hr = set_output( writer );
3669 ok( hr == S_OK, "got %08x\n", hr );
3670 hr = WsWriteStartElement( writer, &prefix, &localname, &ns, NULL );
3671 ok( hr == S_OK, "got %08x\n", hr );
3672 hr = WsWriteStartAttribute( writer, &prefix2, &localname2, &ns2, FALSE, NULL );
3673 ok( hr == S_OK, "got %08x\n", hr );
3674 hr = WsWriteEndAttribute( writer, NULL );
3675 ok( hr == S_OK, "got %08x\n", hr );
3676 hr = WsWriteEndElement( writer, NULL );
3677 ok( hr == S_OK, "got %08x\n", hr );
3678 check_output( writer, "<p:t q:a=\"\" xmlns:p=\"n\" xmlns:q=\"o\"/>", __LINE__ );
3680 WsFreeWriter( writer );
3683 static const WS_XML_STRING *init_xmlstring_dict( WS_XML_DICTIONARY *dict, ULONG id, WS_XML_STRING *str )
3685 if (id >= dict->stringCount) return NULL;
3686 str->length = dict->strings[id].length;
3687 str->bytes = dict->strings[id].bytes;
3688 str->dictionary = dict;
3689 str->id = id;
3690 return str;
3693 static HRESULT CALLBACK dict_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
3695 ULONG *call_count = state;
3697 (*call_count)++;
3698 switch (str->bytes[0])
3700 case 't':
3701 *id = 1;
3702 *found = TRUE;
3703 break;
3705 case 'n':
3706 *id = 2;
3707 *found = TRUE;
3708 break;
3710 case 'z':
3711 *id = 3;
3712 *found = TRUE;
3713 break;
3715 case 'v':
3716 *found = FALSE;
3717 return WS_E_OTHER;
3719 default:
3720 *found = FALSE;
3721 break;
3723 return S_OK;
3726 static void test_dictionary(void)
3728 static const char res[] =
3729 {0x42,0x04,0x01};
3730 static const char res2[] =
3731 {0x42,0x06,0x01};
3732 static const char res3[] =
3733 {0x53,0x06,0x0b,0x01,'p',0x0a,0x01};
3734 static const char res4[] =
3735 {0x43,0x02,'p','2',0x06,0x0b,0x02,'p','2',0x0a,0x01};
3736 static const char res5[] =
3737 {0x42,0x03,0x0a,0x05,0x01};
3738 static const char res6[] =
3739 {0x40,0x01,0x75,0x0a,0x05,0x01};
3740 static const char res7[] =
3741 {0x40,0x01,0x76,0x0a,0x05,0x01};
3742 static const char res8[] =
3743 {0x42,0x03,0x0a,0x05,0x01};
3744 static const char res9[] =
3745 {0x42,0x07,0x0a,0x05,0x01};
3746 static const char res10[] =
3747 {0x42,0xd6,0x03,0x0a,0x05,0x01};
3748 static const char res100[] =
3749 {0x42,0x06,0x06,0x06,0x98,0x00,0x01};
3750 static const char res101[] =
3751 {0x42,0x06,0x1b,0x06,0x98,0x00,0x0b,0x01,'p',0x0a,0x01};
3752 static const char res102[] =
3753 {0x42,0x06,0x07,0x02,'p','2',0x06,0x98,0x00,0x0b,0x02,'p','2',0x0a,0x01};
3754 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
3755 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
3756 WS_XML_STRING prefix, localname, ns, strings[6];
3757 const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
3758 WS_XML_DICTIONARY dict, *dict_builtin;
3759 WS_XML_WRITER *writer;
3760 HRESULT hr;
3761 ULONG i, call_count;
3762 static const struct
3764 ULONG prefix;
3765 ULONG localname;
3766 ULONG ns;
3767 const char *result;
3768 int len_result;
3770 elem_tests[] =
3772 { ~0u, 2, 0, res, sizeof(res) }, /* short dictionary element, invalid dict id */
3773 { ~0u, 3, 0, res2, sizeof(res2) }, /* short dictionary element */
3774 { 1, 3, 5, res3, sizeof(res3) }, /* single character prefix dictionary element */
3775 { 4, 3, 5, res4, sizeof(res4) }, /* dictionary element */
3777 static const struct
3779 ULONG prefix;
3780 ULONG localname;
3781 ULONG ns;
3782 const char *result;
3783 int len_result;
3785 attr_tests[] =
3787 { ~0u, 3, 0, res100, sizeof(res100) }, /* short dictionary attribute */
3788 { 1, 3, 5, res101, sizeof(res101) }, /* single character prefix dictionary attribute */
3789 { 4, 3, 5, res102, sizeof(res102) }, /* dictionary attribute */
3792 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3793 ok( hr == S_OK, "got %08x\n", hr );
3795 strings[0].length = 0;
3796 strings[0].bytes = NULL;
3797 strings[0].dictionary = &dict;
3798 strings[0].id = 0;
3799 strings[1].length = 1;
3800 strings[1].bytes = (BYTE *)"p";
3801 strings[1].dictionary = &dict;
3802 strings[1].id = 1;
3803 strings[2].length = 1;
3804 strings[2].bytes = (BYTE *)"t";
3805 strings[2].dictionary = &dict;
3806 strings[2].id = ~0u;
3807 strings[3].length = 1;
3808 strings[3].bytes = (BYTE *)"u";
3809 strings[3].dictionary = &dict;
3810 strings[3].id = 3;
3811 strings[4].length = 2;
3812 strings[4].bytes = (BYTE *)"p2";
3813 strings[4].dictionary = &dict;
3814 strings[4].id = 4;
3815 strings[5].length = 2;
3816 strings[5].bytes = (BYTE *)"ns";
3817 strings[5].dictionary = &dict;
3818 strings[5].id = 5;
3820 UuidCreate( &dict.guid );
3821 dict.strings = strings;
3822 dict.stringCount = ARRAY_SIZE( strings );
3823 dict.isConst = TRUE;
3825 bin.staticDictionary = &dict;
3827 for (i = 0; i < ARRAY_SIZE( elem_tests ); i++)
3829 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3830 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3832 prefix_ptr = init_xmlstring_dict( &dict, elem_tests[i].prefix, &prefix );
3833 localname_ptr = init_xmlstring_dict( &dict, elem_tests[i].localname, &localname );
3834 ns_ptr = init_xmlstring_dict( &dict, elem_tests[i].ns, &ns );
3836 hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
3837 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3838 hr = WsWriteEndElement( writer, NULL );
3839 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3840 if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
3843 for (i = 0; i < ARRAY_SIZE( attr_tests ); i++)
3845 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3846 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3848 prefix_ptr = init_xmlstring_dict( &dict, attr_tests[i].prefix, &prefix );
3849 localname_ptr = init_xmlstring_dict( &dict, attr_tests[i].localname, &localname );
3850 ns_ptr = init_xmlstring_dict( &dict, attr_tests[i].ns, &ns );
3852 hr = WsWriteStartElement( writer, NULL, &strings[3], &strings[0], NULL );
3853 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3854 hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
3855 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3856 hr = WsWriteEndAttribute( writer, NULL );
3857 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3858 hr = WsWriteEndElement( writer, NULL );
3859 ok( hr == S_OK, "%u: got %08x\n", i, hr );
3860 if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
3863 /* callback */
3864 bin.staticDictionary = NULL;
3865 bin.dynamicStringCallback = dict_cb;
3866 bin.dynamicStringCallbackState = &call_count;
3868 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3869 ok( hr == S_OK, "got %08x\n", hr );
3870 init_xmlstring( "t", &localname );
3871 init_xmlstring( "ns", &ns );
3872 call_count = 0;
3873 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3874 ok( hr == S_OK, "got %08x\n", hr );
3875 hr = WsWriteEndElement( writer, NULL );
3876 ok( hr == S_OK, "got %08x\n", hr );
3877 ok( call_count == 2, "got %u\n", call_count );
3878 check_output_bin( writer, res5, sizeof(res5), __LINE__ );
3880 /* unknown string */
3881 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3882 ok( hr == S_OK, "got %08x\n", hr );
3883 init_xmlstring( "u", &localname );
3884 init_xmlstring( "ns", &ns );
3885 call_count = 0;
3886 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3887 ok( hr == S_OK, "got %08x\n", hr );
3888 hr = WsWriteEndElement( writer, NULL );
3889 ok( hr == S_OK, "got %08x\n", hr );
3890 ok( call_count == 2, "got %u\n", call_count );
3891 check_output_bin( writer, res6, sizeof(res6), __LINE__ );
3893 /* unknown string, error return from callback */
3894 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3895 ok( hr == S_OK, "got %08x\n", hr );
3896 init_xmlstring( "v", &localname );
3897 init_xmlstring( "ns", &ns );
3898 call_count = 0;
3899 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3900 ok( hr == S_OK, "got %08x\n", hr );
3901 hr = WsWriteEndElement( writer, NULL );
3902 ok( hr == S_OK, "got %08x\n", hr );
3903 ok( call_count == 2, "got %u\n", call_count );
3904 check_output_bin( writer, res7, sizeof(res7), __LINE__ );
3906 /* dictionary and callback */
3907 hr = WsGetDictionary( WS_ENCODING_XML_BINARY_1, &dict_builtin, NULL );
3908 ok( hr == S_OK, "got %08x\n", hr );
3909 bin.staticDictionary = dict_builtin;
3911 /* string in dictionary, no string dictionary set */
3912 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3913 ok( hr == S_OK, "got %08x\n", hr );
3914 init_xmlstring( "t", &localname );
3915 init_xmlstring( "ns", &ns );
3916 call_count = 0;
3917 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3918 ok( hr == S_OK, "got %08x\n", hr );
3919 hr = WsWriteEndElement( writer, NULL );
3920 ok( hr == S_OK, "got %08x\n", hr );
3921 ok( call_count == 2, "got %u\n", call_count );
3922 check_output_bin( writer, res8, sizeof(res8), __LINE__ );
3924 /* string not in dictionary, no string dictionary set */
3925 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3926 ok( hr == S_OK, "got %08x\n", hr );
3927 init_xmlstring( "z", &localname );
3928 init_xmlstring( "ns", &ns );
3929 call_count = 0;
3930 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3931 ok( hr == S_OK, "got %08x\n", hr );
3932 hr = WsWriteEndElement( writer, NULL );
3933 ok( hr == S_OK, "got %08x\n", hr );
3934 ok( call_count == 2, "got %u\n", call_count );
3935 check_output_bin( writer, res9, sizeof(res9), __LINE__ );
3937 /* string in dictionary, string dictionary set */
3938 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
3939 ok( hr == S_OK, "got %08x\n", hr );
3940 init_xmlstring_dict( dict_builtin, 235, &localname );
3941 init_xmlstring( "ns", &ns );
3942 call_count = 0;
3943 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
3944 ok( hr == S_OK, "got %08x\n", hr );
3945 hr = WsWriteEndElement( writer, NULL );
3946 ok( hr == S_OK, "got %08x\n", hr );
3947 ok( call_count == 1, "got %u\n", call_count );
3948 check_output_bin( writer, res10, sizeof(res10), __LINE__ );
3950 WsFreeWriter( writer );
3953 static void test_union_type(void)
3955 static WS_XML_STRING str_ns = {0, NULL}, str_a = {1, (BYTE *)"a"}, str_b = {1, (BYTE *)"b"};
3956 static WS_XML_STRING str_none = {4, (BYTE *)"none"}, str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"};
3957 HRESULT hr;
3958 WS_XML_WRITER *writer;
3959 WS_UNION_DESCRIPTION u;
3960 WS_UNION_FIELD_DESCRIPTION f, f2, f3, *fields[3];
3961 WS_FIELD_DESCRIPTION f_struct, *fields_struct[1];
3962 WS_STRUCT_DESCRIPTION s;
3963 enum choice {CHOICE_A = 30, CHOICE_B = 20, CHOICE_C = 10, CHOICE_NONE = 0};
3964 ULONG index[2] = {1, 0};
3965 struct test
3967 enum choice choice;
3968 union
3970 const WCHAR *a;
3971 UINT32 b;
3972 BOOL none;
3973 } value;
3974 } test;
3976 hr = WsCreateWriter( NULL, 0, &writer, NULL );
3977 ok( hr == S_OK, "got %08x\n", hr );
3979 memset( &f, 0, sizeof(f) );
3980 f.value = CHOICE_A;
3981 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
3982 f.field.localName = &str_a;
3983 f.field.ns = &str_ns;
3984 f.field.type = WS_WSZ_TYPE;
3985 f.field.offset = FIELD_OFFSET(struct test, value.a);
3986 fields[0] = &f;
3988 memset( &f2, 0, sizeof(f2) );
3989 f2.value = CHOICE_B;
3990 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
3991 f2.field.localName = &str_b;
3992 f2.field.ns = &str_ns;
3993 f2.field.type = WS_UINT32_TYPE;
3994 f2.field.offset = FIELD_OFFSET(struct test, value.b);
3995 fields[1] = &f2;
3997 memset( &u, 0, sizeof(u) );
3998 u.size = sizeof(struct test);
3999 u.alignment = TYPE_ALIGNMENT(struct test);
4000 u.fields = fields;
4001 u.fieldCount = 2;
4002 u.enumOffset = FIELD_OFFSET(struct test, choice);
4003 u.noneEnumValue = CHOICE_NONE;
4005 memset( &f_struct, 0, sizeof(f_struct) );
4006 f_struct.mapping = WS_ELEMENT_CHOICE_FIELD_MAPPING;
4007 f_struct.type = WS_UNION_TYPE;
4008 f_struct.typeDescription = &u;
4009 fields_struct[0] = &f_struct;
4011 memset( &s, 0, sizeof(s) );
4012 s.size = sizeof(struct test);
4013 s.alignment = TYPE_ALIGNMENT(struct test);
4014 s.fields = fields_struct;
4015 s.fieldCount = 1;
4016 s.typeLocalName = &str_s;
4017 s.typeNs = &str_ns;
4019 hr = set_output( writer );
4020 ok( hr == S_OK, "got %08x\n", hr );
4021 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4022 ok( hr == S_OK, "got %08x\n", hr );
4023 test.choice = CHOICE_A;
4024 test.value.a = L"test";
4025 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4026 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4027 ok( hr == S_OK, "got %08x\n", hr );
4028 hr = WsWriteEndElement( writer, NULL );
4029 ok( hr == S_OK, "got %08x\n", hr );
4030 check_output( writer, "<t><a>test</a></t>", __LINE__ );
4032 u.valueIndices = index;
4033 hr = set_output( writer );
4034 ok( hr == S_OK, "got %08x\n", hr );
4035 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4036 ok( hr == S_OK, "got %08x\n", hr );
4037 test.choice = CHOICE_B;
4038 test.value.b = 123;
4039 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4040 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4041 ok( hr == S_OK, "got %08x\n", hr );
4042 hr = WsWriteEndElement( writer, NULL );
4043 ok( hr == S_OK, "got %08x\n", hr );
4044 check_output( writer, "<t><b>123</b></t>", __LINE__ );
4046 hr = set_output( writer );
4047 ok( hr == S_OK, "got %08x\n", hr );
4048 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4049 ok( hr == S_OK, "got %08x\n", hr );
4050 test.choice = CHOICE_C;
4051 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4052 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4053 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
4055 hr = set_output( writer );
4056 ok( hr == S_OK, "got %08x\n", hr );
4057 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4058 ok( hr == S_OK, "got %08x\n", hr );
4059 test.choice = CHOICE_NONE;
4060 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4061 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4062 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
4064 /* field value equals noneEnumValue */
4065 memset( &f3, 0, sizeof(f3) );
4066 f3.value = CHOICE_NONE;
4067 f3.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4068 f3.field.localName = &str_none;
4069 f3.field.ns = &str_ns;
4070 f3.field.type = WS_BOOL_TYPE;
4071 f3.field.offset = FIELD_OFFSET(struct test, value.none);
4072 fields[2] = &f3;
4074 u.fieldCount = 3;
4075 u.valueIndices = NULL;
4076 hr = set_output( writer );
4077 ok( hr == S_OK, "got %08x\n", hr );
4078 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4079 ok( hr == S_OK, "got %08x\n", hr );
4080 test.choice = CHOICE_NONE;
4081 test.value.none = TRUE;
4082 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4083 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4084 ok( hr == S_OK, "got %08x\n", hr );
4085 hr = WsWriteEndElement( writer, NULL );
4086 ok( hr == S_OK, "got %08x\n", hr );
4087 check_output( writer, "<t><none>true</none></t>", __LINE__ );
4089 hr = set_output( writer );
4090 ok( hr == S_OK, "got %08x\n", hr );
4091 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4092 ok( hr == S_OK, "got %08x\n", hr );
4093 f_struct.options = WS_FIELD_OPTIONAL;
4094 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4095 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4096 ok( hr == S_OK, "got %08x\n", hr );
4097 hr = WsWriteEndElement( writer, NULL );
4098 ok( hr == S_OK, "got %08x\n", hr );
4099 check_output( writer, "<t/>", __LINE__ );
4101 WsFreeWriter( writer );
4104 static void prepare_binary_type_test( WS_XML_WRITER *writer, const WS_XML_STRING *prefix,
4105 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4107 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
4108 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
4109 HRESULT hr;
4111 hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
4112 ok( hr == S_OK, "got %08x\n", hr );
4113 hr = WsWriteStartElement( writer, prefix, localname, ns, NULL );
4114 ok( hr == S_OK, "got %08x\n", hr );
4117 static void test_text_types_binary(void)
4119 static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"}, str_u = {1, (BYTE *)"u"};
4120 static WS_XML_STRING str_ns = {0, NULL};
4121 static const char res[] =
4122 {0x40,0x01,'t',0x40,0x01,'u',0x99,0x04,'t','e','s','t',0x01};
4123 static const char res2[] =
4124 {0x40,0x01,'t',0x40,0x01,'u',0x9e,0x03,'t','e','s',0x9f,0x01,'t',0x01};
4125 static const char res2a[] =
4126 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x03,'t','e','s',0x01};
4127 static const char res2b[] =
4128 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x01,'t',0x01};
4129 static const char res2c[] =
4130 {0x40,0x01,'t',0x40,0x01,'u',0x01,0x01};
4131 static const char res2d[] =
4132 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0xff,'a','a','a','a','a','a','a','a','a','a',
4133 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4134 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4135 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4136 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4137 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4138 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4139 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4140 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4141 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4142 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4143 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4144 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4145 'a','a','a','a','a',0x01};
4146 static const char res2e[] =
4147 {0x40,0x01,'t',0x40,0x01,'u',0x9e,0xff,'a','a','a','a','a','a','a','a','a','a',
4148 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4149 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4150 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4151 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4152 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4153 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4154 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4155 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4156 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4157 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4158 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4159 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4160 'a','a','a','a','a',0x9f,0x01,'a',0x01};
4161 static const char res2f[] =
4162 {0x40,0x01,'t',0x40,0x01,'u',0x9f,0x06,'t','e','s','t','t','e',0x01};
4163 static const char res3[] =
4164 {0x40,0x01,'t',0x40,0x01,'u',0x87,0x01};
4165 static const char res4[] =
4166 {0x40,0x01,'t',0x40,0x01,'u',0x89,0xff,0x01};
4167 static const char res5[] =
4168 {0x40,0x01,'t',0x40,0x01,'u',0x83,0x01};
4169 static const char res5b[] =
4170 {0x40,0x01,'t',0x40,0x01,'u',0x89,0x02,0x01};
4171 static const char res6[] =
4172 {0x40,0x01,'t',0x40,0x01,'u',0x81,0x01};
4173 static const char res7[] =
4174 {0x40,0x01,'t',0x40,0x01,'u',0x89,0x02,0x01};
4175 static const char res8[] =
4176 {0x40,0x01,'t',0x40,0x01,'u',0x93,0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x40,0x01};
4177 static const char res8a[] =
4178 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x7f,0x01};
4179 static const char res8b[] =
4180 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x01};
4181 static const char res8c[] =
4182 {0x40,0x01,'t',0x40,0x01,'u',0x93,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x7f,0x01};
4183 static const char res9[] =
4184 {0x40,0x01,'t',0x40,0x01,'u',0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4185 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4186 static const char res10[] =
4187 {0x40,0x01,'t',0x40,0x01,'u',0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4188 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4189 static const char res11[] =
4190 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01};
4191 static const char res11b[] =
4192 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01};
4193 static const char res11c[] =
4194 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
4195 static const char res11d[] =
4196 {0x40,0x01,'t',0x40,0x01,'u',0x97,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01};
4197 HRESULT hr;
4198 WS_XML_WRITER *writer;
4199 WS_UNION_DESCRIPTION u;
4200 WS_UNION_FIELD_DESCRIPTION f, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, *fields[11];
4201 WS_FIELD_DESCRIPTION f_struct, *fields_struct[1];
4202 WS_STRUCT_DESCRIPTION s;
4203 struct test
4205 WS_XML_TEXT_TYPE type;
4206 union
4208 WS_XML_STRING val_utf8;
4209 WS_STRING val_utf16;
4210 WS_BYTES val_bytes;
4211 BOOL val_bool;
4212 INT32 val_int32;
4213 INT64 val_int64;
4214 UINT64 val_uint64;
4215 double val_double;
4216 GUID val_guid;
4217 WS_UNIQUE_ID val_unique_id;
4218 WS_DATETIME val_datetime;
4219 } u;
4220 } test;
4221 BYTE buf[256];
4223 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4224 ok( hr == S_OK, "got %08x\n", hr );
4226 memset( &f, 0, sizeof(f) );
4227 f.value = WS_XML_TEXT_TYPE_UTF8;
4228 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4229 f.field.localName = &str_u;
4230 f.field.ns = &str_ns;
4231 f.field.type = WS_XML_STRING_TYPE;
4232 f.field.offset = FIELD_OFFSET(struct test, u.val_utf8);
4233 fields[0] = &f;
4235 memset( &f2, 0, sizeof(f2) );
4236 f2.value = WS_XML_TEXT_TYPE_UTF16;
4237 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4238 f2.field.localName = &str_u;
4239 f2.field.ns = &str_ns;
4240 f2.field.type = WS_STRING_TYPE;
4241 f2.field.offset = FIELD_OFFSET(struct test, u.val_utf16);
4242 fields[1] = &f2;
4244 memset( &f3, 0, sizeof(f3) );
4245 f3.value = WS_XML_TEXT_TYPE_BASE64;
4246 f3.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4247 f3.field.localName = &str_u;
4248 f3.field.ns = &str_ns;
4249 f3.field.type = WS_BYTES_TYPE;
4250 f3.field.offset = FIELD_OFFSET(struct test, u.val_bytes);
4251 fields[2] = &f3;
4253 memset( &f4, 0, sizeof(f4) );
4254 f4.value = WS_XML_TEXT_TYPE_BOOL;
4255 f4.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4256 f4.field.localName = &str_u;
4257 f4.field.ns = &str_ns;
4258 f4.field.type = WS_BOOL_TYPE;
4259 f4.field.offset = FIELD_OFFSET(struct test, u.val_bool);
4260 fields[3] = &f4;
4262 memset( &f5, 0, sizeof(f5) );
4263 f5.value = WS_XML_TEXT_TYPE_INT32;
4264 f5.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4265 f5.field.localName = &str_u;
4266 f5.field.ns = &str_ns;
4267 f5.field.type = WS_INT32_TYPE;
4268 f5.field.offset = FIELD_OFFSET(struct test, u.val_int32);
4269 fields[4] = &f5;
4271 memset( &f6, 0, sizeof(f6) );
4272 f6.value = WS_XML_TEXT_TYPE_INT64;
4273 f6.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4274 f6.field.localName = &str_u;
4275 f6.field.ns = &str_ns;
4276 f6.field.type = WS_INT64_TYPE;
4277 f6.field.offset = FIELD_OFFSET(struct test, u.val_int64);
4278 fields[5] = &f6;
4280 memset( &f7, 0, sizeof(f7) );
4281 f7.value = WS_XML_TEXT_TYPE_UINT64;
4282 f7.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4283 f7.field.localName = &str_u;
4284 f7.field.ns = &str_ns;
4285 f7.field.type = WS_UINT64_TYPE;
4286 f7.field.offset = FIELD_OFFSET(struct test, u.val_uint64);
4287 fields[6] = &f7;
4289 memset( &f8, 0, sizeof(f8) );
4290 f8.value = WS_XML_TEXT_TYPE_DOUBLE;
4291 f8.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4292 f8.field.localName = &str_u;
4293 f8.field.ns = &str_ns;
4294 f8.field.type = WS_DOUBLE_TYPE;
4295 f8.field.offset = FIELD_OFFSET(struct test, u.val_double);
4296 fields[7] = &f8;
4298 memset( &f9, 0, sizeof(f9) );
4299 f9.value = WS_XML_TEXT_TYPE_GUID;
4300 f9.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4301 f9.field.localName = &str_u;
4302 f9.field.ns = &str_ns;
4303 f9.field.type = WS_GUID_TYPE;
4304 f9.field.offset = FIELD_OFFSET(struct test, u.val_guid);
4305 fields[8] = &f9;
4307 memset( &f10, 0, sizeof(f10) );
4308 f10.value = WS_XML_TEXT_TYPE_UNIQUE_ID;
4309 f10.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4310 f10.field.localName = &str_u;
4311 f10.field.ns = &str_ns;
4312 f10.field.type = WS_UNIQUE_ID_TYPE;
4313 f10.field.offset = FIELD_OFFSET(struct test, u.val_unique_id);
4314 fields[9] = &f10;
4316 memset( &f11, 0, sizeof(f11) );
4317 f11.value = WS_XML_TEXT_TYPE_DATETIME;
4318 f11.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4319 f11.field.localName = &str_u;
4320 f11.field.ns = &str_ns;
4321 f11.field.type = WS_DATETIME_TYPE;
4322 f11.field.offset = FIELD_OFFSET(struct test, u.val_datetime);
4323 fields[10] = &f11;
4325 memset( &u, 0, sizeof(u) );
4326 u.size = sizeof(struct test);
4327 u.alignment = TYPE_ALIGNMENT(struct test);
4328 u.fields = fields;
4329 u.fieldCount = 11;
4330 u.enumOffset = FIELD_OFFSET(struct test, type);
4332 memset( &f_struct, 0, sizeof(f_struct) );
4333 f_struct.mapping = WS_ELEMENT_CHOICE_FIELD_MAPPING;
4334 f_struct.type = WS_UNION_TYPE;
4335 f_struct.typeDescription = &u;
4336 fields_struct[0] = &f_struct;
4338 memset( &s, 0, sizeof(s) );
4339 s.size = sizeof(struct test);
4340 s.alignment = TYPE_ALIGNMENT(struct test);
4341 s.fields = fields_struct;
4342 s.fieldCount = 1;
4343 s.typeLocalName = &str_s;
4344 s.typeNs = &str_ns;
4346 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4347 test.type = WS_XML_TEXT_TYPE_UTF8;
4348 test.u.val_utf8.bytes = (BYTE *)"test";
4349 test.u.val_utf8.length = 4;
4350 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4351 &test, sizeof(test), NULL );
4352 ok( hr == S_OK, "got %08x\n", hr );
4353 hr = WsWriteEndElement( writer, NULL );
4354 ok( hr == S_OK, "got %08x\n", hr );
4355 check_output_bin( writer, res, sizeof(res), __LINE__ );
4357 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4358 test.type = WS_XML_TEXT_TYPE_UTF16;
4359 test.u.val_utf16.chars = (WCHAR *)L"test";
4360 test.u.val_utf16.length = 4;
4361 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4362 &test, sizeof(test), NULL );
4363 ok( hr == S_OK, "got %08x\n", hr );
4364 hr = WsWriteEndElement( writer, NULL );
4365 ok( hr == S_OK, "got %08x\n", hr );
4366 check_output_bin( writer, res, sizeof(res), __LINE__ );
4368 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4369 test.type = WS_XML_TEXT_TYPE_BASE64;
4370 test.u.val_bytes.bytes = (BYTE *)"test";
4371 test.u.val_bytes.length = 4;
4372 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4373 &test, sizeof(test), NULL );
4374 ok( hr == S_OK, "got %08x\n", hr );
4375 hr = WsWriteEndElement( writer, NULL );
4376 ok( hr == S_OK, "got %08x\n", hr );
4377 check_output_bin( writer, res2, sizeof(res2), __LINE__ );
4379 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4380 test.type = WS_XML_TEXT_TYPE_BASE64;
4381 test.u.val_bytes.bytes = (BYTE *)"tes";
4382 test.u.val_bytes.length = 3;
4383 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4384 &test, sizeof(test), NULL );
4385 ok( hr == S_OK, "got %08x\n", hr );
4386 hr = WsWriteEndElement( writer, NULL );
4387 ok( hr == S_OK, "got %08x\n", hr );
4388 check_output_bin( writer, res2a, sizeof(res2a), __LINE__ );
4390 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4391 test.type = WS_XML_TEXT_TYPE_BASE64;
4392 test.u.val_bytes.bytes = (BYTE *)"t";
4393 test.u.val_bytes.length = 1;
4394 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4395 &test, sizeof(test), NULL );
4396 ok( hr == S_OK, "got %08x\n", hr );
4397 hr = WsWriteEndElement( writer, NULL );
4398 ok( hr == S_OK, "got %08x\n", hr );
4399 check_output_bin( writer, res2b, sizeof(res2b), __LINE__ );
4401 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4402 test.type = WS_XML_TEXT_TYPE_BASE64;
4403 test.u.val_bytes.bytes = (BYTE *)"";
4404 test.u.val_bytes.length = 0;
4405 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4406 &test, sizeof(test), NULL );
4407 ok( hr == S_OK, "got %08x\n", hr );
4408 hr = WsWriteEndElement( writer, NULL );
4409 ok( hr == S_OK, "got %08x\n", hr );
4410 check_output_bin( writer, res2c, sizeof(res2c), __LINE__ );
4412 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4413 memset( buf, 'a', sizeof(buf) );
4414 test.type = WS_XML_TEXT_TYPE_BASE64;
4415 test.u.val_bytes.bytes = buf;
4416 test.u.val_bytes.length = 255;
4417 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4418 &test, sizeof(test), NULL );
4419 ok( hr == S_OK, "got %08x\n", hr );
4420 hr = WsWriteEndElement( writer, NULL );
4421 ok( hr == S_OK, "got %08x\n", hr );
4422 check_output_bin( writer, res2d, sizeof(res2d), __LINE__ );
4424 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4425 test.type = WS_XML_TEXT_TYPE_BASE64;
4426 test.u.val_bytes.bytes = buf;
4427 test.u.val_bytes.length = 256;
4428 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4429 &test, sizeof(test), NULL );
4430 ok( hr == S_OK, "got %08x\n", hr );
4431 hr = WsWriteEndElement( writer, NULL );
4432 ok( hr == S_OK, "got %08x\n", hr );
4433 check_output_bin( writer, res2e, sizeof(res2e), __LINE__ );
4435 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4436 test.type = WS_XML_TEXT_TYPE_BASE64;
4437 test.u.val_bytes.bytes = (BYTE *)"testte";
4438 test.u.val_bytes.length = 6;
4439 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4440 &test, sizeof(test), NULL );
4441 ok( hr == S_OK, "got %08x\n", hr );
4442 hr = WsWriteEndElement( writer, NULL );
4443 ok( hr == S_OK, "got %08x\n", hr );
4444 check_output_bin( writer, res2f, sizeof(res2f), __LINE__ );
4446 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4447 test.type = WS_XML_TEXT_TYPE_BOOL;
4448 test.u.val_bool = TRUE;
4449 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4450 &test, sizeof(test), NULL );
4451 ok( hr == S_OK, "got %08x\n", hr );
4452 hr = WsWriteEndElement( writer, NULL );
4453 ok( hr == S_OK, "got %08x\n", hr );
4454 check_output_bin( writer, res3, sizeof(res3), __LINE__ );
4456 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4457 test.type = WS_XML_TEXT_TYPE_INT32;
4458 test.u.val_int32 = -1;
4459 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4460 &test, sizeof(test), NULL );
4461 ok( hr == S_OK, "got %08x\n", hr );
4462 hr = WsWriteEndElement( writer, NULL );
4463 ok( hr == S_OK, "got %08x\n", hr );
4464 check_output_bin( writer, res4, sizeof(res4), __LINE__ );
4466 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4467 test.type = WS_XML_TEXT_TYPE_INT64;
4468 test.u.val_int64 = -1;
4469 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4470 &test, sizeof(test), NULL );
4471 ok( hr == S_OK, "got %08x\n", hr );
4472 hr = WsWriteEndElement( writer, NULL );
4473 ok( hr == S_OK, "got %08x\n", hr );
4474 check_output_bin( writer, res4, sizeof(res4), __LINE__ );
4476 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4477 test.type = WS_XML_TEXT_TYPE_UINT64;
4478 test.u.val_uint64 = 1;
4479 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4480 &test, sizeof(test), NULL );
4481 ok( hr == S_OK, "got %08x\n", hr );
4482 hr = WsWriteEndElement( writer, NULL );
4483 ok( hr == S_OK, "got %08x\n", hr );
4484 check_output_bin( writer, res5, sizeof(res5), __LINE__ );
4486 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4487 test.type = WS_XML_TEXT_TYPE_UINT64;
4488 test.u.val_uint64 = 2;
4489 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4490 &test, sizeof(test), NULL );
4491 ok( hr == S_OK, "got %08x\n", hr );
4492 hr = WsWriteEndElement( writer, NULL );
4493 ok( hr == S_OK, "got %08x\n", hr );
4494 check_output_bin( writer, res5b, sizeof(res5b), __LINE__ );
4496 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4497 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4498 test.u.val_double = 0.0;
4499 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4500 &test, sizeof(test), NULL );
4501 ok( hr == S_OK, "got %08x\n", hr );
4502 hr = WsWriteEndElement( writer, NULL );
4503 ok( hr == S_OK, "got %08x\n", hr );
4504 check_output_bin( writer, res6, sizeof(res6), __LINE__ );
4506 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4507 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4508 test.u.val_double = 2.0;
4509 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4510 &test, sizeof(test), NULL );
4511 ok( hr == S_OK, "got %08x\n", hr );
4512 hr = WsWriteEndElement( writer, NULL );
4513 ok( hr == S_OK, "got %08x\n", hr );
4514 check_output_bin( writer, res7, sizeof(res7), __LINE__ );
4516 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4517 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4518 test.u.val_double = 2.1;
4519 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4520 &test, sizeof(test), NULL );
4521 ok( hr == S_OK, "got %08x\n", hr );
4522 hr = WsWriteEndElement( writer, NULL );
4523 ok( hr == S_OK, "got %08x\n", hr );
4524 check_output_bin( writer, res8, sizeof(res8), __LINE__ );
4526 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4527 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4528 test.u.val_double = INFINITY;
4529 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4530 &test, sizeof(test), NULL );
4531 ok( hr == S_OK, "got %08x\n", hr );
4532 hr = WsWriteEndElement( writer, NULL );
4533 ok( hr == S_OK, "got %08x\n", hr );
4534 check_output_bin( writer, res8a, sizeof(res8a), __LINE__ );
4536 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4537 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4538 test.u.val_double = -INFINITY;
4539 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4540 &test, sizeof(test), NULL );
4541 ok( hr == S_OK, "got %08x\n", hr );
4542 hr = WsWriteEndElement( writer, NULL );
4543 ok( hr == S_OK, "got %08x\n", hr );
4544 check_output_bin( writer, res8b, sizeof(res8b), __LINE__ );
4546 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4547 test.type = WS_XML_TEXT_TYPE_DOUBLE;
4548 test.u.val_double = NAN;
4549 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4550 &test, sizeof(test), NULL );
4551 ok( hr == S_OK, "got %08x\n", hr );
4552 hr = WsWriteEndElement( writer, NULL );
4553 ok( hr == S_OK, "got %08x\n", hr );
4554 check_output_bin( writer, res8c, sizeof(res8c), __LINE__ );
4556 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4557 test.type = WS_XML_TEXT_TYPE_GUID;
4558 memset( &test.u.val_guid, 0, sizeof(test.u.val_guid) );
4559 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4560 &test, sizeof(test), NULL );
4561 ok( hr == S_OK, "got %08x\n", hr );
4562 hr = WsWriteEndElement( writer, NULL );
4563 ok( hr == S_OK, "got %08x\n", hr );
4564 check_output_bin( writer, res9, sizeof(res9), __LINE__ );
4566 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4567 test.type = WS_XML_TEXT_TYPE_UNIQUE_ID;
4568 memset( &test.u.val_unique_id, 0, sizeof(test.u.val_unique_id) );
4569 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4570 &test, sizeof(test), NULL );
4571 ok( hr == S_OK, "got %08x\n", hr );
4572 hr = WsWriteEndElement( writer, NULL );
4573 ok( hr == S_OK, "got %08x\n", hr );
4574 check_output_bin( writer, res10, sizeof(res10), __LINE__ );
4576 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4577 test.type = WS_XML_TEXT_TYPE_DATETIME;
4578 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4579 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4580 &test, sizeof(test), NULL );
4581 ok( hr == S_OK, "got %08x\n", hr );
4582 hr = WsWriteEndElement( writer, NULL );
4583 ok( hr == S_OK, "got %08x\n", hr );
4584 check_output_bin( writer, res11, sizeof(res11), __LINE__ );
4586 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4587 test.type = WS_XML_TEXT_TYPE_DATETIME;
4588 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4589 test.u.val_datetime.format = WS_DATETIME_FORMAT_LOCAL;
4590 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4591 &test, sizeof(test), NULL );
4592 ok( hr == S_OK, "got %08x\n", hr );
4593 hr = WsWriteEndElement( writer, NULL );
4594 ok( hr == S_OK, "got %08x\n", hr );
4595 check_output_bin( writer, res11b, sizeof(res11b), __LINE__ );
4597 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4598 test.type = WS_XML_TEXT_TYPE_DATETIME;
4599 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4600 test.u.val_datetime.format = WS_DATETIME_FORMAT_NONE;
4601 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4602 &test, sizeof(test), NULL );
4603 ok( hr == S_OK, "got %08x\n", hr );
4604 hr = WsWriteEndElement( writer, NULL );
4605 ok( hr == S_OK, "got %08x\n", hr );
4606 check_output_bin( writer, res11c, sizeof(res11c), __LINE__ );
4608 prepare_binary_type_test( writer, NULL, &str_t, &str_ns );
4609 test.type = WS_XML_TEXT_TYPE_DATETIME;
4610 memset( &test.u.val_datetime, 0, sizeof(test.u.val_datetime) );
4611 test.u.val_datetime.ticks = 1;
4612 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, WS_WRITE_REQUIRED_VALUE,
4613 &test, sizeof(test), NULL );
4614 ok( hr == S_OK, "got %08x\n", hr );
4615 hr = WsWriteEndElement( writer, NULL );
4616 ok( hr == S_OK, "got %08x\n", hr );
4617 check_output_bin( writer, res11d, sizeof(res11d), __LINE__ );
4619 WsFreeWriter( writer );
4622 static void test_repeating_element_choice(void)
4624 static WS_XML_STRING str_ns = {0, NULL}, str_a = {1, (BYTE *)"a"}, str_b = {1, (BYTE *)"b"};
4625 static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"};
4626 HRESULT hr;
4627 WS_XML_WRITER *writer;
4628 WS_UNION_DESCRIPTION u;
4629 WS_UNION_FIELD_DESCRIPTION f, f2, *fields[2];
4630 WS_FIELD_DESCRIPTION f_items, *fields_items[1];
4631 WS_STRUCT_DESCRIPTION s;
4632 enum choice {CHOICE_A, CHOICE_B, CHOICE_NONE};
4633 struct item
4635 enum choice choice;
4636 union
4638 const WCHAR *a;
4639 UINT32 b;
4640 } value;
4641 } items[2];
4642 struct test
4644 struct item *items;
4645 ULONG count;
4646 } test;
4648 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4649 ok( hr == S_OK, "got %08x\n", hr );
4651 memset( &f, 0, sizeof(f) );
4652 f.value = CHOICE_A;
4653 f.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4654 f.field.localName = &str_a;
4655 f.field.ns = &str_ns;
4656 f.field.type = WS_WSZ_TYPE;
4657 f.field.offset = FIELD_OFFSET(struct item, value.a);
4658 fields[0] = &f;
4660 memset( &f2, 0, sizeof(f2) );
4661 f2.value = CHOICE_B;
4662 f2.field.mapping = WS_ELEMENT_FIELD_MAPPING;
4663 f2.field.localName = &str_b;
4664 f2.field.ns = &str_ns;
4665 f2.field.type = WS_UINT32_TYPE;
4666 f2.field.offset = FIELD_OFFSET(struct item, value.b);
4667 fields[1] = &f2;
4669 memset( &u, 0, sizeof(u) );
4670 u.size = sizeof(struct item);
4671 u.alignment = TYPE_ALIGNMENT(struct item);
4672 u.fields = fields;
4673 u.fieldCount = 2;
4674 u.enumOffset = FIELD_OFFSET(struct item, choice);
4675 u.noneEnumValue = CHOICE_NONE;
4677 memset( &f_items, 0, sizeof(f_items) );
4678 f_items.mapping = WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING;
4679 f_items.localName = &str_t;
4680 f_items.ns = &str_ns;
4681 f_items.type = WS_UNION_TYPE;
4682 f_items.typeDescription = &u;
4683 f_items.countOffset = FIELD_OFFSET(struct test, count);
4684 fields_items[0] = &f_items;
4686 memset( &s, 0, sizeof(s) );
4687 s.size = sizeof(struct test);
4688 s.alignment = TYPE_ALIGNMENT(struct test);
4689 s.fields = fields_items;
4690 s.fieldCount = 1;
4691 s.typeLocalName = &str_s;
4692 s.typeNs = &str_ns;
4694 items[0].choice = CHOICE_A;
4695 items[0].value.a = L"test";
4696 items[1].choice = CHOICE_B;
4697 items[1].value.b = 1;
4698 test.items = items;
4699 test.count = 2;
4701 hr = set_output( writer );
4702 ok( hr == S_OK, "got %08x\n", hr );
4703 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4704 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4705 ok( hr == S_OK, "got %08x\n", hr );
4706 check_output( writer, "<t><a>test</a><b>1</b></t>", __LINE__ );
4708 items[0].choice = CHOICE_NONE;
4709 hr = set_output( writer );
4710 ok( hr == S_OK, "got %08x\n", hr );
4711 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4712 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4713 ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
4715 test.count = 0;
4716 hr = set_output( writer );
4717 ok( hr == S_OK, "got %08x\n", hr );
4718 hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4719 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4720 ok( hr == S_OK, "got %08x\n", hr );
4721 check_output( writer, "<t/>", __LINE__ );
4723 WsFreeWriter( writer );
4726 static const struct stream_test
4728 ULONG min_size;
4729 ULONG ret_size;
4731 stream_tests[] =
4733 { 0, 4 },
4734 { 1, 4 },
4735 { 4, 4 },
4736 { 5, 4 },
4739 static CALLBACK HRESULT write_callback( void *state, const WS_BYTES *buf, ULONG count,
4740 const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
4742 ULONG i = *(ULONG *)state;
4743 ok( buf->length == stream_tests[i].ret_size, "%u: got %u\n", i, buf->length );
4744 ok( !memcmp( buf->bytes, "<t/>", stream_tests[i].ret_size ), "%u: wrong data\n", i );
4745 ok( count == 1, "%u: got %u\n", i, count );
4746 return S_OK;
4749 static void test_stream_output(void)
4751 static WS_XML_STRING str_ns = {0, NULL}, str_t = {1, (BYTE *)"t"};
4752 WS_XML_WRITER_TEXT_ENCODING text = {{WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
4753 WS_XML_WRITER_STREAM_OUTPUT stream;
4754 WS_XML_WRITER *writer;
4755 HRESULT hr;
4756 ULONG i = 0;
4758 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4759 ok( hr == S_OK, "got %08x\n", hr );
4761 hr = WsFlushWriter( writer, 0, NULL, NULL );
4762 ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
4764 stream.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
4765 stream.writeCallback = write_callback;
4766 stream.writeCallbackState = &i;
4767 hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
4768 ok( hr == S_OK, "got %08x\n", hr );
4770 hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
4771 ok( hr == S_OK, "got %08x\n", hr );
4773 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4774 ok( hr == S_OK, "got %08x\n", hr );
4775 hr = WsWriteEndElement( writer, NULL );
4776 ok( hr == S_OK, "got %08x\n", hr );
4777 hr = WsFlushWriter( writer, 0, NULL, NULL );
4778 ok( hr == S_OK, "got %08x\n", hr );
4780 for (i = 0; i < ARRAY_SIZE(stream_tests); i++)
4782 stream.writeCallbackState = &i;
4783 hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
4784 ok( hr == S_OK, "%u: got %08x\n", i, hr );
4785 hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
4786 ok( hr == S_OK, "%u: got %08x\n", i, hr );
4787 hr = WsWriteEndElement( writer, NULL );
4788 ok( hr == S_OK, "%u: got %08x\n", i, hr );
4789 hr = WsFlushWriter( writer, stream_tests[i].min_size, NULL, NULL );
4790 ok( hr == S_OK, "%u: got %08x\n", i, hr );
4793 WsFreeWriter( writer );
4796 static void test_description_type(void)
4798 static WS_XML_STRING ns = {0, NULL}, localname = {1, (BYTE *)"t"}, val = {3, (BYTE *)"val"};
4799 HRESULT hr;
4800 WS_XML_WRITER *writer;
4801 WS_FIELD_DESCRIPTION f, f2, *fields[2];
4802 WS_STRUCT_DESCRIPTION s;
4803 struct test
4805 const WS_STRUCT_DESCRIPTION *desc;
4806 INT32 val;
4807 } test;
4809 hr = WsCreateWriter( NULL, 0, &writer, NULL );
4810 ok( hr == S_OK, "got %08x\n", hr );
4812 memset( &f, 0, sizeof(f) );
4813 f.mapping = WS_TYPE_ATTRIBUTE_FIELD_MAPPING;
4814 f.type = WS_DESCRIPTION_TYPE;
4815 fields[0] = &f;
4817 memset( &f2, 0, sizeof(f2) );
4818 f2.mapping = WS_ATTRIBUTE_FIELD_MAPPING;
4819 f2.localName = &val;
4820 f2.ns = &ns;
4821 f2.offset = FIELD_OFFSET(struct test, val);
4822 f2.type = WS_INT32_TYPE;
4823 fields[1] = &f2;
4825 memset( &s, 0, sizeof(s) );
4826 s.size = sizeof(struct test);
4827 s.alignment = TYPE_ALIGNMENT(struct test);
4828 s.fields = fields;
4829 s.fieldCount = 2;
4830 s.typeLocalName = &localname;
4831 s.typeNs = &ns;
4833 test.desc = &s;
4834 test.val = -1;
4836 hr = set_output( writer );
4837 hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
4838 ok( hr == S_OK, "got %08x\n", hr );
4840 hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
4841 WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
4842 ok( hr == S_OK, "got %08x\n", hr );
4844 hr = WsWriteEndElement( writer, NULL );
4845 ok( hr == S_OK, "got %08x\n", hr );
4846 check_output( writer, "<t val=\"-1\"/>", __LINE__ );
4848 WsFreeWriter( writer );
4851 START_TEST(writer)
4853 test_WsCreateWriter();
4854 test_WsCreateXmlBuffer();
4855 test_WsSetOutput();
4856 test_WsSetOutputToBuffer();
4857 test_WsWriteStartElement();
4858 test_WsWriteStartAttribute();
4859 test_WsWriteType();
4860 test_basic_type();
4861 test_simple_struct_type();
4862 test_WsWriteElement();
4863 test_WsWriteValue();
4864 test_WsWriteAttribute();
4865 test_WsWriteStartCData();
4866 test_WsWriteXmlnsAttribute();
4867 test_WsGetPrefixFromNamespace();
4868 test_complex_struct_type();
4869 test_WsMoveWriter();
4870 test_WsGetWriterPosition();
4871 test_WsSetWriterPosition();
4872 test_WsWriteXmlBuffer();
4873 test_WsWriteNode();
4874 test_WsCopyNode();
4875 test_text_types();
4876 test_double();
4877 test_field_options();
4878 test_WsWriteText();
4879 test_WsWriteArray();
4880 test_escapes();
4881 test_write_option();
4882 test_datetime();
4883 test_repeating_element();
4884 test_WsWriteQualifiedName();
4885 test_WsWriteBytes();
4886 test_WsWriteChars();
4887 test_WsWriteCharsUtf8();
4888 test_binary_encoding();
4889 test_namespaces();
4890 test_dictionary();
4891 test_union_type();
4892 test_text_types_binary();
4893 test_repeating_element_choice();
4894 test_stream_output();
4895 test_description_type();