bcrypt: Require macOS version 10.7 or newer for encryption support.
[wine.git] / dlls / webservices / writer.c
blobbe2994af8336bbae7763de1ac038685e43b67fdb
1 /*
2 * Copyright 2015, 2016 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 "config.h"
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "webservices.h"
30 #include "wine/debug.h"
31 #include "wine/list.h"
32 #include "wine/unicode.h"
33 #include "webservices_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
37 static const struct prop_desc writer_props[] =
39 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
40 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
41 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
42 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
43 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
44 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
45 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
46 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
47 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
48 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
49 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
50 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
51 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
52 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
53 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
54 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
55 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
56 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
57 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
60 enum writer_state
62 WRITER_STATE_INITIAL,
63 WRITER_STATE_STARTELEMENT,
64 WRITER_STATE_STARTATTRIBUTE,
65 WRITER_STATE_STARTCDATA,
66 WRITER_STATE_ENDSTARTELEMENT,
67 WRITER_STATE_TEXT,
68 WRITER_STATE_COMMENT,
69 WRITER_STATE_ENDELEMENT,
70 WRITER_STATE_ENDCDATA
73 struct writer
75 ULONG magic;
76 CRITICAL_SECTION cs;
77 ULONG write_pos;
78 unsigned char *write_bufptr;
79 enum writer_state state;
80 struct node *root;
81 struct node *current;
82 WS_XML_STRING *current_ns;
83 WS_XML_WRITER_ENCODING_TYPE output_enc;
84 WS_CHARSET output_charset;
85 WS_XML_WRITER_OUTPUT_TYPE output_type;
86 struct xmlbuf *output_buf;
87 WS_HEAP *output_heap;
88 const WS_XML_DICTIONARY *dict;
89 BOOL dict_do_lookup;
90 WS_DYNAMIC_STRING_CALLBACK dict_cb;
91 void *dict_cb_state;
92 ULONG prop_count;
93 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
96 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
98 static struct writer *alloc_writer(void)
100 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
101 struct writer *ret;
102 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
104 if (!(ret = heap_alloc_zero( size ))) return NULL;
106 ret->magic = WRITER_MAGIC;
107 InitializeCriticalSection( &ret->cs );
108 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
110 prop_init( writer_props, count, ret->prop, &ret[1] );
111 ret->prop_count = count;
112 return ret;
115 static void free_writer( struct writer *writer )
117 destroy_nodes( writer->root );
118 free_xml_string( writer->current_ns );
119 WsFreeHeap( writer->output_heap );
121 writer->cs.DebugInfo->Spare[0] = 0;
122 DeleteCriticalSection( &writer->cs );
123 heap_free( writer );
126 static void write_insert_eof( struct writer *writer, struct node *eof )
128 if (!writer->root) writer->root = eof;
129 else
131 eof->parent = writer->root;
132 list_add_tail( &writer->root->children, &eof->entry );
134 writer->current = eof;
137 static void write_insert_bof( struct writer *writer, struct node *bof )
139 writer->root->parent = bof;
140 list_add_tail( &bof->children, &writer->root->entry );
141 writer->current = writer->root = bof;
144 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
146 node->parent = parent;
147 list_add_before( list_tail( &parent->children ), &node->entry );
148 writer->current = node;
151 static struct node *find_parent( struct writer *writer )
153 if (is_valid_parent( writer->current )) return writer->current;
154 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
155 return NULL;
158 static HRESULT init_writer( struct writer *writer )
160 struct node *node;
162 writer->write_pos = 0;
163 writer->write_bufptr = NULL;
164 destroy_nodes( writer->root );
165 writer->root = writer->current = NULL;
166 free_xml_string( writer->current_ns );
167 writer->current_ns = NULL;
169 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
170 write_insert_eof( writer, node );
171 writer->state = WRITER_STATE_INITIAL;
172 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
173 writer->output_charset = WS_CHARSET_UTF8;
174 writer->dict = NULL;
175 writer->dict_do_lookup = FALSE;
176 writer->dict_cb = NULL;
177 writer->dict_cb_state = NULL;
178 return S_OK;
181 /**************************************************************************
182 * WsCreateWriter [webservices.@]
184 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
185 WS_XML_WRITER **handle, WS_ERROR *error )
187 struct writer *writer;
188 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
189 WS_CHARSET charset = WS_CHARSET_UTF8;
190 HRESULT hr;
192 TRACE( "%p %u %p %p\n", properties, count, handle, error );
193 if (error) FIXME( "ignoring error parameter\n" );
195 if (!handle) return E_INVALIDARG;
196 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
198 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
199 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
200 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
201 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
202 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
203 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
204 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
206 for (i = 0; i < count; i++)
208 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
209 properties[i].valueSize );
210 if (hr != S_OK)
212 free_writer( writer );
213 return hr;
217 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
218 &max_size, sizeof(max_size) );
219 if (hr != S_OK)
221 free_writer( writer );
222 return hr;
225 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
226 if (hr != S_OK)
228 free_writer( writer );
229 return hr;
232 hr = init_writer( writer );
233 if (hr != S_OK)
235 free_writer( writer );
236 return hr;
239 TRACE( "created %p\n", writer );
240 *handle = (WS_XML_WRITER *)writer;
241 return S_OK;
244 /**************************************************************************
245 * WsFreeWriter [webservices.@]
247 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
249 struct writer *writer = (struct writer *)handle;
251 TRACE( "%p\n", handle );
253 if (!writer) return;
255 EnterCriticalSection( &writer->cs );
257 if (writer->magic != WRITER_MAGIC)
259 LeaveCriticalSection( &writer->cs );
260 return;
263 writer->magic = 0;
265 LeaveCriticalSection( &writer->cs );
266 free_writer( writer );
269 /**************************************************************************
270 * WsGetWriterProperty [webservices.@]
272 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
273 void *buf, ULONG size, WS_ERROR *error )
275 struct writer *writer = (struct writer *)handle;
276 HRESULT hr = S_OK;
278 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
279 if (error) FIXME( "ignoring error parameter\n" );
281 if (!writer) return E_INVALIDARG;
283 EnterCriticalSection( &writer->cs );
285 if (writer->magic != WRITER_MAGIC)
287 LeaveCriticalSection( &writer->cs );
288 return E_INVALIDARG;
291 if (!writer->output_type)
293 LeaveCriticalSection( &writer->cs );
294 return WS_E_INVALID_OPERATION;
297 switch (id)
299 case WS_XML_WRITER_PROPERTY_BYTES:
301 WS_BYTES *bytes = buf;
302 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
303 else
305 bytes->bytes = writer->output_buf->bytes.bytes;
306 bytes->length = writer->output_buf->bytes.length;
308 break;
310 case WS_XML_WRITER_PROPERTY_BUFFERS:
311 if (writer->output_buf->bytes.length)
313 WS_BUFFERS *buffers = buf;
314 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
315 else
317 buffers->bufferCount = 1;
318 buffers->buffers = &writer->output_buf->bytes;
320 break;
322 /* fall through */
323 default:
324 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
327 LeaveCriticalSection( &writer->cs );
328 return hr;
331 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
333 /* free current buffer if it's ours */
334 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
336 free_xmlbuf( writer->output_buf );
338 writer->output_buf = xmlbuf;
339 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
340 writer->write_bufptr = xmlbuf->bytes.bytes;
341 writer->write_pos = 0;
344 /**************************************************************************
345 * WsSetOutput [webservices.@]
347 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
348 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
349 ULONG count, WS_ERROR *error )
351 struct writer *writer = (struct writer *)handle;
352 struct node *node;
353 HRESULT hr;
354 ULONG i;
356 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
357 if (error) FIXME( "ignoring error parameter\n" );
359 if (!writer) return E_INVALIDARG;
361 EnterCriticalSection( &writer->cs );
363 if (writer->magic != WRITER_MAGIC)
365 LeaveCriticalSection( &writer->cs );
366 return E_INVALIDARG;
369 for (i = 0; i < count; i++)
371 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
372 properties[i].valueSize );
373 if (hr != S_OK) goto done;
376 if ((hr = init_writer( writer )) != S_OK) goto done;
378 switch (encoding->encodingType)
380 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
382 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
383 if (text->charSet != WS_CHARSET_UTF8)
385 FIXME( "charset %u not supported\n", text->charSet );
386 hr = E_NOTIMPL;
387 goto done;
389 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
390 writer->output_charset = WS_CHARSET_UTF8;
391 break;
393 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
395 WS_XML_WRITER_BINARY_ENCODING *bin = (WS_XML_WRITER_BINARY_ENCODING *)encoding;
396 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
397 writer->output_charset = 0;
398 writer->dict = bin->staticDictionary;
399 writer->dict_cb = bin->dynamicStringCallback;
400 writer->dict_cb_state = bin->dynamicStringCallbackState;
401 break;
403 default:
404 FIXME( "encoding type %u not supported\n", encoding->encodingType );
405 hr = E_NOTIMPL;
406 goto done;
409 switch (output->outputType)
411 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
413 struct xmlbuf *xmlbuf;
414 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, 0, writer->output_enc, writer->output_charset,
415 writer->dict, NULL )))
417 hr = WS_E_QUOTA_EXCEEDED;
418 goto done;
420 set_output_buffer( writer, xmlbuf );
421 break;
423 default:
424 FIXME( "output type %u not supported\n", output->outputType );
425 hr = E_NOTIMPL;
426 goto done;
429 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
430 else write_insert_bof( writer, node );
432 done:
433 LeaveCriticalSection( &writer->cs );
434 return hr;
437 /**************************************************************************
438 * WsSetOutputToBuffer [webservices.@]
440 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
441 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
442 WS_ERROR *error )
444 struct writer *writer = (struct writer *)handle;
445 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
446 struct node *node;
447 HRESULT hr;
448 ULONG i;
450 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
451 if (error) FIXME( "ignoring error parameter\n" );
453 if (!writer || !xmlbuf) return E_INVALIDARG;
455 EnterCriticalSection( &writer->cs );
457 if (writer->magic != WRITER_MAGIC)
459 LeaveCriticalSection( &writer->cs );
460 return E_INVALIDARG;
463 for (i = 0; i < count; i++)
465 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
466 properties[i].valueSize );
467 if (hr != S_OK) goto done;
470 if ((hr = init_writer( writer )) != S_OK) goto done;
471 writer->output_enc = xmlbuf->encoding;
472 writer->output_charset = xmlbuf->charset;
473 set_output_buffer( writer, xmlbuf );
475 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
476 else write_insert_bof( writer, node );
478 done:
479 LeaveCriticalSection( &writer->cs );
480 return hr;
483 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
485 struct xmlbuf *buf = writer->output_buf;
486 SIZE_T new_size;
487 void *tmp;
489 if (buf->size >= writer->write_pos + size)
491 buf->bytes.length = writer->write_pos + size;
492 return S_OK;
494 new_size = max( buf->size * 2, writer->write_pos + size );
495 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
496 writer->write_bufptr = buf->bytes.bytes = tmp;
497 buf->size = new_size;
498 buf->bytes.length = writer->write_pos + size;
499 return S_OK;
502 static inline void write_char( struct writer *writer, unsigned char ch )
504 writer->write_bufptr[writer->write_pos++] = ch;
507 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
509 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
510 writer->write_pos += len;
513 struct escape
515 char ch;
516 const char *entity;
517 ULONG len;
519 static const struct escape escape_lt = { '<', "&lt;", 4 };
520 static const struct escape escape_gt = { '>', "&gt;", 4 };
521 static const struct escape escape_amp = { '&', "&amp;", 5 };
522 static const struct escape escape_apos = { '\'', "&apos;", 6 };
523 static const struct escape escape_quot = { '"', "&quot;", 6 };
525 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
526 const struct escape **escapes, ULONG nb_escapes )
528 ULONG i, j, size;
529 const BYTE *ptr;
530 HRESULT hr;
532 for (i = 0; i < len; i++)
534 ptr = &bytes[i];
535 size = 1;
536 for (j = 0; j < nb_escapes; j++)
538 if (bytes[i] == escapes[j]->ch)
540 ptr = (const BYTE *)escapes[j]->entity;
541 size = escapes[j]->len;
542 break;
545 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
546 write_bytes( writer, ptr, size );
549 return S_OK;
552 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
554 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
555 const struct escape *escapes[3];
557 escapes[0] = single ? &escape_apos : &escape_quot;
558 escapes[1] = &escape_lt;
559 escapes[2] = &escape_amp;
560 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
563 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
565 unsigned char quote = attr->singleQuote ? '\'' : '"';
566 const WS_XML_STRING *prefix = NULL;
567 ULONG size;
568 HRESULT hr;
570 if (attr->prefix) prefix = attr->prefix;
572 /* ' prefix:attr="value"' */
574 size = attr->localName->length + 4 /* ' =""' */;
575 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
576 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
578 write_char( writer, ' ' );
579 if (prefix && prefix->length)
581 write_bytes( writer, prefix->bytes, prefix->length );
582 write_char( writer, ':' );
584 write_bytes( writer, attr->localName->bytes, attr->localName->length );
585 write_char( writer, '=' );
586 write_char( writer, quote );
587 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
588 write_char( writer, quote );
590 return hr;
593 static HRESULT write_int31( struct writer *writer, ULONG len )
595 HRESULT hr;
597 if (len > 0x7fffffff) return E_INVALIDARG;
599 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
600 if (len < 0x80)
602 write_char( writer, len );
603 return S_OK;
605 write_char( writer, (len & 0x7f) | 0x80 );
607 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
608 if ((len >>= 7) < 0x80)
610 write_char( writer, len );
611 return S_OK;
613 write_char( writer, (len & 0x7f) | 0x80 );
615 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
616 if ((len >>= 7) < 0x80)
618 write_char( writer, len );
619 return S_OK;
621 write_char( writer, (len & 0x7f) | 0x80 );
623 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
624 if ((len >>= 7) < 0x80)
626 write_char( writer, len );
627 return S_OK;
629 write_char( writer, (len & 0x7f) | 0x80 );
631 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
632 if ((len >>= 7) < 0x08)
634 write_char( writer, len );
635 return S_OK;
637 return WS_E_INVALID_FORMAT;
640 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
642 HRESULT hr;
643 if ((hr = write_int31( writer, len )) != S_OK) return hr;
644 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
645 write_bytes( writer, bytes, len );
646 return S_OK;
649 static HRESULT write_dict_string( struct writer *writer, ULONG id )
651 HRESULT hr;
652 if (id > 0x7fffffff) return E_INVALIDARG;
653 if ((hr = write_int31( writer, id )) != S_OK) return hr;
654 return S_OK;
657 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
659 if (!text) return RECORD_CHARS8_TEXT;
660 switch (text->textType)
662 case WS_XML_TEXT_TYPE_UTF8:
664 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
665 if (use_dict) return RECORD_DICTIONARY_TEXT;
666 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
667 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
668 return RECORD_CHARS32_TEXT;
670 case WS_XML_TEXT_TYPE_UTF16:
672 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
673 int len = text_utf16->byteCount / sizeof(WCHAR);
674 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
675 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT;
676 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT;
677 return RECORD_CHARS32_TEXT;
679 case WS_XML_TEXT_TYPE_BASE64:
681 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
682 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
683 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
684 return RECORD_BYTES32_TEXT;
686 case WS_XML_TEXT_TYPE_BOOL:
688 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
689 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
691 case WS_XML_TEXT_TYPE_INT32:
693 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
694 if (!text_int32->value) return RECORD_ZERO_TEXT;
695 if (text_int32->value == 1) return RECORD_ONE_TEXT;
696 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
697 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
698 return RECORD_INT32_TEXT;
700 case WS_XML_TEXT_TYPE_INT64:
702 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
703 if (!text_int64->value) return RECORD_ZERO_TEXT;
704 if (text_int64->value == 1) return RECORD_ONE_TEXT;
705 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
706 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
707 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
708 return RECORD_INT64_TEXT;
710 case WS_XML_TEXT_TYPE_UINT64:
712 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
713 if (!text_uint64->value) return RECORD_ZERO_TEXT;
714 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
715 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
716 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
717 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
718 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
719 return RECORD_UINT64_TEXT;
721 case WS_XML_TEXT_TYPE_DOUBLE:
723 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
724 if (!text_double->value) return RECORD_ZERO_TEXT;
725 if (text_double->value == 1) return RECORD_ONE_TEXT;
726 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
727 return RECORD_DOUBLE_TEXT;
728 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
729 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
730 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
731 return RECORD_INT64_TEXT;
733 case WS_XML_TEXT_TYPE_GUID:
734 return RECORD_GUID_TEXT;
736 case WS_XML_TEXT_TYPE_UNIQUE_ID:
737 return RECORD_UNIQUE_ID_TEXT;
739 case WS_XML_TEXT_TYPE_DATETIME:
740 return RECORD_DATETIME_TEXT;
742 default:
743 FIXME( "unhandled text type %u\n", text->textType );
744 return 0;
748 static INT64 get_text_value_int( const WS_XML_TEXT *text )
750 switch (text->textType)
752 case WS_XML_TEXT_TYPE_INT32:
754 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
755 return text_int32->value;
757 case WS_XML_TEXT_TYPE_INT64:
759 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
760 return text_int64->value;
762 case WS_XML_TEXT_TYPE_UINT64:
764 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
765 return text_uint64->value;
767 case WS_XML_TEXT_TYPE_DOUBLE:
769 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
770 return text_double->value;
772 default:
773 ERR( "unhandled text type %u\n", text->textType );
774 assert(0);
775 return 0;
779 static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
781 if (writer->dict && str->dictionary == writer->dict)
783 *id = str->id << 1;
784 return TRUE;
786 if (writer->dict_cb)
788 BOOL found = FALSE;
789 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
790 if (found) *id = (*id << 1) | 1;
791 return found;
793 return FALSE;
796 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
798 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
799 if (*ptr)
801 memcpy( buf, bool_true, sizeof(bool_true) );
802 return sizeof(bool_true);
804 memcpy( buf, bool_false, sizeof(bool_false) );
805 return sizeof(bool_false);
808 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
810 return wsprintfA( (char *)buf, "%d", *ptr );
813 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
815 return wsprintfA( (char *)buf, "%I64d", *ptr );
818 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
820 return wsprintfA( (char *)buf, "%I64u", *ptr );
823 static ULONG format_double( const double *ptr, unsigned char *buf )
825 #ifdef HAVE_POWL
826 static const long double precision = 0.0000000000000001;
827 unsigned char *p = buf;
828 long double val = *ptr;
829 int neg, mag, mag2, use_exp;
831 if (isnan( val ))
833 memcpy( buf, "NaN", 3 );
834 return 3;
836 if (isinf( val ))
838 if (val < 0)
840 memcpy( buf, "-INF", 4 );
841 return 4;
843 memcpy( buf, "INF", 3 );
844 return 3;
846 if (val == 0.0)
848 *p = '0';
849 return 1;
852 if ((neg = val < 0))
854 *p++ = '-';
855 val = -val;
858 mag = log10l( val );
859 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
860 if (use_exp)
862 if (mag < 0) mag -= 1;
863 val = val / powl( 10.0, mag );
864 mag2 = mag;
865 mag = 0;
867 else if (mag < 1) mag = 0;
869 while (val > precision || mag >= 0)
871 long double weight = powl( 10.0, mag );
872 if (weight > 0 && !isinf( weight ))
874 int digit = floorl( val / weight );
875 val -= digit * weight;
876 *(p++) = '0' + digit;
878 if (!mag && val > precision) *(p++) = '.';
879 mag--;
882 if (use_exp)
884 int i, j;
885 *(p++) = 'E';
886 if (mag2 > 0) *(p++) = '+';
887 else
889 *(p++) = '-';
890 mag2 = -mag2;
892 mag = 0;
893 while (mag2 > 0)
895 *(p++) = '0' + mag2 % 10;
896 mag2 /= 10;
897 mag++;
899 for (i = -mag, j = -1; i < j; i++, j--)
901 p[i] ^= p[j];
902 p[j] ^= p[i];
903 p[i] ^= p[j];
907 return p - buf;
908 #else
909 FIXME( "powl not found at build time\n" );
910 return 0;
911 #endif
914 static inline int year_size( int year )
916 return leap_year( year ) ? 366 : 365;
919 #define TZ_OFFSET 8
920 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
922 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
923 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
924 unsigned __int64 ticks, day_ticks;
925 ULONG len;
927 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
928 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
930 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
931 tz_hour = TZ_OFFSET;
933 else
935 ticks = ptr->ticks;
936 tz_hour = 0;
938 day = ticks / TICKS_PER_DAY;
939 day_ticks = ticks % TICKS_PER_DAY;
940 hour = day_ticks / TICKS_PER_HOUR;
941 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
942 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
943 sec_frac = day_ticks % TICKS_PER_SEC;
945 while (day >= year_size( year ))
947 day -= year_size( year );
948 year++;
950 while (day >= month_days[leap_year( year )][month])
952 day -= month_days[leap_year( year )][month];
953 month++;
956 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
957 if (sec_frac)
959 static const char fmt_frac[] = ".%07u";
960 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
961 while (buf[len - 1] == '0') len--;
963 if (ptr->format == WS_DATETIME_FORMAT_UTC)
965 buf[len++] = 'Z';
967 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
969 static const char fmt_tz[] = "%c%02u:00";
970 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
973 return len;
976 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
978 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
979 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
980 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
981 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
984 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
986 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
987 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
988 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
989 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
992 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
994 ULONG len = 0;
995 if (prefix && prefix->length)
997 memcpy( buf, prefix->bytes, prefix->length );
998 len += prefix->length;
999 buf[len++] = ':';
1001 memcpy( buf + len, localname->bytes, localname->length );
1002 return len + localname->length;
1005 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1007 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1008 ULONG i = 0, x;
1010 while (len > 0)
1012 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1013 x = (bin[0] & 3) << 4;
1014 if (len == 1)
1016 buf[i++] = base64[x];
1017 buf[i++] = '=';
1018 buf[i++] = '=';
1019 break;
1021 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1022 x = (bin[1] & 0x0f) << 2;
1023 if (len == 2)
1025 buf[i++] = base64[x];
1026 buf[i++] = '=';
1027 break;
1029 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1030 buf[i++] = base64[bin[2] & 0x3f];
1031 bin += 3;
1032 len -= 3;
1034 return i;
1037 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
1038 WS_XML_UTF8_TEXT **ret )
1040 ULONG len_old = old ? old->value.length : 0;
1041 if (offset) *offset = len_old;
1043 switch (text->textType)
1045 case WS_XML_TEXT_TYPE_UTF8:
1047 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1049 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
1050 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1051 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
1052 return S_OK;
1054 case WS_XML_TEXT_TYPE_UTF16:
1056 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1057 const WCHAR *str = (const WCHAR *)src->bytes;
1058 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1060 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1061 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1062 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
1063 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1064 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
1065 return S_OK;
1067 case WS_XML_TEXT_TYPE_BASE64:
1069 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1070 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1072 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1073 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1074 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
1075 return S_OK;
1077 case WS_XML_TEXT_TYPE_BOOL:
1079 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1081 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
1082 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1083 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
1084 return S_OK;
1086 case WS_XML_TEXT_TYPE_INT32:
1088 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1089 unsigned char buf[12]; /* "-2147483648" */
1090 ULONG len = format_int32( &int32_text->value, buf );
1092 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1093 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1094 memcpy( (*ret)->value.bytes + len_old, buf, len );
1095 return S_OK;
1097 case WS_XML_TEXT_TYPE_INT64:
1099 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1100 unsigned char buf[21]; /* "-9223372036854775808" */
1101 ULONG len = format_int64( &int64_text->value, buf );
1103 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1104 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1105 memcpy( (*ret)->value.bytes + len_old, buf, len );
1106 return S_OK;
1108 case WS_XML_TEXT_TYPE_UINT64:
1110 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1111 unsigned char buf[21]; /* "18446744073709551615" */
1112 ULONG len = format_uint64( &uint64_text->value, buf );
1114 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1115 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1116 memcpy( (*ret)->value.bytes + len_old, buf, len );
1117 return S_OK;
1119 case WS_XML_TEXT_TYPE_DOUBLE:
1121 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1122 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1123 unsigned short fpword;
1124 ULONG len;
1126 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
1127 len = format_double( &double_text->value, buf );
1128 restore_fpword( fpword );
1129 if (!len) return E_NOTIMPL;
1131 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1132 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1133 memcpy( (*ret)->value.bytes + len_old, buf, len );
1134 return S_OK;
1136 case WS_XML_TEXT_TYPE_GUID:
1138 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1140 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
1141 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1142 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1143 return S_OK;
1145 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1147 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1149 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
1150 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1151 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1152 return S_OK;
1154 case WS_XML_TEXT_TYPE_DATETIME:
1156 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1158 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
1159 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1160 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
1161 return S_OK;
1163 case WS_XML_TEXT_TYPE_QNAME:
1165 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
1166 ULONG len = qn->localName->length;
1168 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
1169 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1170 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1171 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
1172 return S_OK;
1174 default:
1175 FIXME( "unhandled text type %u\n", text->textType );
1176 return E_NOTIMPL;
1180 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
1182 enum record_type type;
1183 BOOL use_dict = FALSE;
1184 HRESULT hr;
1185 ULONG id;
1187 if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
1189 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1190 use_dict = get_string_id( writer, &utf8->value, &id );
1192 type = get_attr_text_record_type( text, use_dict );
1194 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1195 write_char( writer, type );
1197 switch (type)
1199 case RECORD_CHARS8_TEXT:
1201 const WS_XML_UTF8_TEXT *text_utf8;
1202 WS_XML_UTF8_TEXT *new = NULL;
1203 UINT8 len;
1205 if (!text)
1207 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1208 write_char( writer, 0 );
1209 return S_OK;
1211 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1212 else
1214 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1215 text_utf8 = new;
1217 len = text_utf8->value.length;
1218 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1220 heap_free( new );
1221 return hr;
1223 write_char( writer, len );
1224 write_bytes( writer, text_utf8->value.bytes, len );
1225 heap_free( new );
1226 return S_OK;
1228 case RECORD_CHARS16_TEXT:
1230 const WS_XML_UTF8_TEXT *text_utf8;
1231 WS_XML_UTF8_TEXT *new = NULL;
1232 UINT16 len;
1234 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1235 else
1237 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1238 text_utf8 = new;
1240 len = text_utf8->value.length;
1241 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1243 heap_free( new );
1244 return hr;
1246 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1247 write_bytes( writer, text_utf8->value.bytes, len );
1248 heap_free( new );
1249 return S_OK;
1251 case RECORD_BYTES8_TEXT:
1253 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1254 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
1255 write_char( writer, text_base64->length );
1256 write_bytes( writer, text_base64->bytes, text_base64->length );
1257 return S_OK;
1259 case RECORD_BYTES16_TEXT:
1261 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1262 UINT16 len = text_base64->length;
1263 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
1264 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1265 write_bytes( writer, text_base64->bytes, len );
1266 return S_OK;
1268 case RECORD_ZERO_TEXT:
1269 case RECORD_ONE_TEXT:
1270 case RECORD_FALSE_TEXT:
1271 case RECORD_TRUE_TEXT:
1272 return S_OK;
1274 case RECORD_INT8_TEXT:
1276 INT8 val = get_text_value_int( text );
1277 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1278 write_char( writer, val );
1279 return S_OK;
1281 case RECORD_INT16_TEXT:
1283 INT16 val = get_text_value_int( text );
1284 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1285 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1286 return S_OK;
1288 case RECORD_INT32_TEXT:
1290 INT32 val = get_text_value_int( text );
1291 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1292 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1293 return S_OK;
1295 case RECORD_INT64_TEXT:
1297 INT64 val = get_text_value_int( text );
1298 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1299 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1300 return S_OK;
1302 case RECORD_UINT64_TEXT:
1304 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
1305 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
1306 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
1307 return S_OK;
1309 case RECORD_DOUBLE_TEXT:
1311 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
1312 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
1313 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
1314 return S_OK;
1316 case RECORD_GUID_TEXT:
1318 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
1319 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
1320 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
1321 return S_OK;
1323 case RECORD_UNIQUE_ID_TEXT:
1325 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
1326 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
1327 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
1328 return S_OK;
1330 case RECORD_DATETIME_TEXT:
1332 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
1333 UINT64 val = text_datetime->value.ticks;
1335 assert( val <= TICKS_MAX );
1336 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
1337 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
1339 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1340 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1341 return S_OK;
1343 default:
1344 FIXME( "unhandled record type %02x\n", type );
1345 return E_NOTIMPL;
1349 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1351 if (!attr->prefix || !attr->prefix->length)
1353 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
1354 return RECORD_SHORT_ATTRIBUTE;
1356 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
1358 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1359 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1361 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
1362 return RECORD_ATTRIBUTE;
1365 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1367 ULONG id;
1368 enum record_type type = get_attr_record_type( attr, get_string_id(writer, attr->localName, &id) );
1369 HRESULT hr;
1371 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1372 write_char( writer, type );
1374 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
1376 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1377 return write_attribute_value_bin( writer, attr->value );
1379 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
1381 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1382 return write_attribute_value_bin( writer, attr->value );
1385 switch (type)
1387 case RECORD_SHORT_ATTRIBUTE:
1388 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1389 break;
1391 case RECORD_ATTRIBUTE:
1392 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1393 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1394 break;
1396 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
1397 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1398 break;
1400 case RECORD_DICTIONARY_ATTRIBUTE:
1401 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1402 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1403 break;
1405 default:
1406 ERR( "unhandled record type %02x\n", type );
1407 return WS_E_NOT_SUPPORTED;
1410 return write_attribute_value_bin( writer, attr->value );
1413 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1415 switch (writer->output_enc)
1417 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
1418 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
1419 default:
1420 ERR( "unhandled encoding %u\n", writer->output_enc );
1421 return WS_E_NOT_SUPPORTED;
1425 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1427 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
1430 /**************************************************************************
1431 * WsGetPrefixFromNamespace [webservices.@]
1433 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
1434 BOOL required, const WS_XML_STRING **prefix,
1435 WS_ERROR *error )
1437 struct writer *writer = (struct writer *)handle;
1438 WS_XML_ELEMENT_NODE *elem;
1439 BOOL found = FALSE;
1440 HRESULT hr = S_OK;
1442 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1443 if (error) FIXME( "ignoring error parameter\n" );
1445 if (!writer || !ns || !prefix) return E_INVALIDARG;
1447 EnterCriticalSection( &writer->cs );
1449 if (writer->magic != WRITER_MAGIC)
1451 LeaveCriticalSection( &writer->cs );
1452 return E_INVALIDARG;
1455 elem = &writer->current->hdr;
1456 if (elem->prefix && is_current_namespace( writer, ns ))
1458 *prefix = elem->prefix;
1459 found = TRUE;
1462 if (!found)
1464 if (required) hr = WS_E_INVALID_FORMAT;
1465 else
1467 *prefix = NULL;
1468 hr = S_FALSE;
1472 LeaveCriticalSection( &writer->cs );
1473 return hr;
1476 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1478 unsigned char quote = attr->singleQuote ? '\'' : '"';
1479 ULONG size;
1480 HRESULT hr;
1482 /* ' xmlns:prefix="namespace"' */
1484 size = attr->ns->length + 9 /* ' xmlns=""' */;
1485 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
1486 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1488 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1489 if (attr->prefix)
1491 write_char( writer, ':' );
1492 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1494 write_char( writer, '=' );
1495 write_char( writer, quote );
1496 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1497 write_char( writer, quote );
1499 return S_OK;
1502 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1504 if (!attr->prefix || !attr->prefix->length)
1506 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1507 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1509 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1510 return RECORD_XMLNS_ATTRIBUTE;
1513 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1515 ULONG id;
1516 enum record_type type = get_xmlns_record_type( attr, get_string_id(writer, attr->ns, &id) );
1517 HRESULT hr;
1519 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1520 write_char( writer, type );
1522 switch (type)
1524 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1525 break;
1527 case RECORD_XMLNS_ATTRIBUTE:
1528 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1529 break;
1531 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1532 return write_dict_string( writer, id );
1534 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1535 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1536 return write_dict_string( writer, id );
1538 default:
1539 ERR( "unhandled record type %02x\n", type );
1540 return WS_E_NOT_SUPPORTED;
1543 return write_string( writer, attr->ns->bytes, attr->ns->length );
1546 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1548 switch (writer->output_enc)
1550 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1551 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1552 default:
1553 ERR( "unhandled encoding %u\n", writer->output_enc );
1554 return WS_E_NOT_SUPPORTED;
1558 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1559 const WS_XML_STRING *ns, BOOL single )
1561 WS_XML_ATTRIBUTE *attr;
1562 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1563 HRESULT hr;
1565 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1567 attr->singleQuote = !!single;
1568 attr->isXmlNs = 1;
1569 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1571 free_attribute( attr );
1572 return E_OUTOFMEMORY;
1574 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1576 free_attribute( attr );
1577 return E_OUTOFMEMORY;
1579 if ((hr = append_attribute( elem, attr )) != S_OK)
1581 free_attribute( attr );
1582 return hr;
1584 return S_OK;
1587 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1589 if (!str1 && !str2) return TRUE;
1590 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1593 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1594 const WS_XML_STRING *ns )
1596 ULONG i;
1597 const struct node *node;
1599 for (node = (const struct node *)elem; node; node = node->parent)
1601 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1603 elem = &node->hdr;
1604 for (i = 0; i < elem->attributeCount; i++)
1606 if (!elem->attributes[i]->isXmlNs) continue;
1607 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1608 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1611 return FALSE;
1614 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1616 WS_XML_STRING *str;
1617 if (!(str = dup_xml_string( ns, writer->dict_do_lookup ))) return E_OUTOFMEMORY;
1618 free_xml_string( writer->current_ns );
1619 writer->current_ns = str;
1620 return S_OK;
1623 static HRESULT set_namespaces( struct writer *writer )
1625 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1626 HRESULT hr;
1627 ULONG i;
1629 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1631 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1632 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1635 for (i = 0; i < elem->attributeCount; i++)
1637 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1638 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1639 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1642 return S_OK;
1645 /**************************************************************************
1646 * WsWriteEndAttribute [webservices.@]
1648 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1650 struct writer *writer = (struct writer *)handle;
1652 TRACE( "%p %p\n", handle, error );
1653 if (error) FIXME( "ignoring error parameter\n" );
1655 if (!writer) return E_INVALIDARG;
1657 EnterCriticalSection( &writer->cs );
1659 if (writer->magic != WRITER_MAGIC)
1661 LeaveCriticalSection( &writer->cs );
1662 return E_INVALIDARG;
1665 writer->state = WRITER_STATE_STARTELEMENT;
1667 LeaveCriticalSection( &writer->cs );
1668 return S_OK;
1671 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1673 ULONG i;
1674 HRESULT hr;
1675 for (i = 0; i < elem->attributeCount; i++)
1677 if (elem->attributes[i]->isXmlNs) continue;
1678 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1680 for (i = 0; i < elem->attributeCount; i++)
1682 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1683 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1685 for (i = 0; i < elem->attributeCount; i++)
1687 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1688 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1690 return S_OK;
1693 static HRESULT write_startelement_text( struct writer *writer )
1695 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1696 ULONG size;
1697 HRESULT hr;
1699 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1701 size = elem->localName->length + 1 /* '<' */;
1702 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1703 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1705 write_char( writer, '<' );
1706 if (elem->prefix && elem->prefix->length)
1708 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1709 write_char( writer, ':' );
1711 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1712 return write_attributes( writer, elem );
1715 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1717 if (!elem->prefix || !elem->prefix->length)
1719 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1720 return RECORD_SHORT_ELEMENT;
1722 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1724 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1725 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1727 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1728 return RECORD_ELEMENT;
1731 static HRESULT write_startelement_bin( struct writer *writer )
1733 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1734 ULONG id;
1735 enum record_type type = get_elem_record_type( elem, get_string_id(writer, elem->localName, &id) );
1736 HRESULT hr;
1738 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1739 write_char( writer, type );
1741 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1743 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1744 return write_attributes( writer, elem );
1746 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1748 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1749 return write_attributes( writer, elem );
1752 switch (type)
1754 case RECORD_SHORT_ELEMENT:
1755 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1756 break;
1758 case RECORD_ELEMENT:
1759 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1760 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1761 break;
1763 case RECORD_SHORT_DICTIONARY_ELEMENT:
1764 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1765 break;
1767 case RECORD_DICTIONARY_ELEMENT:
1768 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1769 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1770 break;
1772 default:
1773 ERR( "unhandled record type %02x\n", type );
1774 return WS_E_NOT_SUPPORTED;
1777 return write_attributes( writer, elem );
1780 static HRESULT write_startelement( struct writer *writer )
1782 switch (writer->output_enc)
1784 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1785 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1786 default:
1787 ERR( "unhandled encoding %u\n", writer->output_enc );
1788 return WS_E_NOT_SUPPORTED;
1792 static struct node *write_find_startelement( struct writer *writer )
1794 struct node *node;
1795 for (node = writer->current; node; node = node->parent)
1797 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1799 return NULL;
1802 static inline BOOL is_empty_element( const struct node *node )
1804 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1805 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1808 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1810 ULONG size;
1811 HRESULT hr;
1813 /* '/>' */
1815 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1817 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1818 write_char( writer, '/' );
1819 write_char( writer, '>' );
1820 return S_OK;
1823 /* '</prefix:localname>' */
1825 size = elem->localName->length + 3 /* '</>' */;
1826 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1827 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1829 write_char( writer, '<' );
1830 write_char( writer, '/' );
1831 if (elem->prefix && elem->prefix->length)
1833 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1834 write_char( writer, ':' );
1836 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1837 write_char( writer, '>' );
1838 return S_OK;
1841 static HRESULT write_endelement_bin( struct writer *writer )
1843 HRESULT hr;
1844 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1845 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1846 write_char( writer, RECORD_ENDELEMENT );
1847 return S_OK;
1850 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1852 switch (writer->output_enc)
1854 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1855 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1856 default:
1857 ERR( "unhandled encoding %u\n", writer->output_enc );
1858 return WS_E_NOT_SUPPORTED;
1862 static HRESULT write_close_element( struct writer *writer, struct node *node )
1864 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1865 elem->isEmpty = is_empty_element( node );
1866 return write_endelement( writer, elem );
1869 static HRESULT write_endelement_node( struct writer *writer )
1871 struct node *node;
1872 HRESULT hr;
1874 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1875 if (writer->state == WRITER_STATE_STARTELEMENT)
1877 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1878 if ((hr = write_startelement( writer )) != S_OK) return hr;
1880 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1881 writer->current = node->parent;
1882 writer->state = WRITER_STATE_ENDELEMENT;
1883 return S_OK;
1886 /**************************************************************************
1887 * WsWriteEndElement [webservices.@]
1889 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1891 struct writer *writer = (struct writer *)handle;
1892 HRESULT hr;
1894 TRACE( "%p %p\n", handle, error );
1895 if (error) FIXME( "ignoring error parameter\n" );
1897 if (!writer) return E_INVALIDARG;
1899 EnterCriticalSection( &writer->cs );
1901 if (writer->magic != WRITER_MAGIC)
1903 LeaveCriticalSection( &writer->cs );
1904 return E_INVALIDARG;
1907 hr = write_endelement_node( writer );
1909 LeaveCriticalSection( &writer->cs );
1910 return hr;
1913 static HRESULT write_endstartelement_text( struct writer *writer )
1915 HRESULT hr;
1916 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1917 write_char( writer, '>' );
1918 return S_OK;
1921 static HRESULT write_endstartelement( struct writer *writer )
1923 switch (writer->output_enc)
1925 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1926 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1927 default:
1928 ERR( "unhandled encoding %u\n", writer->output_enc );
1929 return WS_E_NOT_SUPPORTED;
1933 /**************************************************************************
1934 * WsWriteEndStartElement [webservices.@]
1936 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
1938 struct writer *writer = (struct writer *)handle;
1939 HRESULT hr;
1941 TRACE( "%p %p\n", handle, error );
1942 if (error) FIXME( "ignoring error parameter\n" );
1944 if (!writer) return E_INVALIDARG;
1946 EnterCriticalSection( &writer->cs );
1948 if (writer->magic != WRITER_MAGIC)
1950 LeaveCriticalSection( &writer->cs );
1951 return E_INVALIDARG;
1954 if (writer->state != WRITER_STATE_STARTELEMENT)
1956 LeaveCriticalSection( &writer->cs );
1957 return WS_E_INVALID_OPERATION;
1960 if ((hr = set_namespaces( writer )) != S_OK) goto done;
1961 if ((hr = write_startelement( writer )) != S_OK) goto done;
1962 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
1963 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1965 done:
1966 LeaveCriticalSection( &writer->cs );
1967 return hr;
1970 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1971 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1972 BOOL single )
1974 WS_XML_ATTRIBUTE *attr;
1975 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1976 HRESULT hr;
1978 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1980 if (!prefix && ns->length) prefix = elem->prefix;
1982 attr->singleQuote = !!single;
1983 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1985 free_attribute( attr );
1986 return E_OUTOFMEMORY;
1988 if (!(attr->localName = dup_xml_string( localname, writer->dict_do_lookup )))
1990 free_attribute( attr );
1991 return E_OUTOFMEMORY;
1993 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1995 free_attribute( attr );
1996 return E_OUTOFMEMORY;
1998 if ((hr = append_attribute( elem, attr )) != S_OK)
2000 free_attribute( attr );
2001 return hr;
2003 return S_OK;
2006 /**************************************************************************
2007 * WsWriteStartAttribute [webservices.@]
2009 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2010 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2011 BOOL single, WS_ERROR *error )
2013 struct writer *writer = (struct writer *)handle;
2014 HRESULT hr;
2016 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2017 debugstr_xmlstr(ns), single, error );
2018 if (error) FIXME( "ignoring error parameter\n" );
2020 if (!writer || !localname || !ns) return E_INVALIDARG;
2022 EnterCriticalSection( &writer->cs );
2024 if (writer->magic != WRITER_MAGIC)
2026 LeaveCriticalSection( &writer->cs );
2027 return E_INVALIDARG;
2030 if (writer->state != WRITER_STATE_STARTELEMENT)
2032 LeaveCriticalSection( &writer->cs );
2033 return WS_E_INVALID_OPERATION;
2036 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
2037 writer->state = WRITER_STATE_STARTATTRIBUTE;
2039 LeaveCriticalSection( &writer->cs );
2040 return hr;
2043 /* flush current start element if necessary */
2044 static HRESULT write_flush( struct writer *writer )
2046 if (writer->state == WRITER_STATE_STARTELEMENT)
2048 HRESULT hr;
2049 if ((hr = set_namespaces( writer )) != S_OK) return hr;
2050 if ((hr = write_startelement( writer )) != S_OK) return hr;
2051 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
2052 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2054 return S_OK;
2057 static HRESULT write_add_cdata_node( struct writer *writer )
2059 struct node *node, *parent;
2060 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2061 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2062 write_insert_node( writer, parent, node );
2063 return S_OK;
2066 static HRESULT write_add_endcdata_node( struct writer *writer )
2068 struct node *node;
2069 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
2070 node->parent = writer->current;
2071 list_add_tail( &node->parent->children, &node->entry );
2072 return S_OK;
2075 static HRESULT write_cdata( struct writer *writer )
2077 HRESULT hr;
2078 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
2079 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
2080 return S_OK;
2083 static HRESULT write_cdata_node( struct writer *writer )
2085 HRESULT hr;
2086 if ((hr = write_flush( writer )) != S_OK) return hr;
2087 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
2088 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
2089 if ((hr = write_cdata( writer )) != S_OK) return hr;
2090 writer->state = WRITER_STATE_STARTCDATA;
2091 return S_OK;
2094 /**************************************************************************
2095 * WsWriteStartCData [webservices.@]
2097 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
2099 struct writer *writer = (struct writer *)handle;
2100 HRESULT hr;
2102 TRACE( "%p %p\n", handle, error );
2103 if (error) FIXME( "ignoring error parameter\n" );
2105 if (!writer) return E_INVALIDARG;
2107 EnterCriticalSection( &writer->cs );
2109 if (writer->magic != WRITER_MAGIC)
2111 LeaveCriticalSection( &writer->cs );
2112 return E_INVALIDARG;
2115 hr = write_cdata_node( writer );
2117 LeaveCriticalSection( &writer->cs );
2118 return hr;
2121 static HRESULT write_endcdata( struct writer *writer )
2123 HRESULT hr;
2124 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2125 write_bytes( writer, (const BYTE *)"]]>", 3 );
2126 return S_OK;
2129 static HRESULT write_endcdata_node( struct writer *writer )
2131 HRESULT hr;
2132 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2133 writer->current = writer->current->parent;
2134 writer->state = WRITER_STATE_ENDCDATA;
2135 return S_OK;
2138 /**************************************************************************
2139 * WsWriteEndCData [webservices.@]
2141 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
2143 struct writer *writer = (struct writer *)handle;
2144 HRESULT hr;
2146 TRACE( "%p %p\n", handle, error );
2147 if (error) FIXME( "ignoring error parameter\n" );
2149 if (!writer) return E_INVALIDARG;
2151 EnterCriticalSection( &writer->cs );
2153 if (writer->magic != WRITER_MAGIC)
2155 LeaveCriticalSection( &writer->cs );
2156 return E_INVALIDARG;
2159 if (writer->state != WRITER_STATE_TEXT)
2161 LeaveCriticalSection( &writer->cs );
2162 return WS_E_INVALID_OPERATION;
2165 hr = write_endcdata_node( writer );
2167 LeaveCriticalSection( &writer->cs );
2168 return hr;
2171 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2172 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2174 struct node *node, *parent;
2175 WS_XML_ELEMENT_NODE *elem;
2177 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2179 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
2181 elem = &parent->hdr;
2182 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
2185 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
2186 elem = &node->hdr;
2188 if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2190 free_node( node );
2191 return E_OUTOFMEMORY;
2193 if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2195 free_node( node );
2196 return E_OUTOFMEMORY;
2198 if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2200 free_node( node );
2201 return E_OUTOFMEMORY;
2203 write_insert_node( writer, parent, node );
2204 return S_OK;
2207 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
2209 struct node *node;
2210 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
2211 node->parent = parent;
2212 list_add_tail( &parent->children, &node->entry );
2213 return S_OK;
2216 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2217 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2219 HRESULT hr;
2220 if ((hr = write_flush( writer )) != S_OK) return hr;
2221 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
2222 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
2223 writer->state = WRITER_STATE_STARTELEMENT;
2224 return S_OK;
2227 /**************************************************************************
2228 * WsWriteStartElement [webservices.@]
2230 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2231 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2232 WS_ERROR *error )
2234 struct writer *writer = (struct writer *)handle;
2235 HRESULT hr;
2237 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2238 debugstr_xmlstr(ns), error );
2239 if (error) FIXME( "ignoring error parameter\n" );
2241 if (!writer || !localname || !ns) return E_INVALIDARG;
2243 EnterCriticalSection( &writer->cs );
2245 if (writer->magic != WRITER_MAGIC)
2247 LeaveCriticalSection( &writer->cs );
2248 return E_INVALIDARG;
2251 hr = write_element_node( writer, prefix, localname, ns );
2253 LeaveCriticalSection( &writer->cs );
2254 return hr;
2257 static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2259 if (offset) *offset = 0;
2260 switch (text->textType)
2262 case WS_XML_TEXT_TYPE_UTF8:
2264 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2265 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2266 WS_XML_UTF8_TEXT *new;
2267 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2269 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2270 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2271 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2272 if (offset) *offset = len_old;
2273 *ret = &new->text;
2274 return S_OK;
2276 case WS_XML_TEXT_TYPE_UTF16:
2278 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2279 const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
2280 WS_XML_UTF16_TEXT *new;
2281 ULONG len = utf16->byteCount, len_old = utf16_old ? utf16_old->byteCount : 0;
2283 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2284 if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2285 if (utf16_old) memcpy( new->bytes, utf16_old->bytes, len_old );
2286 memcpy( new->bytes + len_old, utf16->bytes, len );
2287 if (offset) *offset = len_old;
2288 *ret = &new->text;
2289 return S_OK;
2291 case WS_XML_TEXT_TYPE_BASE64:
2293 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2294 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2295 WS_XML_BASE64_TEXT *new;
2296 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2298 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2299 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2300 memcpy( new->bytes + len_old, base64->bytes, len );
2301 if (offset) *offset = len_old;
2302 *ret = &new->text;
2303 return S_OK;
2305 case WS_XML_TEXT_TYPE_BOOL:
2307 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2308 WS_XML_BOOL_TEXT *new;
2310 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2311 *ret = &new->text;
2312 return S_OK;
2314 case WS_XML_TEXT_TYPE_INT32:
2316 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2317 WS_XML_INT32_TEXT *new;
2319 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2320 *ret = &new->text;
2321 return S_OK;
2323 case WS_XML_TEXT_TYPE_INT64:
2325 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2326 WS_XML_INT64_TEXT *new;
2328 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2329 *ret = &new->text;
2330 return S_OK;
2332 case WS_XML_TEXT_TYPE_UINT64:
2334 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2335 WS_XML_UINT64_TEXT *new;
2337 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2338 *ret = &new->text;
2339 return S_OK;
2341 case WS_XML_TEXT_TYPE_DOUBLE:
2343 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2344 WS_XML_DOUBLE_TEXT *new;
2346 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2347 *ret = &new->text;
2348 return S_OK;
2350 case WS_XML_TEXT_TYPE_GUID:
2352 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2353 WS_XML_GUID_TEXT *new;
2355 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2356 *ret = &new->text;
2357 return S_OK;
2359 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2361 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2362 WS_XML_UNIQUE_ID_TEXT *new;
2364 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2365 *ret = &new->text;
2366 return S_OK;
2368 case WS_XML_TEXT_TYPE_DATETIME:
2370 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2371 WS_XML_DATETIME_TEXT *new;
2373 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2374 *ret = &new->text;
2375 return S_OK;
2377 default:
2378 FIXME( "unhandled text type %u\n", text->textType );
2379 return E_NOTIMPL;
2383 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2385 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2386 HRESULT hr;
2388 switch (value->textType)
2390 case WS_XML_TEXT_TYPE_UTF8:
2391 case WS_XML_TEXT_TYPE_UTF16:
2392 case WS_XML_TEXT_TYPE_BASE64:
2393 break;
2395 case WS_XML_TEXT_TYPE_BOOL:
2396 case WS_XML_TEXT_TYPE_INT32:
2397 case WS_XML_TEXT_TYPE_INT64:
2398 case WS_XML_TEXT_TYPE_UINT64:
2399 case WS_XML_TEXT_TYPE_DOUBLE:
2400 case WS_XML_TEXT_TYPE_GUID:
2401 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2402 case WS_XML_TEXT_TYPE_DATETIME:
2403 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2404 break;
2406 default:
2407 FIXME( "unhandled text type %u\n", value->textType );
2408 return E_NOTIMPL;
2411 switch (writer->output_enc)
2413 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2415 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2416 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2417 heap_free( old );
2418 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2419 break;
2421 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2423 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2424 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2425 heap_free( old );
2426 elem->attributes[elem->attributeCount - 1]->value = new;
2427 break;
2429 default:
2430 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2431 return E_NOTIMPL;
2434 return S_OK;
2437 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2439 struct node *node;
2440 WS_XML_TEXT_NODE *text;
2441 HRESULT hr;
2443 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2444 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2445 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2447 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2448 text = (WS_XML_TEXT_NODE *)node;
2450 switch (writer->output_enc)
2452 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2454 WS_XML_UTF8_TEXT *new;
2455 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2457 heap_free( node );
2458 return hr;
2460 text->text = &new->text;
2461 break;
2463 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2465 WS_XML_TEXT *new;
2466 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2468 heap_free( node );
2469 return hr;
2471 text->text = new;
2472 break;
2474 default:
2475 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2476 heap_free( node );
2477 return E_NOTIMPL;
2480 write_insert_node( writer, writer->current, node );
2481 return S_OK;
2484 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2486 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2487 HRESULT hr;
2489 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2491 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2492 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2494 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2496 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2497 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2498 return S_OK;
2501 return WS_E_INVALID_FORMAT;
2504 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
2506 switch (text->textType)
2508 case WS_XML_TEXT_TYPE_UTF8:
2510 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2511 if (use_dict) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT;
2512 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2513 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2514 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2516 case WS_XML_TEXT_TYPE_UTF16:
2518 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
2519 int len = text_utf16->byteCount / sizeof(WCHAR);
2520 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
2521 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2522 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2523 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2525 case WS_XML_TEXT_TYPE_BASE64:
2527 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2528 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2529 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2530 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2531 return RECORD_BYTES32_TEXT;
2533 case WS_XML_TEXT_TYPE_BOOL:
2535 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2536 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2538 case WS_XML_TEXT_TYPE_INT32:
2540 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2541 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2542 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2543 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2544 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2545 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2547 case WS_XML_TEXT_TYPE_INT64:
2549 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2550 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2551 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2552 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2553 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2554 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2555 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2557 case WS_XML_TEXT_TYPE_UINT64:
2559 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2560 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2561 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2562 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2563 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2564 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2565 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2566 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2568 case WS_XML_TEXT_TYPE_DOUBLE:
2570 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2571 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2572 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2573 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2574 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2575 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2576 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2577 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2578 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2580 case WS_XML_TEXT_TYPE_GUID:
2581 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2583 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2584 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2586 case WS_XML_TEXT_TYPE_DATETIME:
2587 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2589 default:
2590 FIXME( "unhandled text type %u\n", text->textType );
2591 return 0;
2595 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2597 enum record_type type;
2598 BOOL use_dict = FALSE;
2599 HRESULT hr;
2600 ULONG id;
2602 if (offset)
2604 FIXME( "no support for appending text in binary mode\n" );
2605 return E_NOTIMPL;
2608 if (text->textType == WS_XML_TEXT_TYPE_UTF8)
2610 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2611 use_dict = get_string_id( writer, &utf8->value, &id );
2614 switch ((type = get_text_record_type( text, use_dict )))
2616 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2618 const WS_XML_UTF8_TEXT *text_utf8;
2619 WS_XML_UTF8_TEXT *new = NULL;
2620 UINT8 len;
2622 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2623 else
2625 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2626 text_utf8 = new;
2628 len = text_utf8->value.length;
2629 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2631 heap_free( new );
2632 return hr;
2634 write_char( writer, type );
2635 write_char( writer, len );
2636 write_bytes( writer, text_utf8->value.bytes, len );
2637 heap_free( new );
2638 return S_OK;
2640 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2642 const WS_XML_UTF8_TEXT *text_utf8;
2643 WS_XML_UTF8_TEXT *new = NULL;
2644 UINT16 len;
2646 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2647 else
2649 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2650 text_utf8 = new;
2652 len = text_utf8->value.length;
2653 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2655 heap_free( new );
2656 return hr;
2658 write_char( writer, type );
2659 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2660 write_bytes( writer, text_utf8->value.bytes, len );
2661 heap_free( new );
2662 return S_OK;
2664 case RECORD_BYTES8_TEXT:
2666 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2667 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2669 if (len)
2671 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2672 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2673 write_char( writer, len );
2674 write_bytes( writer, text_base64->bytes, len );
2676 if (rem)
2678 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2679 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2680 write_char( writer, rem );
2681 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2683 return S_OK;
2685 case RECORD_BYTES16_TEXT:
2687 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2688 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2690 if (len)
2692 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2693 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2694 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2695 write_bytes( writer, text_base64->bytes, len );
2697 if (rem)
2699 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2700 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2701 write_char( writer, rem );
2702 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2704 return S_OK;
2706 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2707 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2708 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2709 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2711 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2712 write_char( writer, type );
2713 return S_OK;
2715 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2717 INT8 val = get_text_value_int( text );
2718 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2719 write_char( writer, type );
2720 write_char( writer, val );
2721 return S_OK;
2723 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2725 INT16 val = get_text_value_int( text );
2726 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2727 write_char( writer, type );
2728 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2729 return S_OK;
2731 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2733 INT32 val = get_text_value_int( text );
2734 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2735 write_char( writer, type );
2736 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2737 return S_OK;
2739 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2741 INT64 val = get_text_value_int( text );
2742 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2743 write_char( writer, type );
2744 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2745 return S_OK;
2747 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2749 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2750 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2751 write_char( writer, type );
2752 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2753 return S_OK;
2755 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2757 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2758 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2759 write_char( writer, type );
2760 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2761 return S_OK;
2763 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2765 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2766 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2767 write_char( writer, type );
2768 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2769 return S_OK;
2771 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2773 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2774 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2775 write_char( writer, type );
2776 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2777 return S_OK;
2779 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2781 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2782 UINT64 val = text_datetime->value.ticks;
2784 assert( val <= TICKS_MAX );
2785 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2786 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2788 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2789 write_char( writer, type );
2790 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2791 return S_OK;
2793 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
2795 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2796 write_char( writer, type );
2797 return write_dict_string( writer, id );
2799 default:
2800 FIXME( "unhandled record type %02x\n", type );
2801 return E_NOTIMPL;
2805 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2807 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2809 switch (writer->output_enc)
2811 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2812 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2813 default:
2814 ERR( "unhandled encoding %u\n", writer->output_enc );
2815 return WS_E_NOT_SUPPORTED;
2819 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2821 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2822 ULONG offset = 0;
2823 HRESULT hr;
2825 if ((hr = write_flush( writer )) != S_OK) return hr;
2826 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2828 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2829 node = (WS_XML_TEXT_NODE *)writer->current;
2831 else
2833 switch (writer->output_enc)
2835 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2837 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2838 offset = old->value.length;
2839 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2840 heap_free( old );
2841 node->text = &new->text;
2842 break;
2844 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2846 WS_XML_TEXT *new, *old = node->text;
2847 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2848 heap_free( old );
2849 node->text = new;
2850 break;
2852 default:
2853 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2854 return E_NOTIMPL;
2858 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2860 writer->state = WRITER_STATE_TEXT;
2861 return S_OK;
2864 /**************************************************************************
2865 * WsWriteText [webservices.@]
2867 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2869 struct writer *writer = (struct writer *)handle;
2870 HRESULT hr;
2872 TRACE( "%p %p %p\n", handle, text, error );
2873 if (error) FIXME( "ignoring error parameter\n" );
2875 if (!writer || !text) return E_INVALIDARG;
2877 EnterCriticalSection( &writer->cs );
2879 if (writer->magic != WRITER_MAGIC)
2881 LeaveCriticalSection( &writer->cs );
2882 return E_INVALIDARG;
2885 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2886 else hr = write_text_node( writer, text );
2888 LeaveCriticalSection( &writer->cs );
2889 return hr;
2892 /**************************************************************************
2893 * WsWriteBytes [webservices.@]
2895 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2897 struct writer *writer = (struct writer *)handle;
2898 WS_XML_BASE64_TEXT base64;
2899 HRESULT hr;
2901 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2902 if (error) FIXME( "ignoring error parameter\n" );
2904 if (!writer) return E_INVALIDARG;
2906 EnterCriticalSection( &writer->cs );
2908 if (writer->magic != WRITER_MAGIC)
2910 LeaveCriticalSection( &writer->cs );
2911 return E_INVALIDARG;
2914 if (!writer->output_type)
2916 LeaveCriticalSection( &writer->cs );
2917 return WS_E_INVALID_OPERATION;
2920 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2921 base64.bytes = (BYTE *)bytes;
2922 base64.length = count;
2924 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2925 else hr = write_text_node( writer, &base64.text );
2927 LeaveCriticalSection( &writer->cs );
2928 return hr;
2931 /**************************************************************************
2932 * WsWriteChars [webservices.@]
2934 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
2936 struct writer *writer = (struct writer *)handle;
2937 WS_XML_UTF16_TEXT utf16;
2938 HRESULT hr;
2940 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
2941 if (error) FIXME( "ignoring error parameter\n" );
2943 if (!writer) return E_INVALIDARG;
2945 EnterCriticalSection( &writer->cs );
2947 if (writer->magic != WRITER_MAGIC)
2949 LeaveCriticalSection( &writer->cs );
2950 return E_INVALIDARG;
2953 if (!writer->output_type)
2955 LeaveCriticalSection( &writer->cs );
2956 return WS_E_INVALID_OPERATION;
2959 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2960 utf16.bytes = (BYTE *)chars;
2961 utf16.byteCount = count * sizeof(WCHAR);
2963 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
2964 else hr = write_text_node( writer, &utf16.text );
2966 LeaveCriticalSection( &writer->cs );
2967 return hr;
2970 /**************************************************************************
2971 * WsWriteCharsUtf8 [webservices.@]
2973 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
2975 struct writer *writer = (struct writer *)handle;
2976 WS_XML_UTF8_TEXT utf8;
2977 HRESULT hr;
2979 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
2980 if (error) FIXME( "ignoring error parameter\n" );
2982 if (!writer) return E_INVALIDARG;
2984 EnterCriticalSection( &writer->cs );
2986 if (writer->magic != WRITER_MAGIC)
2988 LeaveCriticalSection( &writer->cs );
2989 return E_INVALIDARG;
2992 if (!writer->output_type)
2994 LeaveCriticalSection( &writer->cs );
2995 return WS_E_INVALID_OPERATION;
2998 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2999 utf8.value.bytes = (BYTE *)bytes;
3000 utf8.value.length = count;
3002 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
3003 else hr = write_text_node( writer, &utf8.text );
3005 LeaveCriticalSection( &writer->cs );
3006 return hr;
3009 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
3011 switch (mapping)
3013 case WS_ELEMENT_TYPE_MAPPING:
3014 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3015 return write_text_node( writer, text );
3017 case WS_ATTRIBUTE_TYPE_MAPPING:
3018 return write_set_attribute_value( writer, text );
3020 case WS_ANY_ELEMENT_TYPE_MAPPING:
3021 switch (writer->state)
3023 case WRITER_STATE_STARTATTRIBUTE:
3024 return write_set_attribute_value( writer, text );
3026 case WRITER_STATE_STARTELEMENT:
3027 return write_text_node( writer, text );
3029 default:
3030 FIXME( "writer state %u not handled\n", writer->state );
3031 return E_NOTIMPL;
3034 default:
3035 FIXME( "mapping %u not implemented\n", mapping );
3036 return E_NOTIMPL;
3040 static HRESULT write_add_nil_attribute( struct writer *writer )
3042 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
3043 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
3044 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
3045 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
3046 HRESULT hr;
3048 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
3049 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
3050 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
3053 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
3054 const void **ptr )
3056 switch (option)
3058 case WS_WRITE_REQUIRED_VALUE:
3059 case WS_WRITE_NILLABLE_VALUE:
3060 if (!value || size != expected_size) return E_INVALIDARG;
3061 *ptr = value;
3062 return S_OK;
3064 case WS_WRITE_REQUIRED_POINTER:
3065 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
3066 return S_OK;
3068 case WS_WRITE_NILLABLE_POINTER:
3069 if (size != sizeof(const void *)) return E_INVALIDARG;
3070 *ptr = *(const void **)value;
3071 return S_OK;
3073 default:
3074 return E_INVALIDARG;
3078 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
3079 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
3080 const BOOL *value, ULONG size )
3082 WS_XML_BOOL_TEXT text_bool;
3083 const BOOL *ptr;
3084 HRESULT hr;
3086 if (desc)
3088 FIXME( "description not supported\n" );
3089 return E_NOTIMPL;
3092 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3093 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
3094 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3096 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
3097 text_bool.value = *ptr;
3098 return write_type_text( writer, mapping, &text_bool.text );
3101 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3102 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3103 const BOOL *value, ULONG size )
3105 WS_XML_INT32_TEXT text_int32;
3106 const INT8 *ptr;
3107 HRESULT hr;
3109 if (desc)
3111 FIXME( "description not supported\n" );
3112 return E_NOTIMPL;
3115 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3116 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3117 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3119 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3120 text_int32.value = *ptr;
3121 return write_type_text( writer, mapping, &text_int32.text );
3124 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3125 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3126 const BOOL *value, ULONG size )
3128 WS_XML_INT32_TEXT text_int32;
3129 const INT16 *ptr;
3130 HRESULT hr;
3132 if (desc)
3134 FIXME( "description not supported\n" );
3135 return E_NOTIMPL;
3138 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3139 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3140 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3142 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3143 text_int32.value = *ptr;
3144 return write_type_text( writer, mapping, &text_int32.text );
3147 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3148 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3149 const void *value, ULONG size )
3151 WS_XML_INT32_TEXT text_int32;
3152 const INT32 *ptr;
3153 HRESULT hr;
3155 if (desc)
3157 FIXME( "description not supported\n" );
3158 return E_NOTIMPL;
3161 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3162 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3163 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3165 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3166 text_int32.value = *ptr;
3167 return write_type_text( writer, mapping, &text_int32.text );
3170 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3171 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3172 const void *value, ULONG size )
3174 WS_XML_INT64_TEXT text_int64;
3175 const INT64 *ptr;
3176 HRESULT hr;
3178 if (desc)
3180 FIXME( "description not supported\n" );
3181 return E_NOTIMPL;
3184 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3185 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3186 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3188 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3189 text_int64.value = *ptr;
3190 return write_type_text( writer, mapping, &text_int64.text );
3193 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3194 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3195 const void *value, ULONG size )
3197 WS_XML_UINT64_TEXT text_uint64;
3198 const UINT8 *ptr;
3199 HRESULT hr;
3201 if (desc)
3203 FIXME( "description not supported\n" );
3204 return E_NOTIMPL;
3207 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3208 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3209 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3211 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3212 text_uint64.value = *ptr;
3213 return write_type_text( writer, mapping, &text_uint64.text );
3216 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3217 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3218 const void *value, ULONG size )
3220 WS_XML_UINT64_TEXT text_uint64;
3221 const UINT16 *ptr;
3222 HRESULT hr;
3224 if (desc)
3226 FIXME( "description not supported\n" );
3227 return E_NOTIMPL;
3230 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3231 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3232 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3234 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3235 text_uint64.value = *ptr;
3236 return write_type_text( writer, mapping, &text_uint64.text );
3239 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3240 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3241 const void *value, ULONG size )
3243 WS_XML_UINT64_TEXT text_uint64;
3244 const UINT32 *ptr;
3245 HRESULT hr;
3247 if (desc)
3249 FIXME( "description not supported\n" );
3250 return E_NOTIMPL;
3253 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3254 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3255 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3257 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3258 text_uint64.value = *ptr;
3259 return write_type_text( writer, mapping, &text_uint64.text );
3262 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3263 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3264 const void *value, ULONG size )
3266 WS_XML_UINT64_TEXT text_uint64;
3267 const UINT64 *ptr;
3268 HRESULT hr;
3270 if (desc)
3272 FIXME( "description not supported\n" );
3273 return E_NOTIMPL;
3276 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3277 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3278 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3280 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3281 text_uint64.value = *ptr;
3282 return write_type_text( writer, mapping, &text_uint64.text );
3285 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3286 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3287 const void *value, ULONG size )
3289 WS_XML_DOUBLE_TEXT text_double;
3290 const double *ptr;
3291 HRESULT hr;
3293 if (desc)
3295 FIXME( "description not supported\n" );
3296 return E_NOTIMPL;
3299 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3300 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3301 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3303 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3304 text_double.value = *ptr;
3305 return write_type_text( writer, mapping, &text_double.text );
3308 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3309 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3310 const void *value, ULONG size )
3312 WS_XML_DATETIME_TEXT text_datetime;
3313 const WS_DATETIME *ptr;
3314 HRESULT hr;
3316 if (desc)
3318 FIXME( "description not supported\n" );
3319 return E_NOTIMPL;
3322 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3323 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3324 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3325 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3327 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3328 text_datetime.value = *ptr;
3329 return write_type_text( writer, mapping, &text_datetime.text );
3332 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3333 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3334 const void *value, ULONG size )
3336 WS_XML_GUID_TEXT text_guid;
3337 const GUID *ptr;
3338 HRESULT hr;
3340 if (desc)
3342 FIXME( "description not supported\n" );
3343 return E_NOTIMPL;
3346 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3347 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3348 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3350 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3351 text_guid.value = *ptr;
3352 return write_type_text( writer, mapping, &text_guid.text );
3355 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3356 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3357 const void *value, ULONG size )
3359 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3360 WS_XML_UTF16_TEXT text_utf16;
3361 const WS_UNIQUE_ID *ptr;
3362 HRESULT hr;
3364 if (desc)
3366 FIXME( "description not supported\n" );
3367 return E_NOTIMPL;
3370 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3371 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3372 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3374 if (ptr->uri.length)
3376 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3377 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3378 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3379 return write_type_text( writer, mapping, &text_utf16.text );
3382 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3383 text_unique_id.value = ptr->guid;
3384 return write_type_text( writer, mapping, &text_unique_id.text );
3387 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3388 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3389 const void *value, ULONG size )
3391 WS_XML_UTF16_TEXT utf16;
3392 const WS_STRING *ptr;
3393 HRESULT hr;
3395 if (desc)
3397 FIXME( "description not supported\n" );
3398 return E_NOTIMPL;
3401 if (!option) return E_INVALIDARG;
3402 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3403 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3404 if (!ptr->length) return S_OK;
3406 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3407 utf16.bytes = (BYTE *)ptr->chars;
3408 utf16.byteCount = ptr->length * sizeof(WCHAR);
3409 return write_type_text( writer, mapping, &utf16.text );
3412 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3413 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3414 const void *value, ULONG size )
3416 WS_XML_UTF16_TEXT utf16;
3417 const WCHAR *ptr;
3418 HRESULT hr;
3419 int len;
3421 if (desc)
3423 FIXME( "description not supported\n" );
3424 return E_NOTIMPL;
3427 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3428 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3429 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3430 if (!(len = strlenW( ptr ))) return S_OK;
3432 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3433 utf16.bytes = (BYTE *)ptr;
3434 utf16.byteCount = len * sizeof(WCHAR);
3435 return write_type_text( writer, mapping, &utf16.text );
3438 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3439 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3440 const void *value, ULONG size )
3442 WS_XML_BASE64_TEXT base64;
3443 const WS_BYTES *ptr;
3444 HRESULT hr;
3446 if (desc)
3448 FIXME( "description not supported\n" );
3449 return E_NOTIMPL;
3452 if (!option) return E_INVALIDARG;
3453 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3454 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3455 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3456 if (!ptr->length) return S_OK;
3458 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3459 base64.bytes = ptr->bytes;
3460 base64.length = ptr->length;
3461 return write_type_text( writer, mapping, &base64.text );
3464 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3465 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3466 const void *value, ULONG size )
3468 WS_XML_UTF8_TEXT utf8;
3469 const WS_XML_STRING *ptr;
3470 HRESULT hr;
3472 if (desc)
3474 FIXME( "description not supported\n" );
3475 return E_NOTIMPL;
3478 if (!option) return E_INVALIDARG;
3479 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3480 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3481 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3482 if (!ptr->length) return S_OK;
3484 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3485 utf8.value.bytes = ptr->bytes;
3486 utf8.value.length = ptr->length;
3487 return write_type_text( writer, mapping, &utf8.text );
3490 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3492 const struct node *node;
3493 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3495 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3496 ULONG i;
3497 for (i = 0; i < elem->attributeCount; i++)
3499 if (!elem->attributes[i]->isXmlNs) continue;
3500 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3501 *prefix = elem->attributes[i]->prefix;
3502 return S_OK;
3505 return WS_E_INVALID_FORMAT;
3508 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3509 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3510 const void *value, ULONG size )
3512 WS_XML_QNAME_TEXT qname;
3513 const WS_XML_QNAME *ptr;
3514 const WS_XML_STRING *prefix;
3515 HRESULT hr;
3517 if (desc)
3519 FIXME( "description not supported\n" );
3520 return E_NOTIMPL;
3523 if (!option) return E_INVALIDARG;
3524 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3525 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3526 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3528 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3530 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3531 qname.prefix = (WS_XML_STRING *)prefix;
3532 qname.localName = (WS_XML_STRING *)&ptr->localName;
3533 qname.ns = (WS_XML_STRING *)&ptr->ns;
3534 return write_type_text( writer, mapping, &qname.text );
3537 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3539 if (options & WS_FIELD_POINTER)
3541 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3542 return WS_WRITE_REQUIRED_POINTER;
3545 switch (type)
3547 case WS_BOOL_TYPE:
3548 case WS_INT8_TYPE:
3549 case WS_INT16_TYPE:
3550 case WS_INT32_TYPE:
3551 case WS_INT64_TYPE:
3552 case WS_UINT8_TYPE:
3553 case WS_UINT16_TYPE:
3554 case WS_UINT32_TYPE:
3555 case WS_UINT64_TYPE:
3556 case WS_DOUBLE_TYPE:
3557 case WS_DATETIME_TYPE:
3558 case WS_GUID_TYPE:
3559 case WS_UNIQUE_ID_TYPE:
3560 case WS_STRING_TYPE:
3561 case WS_BYTES_TYPE:
3562 case WS_XML_STRING_TYPE:
3563 case WS_XML_QNAME_TYPE:
3564 case WS_STRUCT_TYPE:
3565 case WS_ENUM_TYPE:
3566 case WS_UNION_TYPE:
3567 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3568 return WS_WRITE_REQUIRED_VALUE;
3570 case WS_WSZ_TYPE:
3571 case WS_DESCRIPTION_TYPE:
3572 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3573 return WS_WRITE_REQUIRED_POINTER;
3575 default:
3576 FIXME( "unhandled type %u\n", type );
3577 return 0;
3581 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3583 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3584 const void *, ULONG );
3586 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3587 const void *value, ULONG size )
3589 ULONG i, offset;
3590 const void *ptr;
3591 int enum_value;
3592 HRESULT hr;
3594 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3596 if (size < sizeof(enum_value)) return E_INVALIDARG;
3597 if ((enum_value = *(int *)(char *)ptr + desc->enumOffset) == desc->noneEnumValue)
3599 switch (option)
3601 case WS_WRITE_REQUIRED_VALUE:
3602 return WS_E_INVALID_FORMAT;
3604 case WS_WRITE_NILLABLE_VALUE:
3605 return S_OK;
3607 default:
3608 ERR( "unhandled write option %u\n", option );
3609 return E_INVALIDARG;
3613 for (i = 0; i < desc->fieldCount; i++)
3615 if (desc->fields[i]->value == enum_value)
3617 offset = desc->fields[i]->field.offset;
3618 return write_type_field( writer, &desc->fields[i]->field, ptr, offset );
3622 return E_INVALIDARG;
3625 static HRESULT write_type_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3626 ULONG count )
3628 HRESULT hr = S_OK;
3629 ULONG i, size, offset = 0;
3630 WS_WRITE_OPTION option;
3632 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3634 /* wrapper element */
3635 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3636 return hr;
3638 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3639 size = get_type_size( desc->type, desc->typeDescription );
3640 else
3641 size = sizeof(const void *);
3643 for (i = 0; i < count; i++)
3645 if (desc->type == WS_UNION_TYPE)
3647 if ((hr = write_type_union( writer, desc->typeDescription, option, buf + offset, size )) != S_OK)
3648 return hr;
3650 else
3652 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3653 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3654 buf + offset, size )) != S_OK) return hr;
3655 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3657 offset += size;
3660 if (desc->localName) hr = write_endelement_node( writer );
3661 return hr;
3664 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3665 ULONG offset )
3667 HRESULT hr;
3668 WS_TYPE_MAPPING mapping;
3669 WS_WRITE_OPTION option;
3670 ULONG count, size, field_options = desc->options;
3671 const char *ptr = buf + offset;
3673 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
3675 FIXME( "options 0x%x not supported\n", desc->options );
3676 return E_NOTIMPL;
3679 /* zero-terminated strings are always pointers */
3680 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
3682 if (field_options & WS_FIELD_POINTER)
3683 size = sizeof(const void *);
3684 else
3685 size = get_type_size( desc->type, desc->typeDescription );
3687 if (is_nil_value( ptr, size ))
3689 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3690 if (field_options & WS_FIELD_NILLABLE)
3692 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3693 else option = WS_WRITE_NILLABLE_VALUE;
3695 else
3697 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3698 else option = WS_WRITE_REQUIRED_VALUE;
3701 else
3703 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3704 else option = WS_WRITE_REQUIRED_VALUE;
3707 switch (desc->mapping)
3709 case WS_ATTRIBUTE_FIELD_MAPPING:
3710 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3711 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3712 return hr;
3713 writer->state = WRITER_STATE_STARTATTRIBUTE;
3715 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3716 break;
3718 case WS_ELEMENT_FIELD_MAPPING:
3719 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3720 mapping = WS_ELEMENT_TYPE_MAPPING;
3721 break;
3723 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3724 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3725 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3726 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3728 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3729 case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING:
3730 count = *(const ULONG *)(buf + desc->countOffset);
3731 return write_type_array( writer, desc, *(const char **)ptr, count );
3733 case WS_TEXT_FIELD_MAPPING:
3734 switch (writer->state)
3736 case WRITER_STATE_STARTELEMENT:
3737 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3738 break;
3740 case WRITER_STATE_STARTATTRIBUTE:
3741 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3742 break;
3744 default:
3745 FIXME( "unhandled writer state %u\n", writer->state );
3746 return E_NOTIMPL;
3748 break;
3750 default:
3751 FIXME( "field mapping %u not supported\n", desc->mapping );
3752 return E_NOTIMPL;
3755 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3756 return hr;
3758 switch (mapping)
3760 case WS_ATTRIBUTE_TYPE_MAPPING:
3761 writer->state = WRITER_STATE_STARTELEMENT;
3762 break;
3764 case WS_ELEMENT_TYPE_MAPPING:
3765 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3766 break;
3768 default: break;
3771 return S_OK;
3774 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3775 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3776 const void *value, ULONG size )
3778 ULONG i, offset;
3779 const void *ptr;
3780 HRESULT hr;
3782 if (!desc) return E_INVALIDARG;
3783 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3785 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3787 for (i = 0; i < desc->fieldCount; i++)
3789 offset = desc->fields[i]->offset;
3790 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3793 return S_OK;
3796 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3797 const void *desc, WS_WRITE_OPTION option, const void *value,
3798 ULONG size )
3800 switch (type)
3802 case WS_BOOL_TYPE:
3803 return write_type_bool( writer, mapping, desc, option, value, size );
3805 case WS_INT8_TYPE:
3806 return write_type_int8( writer, mapping, desc, option, value, size );
3808 case WS_INT16_TYPE:
3809 return write_type_int16( writer, mapping, desc, option, value, size );
3811 case WS_INT32_TYPE:
3812 return write_type_int32( writer, mapping, desc, option, value, size );
3814 case WS_INT64_TYPE:
3815 return write_type_int64( writer, mapping, desc, option, value, size );
3817 case WS_UINT8_TYPE:
3818 return write_type_uint8( writer, mapping, desc, option, value, size );
3820 case WS_UINT16_TYPE:
3821 return write_type_uint16( writer, mapping, desc, option, value, size );
3823 case WS_UINT32_TYPE:
3824 return write_type_uint32( writer, mapping, desc, option, value, size );
3826 case WS_UINT64_TYPE:
3827 return write_type_uint64( writer, mapping, desc, option, value, size );
3829 case WS_DOUBLE_TYPE:
3830 return write_type_double( writer, mapping, desc, option, value, size );
3832 case WS_DATETIME_TYPE:
3833 return write_type_datetime( writer, mapping, desc, option, value, size );
3835 case WS_GUID_TYPE:
3836 return write_type_guid( writer, mapping, desc, option, value, size );
3838 case WS_UNIQUE_ID_TYPE:
3839 return write_type_unique_id( writer, mapping, desc, option, value, size );
3841 case WS_STRING_TYPE:
3842 return write_type_string( writer, mapping, desc, option, value, size );
3844 case WS_WSZ_TYPE:
3845 return write_type_wsz( writer, mapping, desc, option, value, size );
3847 case WS_BYTES_TYPE:
3848 return write_type_bytes( writer, mapping, desc, option, value, size );
3850 case WS_XML_STRING_TYPE:
3851 return write_type_xml_string( writer, mapping, desc, option, value, size );
3853 case WS_XML_QNAME_TYPE:
3854 return write_type_qname( writer, mapping, desc, option, value, size );
3856 case WS_STRUCT_TYPE:
3857 return write_type_struct( writer, mapping, desc, option, value, size );
3859 default:
3860 FIXME( "type %u not supported\n", type );
3861 return E_NOTIMPL;
3865 /**************************************************************************
3866 * WsWriteAttribute [webservices.@]
3868 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
3869 WS_WRITE_OPTION option, const void *value, ULONG size,
3870 WS_ERROR *error )
3872 struct writer *writer = (struct writer *)handle;
3873 HRESULT hr;
3875 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3876 if (error) FIXME( "ignoring error parameter\n" );
3878 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
3879 return E_INVALIDARG;
3881 EnterCriticalSection( &writer->cs );
3883 if (writer->magic != WRITER_MAGIC)
3885 LeaveCriticalSection( &writer->cs );
3886 return E_INVALIDARG;
3889 if (writer->state != WRITER_STATE_STARTELEMENT)
3891 LeaveCriticalSection( &writer->cs );
3892 return WS_E_INVALID_OPERATION;
3895 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK)
3897 LeaveCriticalSection( &writer->cs );
3898 return hr;
3900 writer->state = WRITER_STATE_STARTATTRIBUTE;
3902 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
3904 LeaveCriticalSection( &writer->cs );
3905 return hr;
3908 /**************************************************************************
3909 * WsWriteElement [webservices.@]
3911 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3912 WS_WRITE_OPTION option, const void *value, ULONG size,
3913 WS_ERROR *error )
3915 struct writer *writer = (struct writer *)handle;
3916 HRESULT hr;
3918 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3919 if (error) FIXME( "ignoring error parameter\n" );
3921 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
3922 return E_INVALIDARG;
3924 EnterCriticalSection( &writer->cs );
3926 if (writer->magic != WRITER_MAGIC)
3928 LeaveCriticalSection( &writer->cs );
3929 return E_INVALIDARG;
3932 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
3934 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
3935 option, value, size )) != S_OK) goto done;
3937 hr = write_endelement_node( writer );
3939 done:
3940 LeaveCriticalSection( &writer->cs );
3941 return hr;
3944 /**************************************************************************
3945 * WsWriteType [webservices.@]
3947 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
3948 const void *desc, WS_WRITE_OPTION option, const void *value,
3949 ULONG size, WS_ERROR *error )
3951 struct writer *writer = (struct writer *)handle;
3952 HRESULT hr;
3954 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
3955 size, error );
3956 if (error) FIXME( "ignoring error parameter\n" );
3958 if (!writer || !value) return E_INVALIDARG;
3960 EnterCriticalSection( &writer->cs );
3962 if (writer->magic != WRITER_MAGIC)
3964 LeaveCriticalSection( &writer->cs );
3965 return E_INVALIDARG;
3968 switch (mapping)
3970 case WS_ATTRIBUTE_TYPE_MAPPING:
3971 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
3972 else hr = write_type( writer, mapping, type, desc, option, value, size );
3973 break;
3975 case WS_ELEMENT_TYPE_MAPPING:
3976 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3977 case WS_ANY_ELEMENT_TYPE_MAPPING:
3978 hr = write_type( writer, mapping, type, desc, option, value, size );
3979 break;
3981 default:
3982 FIXME( "mapping %u not implemented\n", mapping );
3983 hr = E_NOTIMPL;
3986 LeaveCriticalSection( &writer->cs );
3987 return hr;
3990 WS_TYPE map_value_type( WS_VALUE_TYPE type )
3992 switch (type)
3994 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
3995 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
3996 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
3997 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
3998 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
3999 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
4000 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
4001 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
4002 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
4003 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
4004 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
4005 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
4006 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
4007 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
4008 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
4009 default:
4010 FIXME( "unhandled type %u\n", type );
4011 return ~0u;
4015 /**************************************************************************
4016 * WsWriteValue [webservices.@]
4018 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
4019 ULONG size, WS_ERROR *error )
4021 struct writer *writer = (struct writer *)handle;
4022 WS_TYPE_MAPPING mapping;
4023 HRESULT hr = S_OK;
4024 WS_TYPE type;
4026 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
4027 if (error) FIXME( "ignoring error parameter\n" );
4029 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
4031 EnterCriticalSection( &writer->cs );
4033 if (writer->magic != WRITER_MAGIC)
4035 LeaveCriticalSection( &writer->cs );
4036 return E_INVALIDARG;
4039 switch (writer->state)
4041 case WRITER_STATE_STARTATTRIBUTE:
4042 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
4043 break;
4045 case WRITER_STATE_STARTELEMENT:
4046 mapping = WS_ELEMENT_TYPE_MAPPING;
4047 break;
4049 default:
4050 hr = WS_E_INVALID_FORMAT;
4053 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
4055 LeaveCriticalSection( &writer->cs );
4056 return hr;
4059 /**************************************************************************
4060 * WsWriteArray [webservices.@]
4062 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4063 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
4064 ULONG count, WS_ERROR *error )
4066 struct writer *writer = (struct writer *)handle;
4067 WS_TYPE type;
4068 ULONG type_size, i;
4069 HRESULT hr = S_OK;
4071 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
4072 value_type, array, size, offset, count, error );
4073 if (error) FIXME( "ignoring error parameter\n" );
4075 if (!writer) return E_INVALIDARG;
4077 EnterCriticalSection( &writer->cs );
4079 if (writer->magic != WRITER_MAGIC)
4081 LeaveCriticalSection( &writer->cs );
4082 return E_INVALIDARG;
4085 if (!writer->output_type)
4087 LeaveCriticalSection( &writer->cs );
4088 return WS_E_INVALID_OPERATION;
4091 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
4093 LeaveCriticalSection( &writer->cs );
4094 return E_INVALIDARG;
4097 type_size = get_type_size( type, NULL );
4098 if (size % type_size || (offset + count) * type_size > size || (count && !array))
4100 LeaveCriticalSection( &writer->cs );
4101 return E_INVALIDARG;
4104 for (i = offset; i < count; i++)
4106 const char *ptr = (const char *)array + (offset + i) * type_size;
4107 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4108 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4109 &ptr, sizeof(ptr) )) != S_OK) goto done;
4110 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4113 done:
4114 LeaveCriticalSection( &writer->cs );
4115 return hr;
4118 /**************************************************************************
4119 * WsWriteXmlBuffer [webservices.@]
4121 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4123 struct writer *writer = (struct writer *)handle;
4124 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4125 HRESULT hr;
4127 TRACE( "%p %p %p\n", handle, buffer, error );
4128 if (error) FIXME( "ignoring error parameter\n" );
4130 if (!writer || !xmlbuf) return E_INVALIDARG;
4132 EnterCriticalSection( &writer->cs );
4134 if (writer->magic != WRITER_MAGIC)
4136 LeaveCriticalSection( &writer->cs );
4137 return E_INVALIDARG;
4140 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4142 FIXME( "no support for different encoding and/or charset\n" );
4143 hr = E_NOTIMPL;
4144 goto done;
4147 if ((hr = write_flush( writer )) != S_OK) goto done;
4148 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4149 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4151 done:
4152 LeaveCriticalSection( &writer->cs );
4153 return hr;
4156 /**************************************************************************
4157 * WsWriteXmlBufferToBytes [webservices.@]
4159 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4160 const WS_XML_WRITER_ENCODING *encoding,
4161 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4162 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4164 struct writer *writer = (struct writer *)handle;
4165 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4166 HRESULT hr = S_OK;
4167 char *buf;
4168 ULONG i;
4170 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4171 bytes, size, error );
4172 if (error) FIXME( "ignoring error parameter\n" );
4174 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4176 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4178 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4179 return E_NOTIMPL;
4182 EnterCriticalSection( &writer->cs );
4184 if (writer->magic != WRITER_MAGIC)
4186 LeaveCriticalSection( &writer->cs );
4187 return E_INVALIDARG;
4190 for (i = 0; i < count; i++)
4192 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4193 properties[i].valueSize );
4194 if (hr != S_OK) goto done;
4197 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4198 else
4200 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4201 *bytes = buf;
4202 *size = xmlbuf->bytes.length;
4205 done:
4206 LeaveCriticalSection( &writer->cs );
4207 return hr;
4210 /**************************************************************************
4211 * WsWriteXmlnsAttribute [webservices.@]
4213 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4214 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4216 struct writer *writer = (struct writer *)handle;
4217 HRESULT hr = S_OK;
4219 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4220 single, error );
4221 if (error) FIXME( "ignoring error parameter\n" );
4223 if (!writer || !ns) return E_INVALIDARG;
4225 EnterCriticalSection( &writer->cs );
4227 if (writer->magic != WRITER_MAGIC)
4229 LeaveCriticalSection( &writer->cs );
4230 return E_INVALIDARG;
4233 if (writer->state != WRITER_STATE_STARTELEMENT)
4235 LeaveCriticalSection( &writer->cs );
4236 return WS_E_INVALID_OPERATION;
4239 if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4240 hr = add_namespace_attribute( writer, prefix, ns, single );
4242 LeaveCriticalSection( &writer->cs );
4243 return hr;
4246 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4247 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4249 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4250 HRESULT hr;
4252 if ((hr = write_flush( writer )) != S_OK) return hr;
4253 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4255 qname.prefix = (WS_XML_STRING *)prefix;
4256 qname.localName = (WS_XML_STRING *)localname;
4257 qname.ns = (WS_XML_STRING *)ns;
4259 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4260 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4263 /**************************************************************************
4264 * WsWriteQualifiedName [webservices.@]
4266 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4267 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4268 WS_ERROR *error )
4270 struct writer *writer = (struct writer *)handle;
4271 HRESULT hr;
4273 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4274 debugstr_xmlstr(ns), error );
4275 if (error) FIXME( "ignoring error parameter\n" );
4277 if (!writer) return E_INVALIDARG;
4279 EnterCriticalSection( &writer->cs );
4281 if (writer->magic != WRITER_MAGIC)
4283 LeaveCriticalSection( &writer->cs );
4284 return E_INVALIDARG;
4287 if (!writer->output_type)
4289 LeaveCriticalSection( &writer->cs );
4290 return WS_E_INVALID_OPERATION;
4293 if (writer->state != WRITER_STATE_STARTELEMENT)
4295 LeaveCriticalSection( &writer->cs );
4296 return WS_E_INVALID_FORMAT;
4299 if (!localname || (!prefix && !ns))
4301 LeaveCriticalSection( &writer->cs );
4302 return E_INVALIDARG;
4305 hr = write_qualified_name( writer, prefix, localname, ns );
4307 LeaveCriticalSection( &writer->cs );
4308 return hr;
4311 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4313 BOOL success = FALSE;
4314 struct node *node = writer->current;
4316 switch (move)
4318 case WS_MOVE_TO_ROOT_ELEMENT:
4319 success = move_to_root_element( writer->root, &node );
4320 break;
4322 case WS_MOVE_TO_NEXT_ELEMENT:
4323 success = move_to_next_element( &node );
4324 break;
4326 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4327 success = move_to_prev_element( &node );
4328 break;
4330 case WS_MOVE_TO_CHILD_ELEMENT:
4331 success = move_to_child_element( &node );
4332 break;
4334 case WS_MOVE_TO_END_ELEMENT:
4335 success = move_to_end_element( &node );
4336 break;
4338 case WS_MOVE_TO_PARENT_ELEMENT:
4339 success = move_to_parent_element( &node );
4340 break;
4342 case WS_MOVE_TO_FIRST_NODE:
4343 success = move_to_first_node( &node );
4344 break;
4346 case WS_MOVE_TO_NEXT_NODE:
4347 success = move_to_next_node( &node );
4348 break;
4350 case WS_MOVE_TO_PREVIOUS_NODE:
4351 success = move_to_prev_node( &node );
4352 break;
4354 case WS_MOVE_TO_CHILD_NODE:
4355 success = move_to_child_node( &node );
4356 break;
4358 case WS_MOVE_TO_BOF:
4359 success = move_to_bof( writer->root, &node );
4360 break;
4362 case WS_MOVE_TO_EOF:
4363 success = move_to_eof( writer->root, &node );
4364 break;
4366 default:
4367 FIXME( "unhandled move %u\n", move );
4368 return E_NOTIMPL;
4371 if (success && node == writer->root) return E_INVALIDARG;
4372 writer->current = node;
4374 if (found)
4376 *found = success;
4377 return S_OK;
4379 return success ? S_OK : WS_E_INVALID_FORMAT;
4382 /**************************************************************************
4383 * WsMoveWriter [webservices.@]
4385 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4387 struct writer *writer = (struct writer *)handle;
4388 HRESULT hr;
4390 TRACE( "%p %u %p %p\n", handle, move, found, error );
4391 if (error) FIXME( "ignoring error parameter\n" );
4393 if (!writer) return E_INVALIDARG;
4395 EnterCriticalSection( &writer->cs );
4397 if (writer->magic != WRITER_MAGIC)
4399 LeaveCriticalSection( &writer->cs );
4400 return E_INVALIDARG;
4403 if (!writer->output_type)
4405 LeaveCriticalSection( &writer->cs );
4406 return WS_E_INVALID_OPERATION;
4409 hr = write_move_to( writer, move, found );
4411 LeaveCriticalSection( &writer->cs );
4412 return hr;
4415 /**************************************************************************
4416 * WsGetWriterPosition [webservices.@]
4418 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4420 struct writer *writer = (struct writer *)handle;
4422 TRACE( "%p %p %p\n", handle, pos, error );
4423 if (error) FIXME( "ignoring error parameter\n" );
4425 if (!writer || !pos) return E_INVALIDARG;
4427 EnterCriticalSection( &writer->cs );
4429 if (writer->magic != WRITER_MAGIC)
4431 LeaveCriticalSection( &writer->cs );
4432 return E_INVALIDARG;
4435 if (!writer->output_type)
4437 LeaveCriticalSection( &writer->cs );
4438 return WS_E_INVALID_OPERATION;
4441 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4442 pos->node = writer->current;
4444 LeaveCriticalSection( &writer->cs );
4445 return S_OK;
4448 /**************************************************************************
4449 * WsSetWriterPosition [webservices.@]
4451 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4453 struct writer *writer = (struct writer *)handle;
4455 TRACE( "%p %p %p\n", handle, pos, error );
4456 if (error) FIXME( "ignoring error parameter\n" );
4458 if (!writer || !pos) return E_INVALIDARG;
4460 EnterCriticalSection( &writer->cs );
4462 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4464 LeaveCriticalSection( &writer->cs );
4465 return E_INVALIDARG;
4468 if (!writer->output_type)
4470 LeaveCriticalSection( &writer->cs );
4471 return WS_E_INVALID_OPERATION;
4474 writer->current = pos->node;
4476 LeaveCriticalSection( &writer->cs );
4477 return S_OK;
4480 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4482 struct node *node, *parent;
4483 WS_XML_COMMENT_NODE *comment;
4485 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4486 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4487 comment = (WS_XML_COMMENT_NODE *)node;
4489 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4491 free_node( node );
4492 return E_OUTOFMEMORY;
4494 memcpy( comment->value.bytes, value->bytes, value->length );
4495 comment->value.length = value->length;
4497 write_insert_node( writer, parent, node );
4498 return S_OK;
4501 static HRESULT write_comment_text( struct writer *writer )
4503 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4504 HRESULT hr;
4506 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4507 write_bytes( writer, (const BYTE *)"<!--", 4 );
4508 write_bytes( writer, comment->value.bytes, comment->value.length );
4509 write_bytes( writer, (const BYTE *)"-->", 3 );
4510 return S_OK;
4513 static HRESULT write_comment_bin( struct writer *writer )
4515 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4516 HRESULT hr;
4518 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4519 write_char( writer, RECORD_COMMENT );
4520 return write_string( writer, comment->value.bytes, comment->value.length );
4523 static HRESULT write_comment( struct writer *writer )
4525 switch (writer->output_enc)
4527 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4528 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4529 default:
4530 ERR( "unhandled encoding %u\n", writer->output_enc );
4531 return WS_E_NOT_SUPPORTED;
4535 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4537 HRESULT hr;
4538 if ((hr = write_flush( writer )) != S_OK) return hr;
4539 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4540 if ((hr = write_comment( writer )) != S_OK) return hr;
4541 writer->state = WRITER_STATE_COMMENT;
4542 return S_OK;
4545 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4547 ULONG i;
4548 HRESULT hr;
4550 for (i = 0; i < count; i++)
4552 const WS_XML_STRING *prefix = attrs[i]->prefix;
4553 const WS_XML_STRING *localname = attrs[i]->localName;
4554 const WS_XML_STRING *ns = attrs[i]->ns;
4555 BOOL single = attrs[i]->singleQuote;
4557 if (attrs[i]->isXmlNs)
4559 if ((hr = add_namespace_attribute( writer, prefix, ns, single )) != S_OK) return hr;
4561 else
4563 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
4564 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4567 return S_OK;
4570 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4572 HRESULT hr;
4574 switch (node->nodeType)
4576 case WS_XML_NODE_TYPE_ELEMENT:
4578 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4579 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4580 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4582 case WS_XML_NODE_TYPE_TEXT:
4584 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4585 return write_text_node( writer, text->text );
4587 case WS_XML_NODE_TYPE_END_ELEMENT:
4588 return write_endelement_node( writer );
4590 case WS_XML_NODE_TYPE_COMMENT:
4592 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4593 return write_comment_node( writer, &comment->value );
4595 case WS_XML_NODE_TYPE_CDATA:
4596 return write_cdata_node( writer );
4598 case WS_XML_NODE_TYPE_END_CDATA:
4599 return write_endcdata_node( writer );
4601 case WS_XML_NODE_TYPE_EOF:
4602 case WS_XML_NODE_TYPE_BOF:
4603 return S_OK;
4605 default:
4606 WARN( "unknown node type %u\n", node->nodeType );
4607 return E_INVALIDARG;
4611 /**************************************************************************
4612 * WsWriteNode [webservices.@]
4614 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4616 struct writer *writer = (struct writer *)handle;
4617 HRESULT hr;
4619 TRACE( "%p %p %p\n", handle, node, error );
4620 if (error) FIXME( "ignoring error parameter\n" );
4622 if (!writer || !node) return E_INVALIDARG;
4624 EnterCriticalSection( &writer->cs );
4626 if (writer->magic != WRITER_MAGIC)
4628 LeaveCriticalSection( &writer->cs );
4629 return E_INVALIDARG;
4632 if (!writer->output_type)
4634 LeaveCriticalSection( &writer->cs );
4635 return WS_E_INVALID_OPERATION;
4638 hr = write_node( writer, node );
4640 LeaveCriticalSection( &writer->cs );
4641 return hr;
4644 static HRESULT write_tree_node( struct writer *writer )
4646 HRESULT hr;
4648 switch (node_type( writer->current ))
4650 case WS_XML_NODE_TYPE_ELEMENT:
4651 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4652 return hr;
4653 if ((hr = write_startelement( writer )) != S_OK) return hr;
4654 writer->state = WRITER_STATE_STARTELEMENT;
4655 return S_OK;
4657 case WS_XML_NODE_TYPE_TEXT:
4658 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4659 return hr;
4660 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4661 writer->state = WRITER_STATE_TEXT;
4662 return S_OK;
4664 case WS_XML_NODE_TYPE_END_ELEMENT:
4665 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4666 writer->state = WRITER_STATE_ENDELEMENT;
4667 return S_OK;
4669 case WS_XML_NODE_TYPE_COMMENT:
4670 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4671 return hr;
4672 if ((hr = write_comment( writer )) != S_OK) return hr;
4673 writer->state = WRITER_STATE_COMMENT;
4674 return S_OK;
4676 case WS_XML_NODE_TYPE_CDATA:
4677 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4678 return hr;
4679 if ((hr = write_cdata( writer )) != S_OK) return hr;
4680 writer->state = WRITER_STATE_STARTCDATA;
4681 return S_OK;
4683 case WS_XML_NODE_TYPE_END_CDATA:
4684 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4685 writer->state = WRITER_STATE_ENDCDATA;
4686 return S_OK;
4688 case WS_XML_NODE_TYPE_EOF:
4689 case WS_XML_NODE_TYPE_BOF:
4690 return S_OK;
4692 default:
4693 ERR( "unknown node type %u\n", node_type(writer->current) );
4694 return E_INVALIDARG;
4698 static HRESULT write_tree( struct writer *writer )
4700 HRESULT hr;
4702 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4703 for (;;)
4705 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4706 if (move_to_child_node( &writer->current ))
4708 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4709 continue;
4711 if (move_to_next_node( &writer->current ))
4713 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4714 continue;
4716 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4718 ERR( "invalid tree\n" );
4719 return WS_E_INVALID_FORMAT;
4721 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4723 return S_OK;
4726 static void write_rewind( struct writer *writer )
4728 writer->write_pos = 0;
4729 writer->current = writer->root;
4730 writer->state = WRITER_STATE_INITIAL;
4733 /**************************************************************************
4734 * WsCopyNode [webservices.@]
4736 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4738 struct writer *writer = (struct writer *)handle;
4739 struct node *parent, *current, *node = NULL;
4740 HRESULT hr;
4742 TRACE( "%p %p %p\n", handle, reader, error );
4743 if (error) FIXME( "ignoring error parameter\n" );
4745 if (!writer) return E_INVALIDARG;
4747 EnterCriticalSection( &writer->cs );
4749 if (writer->magic != WRITER_MAGIC)
4751 LeaveCriticalSection( &writer->cs );
4752 return E_INVALIDARG;
4755 if (!(parent = find_parent( writer )))
4757 LeaveCriticalSection( &writer->cs );
4758 return WS_E_INVALID_FORMAT;
4761 if ((hr = copy_node( reader, &node )) != S_OK) goto done;
4762 current = writer->current;
4763 write_insert_node( writer, parent, node );
4765 write_rewind( writer );
4766 if ((hr = write_tree( writer )) != S_OK) goto done;
4767 writer->current = current;
4769 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4771 done:
4772 LeaveCriticalSection( &writer->cs );
4773 return hr;
4776 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4778 return write_type_field( writer, desc, value, 0 );
4781 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4783 ULONG i, ret = 0;
4784 for (i = 0; i < count; i++)
4786 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4787 continue;
4788 if (args[i]) ret = *(const ULONG *)args[i];
4789 break;
4791 return ret;
4794 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4795 ULONG len )
4797 return write_type_array( writer, desc, value, len );
4800 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4801 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4803 struct writer *writer = (struct writer *)handle;
4804 const WS_STRUCT_DESCRIPTION *desc_struct;
4805 const WS_FIELD_DESCRIPTION *desc_field;
4806 HRESULT hr;
4807 ULONG i;
4809 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4811 EnterCriticalSection( &writer->cs );
4813 if (writer->magic != WRITER_MAGIC)
4815 LeaveCriticalSection( &writer->cs );
4816 return E_INVALIDARG;
4819 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4821 for (i = 0; i < count; i++)
4823 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4824 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4826 FIXME( "messages type not supported\n" );
4827 hr = E_NOTIMPL;
4828 goto done;
4830 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4831 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4833 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4835 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4837 const void *ptr = *(const void **)args[i];
4838 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4839 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4843 hr = write_endelement_node( writer );
4845 done:
4846 LeaveCriticalSection( &writer->cs );
4847 return hr;
4850 HRESULT writer_enable_lookup( WS_XML_WRITER *handle )
4852 struct writer *writer = (struct writer *)handle;
4854 EnterCriticalSection( &writer->cs );
4856 if (writer->magic != WRITER_MAGIC)
4858 LeaveCriticalSection( &writer->cs );
4859 return E_INVALIDARG;
4862 writer->dict_do_lookup = TRUE;
4864 LeaveCriticalSection( &writer->cs );
4865 return S_OK;