webservices: Add support for writing attributes and text in binary mode.
[wine.git] / dlls / webservices / writer.c
blobadf110dae6b6ffaf7f67e5f3cf3e08b87e1b7b53
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 <stdarg.h>
21 #include <stdio.h>
22 #include <math.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "webservices.h"
29 #include "wine/debug.h"
30 #include "wine/list.h"
31 #include "wine/unicode.h"
32 #include "webservices_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
36 static const struct prop_desc writer_props[] =
38 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
39 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
40 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
41 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
42 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
43 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
44 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
45 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
46 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
47 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
48 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
49 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
50 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
51 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
52 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
53 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
54 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
55 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
56 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
59 enum writer_state
61 WRITER_STATE_INITIAL,
62 WRITER_STATE_STARTELEMENT,
63 WRITER_STATE_STARTATTRIBUTE,
64 WRITER_STATE_STARTCDATA,
65 WRITER_STATE_ENDSTARTELEMENT,
66 WRITER_STATE_TEXT,
67 WRITER_STATE_COMMENT,
68 WRITER_STATE_ENDELEMENT,
69 WRITER_STATE_ENDCDATA
72 struct writer
74 ULONG magic;
75 CRITICAL_SECTION cs;
76 ULONG write_pos;
77 unsigned char *write_bufptr;
78 enum writer_state state;
79 struct node *root;
80 struct node *current;
81 WS_XML_STRING *current_ns;
82 WS_XML_WRITER_ENCODING_TYPE output_enc;
83 WS_XML_WRITER_OUTPUT_TYPE output_type;
84 struct xmlbuf *output_buf;
85 WS_HEAP *output_heap;
86 ULONG prop_count;
87 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
90 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
92 static struct writer *alloc_writer(void)
94 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
95 struct writer *ret;
96 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
98 if (!(ret = heap_alloc_zero( size ))) return NULL;
100 ret->magic = WRITER_MAGIC;
101 InitializeCriticalSection( &ret->cs );
102 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
104 prop_init( writer_props, count, ret->prop, &ret[1] );
105 ret->prop_count = count;
106 return ret;
109 static void free_writer( struct writer *writer )
111 destroy_nodes( writer->root );
112 heap_free( writer->current_ns );
113 WsFreeHeap( writer->output_heap );
115 writer->cs.DebugInfo->Spare[0] = 0;
116 DeleteCriticalSection( &writer->cs );
117 heap_free( writer );
120 static void write_insert_eof( struct writer *writer, struct node *eof )
122 if (!writer->root) writer->root = eof;
123 else
125 eof->parent = writer->root;
126 list_add_tail( &writer->root->children, &eof->entry );
128 writer->current = eof;
131 static void write_insert_bof( struct writer *writer, struct node *bof )
133 writer->root->parent = bof;
134 list_add_tail( &bof->children, &writer->root->entry );
135 writer->current = writer->root = bof;
138 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
140 node->parent = parent;
141 list_add_before( list_tail( &parent->children ), &node->entry );
142 writer->current = node;
145 static struct node *find_parent( struct writer *writer )
147 if (is_valid_parent( writer->current )) return writer->current;
148 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
149 return NULL;
152 static HRESULT init_writer( struct writer *writer )
154 struct node *node;
156 writer->write_pos = 0;
157 writer->write_bufptr = NULL;
158 destroy_nodes( writer->root );
159 writer->root = writer->current = NULL;
160 heap_free( writer->current_ns );
161 writer->current_ns = NULL;
163 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
164 write_insert_eof( writer, node );
165 writer->state = WRITER_STATE_INITIAL;
166 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
167 return S_OK;
170 /**************************************************************************
171 * WsCreateWriter [webservices.@]
173 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
174 WS_XML_WRITER **handle, WS_ERROR *error )
176 struct writer *writer;
177 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
178 WS_CHARSET charset = WS_CHARSET_UTF8;
179 HRESULT hr;
181 TRACE( "%p %u %p %p\n", properties, count, handle, error );
182 if (error) FIXME( "ignoring error parameter\n" );
184 if (!handle) return E_INVALIDARG;
185 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
187 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
188 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
189 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
190 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
191 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
192 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
193 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
195 for (i = 0; i < count; i++)
197 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
198 properties[i].valueSize );
199 if (hr != S_OK)
201 free_writer( writer );
202 return hr;
206 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
207 &max_size, sizeof(max_size) );
208 if (hr != S_OK)
210 free_writer( writer );
211 return hr;
214 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
215 if (hr != S_OK)
217 free_writer( writer );
218 return hr;
221 hr = init_writer( writer );
222 if (hr != S_OK)
224 free_writer( writer );
225 return hr;
228 *handle = (WS_XML_WRITER *)writer;
229 return S_OK;
232 /**************************************************************************
233 * WsFreeWriter [webservices.@]
235 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
237 struct writer *writer = (struct writer *)handle;
239 TRACE( "%p\n", handle );
241 if (!writer) return;
243 EnterCriticalSection( &writer->cs );
245 if (writer->magic != WRITER_MAGIC)
247 LeaveCriticalSection( &writer->cs );
248 return;
251 writer->magic = 0;
253 LeaveCriticalSection( &writer->cs );
254 free_writer( writer );
257 /**************************************************************************
258 * WsGetWriterProperty [webservices.@]
260 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
261 void *buf, ULONG size, WS_ERROR *error )
263 struct writer *writer = (struct writer *)handle;
264 HRESULT hr = S_OK;
266 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
267 if (error) FIXME( "ignoring error parameter\n" );
269 if (!writer) return E_INVALIDARG;
271 EnterCriticalSection( &writer->cs );
273 if (writer->magic != WRITER_MAGIC)
275 LeaveCriticalSection( &writer->cs );
276 return E_INVALIDARG;
279 if (!writer->output_type)
281 LeaveCriticalSection( &writer->cs );
282 return WS_E_INVALID_OPERATION;
285 switch (id)
287 case WS_XML_WRITER_PROPERTY_BYTES:
289 WS_BYTES *bytes = buf;
290 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
291 else
293 bytes->bytes = writer->output_buf->bytes.bytes;
294 bytes->length = writer->output_buf->bytes.length;
296 break;
298 case WS_XML_WRITER_PROPERTY_BUFFERS:
299 if (writer->output_buf->bytes.length)
301 WS_BUFFERS *buffers = buf;
302 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
303 else
305 buffers->bufferCount = 1;
306 buffers->buffers = &writer->output_buf->bytes;
308 break;
310 /* fall through */
311 default:
312 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
315 LeaveCriticalSection( &writer->cs );
316 return hr;
319 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
321 /* free current buffer if it's ours */
322 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
324 free_xmlbuf( writer->output_buf );
326 writer->output_buf = xmlbuf;
327 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
328 writer->write_bufptr = xmlbuf->bytes.bytes;
329 writer->write_pos = 0;
332 /**************************************************************************
333 * WsSetOutput [webservices.@]
335 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
336 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
337 ULONG count, WS_ERROR *error )
339 struct writer *writer = (struct writer *)handle;
340 struct node *node;
341 HRESULT hr;
342 ULONG i;
344 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
345 if (error) FIXME( "ignoring error parameter\n" );
347 if (!writer) return E_INVALIDARG;
349 EnterCriticalSection( &writer->cs );
351 if (writer->magic != WRITER_MAGIC)
353 LeaveCriticalSection( &writer->cs );
354 return E_INVALIDARG;
357 for (i = 0; i < count; i++)
359 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
360 properties[i].valueSize );
361 if (hr != S_OK) goto done;
364 if ((hr = init_writer( writer )) != S_OK) goto done;
366 switch (encoding->encodingType)
368 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
370 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
371 if (text->charSet != WS_CHARSET_UTF8)
373 FIXME( "charset %u not supported\n", text->charSet );
374 hr = E_NOTIMPL;
375 goto done;
377 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
378 break;
380 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
382 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
383 break;
385 default:
386 FIXME( "encoding type %u not supported\n", encoding->encodingType );
387 hr = E_NOTIMPL;
388 goto done;
391 switch (output->outputType)
393 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
395 struct xmlbuf *xmlbuf;
397 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap ))) hr = WS_E_QUOTA_EXCEEDED;
398 else set_output_buffer( writer, xmlbuf );
399 break;
401 default:
402 FIXME( "output type %u not supported\n", output->outputType );
403 hr = E_NOTIMPL;
404 goto done;
407 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
408 else write_insert_bof( writer, node );
410 done:
411 LeaveCriticalSection( &writer->cs );
412 return hr;
415 /**************************************************************************
416 * WsSetOutputToBuffer [webservices.@]
418 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
419 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
420 WS_ERROR *error )
422 struct writer *writer = (struct writer *)handle;
423 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
424 struct node *node;
425 HRESULT hr;
426 ULONG i;
428 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
429 if (error) FIXME( "ignoring error parameter\n" );
431 if (!writer || !xmlbuf) return E_INVALIDARG;
433 EnterCriticalSection( &writer->cs );
435 if (writer->magic != WRITER_MAGIC)
437 LeaveCriticalSection( &writer->cs );
438 return E_INVALIDARG;
441 for (i = 0; i < count; i++)
443 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
444 properties[i].valueSize );
445 if (hr != S_OK) goto done;
448 if ((hr = init_writer( writer )) != S_OK) goto done;
449 set_output_buffer( writer, xmlbuf );
451 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
452 else write_insert_bof( writer, node );
454 done:
455 LeaveCriticalSection( &writer->cs );
456 return hr;
459 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
461 struct xmlbuf *buf = writer->output_buf;
462 SIZE_T new_size;
463 void *tmp;
465 if (buf->size >= writer->write_pos + size)
467 buf->bytes.length = writer->write_pos + size;
468 return S_OK;
470 new_size = max( buf->size * 2, writer->write_pos + size );
471 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
472 writer->write_bufptr = buf->bytes.bytes = tmp;
473 buf->size = new_size;
474 buf->bytes.length = writer->write_pos + size;
475 return S_OK;
478 static inline void write_char( struct writer *writer, unsigned char ch )
480 writer->write_bufptr[writer->write_pos++] = ch;
483 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
485 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
486 writer->write_pos += len;
489 struct escape
491 char ch;
492 const char *entity;
493 ULONG len;
495 static const struct escape escape_lt = { '<', "&lt;", 4 };
496 static const struct escape escape_gt = { '>', "&gt;", 4 };
497 static const struct escape escape_amp = { '&', "&amp;", 5 };
498 static const struct escape escape_apos = { '\'', "&apos;", 6 };
499 static const struct escape escape_quot = { '"', "&quot;", 6 };
501 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
502 const struct escape **escapes, ULONG nb_escapes )
504 ULONG i, j, size;
505 const BYTE *ptr;
506 HRESULT hr;
508 for (i = 0; i < len; i++)
510 ptr = &bytes[i];
511 size = 1;
512 for (j = 0; j < nb_escapes; j++)
514 if (bytes[i] == escapes[j]->ch)
516 ptr = (const BYTE *)escapes[j]->entity;
517 size = escapes[j]->len;
518 break;
521 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
522 write_bytes( writer, ptr, size );
525 return S_OK;
528 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
530 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
531 const struct escape *escapes[3];
533 escapes[0] = single ? &escape_apos : &escape_quot;
534 escapes[1] = &escape_lt;
535 escapes[2] = &escape_amp;
536 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
539 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
541 unsigned char quote = attr->singleQuote ? '\'' : '"';
542 const WS_XML_STRING *prefix = NULL;
543 ULONG size;
544 HRESULT hr;
546 if (attr->prefix) prefix = attr->prefix;
548 /* ' prefix:attr="value"' */
550 size = attr->localName->length + 4 /* ' =""' */;
551 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
552 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
554 write_char( writer, ' ' );
555 if (prefix && prefix->length)
557 write_bytes( writer, prefix->bytes, prefix->length );
558 write_char( writer, ':' );
560 write_bytes( writer, attr->localName->bytes, attr->localName->length );
561 write_char( writer, '=' );
562 write_char( writer, quote );
563 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
564 write_char( writer, quote );
566 return hr;
569 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr )
571 if (!attr->prefix || !attr->prefix->length) return RECORD_SHORT_ATTRIBUTE;
572 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
574 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
576 return RECORD_ATTRIBUTE;
579 static HRESULT write_int31( struct writer *writer, ULONG len )
581 HRESULT hr;
583 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
584 if (len < 0x80)
586 write_char( writer, len );
587 return S_OK;
589 write_char( writer, (len & 0x7f) | 0x80 );
591 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
592 if ((len >>= 7) < 0x80)
594 write_char( writer, len );
595 return S_OK;
597 write_char( writer, (len & 0x7f) | 0x80 );
599 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
600 if ((len >>= 7) < 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) < 0x08)
618 write_char( writer, len );
619 return S_OK;
621 return WS_E_INVALID_FORMAT;
624 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
626 HRESULT hr;
627 if ((hr = write_int31( writer, len )) != S_OK) return hr;
628 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
629 write_bytes( writer, bytes, len );
630 return S_OK;
633 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL attr )
635 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
636 if (!utf8 || utf8->value.length <= 0xff) return attr ? RECORD_CHARS8_TEXT : RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
637 return 0;
640 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
642 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
643 enum record_type type = get_text_record_type( text, TRUE );
644 HRESULT hr;
646 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
647 write_char( writer, type );
649 switch (type)
651 case RECORD_CHARS8_TEXT:
652 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
653 if (!utf8 || !utf8->value.length) write_char( writer, 0 );
654 else
656 write_char( writer, utf8->value.length );
657 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
658 write_bytes( writer, utf8->value.bytes, utf8->value.length );
660 return S_OK;
662 default:
663 ERR( "unhandled record type %u\n", type );
664 return WS_E_NOT_SUPPORTED;
668 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
670 enum record_type type = get_attr_record_type( attr );
671 HRESULT hr;
673 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
674 write_char( writer, type );
676 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
678 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
679 return write_attribute_value_bin( writer, attr->value );
682 switch (type)
684 case RECORD_SHORT_ATTRIBUTE:
685 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
686 break;
688 case RECORD_ATTRIBUTE:
689 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
690 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
691 break;
693 default:
694 ERR( "unhandled record type %u\n", type );
695 return WS_E_NOT_SUPPORTED;
698 return write_attribute_value_bin( writer, attr->value );
701 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
703 switch (writer->output_enc)
705 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
706 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
707 default:
708 ERR( "unhandled encoding %u\n", writer->output_enc );
709 return WS_E_NOT_SUPPORTED;
713 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
715 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
718 /**************************************************************************
719 * WsGetPrefixFromNamespace [webservices.@]
721 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
722 BOOL required, const WS_XML_STRING **prefix,
723 WS_ERROR *error )
725 struct writer *writer = (struct writer *)handle;
726 WS_XML_ELEMENT_NODE *elem;
727 BOOL found = FALSE;
728 HRESULT hr = S_OK;
730 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
731 if (error) FIXME( "ignoring error parameter\n" );
733 if (!writer || !ns || !prefix) return E_INVALIDARG;
735 EnterCriticalSection( &writer->cs );
737 if (writer->magic != WRITER_MAGIC)
739 LeaveCriticalSection( &writer->cs );
740 return E_INVALIDARG;
743 elem = &writer->current->hdr;
744 if (elem->prefix && is_current_namespace( writer, ns ))
746 *prefix = elem->prefix;
747 found = TRUE;
750 if (!found)
752 if (required) hr = WS_E_INVALID_FORMAT;
753 else
755 *prefix = NULL;
756 hr = S_FALSE;
760 LeaveCriticalSection( &writer->cs );
761 return hr;
764 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
766 unsigned char quote = attr->singleQuote ? '\'' : '"';
767 ULONG size;
768 HRESULT hr;
770 /* ' xmlns:prefix="namespace"' */
772 size = attr->ns->length + 9 /* ' xmlns=""' */;
773 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
774 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
776 write_bytes( writer, (const BYTE *)" xmlns", 6 );
777 if (attr->prefix)
779 write_char( writer, ':' );
780 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
782 write_char( writer, '=' );
783 write_char( writer, quote );
784 write_bytes( writer, attr->ns->bytes, attr->ns->length );
785 write_char( writer, quote );
787 return S_OK;
790 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr )
792 if (!attr->prefix || !attr->prefix->length) return RECORD_SHORT_XMLNS_ATTRIBUTE;
793 return RECORD_XMLNS_ATTRIBUTE;
796 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
798 enum record_type type = get_xmlns_record_type( attr );
799 HRESULT hr;
801 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
802 write_char( writer, type );
804 switch (type)
806 case RECORD_SHORT_XMLNS_ATTRIBUTE:
807 break;
809 case RECORD_XMLNS_ATTRIBUTE:
810 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
811 break;
813 default:
814 ERR( "unhandled record type %u\n", type );
815 return WS_E_NOT_SUPPORTED;
818 return write_string( writer, attr->ns->bytes, attr->ns->length );
821 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
823 switch (writer->output_enc)
825 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
826 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
827 default:
828 ERR( "unhandled encoding %u\n", writer->output_enc );
829 return WS_E_NOT_SUPPORTED;
833 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
834 const WS_XML_STRING *ns, BOOL single )
836 WS_XML_ATTRIBUTE *attr;
837 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
838 HRESULT hr;
840 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
842 attr->singleQuote = !!single;
843 attr->isXmlNs = 1;
844 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
846 free_attribute( attr );
847 return E_OUTOFMEMORY;
849 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
851 free_attribute( attr );
852 return E_OUTOFMEMORY;
854 if ((hr = append_attribute( elem, attr )) != S_OK)
856 free_attribute( attr );
857 return hr;
859 return S_OK;
862 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
864 if (!str1 && !str2) return TRUE;
865 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
868 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
869 const WS_XML_STRING *ns )
871 ULONG i;
872 const struct node *node;
874 for (node = (const struct node *)elem; node; node = node->parent)
876 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
878 elem = &node->hdr;
879 for (i = 0; i < elem->attributeCount; i++)
881 if (!elem->attributes[i]->isXmlNs) continue;
882 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
883 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
886 return FALSE;
889 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
891 WS_XML_STRING *str;
892 if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
893 heap_free( writer->current_ns );
894 writer->current_ns = str;
895 return S_OK;
898 static HRESULT set_namespaces( struct writer *writer )
900 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
901 HRESULT hr;
902 ULONG i;
904 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
906 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
907 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
910 for (i = 0; i < elem->attributeCount; i++)
912 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
913 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
914 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
917 return S_OK;
920 /**************************************************************************
921 * WsWriteEndAttribute [webservices.@]
923 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
925 struct writer *writer = (struct writer *)handle;
927 TRACE( "%p %p\n", handle, error );
928 if (error) FIXME( "ignoring error parameter\n" );
930 if (!writer) return E_INVALIDARG;
932 EnterCriticalSection( &writer->cs );
934 if (writer->magic != WRITER_MAGIC)
936 LeaveCriticalSection( &writer->cs );
937 return E_INVALIDARG;
940 writer->state = WRITER_STATE_STARTELEMENT;
942 LeaveCriticalSection( &writer->cs );
943 return S_OK;
946 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
948 ULONG i;
949 HRESULT hr;
950 for (i = 0; i < elem->attributeCount; i++)
952 if (elem->attributes[i]->isXmlNs) continue;
953 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
955 for (i = 0; i < elem->attributeCount; i++)
957 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
958 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
960 for (i = 0; i < elem->attributeCount; i++)
962 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
963 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
965 return S_OK;
968 static HRESULT write_startelement_text( struct writer *writer )
970 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
971 ULONG size;
972 HRESULT hr;
974 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
976 size = elem->localName->length + 1 /* '<' */;
977 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
978 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
980 write_char( writer, '<' );
981 if (elem->prefix && elem->prefix->length)
983 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
984 write_char( writer, ':' );
986 write_bytes( writer, elem->localName->bytes, elem->localName->length );
987 return write_attributes( writer, elem );
990 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem )
992 if (!elem->prefix || !elem->prefix->length) return RECORD_SHORT_ELEMENT;
993 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
995 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
997 return RECORD_ELEMENT;
1000 static HRESULT write_startelement_bin( struct writer *writer )
1002 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1003 enum record_type type = get_elem_record_type( elem );
1004 HRESULT hr;
1006 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1007 write_char( writer, type );
1009 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1011 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1012 return write_attributes( writer, elem );
1015 switch (type)
1017 case RECORD_SHORT_ELEMENT:
1018 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1019 break;
1021 case RECORD_ELEMENT:
1022 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1023 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1024 break;
1026 default:
1027 ERR( "unhandled record type %u\n", type );
1028 return WS_E_NOT_SUPPORTED;
1031 return write_attributes( writer, elem );
1034 static HRESULT write_startelement( struct writer *writer )
1036 switch (writer->output_enc)
1038 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1039 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1040 default:
1041 ERR( "unhandled encoding %u\n", writer->output_enc );
1042 return WS_E_NOT_SUPPORTED;
1046 static struct node *write_find_startelement( struct writer *writer )
1048 struct node *node;
1049 for (node = writer->current; node; node = node->parent)
1051 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1053 return NULL;
1056 static inline BOOL is_empty_element( const struct node *node )
1058 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1059 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1062 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1064 ULONG size;
1065 HRESULT hr;
1067 /* '/>' */
1069 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1071 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1072 write_char( writer, '/' );
1073 write_char( writer, '>' );
1074 return S_OK;
1077 /* '</prefix:localname>' */
1079 size = elem->localName->length + 3 /* '</>' */;
1080 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1081 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1083 write_char( writer, '<' );
1084 write_char( writer, '/' );
1085 if (elem->prefix && elem->prefix->length)
1087 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1088 write_char( writer, ':' );
1090 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1091 write_char( writer, '>' );
1092 return S_OK;
1095 static HRESULT write_endelement_bin( struct writer *writer )
1097 HRESULT hr;
1098 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1099 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1100 write_char( writer, RECORD_ENDELEMENT );
1101 return S_OK;
1104 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1106 switch (writer->output_enc)
1108 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1109 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1110 default:
1111 ERR( "unhandled encoding %u\n", writer->output_enc );
1112 return WS_E_NOT_SUPPORTED;
1116 static HRESULT write_close_element( struct writer *writer, struct node *node )
1118 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1119 elem->isEmpty = is_empty_element( node );
1120 return write_endelement( writer, elem );
1123 static HRESULT write_endelement_node( struct writer *writer )
1125 struct node *node;
1126 HRESULT hr;
1128 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1129 if (writer->state == WRITER_STATE_STARTELEMENT)
1131 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1132 if ((hr = write_startelement( writer )) != S_OK) return hr;
1134 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1135 writer->current = node->parent;
1136 writer->state = WRITER_STATE_ENDELEMENT;
1137 return S_OK;
1140 /**************************************************************************
1141 * WsWriteEndElement [webservices.@]
1143 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1145 struct writer *writer = (struct writer *)handle;
1146 HRESULT hr;
1148 TRACE( "%p %p\n", handle, error );
1149 if (error) FIXME( "ignoring error parameter\n" );
1151 if (!writer) return E_INVALIDARG;
1153 EnterCriticalSection( &writer->cs );
1155 if (writer->magic != WRITER_MAGIC)
1157 LeaveCriticalSection( &writer->cs );
1158 return E_INVALIDARG;
1161 hr = write_endelement_node( writer );
1163 LeaveCriticalSection( &writer->cs );
1164 return hr;
1167 static HRESULT write_endstartelement_text( struct writer *writer )
1169 HRESULT hr;
1170 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1171 write_char( writer, '>' );
1172 return S_OK;
1175 static HRESULT write_endstartelement( struct writer *writer )
1177 switch (writer->output_enc)
1179 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1180 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1181 default:
1182 ERR( "unhandled encoding %u\n", writer->output_enc );
1183 return WS_E_NOT_SUPPORTED;
1187 /**************************************************************************
1188 * WsWriteEndStartElement [webservices.@]
1190 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
1192 struct writer *writer = (struct writer *)handle;
1193 HRESULT hr;
1195 TRACE( "%p %p\n", handle, error );
1196 if (error) FIXME( "ignoring error parameter\n" );
1198 if (!writer) return E_INVALIDARG;
1200 EnterCriticalSection( &writer->cs );
1202 if (writer->magic != WRITER_MAGIC)
1204 LeaveCriticalSection( &writer->cs );
1205 return E_INVALIDARG;
1208 if (writer->state != WRITER_STATE_STARTELEMENT)
1210 LeaveCriticalSection( &writer->cs );
1211 return WS_E_INVALID_OPERATION;
1214 if ((hr = set_namespaces( writer )) != S_OK) goto done;
1215 if ((hr = write_startelement( writer )) != S_OK) goto done;
1216 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
1217 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1219 done:
1220 LeaveCriticalSection( &writer->cs );
1221 return hr;
1224 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1225 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1226 BOOL single )
1228 WS_XML_ATTRIBUTE *attr;
1229 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1230 HRESULT hr;
1232 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1234 if (!prefix && ns->length) prefix = elem->prefix;
1236 attr->singleQuote = !!single;
1237 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
1239 free_attribute( attr );
1240 return E_OUTOFMEMORY;
1242 if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
1244 free_attribute( attr );
1245 return E_OUTOFMEMORY;
1247 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
1249 free_attribute( attr );
1250 return E_OUTOFMEMORY;
1252 if ((hr = append_attribute( elem, attr )) != S_OK)
1254 free_attribute( attr );
1255 return hr;
1257 return S_OK;
1260 /**************************************************************************
1261 * WsWriteStartAttribute [webservices.@]
1263 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1264 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1265 BOOL single, WS_ERROR *error )
1267 struct writer *writer = (struct writer *)handle;
1268 HRESULT hr;
1270 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1271 debugstr_xmlstr(ns), single, error );
1272 if (error) FIXME( "ignoring error parameter\n" );
1274 if (!writer || !localname || !ns) return E_INVALIDARG;
1276 EnterCriticalSection( &writer->cs );
1278 if (writer->magic != WRITER_MAGIC)
1280 LeaveCriticalSection( &writer->cs );
1281 return E_INVALIDARG;
1284 if (writer->state != WRITER_STATE_STARTELEMENT)
1286 LeaveCriticalSection( &writer->cs );
1287 return WS_E_INVALID_OPERATION;
1290 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
1291 writer->state = WRITER_STATE_STARTATTRIBUTE;
1293 LeaveCriticalSection( &writer->cs );
1294 return hr;
1297 /* flush current start element if necessary */
1298 static HRESULT write_flush( struct writer *writer )
1300 if (writer->state == WRITER_STATE_STARTELEMENT)
1302 HRESULT hr;
1303 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1304 if ((hr = write_startelement( writer )) != S_OK) return hr;
1305 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
1306 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1308 return S_OK;
1311 static HRESULT write_add_cdata_node( struct writer *writer )
1313 struct node *node, *parent;
1314 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1315 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1316 write_insert_node( writer, parent, node );
1317 return S_OK;
1320 static HRESULT write_add_endcdata_node( struct writer *writer )
1322 struct node *node;
1323 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
1324 node->parent = writer->current;
1325 list_add_tail( &node->parent->children, &node->entry );
1326 return S_OK;
1329 static HRESULT write_cdata( struct writer *writer )
1331 HRESULT hr;
1332 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
1333 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
1334 return S_OK;
1337 static HRESULT write_cdata_node( struct writer *writer )
1339 HRESULT hr;
1340 if ((hr = write_flush( writer )) != S_OK) return hr;
1341 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
1342 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
1343 if ((hr = write_cdata( writer )) != S_OK) return hr;
1344 writer->state = WRITER_STATE_STARTCDATA;
1345 return S_OK;
1348 /**************************************************************************
1349 * WsWriteStartCData [webservices.@]
1351 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
1353 struct writer *writer = (struct writer *)handle;
1354 HRESULT hr;
1356 TRACE( "%p %p\n", handle, error );
1357 if (error) FIXME( "ignoring error parameter\n" );
1359 if (!writer) return E_INVALIDARG;
1361 EnterCriticalSection( &writer->cs );
1363 if (writer->magic != WRITER_MAGIC)
1365 LeaveCriticalSection( &writer->cs );
1366 return E_INVALIDARG;
1369 hr = write_cdata_node( writer );
1371 LeaveCriticalSection( &writer->cs );
1372 return hr;
1375 static HRESULT write_endcdata( struct writer *writer )
1377 HRESULT hr;
1378 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
1379 write_bytes( writer, (const BYTE *)"]]>", 3 );
1380 return S_OK;
1383 static HRESULT write_endcdata_node( struct writer *writer )
1385 HRESULT hr;
1386 if ((hr = write_endcdata( writer )) != S_OK) return hr;
1387 writer->current = writer->current->parent;
1388 writer->state = WRITER_STATE_ENDCDATA;
1389 return S_OK;
1392 /**************************************************************************
1393 * WsWriteEndCData [webservices.@]
1395 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
1397 struct writer *writer = (struct writer *)handle;
1398 HRESULT hr;
1400 TRACE( "%p %p\n", handle, error );
1401 if (error) FIXME( "ignoring error parameter\n" );
1403 if (!writer) return E_INVALIDARG;
1405 EnterCriticalSection( &writer->cs );
1407 if (writer->magic != WRITER_MAGIC)
1409 LeaveCriticalSection( &writer->cs );
1410 return E_INVALIDARG;
1413 if (writer->state != WRITER_STATE_TEXT)
1415 LeaveCriticalSection( &writer->cs );
1416 return WS_E_INVALID_OPERATION;
1419 hr = write_endcdata_node( writer );
1421 LeaveCriticalSection( &writer->cs );
1422 return hr;
1425 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1426 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1428 struct node *node, *parent;
1429 WS_XML_ELEMENT_NODE *elem;
1431 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1433 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1435 elem = &parent->hdr;
1436 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
1439 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
1440 elem = &node->hdr;
1442 if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
1444 free_node( node );
1445 return E_OUTOFMEMORY;
1447 if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
1449 free_node( node );
1450 return E_OUTOFMEMORY;
1452 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
1454 free_node( node );
1455 return E_OUTOFMEMORY;
1457 write_insert_node( writer, parent, node );
1458 return S_OK;
1461 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1463 struct node *node;
1464 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1465 node->parent = parent;
1466 list_add_tail( &parent->children, &node->entry );
1467 return S_OK;
1470 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1471 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1473 HRESULT hr;
1474 if ((hr = write_flush( writer )) != S_OK) return hr;
1475 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1476 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1477 writer->state = WRITER_STATE_STARTELEMENT;
1478 return S_OK;
1481 /**************************************************************************
1482 * WsWriteStartElement [webservices.@]
1484 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1485 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1486 WS_ERROR *error )
1488 struct writer *writer = (struct writer *)handle;
1489 HRESULT hr;
1491 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1492 debugstr_xmlstr(ns), error );
1493 if (error) FIXME( "ignoring error parameter\n" );
1495 if (!writer || !localname || !ns) return E_INVALIDARG;
1497 EnterCriticalSection( &writer->cs );
1499 if (writer->magic != WRITER_MAGIC)
1501 LeaveCriticalSection( &writer->cs );
1502 return E_INVALIDARG;
1505 hr = write_element_node( writer, prefix, localname, ns );
1507 LeaveCriticalSection( &writer->cs );
1508 return hr;
1511 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1513 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1514 if (*ptr)
1516 memcpy( buf, bool_true, sizeof(bool_true) );
1517 return sizeof(bool_true);
1519 memcpy( buf, bool_false, sizeof(bool_false) );
1520 return sizeof(bool_false);
1523 static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
1525 return wsprintfA( (char *)buf, "%d", *ptr );
1528 static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
1530 return wsprintfA( (char *)buf, "%d", *ptr );
1533 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1535 return wsprintfA( (char *)buf, "%d", *ptr );
1538 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1540 return wsprintfA( (char *)buf, "%I64d", *ptr );
1543 static ULONG format_uint8( const UINT8 *ptr, unsigned char *buf )
1545 return wsprintfA( (char *)buf, "%u", *ptr );
1548 static ULONG format_uint16( const UINT16 *ptr, unsigned char *buf )
1550 return wsprintfA( (char *)buf, "%u", *ptr );
1553 static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
1555 return wsprintfA( (char *)buf, "%u", *ptr );
1558 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1560 return wsprintfA( (char *)buf, "%I64u", *ptr );
1563 static ULONG format_double( const double *ptr, unsigned char *buf )
1565 #ifdef HAVE_POWL
1566 static const long double precision = 0.0000000000000001;
1567 unsigned char *p = buf;
1568 long double val = *ptr;
1569 int neg, mag, mag2, use_exp;
1571 if (isnan( val ))
1573 memcpy( buf, "NaN", 3 );
1574 return 3;
1576 if (isinf( val ))
1578 if (val < 0)
1580 memcpy( buf, "-INF", 4 );
1581 return 4;
1583 memcpy( buf, "INF", 3 );
1584 return 3;
1586 if (val == 0.0)
1588 *p = '0';
1589 return 1;
1592 if ((neg = val < 0))
1594 *p++ = '-';
1595 val = -val;
1598 mag = log10l( val );
1599 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1600 if (use_exp)
1602 if (mag < 0) mag -= 1;
1603 val = val / powl( 10.0, mag );
1604 mag2 = mag;
1605 mag = 0;
1607 else if (mag < 1) mag = 0;
1609 while (val > precision || mag >= 0)
1611 long double weight = powl( 10.0, mag );
1612 if (weight > 0 && !isinf( weight ))
1614 int digit = floorl( val / weight );
1615 val -= digit * weight;
1616 *(p++) = '0' + digit;
1618 if (!mag && val > precision) *(p++) = '.';
1619 mag--;
1622 if (use_exp)
1624 int i, j;
1625 *(p++) = 'E';
1626 if (mag2 > 0) *(p++) = '+';
1627 else
1629 *(p++) = '-';
1630 mag2 = -mag2;
1632 mag = 0;
1633 while (mag2 > 0)
1635 *(p++) = '0' + mag2 % 10;
1636 mag2 /= 10;
1637 mag++;
1639 for (i = -mag, j = -1; i < j; i++, j--)
1641 p[i] ^= p[j];
1642 p[j] ^= p[i];
1643 p[i] ^= p[j];
1647 return p - buf;
1648 #else
1649 FIXME( "powl not found at build time\n" );
1650 return 0;
1651 #endif
1654 static inline int year_size( int year )
1656 return leap_year( year ) ? 366 : 365;
1659 #define TZ_OFFSET 8
1660 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1662 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1663 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
1664 unsigned __int64 ticks, day_ticks;
1665 ULONG len;
1667 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1668 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1670 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1671 tz_hour = TZ_OFFSET;
1673 else
1675 ticks = ptr->ticks;
1676 tz_hour = 0;
1678 day = ticks / TICKS_PER_DAY;
1679 day_ticks = ticks % TICKS_PER_DAY;
1680 hour = day_ticks / TICKS_PER_HOUR;
1681 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1682 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1683 sec_frac = day_ticks % TICKS_PER_SEC;
1685 while (day >= year_size( year ))
1687 day -= year_size( year );
1688 year++;
1690 while (day >= month_days[leap_year( year )][month])
1692 day -= month_days[leap_year( year )][month];
1693 month++;
1696 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1697 if (sec_frac)
1699 static const char fmt_frac[] = ".%07u";
1700 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1701 while (buf[len - 1] == '0') len--;
1703 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1705 buf[len++] = 'Z';
1707 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1709 static const char fmt_tz[] = "%c%02u:00";
1710 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1713 return len;
1716 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1718 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1719 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1720 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1721 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1724 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1726 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1727 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1728 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1729 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1732 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1734 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1735 ULONG i = 0, x;
1737 while (len > 0)
1739 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1740 x = (bin[0] & 3) << 4;
1741 if (len == 1)
1743 buf[i++] = base64[x];
1744 buf[i++] = '=';
1745 buf[i++] = '=';
1746 break;
1748 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1749 x = (bin[1] & 0x0f) << 2;
1750 if (len == 2)
1752 buf[i++] = base64[x];
1753 buf[i++] = '=';
1754 break;
1756 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1757 buf[i++] = base64[bin[2] & 0x3f];
1758 bin += 3;
1759 len -= 3;
1761 return i;
1764 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, WS_XML_UTF8_TEXT **ret )
1766 ULONG len_old = old ? old->value.length : 0;
1768 switch (text->textType)
1770 case WS_XML_TEXT_TYPE_UTF8:
1772 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1774 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
1775 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1776 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
1777 return S_OK;
1779 case WS_XML_TEXT_TYPE_UTF16:
1781 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1782 const WCHAR *str = (const WCHAR *)src->bytes;
1783 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1785 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1786 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1787 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
1788 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1789 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
1790 return S_OK;
1792 case WS_XML_TEXT_TYPE_BASE64:
1794 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1795 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1797 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1798 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1799 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
1800 return S_OK;
1802 case WS_XML_TEXT_TYPE_BOOL:
1804 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1806 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
1807 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1808 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
1809 return S_OK;
1811 case WS_XML_TEXT_TYPE_INT32:
1813 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1814 unsigned char buf[12]; /* "-2147483648" */
1815 ULONG len = format_int32( &int32_text->value, buf );
1817 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1818 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1819 memcpy( (*ret)->value.bytes + len_old, buf, len );
1820 return S_OK;
1822 case WS_XML_TEXT_TYPE_INT64:
1824 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1825 unsigned char buf[21]; /* "-9223372036854775808" */
1826 ULONG len = format_int64( &int64_text->value, buf );
1828 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1829 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1830 memcpy( (*ret)->value.bytes + len_old, buf, len );
1831 return S_OK;
1833 case WS_XML_TEXT_TYPE_UINT64:
1835 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1836 unsigned char buf[21]; /* "18446744073709551615" */
1837 ULONG len = format_uint64( &uint64_text->value, buf );
1839 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1840 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1841 memcpy( (*ret)->value.bytes + len_old, buf, len );
1842 return S_OK;
1844 case WS_XML_TEXT_TYPE_DOUBLE:
1846 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1847 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1848 unsigned short fpword;
1849 ULONG len;
1851 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
1852 len = format_double( &double_text->value, buf );
1853 restore_fpword( fpword );
1854 if (!len) return E_NOTIMPL;
1856 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1857 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1858 memcpy( (*ret)->value.bytes + len_old, buf, len );
1859 return S_OK;
1861 case WS_XML_TEXT_TYPE_GUID:
1863 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1865 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
1866 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1867 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1868 return S_OK;
1870 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1872 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1874 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
1875 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1876 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1877 return S_OK;
1879 case WS_XML_TEXT_TYPE_DATETIME:
1881 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1883 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
1884 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1885 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
1886 return S_OK;
1888 default:
1889 FIXME( "unhandled text type %u\n", text->textType );
1890 return E_NOTIMPL;
1894 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
1896 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1897 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
1898 HRESULT hr;
1900 switch (value->textType)
1902 case WS_XML_TEXT_TYPE_UTF8:
1903 case WS_XML_TEXT_TYPE_UTF16:
1904 case WS_XML_TEXT_TYPE_BASE64:
1905 break;
1907 case WS_XML_TEXT_TYPE_BOOL:
1908 case WS_XML_TEXT_TYPE_INT32:
1909 case WS_XML_TEXT_TYPE_INT64:
1910 case WS_XML_TEXT_TYPE_UINT64:
1911 case WS_XML_TEXT_TYPE_DOUBLE:
1912 case WS_XML_TEXT_TYPE_GUID:
1913 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1914 case WS_XML_TEXT_TYPE_DATETIME:
1915 if (old) return WS_E_INVALID_OPERATION;
1916 break;
1918 default:
1919 FIXME( "unhandled text type %u\n", value->textType );
1920 return E_NOTIMPL;
1923 if ((hr = text_to_utf8text( value, old, &new )) != S_OK) return hr;
1925 heap_free( old );
1926 elem->attributes[elem->attributeCount - 1]->value = &new->text;
1928 return S_OK;
1931 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
1933 struct node *node;
1934 WS_XML_TEXT_NODE *text;
1935 WS_XML_UTF8_TEXT *utf8;
1936 HRESULT hr;
1938 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
1939 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
1940 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
1942 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1943 if ((hr = text_to_utf8text( value, NULL, &utf8 )) != S_OK)
1945 heap_free( node );
1946 return hr;
1948 text = (WS_XML_TEXT_NODE *)node;
1949 text->text = &utf8->text;
1951 write_insert_node( writer, writer->current, node );
1952 return S_OK;
1955 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
1957 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1958 HRESULT hr;
1960 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
1962 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
1963 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
1965 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
1967 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
1968 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
1969 return S_OK;
1972 return WS_E_INVALID_FORMAT;
1975 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
1977 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1978 enum record_type type = get_text_record_type( text, FALSE );
1979 HRESULT hr;
1981 if (offset)
1983 FIXME( "no support for appending text in binary mode\n" );
1984 return WS_E_NOT_SUPPORTED;
1987 switch (type)
1989 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
1990 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1991 write_char( writer, type );
1992 if (!utf8 || !utf8->value.length) write_char( writer, 0 );
1993 else
1995 write_char( writer, utf8->value.length );
1996 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
1997 write_bytes( writer, utf8->value.bytes, utf8->value.length );
1999 return S_OK;
2001 default:
2002 FIXME( "unhandled record type %u\n", type );
2003 return WS_E_NOT_SUPPORTED;
2007 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2009 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2011 switch (writer->output_enc)
2013 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2014 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2015 default:
2016 ERR( "unhandled encoding %u\n", writer->output_enc );
2017 return WS_E_NOT_SUPPORTED;
2021 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2023 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2024 ULONG offset;
2025 HRESULT hr;
2027 if ((hr = write_flush( writer )) != S_OK) return hr;
2028 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2030 offset = 0;
2031 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2032 node = (WS_XML_TEXT_NODE *)writer->current;
2034 else
2036 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2038 offset = old->value.length;
2039 if ((hr = text_to_utf8text( text, old, &new )) != S_OK) return hr;
2040 heap_free( old );
2041 node->text = &new->text;
2044 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2046 writer->state = WRITER_STATE_TEXT;
2047 return S_OK;
2050 /**************************************************************************
2051 * WsWriteText [webservices.@]
2053 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2055 struct writer *writer = (struct writer *)handle;
2056 HRESULT hr;
2058 TRACE( "%p %p %p\n", handle, text, error );
2059 if (error) FIXME( "ignoring error parameter\n" );
2061 if (!writer || !text) return E_INVALIDARG;
2063 EnterCriticalSection( &writer->cs );
2065 if (writer->magic != WRITER_MAGIC)
2067 LeaveCriticalSection( &writer->cs );
2068 return E_INVALIDARG;
2071 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2072 else hr = write_text_node( writer, text );
2074 LeaveCriticalSection( &writer->cs );
2075 return hr;
2078 /**************************************************************************
2079 * WsWriteBytes [webservices.@]
2081 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2083 struct writer *writer = (struct writer *)handle;
2084 WS_XML_BASE64_TEXT base64;
2085 HRESULT hr;
2087 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2088 if (error) FIXME( "ignoring error parameter\n" );
2090 if (!writer) return E_INVALIDARG;
2092 EnterCriticalSection( &writer->cs );
2094 if (writer->magic != WRITER_MAGIC)
2096 LeaveCriticalSection( &writer->cs );
2097 return E_INVALIDARG;
2100 if (!writer->output_type)
2102 LeaveCriticalSection( &writer->cs );
2103 return WS_E_INVALID_OPERATION;
2106 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2107 base64.bytes = (BYTE *)bytes;
2108 base64.length = count;
2110 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2111 else hr = write_text_node( writer, &base64.text );
2113 LeaveCriticalSection( &writer->cs );
2114 return hr;
2117 /**************************************************************************
2118 * WsWriteChars [webservices.@]
2120 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
2122 struct writer *writer = (struct writer *)handle;
2123 WS_XML_UTF16_TEXT utf16;
2124 HRESULT hr;
2126 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
2127 if (error) FIXME( "ignoring error parameter\n" );
2129 if (!writer) return E_INVALIDARG;
2131 EnterCriticalSection( &writer->cs );
2133 if (writer->magic != WRITER_MAGIC)
2135 LeaveCriticalSection( &writer->cs );
2136 return E_INVALIDARG;
2139 if (!writer->output_type)
2141 LeaveCriticalSection( &writer->cs );
2142 return WS_E_INVALID_OPERATION;
2145 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2146 utf16.bytes = (BYTE *)chars;
2147 utf16.byteCount = count * sizeof(WCHAR);
2149 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
2150 else hr = write_text_node( writer, &utf16.text );
2152 LeaveCriticalSection( &writer->cs );
2153 return hr;
2156 /**************************************************************************
2157 * WsWriteCharsUtf8 [webservices.@]
2159 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
2161 struct writer *writer = (struct writer *)handle;
2162 WS_XML_UTF8_TEXT utf8;
2163 HRESULT hr;
2165 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
2166 if (error) FIXME( "ignoring error parameter\n" );
2168 if (!writer) return E_INVALIDARG;
2170 EnterCriticalSection( &writer->cs );
2172 if (writer->magic != WRITER_MAGIC)
2174 LeaveCriticalSection( &writer->cs );
2175 return E_INVALIDARG;
2178 if (!writer->output_type)
2180 LeaveCriticalSection( &writer->cs );
2181 return WS_E_INVALID_OPERATION;
2184 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2185 utf8.value.bytes = (BYTE *)bytes;
2186 utf8.value.length = count;
2188 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
2189 else hr = write_text_node( writer, &utf8.text );
2191 LeaveCriticalSection( &writer->cs );
2192 return hr;
2195 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
2197 switch (mapping)
2199 case WS_ELEMENT_TYPE_MAPPING:
2200 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2201 return write_text_node( writer, text );
2203 case WS_ATTRIBUTE_TYPE_MAPPING:
2204 return write_set_attribute_value( writer, text );
2206 case WS_ANY_ELEMENT_TYPE_MAPPING:
2207 switch (writer->state)
2209 case WRITER_STATE_STARTATTRIBUTE:
2210 return write_set_attribute_value( writer, text );
2212 case WRITER_STATE_STARTELEMENT:
2213 return write_text_node( writer, text );
2215 default:
2216 FIXME( "writer state %u not handled\n", writer->state );
2217 return E_NOTIMPL;
2220 default:
2221 FIXME( "mapping %u not implemented\n", mapping );
2222 return E_NOTIMPL;
2226 static HRESULT write_add_nil_attribute( struct writer *writer )
2228 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
2229 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
2230 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
2231 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
2232 HRESULT hr;
2234 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
2235 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
2236 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
2239 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
2240 const void **ptr )
2242 switch (option)
2244 case WS_WRITE_REQUIRED_VALUE:
2245 case WS_WRITE_NILLABLE_VALUE:
2246 if (!value || size != expected_size) return E_INVALIDARG;
2247 *ptr = value;
2248 return S_OK;
2250 case WS_WRITE_REQUIRED_POINTER:
2251 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
2252 return S_OK;
2254 case WS_WRITE_NILLABLE_POINTER:
2255 if (size != sizeof(const void *)) return E_INVALIDARG;
2256 *ptr = *(const void **)value;
2257 return S_OK;
2259 default:
2260 return E_INVALIDARG;
2264 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
2265 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
2266 const BOOL *value, ULONG size )
2268 WS_XML_UTF8_TEXT utf8;
2269 unsigned char buf[6]; /* "false" */
2270 const BOOL *ptr;
2271 HRESULT hr;
2273 if (desc)
2275 FIXME( "description not supported\n" );
2276 return E_NOTIMPL;
2279 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2280 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
2281 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2283 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2284 utf8.value.bytes = buf;
2285 utf8.value.length = format_bool( ptr, buf );
2286 return write_type_text( writer, mapping, &utf8.text );
2289 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
2290 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
2291 const BOOL *value, ULONG size )
2293 WS_XML_UTF8_TEXT utf8;
2294 unsigned char buf[5]; /* "-128" */
2295 const INT8 *ptr;
2296 HRESULT hr;
2298 if (desc)
2300 FIXME( "description not supported\n" );
2301 return E_NOTIMPL;
2304 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2305 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
2306 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2308 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2309 utf8.value.bytes = buf;
2310 utf8.value.length = format_int8( ptr, buf );
2311 return write_type_text( writer, mapping, &utf8.text );
2314 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
2315 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
2316 const BOOL *value, ULONG size )
2318 WS_XML_UTF8_TEXT utf8;
2319 unsigned char buf[7]; /* "-32768" */
2320 const INT16 *ptr;
2321 HRESULT hr;
2323 if (desc)
2325 FIXME( "description not supported\n" );
2326 return E_NOTIMPL;
2329 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2330 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
2331 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2333 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2334 utf8.value.bytes = buf;
2335 utf8.value.length = format_int16( ptr, buf );
2336 return write_type_text( writer, mapping, &utf8.text );
2339 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
2340 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
2341 const void *value, ULONG size )
2343 WS_XML_UTF8_TEXT utf8;
2344 unsigned char buf[12]; /* "-2147483648" */
2345 const INT32 *ptr;
2346 HRESULT hr;
2348 if (desc)
2350 FIXME( "description not supported\n" );
2351 return E_NOTIMPL;
2354 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2355 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
2356 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2358 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2359 utf8.value.bytes = buf;
2360 utf8.value.length = format_int32( ptr, buf );
2361 return write_type_text( writer, mapping, &utf8.text );
2364 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
2365 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
2366 const void *value, ULONG size )
2368 WS_XML_UTF8_TEXT utf8;
2369 unsigned char buf[21]; /* "-9223372036854775808" */
2370 const INT64 *ptr;
2371 HRESULT hr;
2373 if (desc)
2375 FIXME( "description not supported\n" );
2376 return E_NOTIMPL;
2379 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2380 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
2381 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2383 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2384 utf8.value.bytes = buf;
2385 utf8.value.length = format_int64( ptr, buf );
2386 return write_type_text( writer, mapping, &utf8.text );
2389 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
2390 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
2391 const void *value, ULONG size )
2393 WS_XML_UTF8_TEXT utf8;
2394 unsigned char buf[4]; /* "255" */
2395 const UINT8 *ptr;
2396 HRESULT hr;
2398 if (desc)
2400 FIXME( "description not supported\n" );
2401 return E_NOTIMPL;
2404 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2405 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
2406 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2408 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2409 utf8.value.bytes = buf;
2410 utf8.value.length = format_uint8( ptr, buf );
2411 return write_type_text( writer, mapping, &utf8.text );
2414 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
2415 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
2416 const void *value, ULONG size )
2418 WS_XML_UTF8_TEXT utf8;
2419 unsigned char buf[6]; /* "65535" */
2420 const UINT16 *ptr;
2421 HRESULT hr;
2423 if (desc)
2425 FIXME( "description not supported\n" );
2426 return E_NOTIMPL;
2429 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2430 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
2431 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2433 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2434 utf8.value.bytes = buf;
2435 utf8.value.length = format_uint16( ptr, buf );
2436 return write_type_text( writer, mapping, &utf8.text );
2439 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
2440 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
2441 const void *value, ULONG size )
2443 WS_XML_UTF8_TEXT utf8;
2444 unsigned char buf[11]; /* "4294967295" */
2445 const UINT32 *ptr;
2446 HRESULT hr;
2448 if (desc)
2450 FIXME( "description not supported\n" );
2451 return E_NOTIMPL;
2454 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2455 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
2456 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2458 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2459 utf8.value.bytes = buf;
2460 utf8.value.length = format_uint32( ptr, buf );
2461 return write_type_text( writer, mapping, &utf8.text );
2464 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
2465 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
2466 const void *value, ULONG size )
2468 WS_XML_UTF8_TEXT utf8;
2469 unsigned char buf[21]; /* "18446744073709551615" */
2470 const UINT64 *ptr;
2471 HRESULT hr;
2473 if (desc)
2475 FIXME( "description not supported\n" );
2476 return E_NOTIMPL;
2479 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2480 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
2481 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2483 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2484 utf8.value.bytes = buf;
2485 utf8.value.length = format_uint64( ptr, buf );
2486 return write_type_text( writer, mapping, &utf8.text );
2489 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
2490 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
2491 const void *value, ULONG size )
2493 WS_XML_UTF8_TEXT utf8;
2494 unsigned char buf[34]; /* "0000-00-00T00:00:00.0000000-00:00" */
2495 const WS_DATETIME *ptr;
2496 HRESULT hr;
2498 if (desc)
2500 FIXME( "description not supported\n" );
2501 return E_NOTIMPL;
2504 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2505 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
2506 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2507 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
2509 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2510 utf8.value.bytes = buf;
2511 utf8.value.length = format_datetime( ptr, buf );
2512 return write_type_text( writer, mapping, &utf8.text );
2515 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
2516 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
2517 const void *value, ULONG size )
2519 WS_XML_UTF8_TEXT utf8;
2520 unsigned char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
2521 const GUID *ptr;
2522 HRESULT hr;
2524 if (desc)
2526 FIXME( "description not supported\n" );
2527 return E_NOTIMPL;
2530 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2531 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
2532 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2534 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2535 utf8.value.bytes = buf;
2536 utf8.value.length = format_guid( ptr, buf );
2537 return write_type_text( writer, mapping, &utf8.text );
2540 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
2541 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
2542 const void *value, ULONG size )
2544 WS_XML_UTF16_TEXT utf16;
2545 const WS_STRING *ptr;
2546 HRESULT hr;
2548 if (desc)
2550 FIXME( "description not supported\n" );
2551 return E_NOTIMPL;
2554 if (!option) return E_INVALIDARG;
2555 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
2556 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2557 if (!ptr->length) return S_OK;
2559 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2560 utf16.bytes = (BYTE *)ptr->chars;
2561 utf16.byteCount = ptr->length * sizeof(WCHAR);
2562 return write_type_text( writer, mapping, &utf16.text );
2565 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
2566 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
2567 const void *value, ULONG size )
2569 WS_XML_UTF16_TEXT utf16;
2570 const WCHAR *ptr;
2571 HRESULT hr;
2572 int len;
2574 if (desc)
2576 FIXME( "description not supported\n" );
2577 return E_NOTIMPL;
2580 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2581 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
2582 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2583 if (!(len = strlenW( ptr ))) return S_OK;
2585 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2586 utf16.bytes = (BYTE *)ptr;
2587 utf16.byteCount = len * sizeof(WCHAR);
2588 return write_type_text( writer, mapping, &utf16.text );
2591 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
2592 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
2593 const void *value, ULONG size )
2595 WS_XML_BASE64_TEXT base64;
2596 const WS_BYTES *ptr;
2597 HRESULT hr;
2599 if (desc)
2601 FIXME( "description not supported\n" );
2602 return E_NOTIMPL;
2605 if (!option) return E_INVALIDARG;
2606 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
2607 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
2608 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
2609 if (!ptr->length) return S_OK;
2611 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2612 base64.bytes = ptr->bytes;
2613 base64.length = ptr->length;
2614 return write_type_text( writer, mapping, &base64.text );
2617 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
2618 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
2619 const void *value, ULONG size )
2621 WS_XML_UTF8_TEXT utf8;
2622 const WS_XML_STRING *ptr;
2623 HRESULT hr;
2625 if (desc)
2627 FIXME( "description not supported\n" );
2628 return E_NOTIMPL;
2631 if (!option) return E_INVALIDARG;
2632 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
2633 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2634 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
2635 if (!ptr->length) return S_OK;
2637 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2638 utf8.value.bytes = ptr->bytes;
2639 utf8.value.length = ptr->length;
2640 return write_type_text( writer, mapping, &utf8.text );
2643 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
2645 if (options & WS_FIELD_POINTER)
2647 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
2648 return WS_WRITE_REQUIRED_POINTER;
2651 switch (type)
2653 case WS_BOOL_TYPE:
2654 case WS_INT8_TYPE:
2655 case WS_INT16_TYPE:
2656 case WS_INT32_TYPE:
2657 case WS_INT64_TYPE:
2658 case WS_UINT8_TYPE:
2659 case WS_UINT16_TYPE:
2660 case WS_UINT32_TYPE:
2661 case WS_UINT64_TYPE:
2662 case WS_DOUBLE_TYPE:
2663 case WS_DATETIME_TYPE:
2664 case WS_GUID_TYPE:
2665 case WS_STRING_TYPE:
2666 case WS_BYTES_TYPE:
2667 case WS_XML_STRING_TYPE:
2668 case WS_STRUCT_TYPE:
2669 case WS_ENUM_TYPE:
2670 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
2671 return WS_WRITE_REQUIRED_VALUE;
2673 case WS_WSZ_TYPE:
2674 case WS_DESCRIPTION_TYPE:
2675 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
2676 return WS_WRITE_REQUIRED_POINTER;
2678 default:
2679 FIXME( "unhandled type %u\n", type );
2680 return 0;
2684 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
2685 const void *, ULONG );
2687 static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
2688 const char *buf, ULONG count )
2690 HRESULT hr = S_OK;
2691 ULONG i, size, offset = 0;
2692 WS_WRITE_OPTION option;
2694 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
2696 /* wrapper element */
2697 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
2698 return hr;
2700 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
2701 size = get_type_size( desc->type, desc->typeDescription );
2702 else
2703 size = sizeof(const void *);
2705 for (i = 0; i < count; i++)
2707 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
2708 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
2709 buf + offset, size )) != S_OK) return hr;
2710 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2711 offset += size;
2714 if (desc->localName) hr = write_endelement_node( writer );
2715 return hr;
2718 static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
2719 const char *buf, ULONG offset )
2721 HRESULT hr;
2722 WS_TYPE_MAPPING mapping;
2723 WS_WRITE_OPTION option;
2724 ULONG count, size, field_options = desc->options;
2725 const char *ptr = buf + offset;
2727 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
2729 FIXME( "options 0x%x not supported\n", desc->options );
2730 return E_NOTIMPL;
2733 /* zero-terminated strings are always pointers */
2734 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
2736 if (field_options & WS_FIELD_POINTER)
2737 size = sizeof(const void *);
2738 else
2739 size = get_type_size( desc->type, desc->typeDescription );
2741 if (is_nil_value( ptr, size ))
2743 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
2744 if (field_options & WS_FIELD_NILLABLE)
2746 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
2747 else option = WS_WRITE_NILLABLE_VALUE;
2749 else return E_INVALIDARG;
2751 else
2753 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
2754 else option = WS_WRITE_REQUIRED_VALUE;
2757 switch (desc->mapping)
2759 case WS_ATTRIBUTE_FIELD_MAPPING:
2760 if (!desc->localName || !desc->ns) return E_INVALIDARG;
2761 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
2762 return hr;
2763 writer->state = WRITER_STATE_STARTATTRIBUTE;
2765 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2766 break;
2768 case WS_ELEMENT_FIELD_MAPPING:
2769 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
2770 mapping = WS_ELEMENT_TYPE_MAPPING;
2771 break;
2773 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
2774 count = *(const ULONG *)(buf + desc->countOffset);
2775 return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
2777 case WS_TEXT_FIELD_MAPPING:
2778 switch (writer->state)
2780 case WRITER_STATE_STARTELEMENT:
2781 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
2782 break;
2784 case WRITER_STATE_STARTATTRIBUTE:
2785 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2786 break;
2788 default:
2789 FIXME( "unhandled writer state %u\n", writer->state );
2790 return E_NOTIMPL;
2792 break;
2794 default:
2795 FIXME( "field mapping %u not supported\n", desc->mapping );
2796 return E_NOTIMPL;
2799 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
2800 return hr;
2802 switch (mapping)
2804 case WS_ATTRIBUTE_TYPE_MAPPING:
2805 writer->state = WRITER_STATE_STARTELEMENT;
2806 break;
2808 case WS_ELEMENT_TYPE_MAPPING:
2809 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2810 break;
2812 default: break;
2815 return S_OK;
2818 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
2819 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
2820 const void *value, ULONG size )
2822 ULONG i, offset;
2823 const void *ptr;
2824 HRESULT hr;
2826 if (!desc) return E_INVALIDARG;
2827 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
2829 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
2831 for (i = 0; i < desc->fieldCount; i++)
2833 offset = desc->fields[i]->offset;
2834 if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, offset )) != S_OK)
2835 return hr;
2838 return S_OK;
2842 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
2843 const void *desc, WS_WRITE_OPTION option, const void *value,
2844 ULONG size )
2846 switch (type)
2848 case WS_BOOL_TYPE:
2849 return write_type_bool( writer, mapping, desc, option, value, size );
2851 case WS_INT8_TYPE:
2852 return write_type_int8( writer, mapping, desc, option, value, size );
2854 case WS_INT16_TYPE:
2855 return write_type_int16( writer, mapping, desc, option, value, size );
2857 case WS_INT32_TYPE:
2858 return write_type_int32( writer, mapping, desc, option, value, size );
2860 case WS_INT64_TYPE:
2861 return write_type_int64( writer, mapping, desc, option, value, size );
2863 case WS_UINT8_TYPE:
2864 return write_type_uint8( writer, mapping, desc, option, value, size );
2866 case WS_UINT16_TYPE:
2867 return write_type_uint16( writer, mapping, desc, option, value, size );
2869 case WS_UINT32_TYPE:
2870 return write_type_uint32( writer, mapping, desc, option, value, size );
2872 case WS_UINT64_TYPE:
2873 return write_type_uint64( writer, mapping, desc, option, value, size );
2875 case WS_DATETIME_TYPE:
2876 return write_type_datetime( writer, mapping, desc, option, value, size );
2878 case WS_GUID_TYPE:
2879 return write_type_guid( writer, mapping, desc, option, value, size );
2881 case WS_STRING_TYPE:
2882 return write_type_string( writer, mapping, desc, option, value, size );
2884 case WS_WSZ_TYPE:
2885 return write_type_wsz( writer, mapping, desc, option, value, size );
2887 case WS_BYTES_TYPE:
2888 return write_type_bytes( writer, mapping, desc, option, value, size );
2890 case WS_XML_STRING_TYPE:
2891 return write_type_xml_string( writer, mapping, desc, option, value, size );
2893 case WS_STRUCT_TYPE:
2894 return write_type_struct( writer, mapping, desc, option, value, size );
2896 default:
2897 FIXME( "type %u not supported\n", type );
2898 return E_NOTIMPL;
2902 /**************************************************************************
2903 * WsWriteAttribute [webservices.@]
2905 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
2906 WS_WRITE_OPTION option, const void *value, ULONG size,
2907 WS_ERROR *error )
2909 struct writer *writer = (struct writer *)handle;
2910 HRESULT hr;
2912 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2913 if (error) FIXME( "ignoring error parameter\n" );
2915 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
2916 return E_INVALIDARG;
2918 EnterCriticalSection( &writer->cs );
2920 if (writer->magic != WRITER_MAGIC)
2922 LeaveCriticalSection( &writer->cs );
2923 return E_INVALIDARG;
2926 if (writer->state != WRITER_STATE_STARTELEMENT)
2928 LeaveCriticalSection( &writer->cs );
2929 return WS_E_INVALID_OPERATION;
2932 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK)
2934 LeaveCriticalSection( &writer->cs );
2935 return hr;
2937 writer->state = WRITER_STATE_STARTATTRIBUTE;
2939 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
2941 LeaveCriticalSection( &writer->cs );
2942 return hr;
2945 /**************************************************************************
2946 * WsWriteElement [webservices.@]
2948 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
2949 WS_WRITE_OPTION option, const void *value, ULONG size,
2950 WS_ERROR *error )
2952 struct writer *writer = (struct writer *)handle;
2953 HRESULT hr;
2955 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2956 if (error) FIXME( "ignoring error parameter\n" );
2958 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
2959 return E_INVALIDARG;
2961 EnterCriticalSection( &writer->cs );
2963 if (writer->magic != WRITER_MAGIC)
2965 LeaveCriticalSection( &writer->cs );
2966 return E_INVALIDARG;
2969 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
2971 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
2972 option, value, size )) != S_OK) goto done;
2974 hr = write_endelement_node( writer );
2976 done:
2977 LeaveCriticalSection( &writer->cs );
2978 return hr;
2981 /**************************************************************************
2982 * WsWriteType [webservices.@]
2984 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
2985 const void *desc, WS_WRITE_OPTION option, const void *value,
2986 ULONG size, WS_ERROR *error )
2988 struct writer *writer = (struct writer *)handle;
2989 HRESULT hr;
2991 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
2992 size, error );
2993 if (error) FIXME( "ignoring error parameter\n" );
2995 if (!writer || !value) return E_INVALIDARG;
2997 EnterCriticalSection( &writer->cs );
2999 if (writer->magic != WRITER_MAGIC)
3001 LeaveCriticalSection( &writer->cs );
3002 return E_INVALIDARG;
3005 switch (mapping)
3007 case WS_ATTRIBUTE_TYPE_MAPPING:
3008 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
3009 else hr = write_type( writer, mapping, type, desc, option, value, size );
3010 break;
3012 case WS_ELEMENT_TYPE_MAPPING:
3013 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3014 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
3015 else hr = write_type( writer, mapping, type, desc, option, value, size );
3016 break;
3018 case WS_ANY_ELEMENT_TYPE_MAPPING:
3019 hr = write_type( writer, mapping, type, desc, option, value, size );
3020 break;
3022 default:
3023 FIXME( "mapping %u not implemented\n", mapping );
3024 hr = E_NOTIMPL;
3027 LeaveCriticalSection( &writer->cs );
3028 return hr;
3031 WS_TYPE map_value_type( WS_VALUE_TYPE type )
3033 switch (type)
3035 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
3036 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
3037 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
3038 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
3039 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
3040 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
3041 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
3042 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
3043 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
3044 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
3045 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
3046 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
3047 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
3048 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
3049 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
3050 default:
3051 FIXME( "unhandled type %u\n", type );
3052 return ~0u;
3056 /**************************************************************************
3057 * WsWriteValue [webservices.@]
3059 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
3060 ULONG size, WS_ERROR *error )
3062 struct writer *writer = (struct writer *)handle;
3063 WS_TYPE_MAPPING mapping;
3064 HRESULT hr = S_OK;
3065 WS_TYPE type;
3067 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
3068 if (error) FIXME( "ignoring error parameter\n" );
3070 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
3072 EnterCriticalSection( &writer->cs );
3074 if (writer->magic != WRITER_MAGIC)
3076 LeaveCriticalSection( &writer->cs );
3077 return E_INVALIDARG;
3080 switch (writer->state)
3082 case WRITER_STATE_STARTATTRIBUTE:
3083 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3084 break;
3086 case WRITER_STATE_STARTELEMENT:
3087 mapping = WS_ELEMENT_TYPE_MAPPING;
3088 break;
3090 default:
3091 hr = WS_E_INVALID_FORMAT;
3094 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
3096 LeaveCriticalSection( &writer->cs );
3097 return hr;
3100 /**************************************************************************
3101 * WsWriteArray [webservices.@]
3103 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3104 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
3105 ULONG count, WS_ERROR *error )
3107 struct writer *writer = (struct writer *)handle;
3108 WS_TYPE type;
3109 ULONG type_size, i;
3110 HRESULT hr = S_OK;
3112 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3113 value_type, array, size, offset, count, error );
3114 if (error) FIXME( "ignoring error parameter\n" );
3116 if (!writer) return E_INVALIDARG;
3118 EnterCriticalSection( &writer->cs );
3120 if (writer->magic != WRITER_MAGIC)
3122 LeaveCriticalSection( &writer->cs );
3123 return E_INVALIDARG;
3126 if (!writer->output_type)
3128 LeaveCriticalSection( &writer->cs );
3129 return WS_E_INVALID_OPERATION;
3132 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
3134 LeaveCriticalSection( &writer->cs );
3135 return E_INVALIDARG;
3138 type_size = get_type_size( type, NULL );
3139 if (size % type_size || (offset + count) * type_size > size || (count && !array))
3141 LeaveCriticalSection( &writer->cs );
3142 return E_INVALIDARG;
3145 for (i = offset; i < count; i++)
3147 const char *ptr = (const char *)array + (offset + i) * type_size;
3148 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
3149 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
3150 &ptr, sizeof(ptr) )) != S_OK) goto done;
3151 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
3154 done:
3155 LeaveCriticalSection( &writer->cs );
3156 return hr;
3159 /**************************************************************************
3160 * WsWriteXmlBuffer [webservices.@]
3162 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
3164 struct writer *writer = (struct writer *)handle;
3165 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
3166 HRESULT hr;
3168 TRACE( "%p %p %p\n", handle, buffer, error );
3169 if (error) FIXME( "ignoring error parameter\n" );
3171 if (!writer || !xmlbuf) return E_INVALIDARG;
3173 EnterCriticalSection( &writer->cs );
3175 if (writer->magic != WRITER_MAGIC)
3177 LeaveCriticalSection( &writer->cs );
3178 return E_INVALIDARG;
3181 if ((hr = write_flush( writer )) != S_OK) goto done;
3182 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
3183 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
3185 done:
3186 LeaveCriticalSection( &writer->cs );
3187 return hr;
3190 /**************************************************************************
3191 * WsWriteXmlBufferToBytes [webservices.@]
3193 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
3194 const WS_XML_WRITER_ENCODING *encoding,
3195 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
3196 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
3198 struct writer *writer = (struct writer *)handle;
3199 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
3200 HRESULT hr = S_OK;
3201 char *buf;
3202 ULONG i;
3204 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
3205 bytes, size, error );
3206 if (error) FIXME( "ignoring error parameter\n" );
3208 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
3210 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
3212 FIXME( "encoding type %u not supported\n", encoding->encodingType );
3213 return E_NOTIMPL;
3216 EnterCriticalSection( &writer->cs );
3218 if (writer->magic != WRITER_MAGIC)
3220 LeaveCriticalSection( &writer->cs );
3221 return E_INVALIDARG;
3224 for (i = 0; i < count; i++)
3226 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
3227 properties[i].valueSize );
3228 if (hr != S_OK) goto done;
3231 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
3232 else
3234 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
3235 *bytes = buf;
3236 *size = xmlbuf->bytes.length;
3239 done:
3240 LeaveCriticalSection( &writer->cs );
3241 return hr;
3244 /**************************************************************************
3245 * WsWriteXmlnsAttribute [webservices.@]
3247 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
3248 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
3250 struct writer *writer = (struct writer *)handle;
3251 HRESULT hr = S_OK;
3253 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
3254 single, error );
3255 if (error) FIXME( "ignoring error parameter\n" );
3257 if (!writer || !ns) return E_INVALIDARG;
3259 EnterCriticalSection( &writer->cs );
3261 if (writer->magic != WRITER_MAGIC)
3263 LeaveCriticalSection( &writer->cs );
3264 return E_INVALIDARG;
3267 if (writer->state != WRITER_STATE_STARTELEMENT)
3269 LeaveCriticalSection( &writer->cs );
3270 return WS_E_INVALID_OPERATION;
3273 if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
3274 hr = add_namespace_attribute( writer, prefix, ns, single );
3276 LeaveCriticalSection( &writer->cs );
3277 return hr;
3280 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3282 const struct node *node;
3283 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3285 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3286 ULONG i;
3287 for (i = 0; i < elem->attributeCount; i++)
3289 if (!elem->attributes[i]->isXmlNs) continue;
3290 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3291 *prefix = elem->attributes[i]->prefix;
3292 return S_OK;
3295 return WS_E_INVALID_FORMAT;
3298 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
3299 const WS_XML_STRING *localname )
3301 HRESULT hr;
3302 if (prefix->length)
3304 if ((hr = write_grow_buffer( writer, prefix->length + localname->length + 1 )) != S_OK) return hr;
3305 write_bytes( writer, prefix->bytes, prefix->length );
3306 write_char( writer, ':' );
3308 else if ((hr = write_grow_buffer( writer, localname->length )) != S_OK) return hr;
3309 write_bytes( writer, localname->bytes, localname->length );
3310 return S_OK;
3313 /**************************************************************************
3314 * WsWriteQualifiedName [webservices.@]
3316 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
3317 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3318 WS_ERROR *error )
3320 struct writer *writer = (struct writer *)handle;
3321 HRESULT hr;
3323 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
3324 debugstr_xmlstr(ns), error );
3325 if (error) FIXME( "ignoring error parameter\n" );
3327 if (!writer) return E_INVALIDARG;
3329 EnterCriticalSection( &writer->cs );
3331 if (writer->magic != WRITER_MAGIC)
3333 LeaveCriticalSection( &writer->cs );
3334 return E_INVALIDARG;
3337 if (!writer->output_type)
3339 LeaveCriticalSection( &writer->cs );
3340 return WS_E_INVALID_OPERATION;
3343 if (writer->state != WRITER_STATE_STARTELEMENT)
3345 LeaveCriticalSection( &writer->cs );
3346 return WS_E_INVALID_FORMAT;
3349 if (!localname || (!prefix && !ns))
3351 LeaveCriticalSection( &writer->cs );
3352 return E_INVALIDARG;
3355 if ((hr = write_flush( writer )) != S_OK) goto done;
3356 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) goto done;
3357 hr = write_qualified_name( writer, prefix, localname );
3359 done:
3360 LeaveCriticalSection( &writer->cs );
3361 return hr;
3364 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
3366 BOOL success = FALSE;
3367 struct node *node = writer->current;
3369 switch (move)
3371 case WS_MOVE_TO_ROOT_ELEMENT:
3372 success = move_to_root_element( writer->root, &node );
3373 break;
3375 case WS_MOVE_TO_NEXT_ELEMENT:
3376 success = move_to_next_element( &node );
3377 break;
3379 case WS_MOVE_TO_PREVIOUS_ELEMENT:
3380 success = move_to_prev_element( &node );
3381 break;
3383 case WS_MOVE_TO_CHILD_ELEMENT:
3384 success = move_to_child_element( &node );
3385 break;
3387 case WS_MOVE_TO_END_ELEMENT:
3388 success = move_to_end_element( &node );
3389 break;
3391 case WS_MOVE_TO_PARENT_ELEMENT:
3392 success = move_to_parent_element( &node );
3393 break;
3395 case WS_MOVE_TO_FIRST_NODE:
3396 success = move_to_first_node( &node );
3397 break;
3399 case WS_MOVE_TO_NEXT_NODE:
3400 success = move_to_next_node( &node );
3401 break;
3403 case WS_MOVE_TO_PREVIOUS_NODE:
3404 success = move_to_prev_node( &node );
3405 break;
3407 case WS_MOVE_TO_CHILD_NODE:
3408 success = move_to_child_node( &node );
3409 break;
3411 case WS_MOVE_TO_BOF:
3412 success = move_to_bof( writer->root, &node );
3413 break;
3415 case WS_MOVE_TO_EOF:
3416 success = move_to_eof( writer->root, &node );
3417 break;
3419 default:
3420 FIXME( "unhandled move %u\n", move );
3421 return E_NOTIMPL;
3424 if (success && node == writer->root) return E_INVALIDARG;
3425 writer->current = node;
3427 if (found)
3429 *found = success;
3430 return S_OK;
3432 return success ? S_OK : WS_E_INVALID_FORMAT;
3435 /**************************************************************************
3436 * WsMoveWriter [webservices.@]
3438 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
3440 struct writer *writer = (struct writer *)handle;
3441 HRESULT hr;
3443 TRACE( "%p %u %p %p\n", handle, move, found, error );
3444 if (error) FIXME( "ignoring error parameter\n" );
3446 if (!writer) return E_INVALIDARG;
3448 EnterCriticalSection( &writer->cs );
3450 if (writer->magic != WRITER_MAGIC)
3452 LeaveCriticalSection( &writer->cs );
3453 return E_INVALIDARG;
3456 if (!writer->output_type)
3458 LeaveCriticalSection( &writer->cs );
3459 return WS_E_INVALID_OPERATION;
3462 hr = write_move_to( writer, move, found );
3464 LeaveCriticalSection( &writer->cs );
3465 return hr;
3468 /**************************************************************************
3469 * WsGetWriterPosition [webservices.@]
3471 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
3473 struct writer *writer = (struct writer *)handle;
3475 TRACE( "%p %p %p\n", handle, pos, error );
3476 if (error) FIXME( "ignoring error parameter\n" );
3478 if (!writer || !pos) return E_INVALIDARG;
3480 EnterCriticalSection( &writer->cs );
3482 if (writer->magic != WRITER_MAGIC)
3484 LeaveCriticalSection( &writer->cs );
3485 return E_INVALIDARG;
3488 if (!writer->output_type)
3490 LeaveCriticalSection( &writer->cs );
3491 return WS_E_INVALID_OPERATION;
3494 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
3495 pos->node = writer->current;
3497 LeaveCriticalSection( &writer->cs );
3498 return S_OK;
3501 /**************************************************************************
3502 * WsSetWriterPosition [webservices.@]
3504 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
3506 struct writer *writer = (struct writer *)handle;
3508 TRACE( "%p %p %p\n", handle, pos, error );
3509 if (error) FIXME( "ignoring error parameter\n" );
3511 if (!writer || !pos) return E_INVALIDARG;
3513 EnterCriticalSection( &writer->cs );
3515 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
3517 LeaveCriticalSection( &writer->cs );
3518 return E_INVALIDARG;
3521 if (!writer->output_type)
3523 LeaveCriticalSection( &writer->cs );
3524 return WS_E_INVALID_OPERATION;
3527 writer->current = pos->node;
3529 LeaveCriticalSection( &writer->cs );
3530 return S_OK;
3533 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
3535 struct node *node, *parent;
3536 WS_XML_COMMENT_NODE *comment;
3538 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
3539 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
3540 comment = (WS_XML_COMMENT_NODE *)node;
3542 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
3544 free_node( node );
3545 return E_OUTOFMEMORY;
3547 memcpy( comment->value.bytes, value->bytes, value->length );
3548 comment->value.length = value->length;
3550 write_insert_node( writer, parent, node );
3551 return S_OK;
3554 static HRESULT write_comment( struct writer *writer )
3556 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
3557 HRESULT hr;
3559 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
3560 write_bytes( writer, (const BYTE *)"<!--", 4 );
3561 write_bytes( writer, comment->value.bytes, comment->value.length );
3562 write_bytes( writer, (const BYTE *)"-->", 3 );
3563 return S_OK;
3566 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
3568 HRESULT hr;
3569 if ((hr = write_flush( writer )) != S_OK) return hr;
3570 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
3571 if ((hr = write_comment( writer )) != S_OK) return hr;
3572 writer->state = WRITER_STATE_COMMENT;
3573 return S_OK;
3576 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
3578 ULONG i;
3579 HRESULT hr;
3581 for (i = 0; i < count; i++)
3583 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
3584 attrs[i]->singleQuote )) != S_OK) return hr;
3585 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
3587 return S_OK;
3590 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
3592 HRESULT hr;
3594 switch (node->nodeType)
3596 case WS_XML_NODE_TYPE_ELEMENT:
3598 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
3599 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
3600 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
3602 case WS_XML_NODE_TYPE_TEXT:
3604 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
3605 return write_text_node( writer, text->text );
3607 case WS_XML_NODE_TYPE_END_ELEMENT:
3608 return write_endelement_node( writer );
3610 case WS_XML_NODE_TYPE_COMMENT:
3612 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
3613 return write_comment_node( writer, &comment->value );
3615 case WS_XML_NODE_TYPE_CDATA:
3616 return write_cdata_node( writer );
3618 case WS_XML_NODE_TYPE_END_CDATA:
3619 return write_endcdata_node( writer );
3621 case WS_XML_NODE_TYPE_EOF:
3622 case WS_XML_NODE_TYPE_BOF:
3623 return S_OK;
3625 default:
3626 WARN( "unknown node type %u\n", node->nodeType );
3627 return E_INVALIDARG;
3631 /**************************************************************************
3632 * WsWriteNode [webservices.@]
3634 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
3636 struct writer *writer = (struct writer *)handle;
3637 HRESULT hr;
3639 TRACE( "%p %p %p\n", handle, node, error );
3640 if (error) FIXME( "ignoring error parameter\n" );
3642 if (!writer || !node) return E_INVALIDARG;
3644 EnterCriticalSection( &writer->cs );
3646 if (writer->magic != WRITER_MAGIC)
3648 LeaveCriticalSection( &writer->cs );
3649 return E_INVALIDARG;
3652 if (!writer->output_type)
3654 LeaveCriticalSection( &writer->cs );
3655 return WS_E_INVALID_OPERATION;
3658 hr = write_node( writer, node );
3660 LeaveCriticalSection( &writer->cs );
3661 return hr;
3664 static HRESULT write_tree_node( struct writer *writer )
3666 HRESULT hr;
3668 switch (node_type( writer->current ))
3670 case WS_XML_NODE_TYPE_ELEMENT:
3671 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
3672 return hr;
3673 if ((hr = write_startelement( writer )) != S_OK) return hr;
3674 writer->state = WRITER_STATE_STARTELEMENT;
3675 return S_OK;
3677 case WS_XML_NODE_TYPE_TEXT:
3678 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
3679 return hr;
3680 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
3681 writer->state = WRITER_STATE_TEXT;
3682 return S_OK;
3684 case WS_XML_NODE_TYPE_END_ELEMENT:
3685 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
3686 writer->state = WRITER_STATE_ENDELEMENT;
3687 return S_OK;
3689 case WS_XML_NODE_TYPE_COMMENT:
3690 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
3691 return hr;
3692 if ((hr = write_comment( writer )) != S_OK) return hr;
3693 writer->state = WRITER_STATE_COMMENT;
3694 return S_OK;
3696 case WS_XML_NODE_TYPE_CDATA:
3697 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
3698 return hr;
3699 if ((hr = write_cdata( writer )) != S_OK) return hr;
3700 writer->state = WRITER_STATE_STARTCDATA;
3701 return S_OK;
3703 case WS_XML_NODE_TYPE_END_CDATA:
3704 if ((hr = write_endcdata( writer )) != S_OK) return hr;
3705 writer->state = WRITER_STATE_ENDCDATA;
3706 return S_OK;
3708 case WS_XML_NODE_TYPE_EOF:
3709 case WS_XML_NODE_TYPE_BOF:
3710 return S_OK;
3712 default:
3713 ERR( "unknown node type %u\n", node_type(writer->current) );
3714 return E_INVALIDARG;
3718 static HRESULT write_tree( struct writer *writer )
3720 HRESULT hr;
3722 if ((hr = write_tree_node( writer )) != S_OK) return hr;
3723 for (;;)
3725 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
3726 if (move_to_child_node( &writer->current ))
3728 if ((hr = write_tree_node( writer )) != S_OK) return hr;
3729 continue;
3731 if (move_to_next_node( &writer->current ))
3733 if ((hr = write_tree_node( writer )) != S_OK) return hr;
3734 continue;
3736 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
3738 ERR( "invalid tree\n" );
3739 return WS_E_INVALID_FORMAT;
3741 if ((hr = write_tree_node( writer )) != S_OK) return hr;
3743 return S_OK;
3746 static void write_rewind( struct writer *writer )
3748 writer->write_pos = 0;
3749 writer->current = writer->root;
3750 writer->state = WRITER_STATE_INITIAL;
3753 /**************************************************************************
3754 * WsCopyNode [webservices.@]
3756 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
3758 struct writer *writer = (struct writer *)handle;
3759 struct node *parent, *current, *node = NULL;
3760 HRESULT hr;
3762 TRACE( "%p %p %p\n", handle, reader, error );
3763 if (error) FIXME( "ignoring error parameter\n" );
3765 if (!writer) return E_INVALIDARG;
3767 EnterCriticalSection( &writer->cs );
3769 if (writer->magic != WRITER_MAGIC)
3771 LeaveCriticalSection( &writer->cs );
3772 return E_INVALIDARG;
3775 if (!(parent = find_parent( writer )))
3777 LeaveCriticalSection( &writer->cs );
3778 return WS_E_INVALID_FORMAT;
3781 if ((hr = copy_node( reader, &node )) != S_OK) goto done;
3782 current = writer->current;
3783 write_insert_node( writer, parent, node );
3785 write_rewind( writer );
3786 if ((hr = write_tree( writer )) != S_OK) goto done;
3787 writer->current = current;
3789 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
3791 done:
3792 LeaveCriticalSection( &writer->cs );
3793 return hr;
3796 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
3798 return write_type_struct_field( writer, desc, value, 0 );
3801 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
3803 ULONG i, ret = 0;
3804 for (i = 0; i < count; i++)
3806 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
3807 continue;
3808 if (args[i]) ret = *(const ULONG *)args[i];
3809 break;
3811 return ret;
3814 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
3815 ULONG len )
3817 return write_type_repeating_element( writer, desc, value, len );
3820 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3821 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
3823 struct writer *writer = (struct writer *)handle;
3824 const WS_STRUCT_DESCRIPTION *desc_struct;
3825 const WS_FIELD_DESCRIPTION *desc_field;
3826 HRESULT hr;
3827 ULONG i;
3829 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
3831 EnterCriticalSection( &writer->cs );
3833 if (writer->magic != WRITER_MAGIC)
3835 LeaveCriticalSection( &writer->cs );
3836 return E_INVALIDARG;
3839 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
3841 for (i = 0; i < count; i++)
3843 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
3844 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
3846 FIXME( "messages type not supported\n" );
3847 hr = E_NOTIMPL;
3848 goto done;
3850 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
3851 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
3853 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
3855 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
3857 const void *ptr = *(const void **)args[i];
3858 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
3859 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
3863 hr = write_endelement_node( writer );
3865 done:
3866 LeaveCriticalSection( &writer->cs );
3867 return hr;