webservices: WS_FIELD_OPTIONAL takes precedence over WS_FIELD_NILLABLE.
[wine.git] / dlls / webservices / writer.c
blobb59e9036379bce5027a3372cfed58d1c79f15839
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 write_pos;
75 unsigned char *write_bufptr;
76 enum writer_state state;
77 struct node *root;
78 struct node *current;
79 WS_XML_STRING *current_ns;
80 WS_XML_WRITER_OUTPUT_TYPE output_type;
81 struct xmlbuf *output_buf;
82 WS_HEAP *output_heap;
83 ULONG prop_count;
84 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
87 static struct writer *alloc_writer(void)
89 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
90 struct writer *ret;
91 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
93 if (!(ret = heap_alloc_zero( size ))) return NULL;
94 prop_init( writer_props, count, ret->prop, &ret[1] );
95 ret->prop_count = count;
96 return ret;
99 static void free_writer( struct writer *writer )
101 if (!writer) return;
102 destroy_nodes( writer->root );
103 heap_free( writer->current_ns );
104 WsFreeHeap( writer->output_heap );
105 heap_free( writer );
108 static void write_insert_eof( struct writer *writer, struct node *eof )
110 if (!writer->root) writer->root = eof;
111 else
113 eof->parent = writer->root;
114 list_add_tail( &writer->root->children, &eof->entry );
116 writer->current = eof;
119 static void write_insert_bof( struct writer *writer, struct node *bof )
121 writer->root->parent = bof;
122 list_add_tail( &bof->children, &writer->root->entry );
123 writer->current = writer->root = bof;
126 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
128 node->parent = parent;
129 list_add_before( list_tail( &parent->children ), &node->entry );
130 writer->current = node;
133 static HRESULT write_init_state( struct writer *writer )
135 struct node *node;
137 heap_free( writer->current_ns );
138 writer->current_ns = NULL;
139 destroy_nodes( writer->root );
140 writer->root = NULL;
142 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
143 write_insert_eof( writer, node );
144 writer->state = WRITER_STATE_INITIAL;
145 return S_OK;
148 /**************************************************************************
149 * WsCreateWriter [webservices.@]
151 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
152 WS_XML_WRITER **handle, WS_ERROR *error )
154 struct writer *writer;
155 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
156 WS_CHARSET charset = WS_CHARSET_UTF8;
157 HRESULT hr;
159 TRACE( "%p %u %p %p\n", properties, count, handle, error );
160 if (error) FIXME( "ignoring error parameter\n" );
162 if (!handle) return E_INVALIDARG;
163 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
165 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
166 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
167 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
168 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
169 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
170 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
171 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
173 for (i = 0; i < count; i++)
175 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
176 properties[i].valueSize );
177 if (hr != S_OK)
179 free_writer( writer );
180 return hr;
184 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
185 &max_size, sizeof(max_size) );
186 if (hr != S_OK)
188 free_writer( writer );
189 return hr;
192 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
193 if (hr != S_OK)
195 free_writer( writer );
196 return hr;
199 hr = write_init_state( writer );
200 if (hr != S_OK)
202 free_writer( writer );
203 return hr;
206 *handle = (WS_XML_WRITER *)writer;
207 return S_OK;
210 /**************************************************************************
211 * WsFreeWriter [webservices.@]
213 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
215 struct writer *writer = (struct writer *)handle;
217 TRACE( "%p\n", handle );
218 free_writer( writer );
221 #define XML_BUFFER_INITIAL_ALLOCATED_SIZE 256
222 static struct xmlbuf *alloc_xmlbuf( WS_HEAP *heap )
224 struct xmlbuf *ret;
226 if (!(ret = ws_alloc( heap, sizeof(*ret) ))) return NULL;
227 if (!(ret->ptr = ws_alloc( heap, XML_BUFFER_INITIAL_ALLOCATED_SIZE )))
229 ws_free( heap, ret );
230 return NULL;
232 ret->heap = heap;
233 ret->size_allocated = XML_BUFFER_INITIAL_ALLOCATED_SIZE;
234 ret->size = 0;
235 return ret;
238 static void free_xmlbuf( struct xmlbuf *xmlbuf )
240 if (!xmlbuf) return;
241 ws_free( xmlbuf->heap, xmlbuf->ptr );
242 ws_free( xmlbuf->heap, xmlbuf );
245 /**************************************************************************
246 * WsCreateXmlBuffer [webservices.@]
248 HRESULT WINAPI WsCreateXmlBuffer( WS_HEAP *heap, const WS_XML_BUFFER_PROPERTY *properties,
249 ULONG count, WS_XML_BUFFER **handle, WS_ERROR *error )
251 struct xmlbuf *xmlbuf;
253 if (!heap || !handle) return E_INVALIDARG;
254 if (count) FIXME( "properties not implemented\n" );
256 if (!(xmlbuf = alloc_xmlbuf( heap ))) return E_OUTOFMEMORY;
258 *handle = (WS_XML_BUFFER *)xmlbuf;
259 return S_OK;
262 /**************************************************************************
263 * WsGetWriterProperty [webservices.@]
265 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
266 void *buf, ULONG size, WS_ERROR *error )
268 struct writer *writer = (struct writer *)handle;
270 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
271 if (error) FIXME( "ignoring error parameter\n" );
273 if (!writer->output_type) return WS_E_INVALID_OPERATION;
275 switch (id)
277 case WS_XML_WRITER_PROPERTY_BYTES:
279 WS_BYTES *bytes = buf;
280 if (size != sizeof(*bytes)) return E_INVALIDARG;
281 bytes->bytes = writer->output_buf->ptr;
282 bytes->length = writer->output_buf->size;
283 return S_OK;
285 default:
286 return prop_get( writer->prop, writer->prop_count, id, buf, size );
290 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
292 /* free current buffer if it's ours */
293 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
295 free_xmlbuf( writer->output_buf );
297 writer->output_buf = xmlbuf;
298 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
299 writer->write_bufptr = xmlbuf->ptr;
300 writer->write_pos = 0;
303 /**************************************************************************
304 * WsSetOutput [webservices.@]
306 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
307 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
308 ULONG count, WS_ERROR *error )
310 struct writer *writer = (struct writer *)handle;
311 struct node *node;
312 HRESULT hr;
313 ULONG i;
315 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
316 if (error) FIXME( "ignoring error parameter\n" );
318 if (!writer) return E_INVALIDARG;
320 for (i = 0; i < count; i++)
322 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
323 properties[i].valueSize );
324 if (hr != S_OK) return hr;
327 if ((hr = write_init_state( writer )) != S_OK) return hr;
329 switch (encoding->encodingType)
331 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
333 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
334 if (text->charSet != WS_CHARSET_UTF8)
336 FIXME( "charset %u not supported\n", text->charSet );
337 return E_NOTIMPL;
339 break;
341 default:
342 FIXME( "encoding type %u not supported\n", encoding->encodingType );
343 return E_NOTIMPL;
345 switch (output->outputType)
347 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
349 struct xmlbuf *xmlbuf;
351 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap ))) return E_OUTOFMEMORY;
352 set_output_buffer( writer, xmlbuf );
353 break;
355 default:
356 FIXME( "output type %u not supported\n", output->outputType );
357 return E_NOTIMPL;
360 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
361 write_insert_bof( writer, node );
362 return S_OK;
365 /**************************************************************************
366 * WsSetOutputToBuffer [webservices.@]
368 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
369 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
370 WS_ERROR *error )
372 struct writer *writer = (struct writer *)handle;
373 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
374 struct node *node;
375 HRESULT hr;
376 ULONG i;
378 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
379 if (error) FIXME( "ignoring error parameter\n" );
381 if (!writer || !xmlbuf) return E_INVALIDARG;
383 for (i = 0; i < count; i++)
385 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
386 properties[i].valueSize );
387 if (hr != S_OK) return hr;
390 if ((hr = write_init_state( writer )) != S_OK) return hr;
391 set_output_buffer( writer, xmlbuf );
393 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
394 write_insert_bof( writer, node );
395 return S_OK;
398 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
400 struct xmlbuf *buf = writer->output_buf;
401 SIZE_T new_size;
402 void *tmp;
404 if (buf->size_allocated >= writer->write_pos + size)
406 buf->size = writer->write_pos + size;
407 return S_OK;
409 new_size = max( buf->size_allocated * 2, writer->write_pos + size );
410 if (!(tmp = ws_realloc( buf->heap, buf->ptr, new_size ))) return E_OUTOFMEMORY;
411 writer->write_bufptr = buf->ptr = tmp;
412 buf->size_allocated = new_size;
413 buf->size = writer->write_pos + size;
414 return S_OK;
417 static inline void write_char( struct writer *writer, unsigned char ch )
419 writer->write_bufptr[writer->write_pos++] = ch;
422 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
424 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
425 writer->write_pos += len;
428 struct escape
430 char ch;
431 const char *entity;
432 ULONG len;
434 static const struct escape escape_lt = { '<', "&lt;", 4 };
435 static const struct escape escape_gt = { '>', "&gt;", 4 };
436 static const struct escape escape_amp = { '&', "&amp;", 5 };
437 static const struct escape escape_apos = { '\'', "&apos;", 6 };
438 static const struct escape escape_quot = { '"', "&quot;", 6 };
440 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
441 const struct escape **escapes, ULONG nb_escapes )
443 ULONG i, j, size;
444 const BYTE *ptr;
445 HRESULT hr;
447 for (i = 0; i < len; i++)
449 ptr = &bytes[i];
450 size = 1;
451 for (j = 0; j < nb_escapes; j++)
453 if (bytes[i] == escapes[j]->ch)
455 ptr = (const BYTE *)escapes[j]->entity;
456 size = escapes[j]->len;
457 break;
460 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
461 write_bytes( writer, ptr, size );
464 return S_OK;
467 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
469 WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
470 unsigned char quote = attr->singleQuote ? '\'' : '"';
471 const WS_XML_STRING *prefix;
472 ULONG size;
473 HRESULT hr;
475 if (attr->prefix) prefix = attr->prefix;
476 else prefix = writer->current->hdr.prefix;
478 /* ' prefix:attr="value"' */
480 size = attr->localName->length + 4 /* ' =""' */;
481 if (prefix) size += prefix->length + 1 /* ':' */;
482 if (text) size += text->value.length;
483 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
485 write_char( writer, ' ' );
486 if (prefix)
488 write_bytes( writer, prefix->bytes, prefix->length );
489 write_char( writer, ':' );
491 write_bytes( writer, attr->localName->bytes, attr->localName->length );
492 write_char( writer, '=' );
493 write_char( writer, quote );
494 if (text)
496 const struct escape *escapes[3];
497 escapes[0] = attr->singleQuote ? &escape_apos : &escape_quot;
498 escapes[1] = &escape_lt;
499 escapes[2] = &escape_amp;
500 hr = write_bytes_escape( writer, text->value.bytes, text->value.length, escapes, 3 );
502 write_char( writer, quote );
504 return hr;
507 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
509 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
512 /**************************************************************************
513 * WsGetPrefixFromNamespace [webservices.@]
515 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
516 BOOL required, const WS_XML_STRING **prefix,
517 WS_ERROR *error )
519 struct writer *writer = (struct writer *)handle;
520 WS_XML_ELEMENT_NODE *elem;
521 BOOL found = FALSE;
523 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
524 if (error) FIXME( "ignoring error parameter\n" );
526 if (!writer || !ns || !prefix) return E_INVALIDARG;
528 elem = &writer->current->hdr;
529 if (elem->prefix && is_current_namespace( writer, ns ))
531 *prefix = elem->prefix;
532 found = TRUE;
534 if (!found)
536 if (required) return WS_E_INVALID_FORMAT;
537 *prefix = NULL;
538 return S_FALSE;
540 return S_OK;
543 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
545 WS_XML_STRING *str;
546 if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
547 heap_free( writer->current_ns );
548 writer->current_ns = str;
549 return S_OK;
552 static HRESULT write_namespace_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
554 unsigned char quote = attr->singleQuote ? '\'' : '"';
555 ULONG size;
556 HRESULT hr;
558 /* ' xmlns:prefix="namespace"' */
560 size = attr->ns->length + 9 /* ' xmlns=""' */;
561 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
562 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
564 write_bytes( writer, (const BYTE *)" xmlns", 6 );
565 if (attr->prefix)
567 write_char( writer, ':' );
568 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
570 write_char( writer, '=' );
571 write_char( writer, quote );
572 write_bytes( writer, attr->ns->bytes, attr->ns->length );
573 write_char( writer, quote );
575 return S_OK;
578 static HRESULT write_add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
579 const WS_XML_STRING *ns, BOOL single )
581 WS_XML_ATTRIBUTE *attr;
582 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
583 HRESULT hr;
585 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
587 attr->singleQuote = !!single;
588 attr->isXmlNs = 1;
589 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
591 free_attribute( attr );
592 return E_OUTOFMEMORY;
594 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
596 free_attribute( attr );
597 return E_OUTOFMEMORY;
599 if ((hr = append_attribute( elem, attr )) != S_OK)
601 free_attribute( attr );
602 return hr;
604 return S_OK;
607 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
609 if (!str1 && !str2) return TRUE;
610 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
613 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
614 const WS_XML_STRING *ns )
616 ULONG i;
617 const struct node *node;
619 for (node = (const struct node *)elem; node; node = node->parent)
621 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
623 elem = &node->hdr;
624 for (i = 0; i < elem->attributeCount; i++)
626 if (!elem->attributes[i]->isXmlNs) continue;
627 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
628 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
631 return FALSE;
634 static HRESULT write_set_element_namespace( struct writer *writer )
636 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
637 HRESULT hr;
639 if (!elem->ns->length || namespace_in_scope( elem, elem->prefix, elem->ns )) return S_OK;
641 if ((hr = write_add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK)
642 return hr;
644 return set_current_namespace( writer, elem->ns );
647 /**************************************************************************
648 * WsWriteEndAttribute [webservices.@]
650 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
652 struct writer *writer = (struct writer *)handle;
654 TRACE( "%p %p\n", handle, error );
655 if (error) FIXME( "ignoring error parameter\n" );
657 if (!writer) return E_INVALIDARG;
659 writer->state = WRITER_STATE_STARTELEMENT;
660 return S_OK;
663 static HRESULT write_startelement( struct writer *writer )
665 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
666 ULONG size, i;
667 HRESULT hr;
669 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
671 size = elem->localName->length + 1 /* '<' */;
672 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
673 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
675 write_char( writer, '<' );
676 if (elem->prefix)
678 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
679 write_char( writer, ':' );
681 write_bytes( writer, elem->localName->bytes, elem->localName->length );
682 for (i = 0; i < elem->attributeCount; i++)
684 if (elem->attributes[i]->isXmlNs) continue;
685 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
687 for (i = 0; i < elem->attributeCount; i++)
689 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
690 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
692 for (i = 0; i < elem->attributeCount; i++)
694 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
695 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
697 return S_OK;
700 static struct node *write_find_startelement( struct writer *writer )
702 struct node *node;
703 for (node = writer->current; node; node = node->parent)
705 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
707 return NULL;
710 static inline BOOL is_empty_element( const struct node *node )
712 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
713 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
716 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
718 ULONG size;
719 HRESULT hr;
721 /* '/>' */
723 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
725 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
726 write_char( writer, '/' );
727 write_char( writer, '>' );
728 return S_OK;
731 /* '</prefix:localname>' */
733 size = elem->localName->length + 3 /* '</>' */;
734 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
735 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
737 write_char( writer, '<' );
738 write_char( writer, '/' );
739 if (elem->prefix)
741 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
742 write_char( writer, ':' );
744 write_bytes( writer, elem->localName->bytes, elem->localName->length );
745 write_char( writer, '>' );
746 return S_OK;
749 static HRESULT write_close_element( struct writer *writer, struct node *node )
751 WS_XML_ELEMENT_NODE *elem = &node->hdr;
752 elem->isEmpty = is_empty_element( node );
753 return write_endelement( writer, elem );
756 static HRESULT write_endelement_node( struct writer *writer )
758 struct node *node;
759 HRESULT hr;
761 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
762 if (writer->state == WRITER_STATE_STARTELEMENT)
764 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
765 if ((hr = write_startelement( writer )) != S_OK) return hr;
767 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
768 writer->current = node->parent;
769 writer->state = WRITER_STATE_ENDELEMENT;
770 return S_OK;
773 /**************************************************************************
774 * WsWriteEndElement [webservices.@]
776 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
778 struct writer *writer = (struct writer *)handle;
780 TRACE( "%p %p\n", handle, error );
781 if (error) FIXME( "ignoring error parameter\n" );
783 if (!writer) return E_INVALIDARG;
784 return write_endelement_node( writer );
787 static HRESULT write_endstartelement( struct writer *writer )
789 HRESULT hr;
790 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
791 write_char( writer, '>' );
792 return S_OK;
795 /**************************************************************************
796 * WsWriteEndStartElement [webservices.@]
798 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
800 struct writer *writer = (struct writer *)handle;
801 HRESULT hr;
803 TRACE( "%p %p\n", handle, error );
804 if (error) FIXME( "ignoring error parameter\n" );
806 if (!writer) return E_INVALIDARG;
807 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
809 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
810 if ((hr = write_startelement( writer )) != S_OK) return hr;
811 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
813 writer->state = WRITER_STATE_ENDSTARTELEMENT;
814 return S_OK;
817 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
818 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
819 BOOL single )
821 WS_XML_ATTRIBUTE *attr;
822 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
823 HRESULT hr;
825 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
827 if (!prefix) prefix = elem->prefix;
829 attr->singleQuote = !!single;
830 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
832 free_attribute( attr );
833 return E_OUTOFMEMORY;
835 if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
837 free_attribute( attr );
838 return E_OUTOFMEMORY;
840 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
842 free_attribute( attr );
843 return E_OUTOFMEMORY;
845 if ((hr = append_attribute( elem, attr )) != S_OK)
847 free_attribute( attr );
848 return hr;
850 return S_OK;
853 /**************************************************************************
854 * WsWriteStartAttribute [webservices.@]
856 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
857 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
858 BOOL single, WS_ERROR *error )
860 struct writer *writer = (struct writer *)handle;
861 HRESULT hr;
863 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
864 debugstr_xmlstr(ns), single, error );
865 if (error) FIXME( "ignoring error parameter\n" );
867 if (!writer || !localname || !ns) return E_INVALIDARG;
869 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
871 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
872 writer->state = WRITER_STATE_STARTATTRIBUTE;
873 return S_OK;
876 /* flush current start element if necessary */
877 static HRESULT write_flush( struct writer *writer )
879 if (writer->state == WRITER_STATE_STARTELEMENT)
881 HRESULT hr;
882 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
883 if ((hr = write_startelement( writer )) != S_OK) return hr;
884 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
885 writer->state = WRITER_STATE_ENDSTARTELEMENT;
887 return S_OK;
890 static HRESULT write_add_cdata_node( struct writer *writer )
892 struct node *node, *parent;
893 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
894 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
895 write_insert_node( writer, parent, node );
896 return S_OK;
899 static HRESULT write_add_endcdata_node( struct writer *writer )
901 struct node *node;
902 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
903 node->parent = writer->current;
904 list_add_tail( &node->parent->children, &node->entry );
905 return S_OK;
908 static HRESULT write_cdata( struct writer *writer )
910 HRESULT hr;
911 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
912 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
913 return S_OK;
916 static HRESULT write_cdata_node( struct writer *writer )
918 HRESULT hr;
919 if ((hr = write_flush( writer )) != S_OK) return hr;
920 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
921 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
922 if ((hr = write_cdata( writer )) != S_OK) return hr;
923 writer->state = WRITER_STATE_STARTCDATA;
924 return S_OK;
927 /**************************************************************************
928 * WsWriteStartCData [webservices.@]
930 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
932 struct writer *writer = (struct writer *)handle;
934 TRACE( "%p %p\n", handle, error );
935 if (error) FIXME( "ignoring error parameter\n" );
937 if (!writer) return E_INVALIDARG;
938 return write_cdata_node( writer );
941 static HRESULT write_endcdata( struct writer *writer )
943 HRESULT hr;
944 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
945 write_bytes( writer, (const BYTE *)"]]>", 3 );
946 return S_OK;
949 static HRESULT write_endcdata_node( struct writer *writer )
951 HRESULT hr;
952 if ((hr = write_endcdata( writer )) != S_OK) return hr;
953 writer->current = writer->current->parent;
954 writer->state = WRITER_STATE_ENDCDATA;
955 return S_OK;
958 /**************************************************************************
959 * WsWriteEndCData [webservices.@]
961 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
963 struct writer *writer = (struct writer *)handle;
965 TRACE( "%p %p\n", handle, error );
966 if (error) FIXME( "ignoring error parameter\n" );
968 if (!writer) return E_INVALIDARG;
969 if (writer->state != WRITER_STATE_TEXT) return WS_E_INVALID_OPERATION;
971 return write_endcdata_node( writer );
974 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
975 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
977 struct node *node, *parent;
978 WS_XML_ELEMENT_NODE *elem;
980 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
982 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
984 elem = &parent->hdr;
985 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
988 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
989 elem = &node->hdr;
991 if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
993 free_node( node );
994 return E_OUTOFMEMORY;
996 if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
998 free_node( node );
999 return E_OUTOFMEMORY;
1001 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
1003 free_node( node );
1004 return E_OUTOFMEMORY;
1006 write_insert_node( writer, parent, node );
1007 return S_OK;
1010 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1012 struct node *node;
1013 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1014 node->parent = parent;
1015 list_add_tail( &parent->children, &node->entry );
1016 return S_OK;
1019 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1020 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1022 HRESULT hr;
1023 if ((hr = write_flush( writer )) != S_OK) return hr;
1024 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1025 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1026 writer->state = WRITER_STATE_STARTELEMENT;
1027 return S_OK;
1030 /**************************************************************************
1031 * WsWriteStartElement [webservices.@]
1033 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1034 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1035 WS_ERROR *error )
1037 struct writer *writer = (struct writer *)handle;
1039 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1040 debugstr_xmlstr(ns), error );
1041 if (error) FIXME( "ignoring error parameter\n" );
1043 if (!writer || !localname || !ns) return E_INVALIDARG;
1044 return write_element_node( writer, prefix, localname, ns );
1047 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1049 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1050 if (*ptr)
1052 memcpy( buf, bool_true, sizeof(bool_true) );
1053 return sizeof(bool_true);
1055 memcpy( buf, bool_false, sizeof(bool_false) );
1056 return sizeof(bool_false);
1059 static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
1061 return wsprintfA( (char *)buf, "%d", *ptr );
1064 static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
1066 return wsprintfA( (char *)buf, "%d", *ptr );
1069 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1071 return wsprintfA( (char *)buf, "%d", *ptr );
1074 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1076 return wsprintfA( (char *)buf, "%I64d", *ptr );
1079 static ULONG format_uint8( const UINT8 *ptr, unsigned char *buf )
1081 return wsprintfA( (char *)buf, "%u", *ptr );
1084 static ULONG format_uint16( const UINT16 *ptr, unsigned char *buf )
1086 return wsprintfA( (char *)buf, "%u", *ptr );
1089 static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
1091 return wsprintfA( (char *)buf, "%u", *ptr );
1094 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1096 return wsprintfA( (char *)buf, "%I64u", *ptr );
1099 static ULONG format_double( const double *ptr, unsigned char *buf )
1101 #ifdef HAVE_POWL
1102 static const long double precision = 0.0000000000000001;
1103 unsigned char *p = buf;
1104 long double val = *ptr;
1105 int neg, mag, mag2, use_exp;
1107 if (isnan( val ))
1109 memcpy( buf, "NaN", 3 );
1110 return 3;
1112 if (isinf( val ))
1114 if (val < 0)
1116 memcpy( buf, "-INF", 4 );
1117 return 4;
1119 memcpy( buf, "INF", 3 );
1120 return 3;
1122 if (val == 0.0)
1124 *p = '0';
1125 return 1;
1128 if ((neg = val < 0))
1130 *p++ = '-';
1131 val = -val;
1134 mag = log10l( val );
1135 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1136 if (use_exp)
1138 if (mag < 0) mag -= 1;
1139 val = val / powl( 10.0, mag );
1140 mag2 = mag;
1141 mag = 0;
1143 else if (mag < 1) mag = 0;
1145 while (val > precision || mag >= 0)
1147 long double weight = powl( 10.0, mag );
1148 if (weight > 0 && !isinf( weight ))
1150 int digit = floorl( val / weight );
1151 val -= digit * weight;
1152 *(p++) = '0' + digit;
1154 if (!mag && val > precision) *(p++) = '.';
1155 mag--;
1158 if (use_exp)
1160 int i, j;
1161 *(p++) = 'E';
1162 if (mag2 > 0) *(p++) = '+';
1163 else
1165 *(p++) = '-';
1166 mag2 = -mag2;
1168 mag = 0;
1169 while (mag2 > 0)
1171 *(p++) = '0' + mag2 % 10;
1172 mag2 /= 10;
1173 mag++;
1175 for (i = -mag, j = -1; i < j; i++, j--)
1177 p[i] ^= p[j];
1178 p[j] ^= p[i];
1179 p[i] ^= p[j];
1183 return p - buf;
1184 #else
1185 FIXME( "powl not found at build time\n" );
1186 return 0;
1187 #endif
1190 static inline int year_size( int year )
1192 return leap_year( year ) ? 366 : 365;
1195 #define TZ_OFFSET 8
1196 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1198 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1199 int day, hour, min, sec, sec_frac, month = 1, year = 1, tz_hour;
1200 unsigned __int64 ticks, day_ticks;
1201 ULONG len;
1203 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1204 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1206 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1207 tz_hour = TZ_OFFSET;
1209 else
1211 ticks = ptr->ticks;
1212 tz_hour = 0;
1214 day = ticks / TICKS_PER_DAY;
1215 day_ticks = ticks % TICKS_PER_DAY;
1216 hour = day_ticks / TICKS_PER_HOUR;
1217 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1218 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1219 sec_frac = day_ticks % TICKS_PER_SEC;
1221 while (day >= year_size( year ))
1223 day -= year_size( year );
1224 year++;
1226 while (day >= month_days[leap_year( year )][month])
1228 day -= month_days[leap_year( year )][month];
1229 month++;
1231 day++;
1233 len = sprintf( (char *)buf, fmt, year, month, day, hour, min, sec );
1234 if (sec_frac)
1236 static const char fmt_frac[] = ".%07u";
1237 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1238 while (buf[len - 1] == '0') len--;
1240 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1242 buf[len++] = 'Z';
1244 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1246 static const char fmt_tz[] = "%c%02u:00";
1247 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1250 return len;
1253 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1255 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1256 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1257 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1258 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1261 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1263 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1264 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1265 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1266 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1269 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1271 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1272 ULONG i = 0, x;
1274 while (len > 0)
1276 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1277 x = (bin[0] & 3) << 4;
1278 if (len == 1)
1280 buf[i++] = base64[x];
1281 buf[i++] = '=';
1282 buf[i++] = '=';
1283 break;
1285 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1286 x = (bin[1] & 0x0f) << 2;
1287 if (len == 2)
1289 buf[i++] = base64[x];
1290 buf[i++] = '=';
1291 break;
1293 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1294 buf[i++] = base64[bin[2] & 0x3f];
1295 bin += 3;
1296 len -= 3;
1298 return i;
1301 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret )
1303 switch (text->textType)
1305 case WS_XML_TEXT_TYPE_UTF8:
1307 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1308 if (!(*ret = alloc_utf8_text( src->value.bytes, src->value.length ))) return E_OUTOFMEMORY;
1309 return S_OK;
1311 case WS_XML_TEXT_TYPE_UTF16:
1313 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1314 const WCHAR *str = (const WCHAR *)src->bytes;
1315 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1317 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1318 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1319 if (!(*ret = alloc_utf8_text( NULL, len_utf8 ))) return E_OUTOFMEMORY;
1320 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes, (*ret)->value.length, NULL, NULL );
1321 return S_OK;
1323 case WS_XML_TEXT_TYPE_BASE64:
1325 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1326 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1327 if (!(*ret = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY;
1328 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes );
1329 return S_OK;
1331 case WS_XML_TEXT_TYPE_BOOL:
1333 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1334 if (!(*ret = alloc_utf8_text( NULL, 5 ))) return E_OUTOFMEMORY;
1335 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes );
1336 return S_OK;
1338 case WS_XML_TEXT_TYPE_INT32:
1340 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1341 unsigned char buf[12]; /* "-2147483648" */
1342 ULONG len = format_int32( &int32_text->value, buf );
1343 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1344 return S_OK;
1346 case WS_XML_TEXT_TYPE_INT64:
1348 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1349 unsigned char buf[21]; /* "-9223372036854775808" */
1350 ULONG len = format_int64( &int64_text->value, buf );
1351 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1352 return S_OK;
1354 case WS_XML_TEXT_TYPE_UINT64:
1356 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1357 unsigned char buf[21]; /* "18446744073709551615" */
1358 ULONG len = format_uint64( &uint64_text->value, buf );
1359 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1360 return S_OK;
1362 case WS_XML_TEXT_TYPE_DOUBLE:
1364 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1365 unsigned char buf[24]; /* "-1.1111111111111111E-308" */
1366 unsigned short fpword;
1367 ULONG len;
1369 if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
1370 len = format_double( &double_text->value, buf );
1371 restore_fp_rounding( fpword );
1372 if (!len) return E_NOTIMPL;
1373 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1374 return S_OK;
1376 case WS_XML_TEXT_TYPE_GUID:
1378 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1379 if (!(*ret = alloc_utf8_text( NULL, 37 ))) return E_OUTOFMEMORY;
1380 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes );
1381 return S_OK;
1383 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1385 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1386 if (!(*ret = alloc_utf8_text( NULL, 46 ))) return E_OUTOFMEMORY;
1387 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes );
1388 return S_OK;
1390 case WS_XML_TEXT_TYPE_DATETIME:
1392 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1393 if (!(*ret = alloc_utf8_text( NULL, 34 ))) return E_OUTOFMEMORY;
1394 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes );
1395 return S_OK;
1397 default:
1398 FIXME( "unhandled text type %u\n", text->textType );
1399 return E_NOTIMPL;
1403 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
1405 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1406 WS_XML_UTF8_TEXT *utf8;
1407 HRESULT hr;
1409 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK) return hr;
1410 elem->attributes[elem->attributeCount - 1]->value = &utf8->text;
1411 return S_OK;
1414 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
1416 struct node *node;
1417 WS_XML_TEXT_NODE *text;
1418 WS_XML_UTF8_TEXT *utf8;
1419 HRESULT hr;
1421 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
1422 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
1423 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
1425 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1426 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK)
1428 heap_free( node );
1429 return hr;
1431 text = (WS_XML_TEXT_NODE *)node;
1432 text->text = &utf8->text;
1434 write_insert_node( writer, writer->current, node );
1435 return S_OK;
1438 static HRESULT write_text( struct writer *writer )
1440 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)writer->current;
1441 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
1442 HRESULT hr;
1444 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
1445 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
1447 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
1448 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
1450 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
1452 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
1453 write_bytes( writer, utf8->value.bytes, utf8->value.length );
1454 return S_OK;
1457 return WS_E_INVALID_FORMAT;
1460 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
1462 HRESULT hr;
1463 if ((hr = write_flush( writer )) != S_OK) return hr;
1464 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
1465 if ((hr = write_text( writer )) != S_OK) return hr;
1466 writer->state = WRITER_STATE_TEXT;
1467 return S_OK;
1470 /**************************************************************************
1471 * WsWriteText [webservices.@]
1473 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
1475 struct writer *writer = (struct writer *)handle;
1477 TRACE( "%p %p %p\n", handle, text, error );
1479 if (!writer || !text) return E_INVALIDARG;
1481 if (writer->state == WRITER_STATE_STARTATTRIBUTE) return write_set_attribute_value( writer, text );
1482 return write_text_node( writer, text );
1485 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
1487 switch (mapping)
1489 case WS_ELEMENT_TYPE_MAPPING:
1490 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1491 return write_text_node( writer, text );
1493 case WS_ATTRIBUTE_TYPE_MAPPING:
1494 return write_set_attribute_value( writer, text );
1496 case WS_ANY_ELEMENT_TYPE_MAPPING:
1497 switch (writer->state)
1499 case WRITER_STATE_STARTATTRIBUTE:
1500 return write_set_attribute_value( writer, text );
1502 case WRITER_STATE_STARTELEMENT:
1503 return write_text_node( writer, text );
1505 default:
1506 FIXME( "writer state %u not handled\n", writer->state );
1507 return E_NOTIMPL;
1510 default:
1511 FIXME( "mapping %u not implemented\n", mapping );
1512 return E_NOTIMPL;
1516 static HRESULT write_add_nil_attribute( struct writer *writer )
1518 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
1519 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
1520 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
1521 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
1522 HRESULT hr;
1524 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
1525 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
1526 return write_add_namespace_attribute( writer, &prefix, &ns, FALSE );
1529 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
1530 const void **ptr )
1532 switch (option)
1534 case WS_WRITE_REQUIRED_VALUE:
1535 case WS_WRITE_NILLABLE_VALUE:
1536 if (!value || size != expected_size) return E_INVALIDARG;
1537 *ptr = value;
1538 return S_OK;
1540 case WS_WRITE_REQUIRED_POINTER:
1541 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
1542 return S_OK;
1544 case WS_WRITE_NILLABLE_POINTER:
1545 if (size != sizeof(const void *)) return E_INVALIDARG;
1546 *ptr = *(const void **)value;
1547 return S_OK;
1549 default:
1550 return E_INVALIDARG;
1554 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
1555 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
1556 const BOOL *value, ULONG size )
1558 WS_XML_UTF8_TEXT utf8;
1559 unsigned char buf[6]; /* "false" */
1560 const BOOL *ptr;
1561 HRESULT hr;
1563 if (desc)
1565 FIXME( "description not supported\n" );
1566 return E_NOTIMPL;
1569 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1570 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
1571 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1573 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1574 utf8.value.bytes = buf;
1575 utf8.value.length = format_bool( ptr, buf );
1576 return write_type_text( writer, mapping, &utf8.text );
1579 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
1580 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
1581 const BOOL *value, ULONG size )
1583 WS_XML_UTF8_TEXT utf8;
1584 unsigned char buf[5]; /* "-128" */
1585 const INT8 *ptr;
1586 HRESULT hr;
1588 if (desc)
1590 FIXME( "description not supported\n" );
1591 return E_NOTIMPL;
1594 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1595 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
1596 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1598 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1599 utf8.value.bytes = buf;
1600 utf8.value.length = format_int8( ptr, buf );
1601 return write_type_text( writer, mapping, &utf8.text );
1604 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
1605 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
1606 const BOOL *value, ULONG size )
1608 WS_XML_UTF8_TEXT utf8;
1609 unsigned char buf[7]; /* "-32768" */
1610 const INT16 *ptr;
1611 HRESULT hr;
1613 if (desc)
1615 FIXME( "description not supported\n" );
1616 return E_NOTIMPL;
1619 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1620 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
1621 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1623 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1624 utf8.value.bytes = buf;
1625 utf8.value.length = format_int16( ptr, buf );
1626 return write_type_text( writer, mapping, &utf8.text );
1629 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
1630 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
1631 const void *value, ULONG size )
1633 WS_XML_UTF8_TEXT utf8;
1634 unsigned char buf[12]; /* "-2147483648" */
1635 const INT32 *ptr;
1636 HRESULT hr;
1638 if (desc)
1640 FIXME( "description not supported\n" );
1641 return E_NOTIMPL;
1644 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1645 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
1646 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1648 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1649 utf8.value.bytes = buf;
1650 utf8.value.length = format_int32( ptr, buf );
1651 return write_type_text( writer, mapping, &utf8.text );
1654 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
1655 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
1656 const void *value, ULONG size )
1658 WS_XML_UTF8_TEXT utf8;
1659 unsigned char buf[21]; /* "-9223372036854775808" */
1660 const INT64 *ptr;
1661 HRESULT hr;
1663 if (desc)
1665 FIXME( "description not supported\n" );
1666 return E_NOTIMPL;
1669 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1670 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
1671 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1673 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1674 utf8.value.bytes = buf;
1675 utf8.value.length = format_int64( ptr, buf );
1676 return write_type_text( writer, mapping, &utf8.text );
1679 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
1680 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
1681 const void *value, ULONG size )
1683 WS_XML_UTF8_TEXT utf8;
1684 unsigned char buf[4]; /* "255" */
1685 const UINT8 *ptr;
1686 HRESULT hr;
1688 if (desc)
1690 FIXME( "description not supported\n" );
1691 return E_NOTIMPL;
1694 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1695 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
1696 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1698 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1699 utf8.value.bytes = buf;
1700 utf8.value.length = format_uint8( ptr, buf );
1701 return write_type_text( writer, mapping, &utf8.text );
1704 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
1705 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
1706 const void *value, ULONG size )
1708 WS_XML_UTF8_TEXT utf8;
1709 unsigned char buf[6]; /* "65535" */
1710 const UINT16 *ptr;
1711 HRESULT hr;
1713 if (desc)
1715 FIXME( "description not supported\n" );
1716 return E_NOTIMPL;
1719 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1720 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
1721 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1723 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1724 utf8.value.bytes = buf;
1725 utf8.value.length = format_uint16( ptr, buf );
1726 return write_type_text( writer, mapping, &utf8.text );
1729 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
1730 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
1731 const void *value, ULONG size )
1733 WS_XML_UTF8_TEXT utf8;
1734 unsigned char buf[11]; /* "4294967295" */
1735 const UINT32 *ptr;
1736 HRESULT hr;
1738 if (desc)
1740 FIXME( "description not supported\n" );
1741 return E_NOTIMPL;
1744 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1745 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
1746 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1748 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1749 utf8.value.bytes = buf;
1750 utf8.value.length = format_uint32( ptr, buf );
1751 return write_type_text( writer, mapping, &utf8.text );
1754 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
1755 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
1756 const void *value, ULONG size )
1758 WS_XML_UTF8_TEXT utf8;
1759 unsigned char buf[21]; /* "18446744073709551615" */
1760 const UINT64 *ptr;
1761 HRESULT hr;
1763 if (desc)
1765 FIXME( "description not supported\n" );
1766 return E_NOTIMPL;
1769 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1770 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
1771 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1773 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1774 utf8.value.bytes = buf;
1775 utf8.value.length = format_uint64( ptr, buf );
1776 return write_type_text( writer, mapping, &utf8.text );
1779 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
1780 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
1781 const void *value, ULONG size )
1783 WS_XML_UTF8_TEXT utf8;
1784 unsigned char buf[34]; /* "0000-00-00T00:00:00.0000000-00:00" */
1785 const WS_DATETIME *ptr;
1786 HRESULT hr;
1788 if (desc)
1790 FIXME( "description not supported\n" );
1791 return E_NOTIMPL;
1794 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1795 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
1796 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1797 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
1799 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1800 utf8.value.bytes = buf;
1801 utf8.value.length = format_datetime( ptr, buf );
1802 return write_type_text( writer, mapping, &utf8.text );
1805 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
1806 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
1807 const void *value, ULONG size )
1809 WS_XML_UTF8_TEXT utf8;
1810 unsigned char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
1811 const GUID *ptr;
1812 HRESULT hr;
1814 if (desc)
1816 FIXME( "description not supported\n" );
1817 return E_NOTIMPL;
1820 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1821 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
1822 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1824 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1825 utf8.value.bytes = buf;
1826 utf8.value.length = format_guid( ptr, buf );
1827 return write_type_text( writer, mapping, &utf8.text );
1830 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
1831 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
1832 const void *value, ULONG size )
1834 WS_XML_UTF16_TEXT utf16;
1835 const WS_STRING *ptr;
1836 HRESULT hr;
1838 if (desc)
1840 FIXME( "description not supported\n" );
1841 return E_NOTIMPL;
1844 if (!option) return E_INVALIDARG;
1845 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
1846 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1847 if (!ptr->length) return S_OK;
1849 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1850 utf16.bytes = (BYTE *)ptr->chars;
1851 utf16.byteCount = ptr->length * sizeof(WCHAR);
1852 return write_type_text( writer, mapping, &utf16.text );
1855 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
1856 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
1857 const void *value, ULONG size )
1859 WS_XML_UTF16_TEXT utf16;
1860 const WCHAR *ptr;
1861 HRESULT hr;
1862 int len;
1864 if (desc)
1866 FIXME( "description not supported\n" );
1867 return E_NOTIMPL;
1870 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1871 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
1872 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1873 if (!(len = strlenW( ptr ))) return S_OK;
1875 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1876 utf16.bytes = (BYTE *)ptr;
1877 utf16.byteCount = len * sizeof(WCHAR);
1878 return write_type_text( writer, mapping, &utf16.text );
1881 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
1882 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
1883 const void *value, ULONG size )
1885 WS_XML_BASE64_TEXT base64;
1886 const WS_BYTES *ptr;
1887 HRESULT hr;
1889 if (desc)
1891 FIXME( "description not supported\n" );
1892 return E_NOTIMPL;
1895 if (!option) return E_INVALIDARG;
1896 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
1897 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
1898 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
1899 if (!ptr->length) return S_OK;
1901 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
1902 base64.bytes = ptr->bytes;
1903 base64.length = ptr->length;
1904 return write_type_text( writer, mapping, &base64.text );
1907 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
1908 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
1909 const void *value, ULONG size )
1911 WS_XML_UTF8_TEXT utf8;
1912 const WS_XML_STRING *ptr;
1913 HRESULT hr;
1915 if (desc)
1917 FIXME( "description not supported\n" );
1918 return E_NOTIMPL;
1921 if (!option) return E_INVALIDARG;
1922 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
1923 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1924 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
1925 if (!ptr->length) return S_OK;
1927 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1928 utf8.value.bytes = ptr->bytes;
1929 utf8.value.length = ptr->length;
1930 return write_type_text( writer, mapping, &utf8.text );
1933 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
1934 const void *, ULONG );
1936 static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
1937 const void *value, ULONG size )
1939 HRESULT hr;
1940 WS_TYPE_MAPPING mapping;
1941 WS_WRITE_OPTION option;
1942 ULONG field_options = desc->options;
1944 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
1946 FIXME( "options 0x%x not supported\n", desc->options );
1947 return E_NOTIMPL;
1950 /* zero-terminated strings are always pointers */
1951 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
1953 if (is_nil_value( value, size ))
1955 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
1956 if (field_options & WS_FIELD_NILLABLE)
1958 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
1959 else option = WS_WRITE_NILLABLE_VALUE;
1961 else return E_INVALIDARG;
1963 else
1965 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
1966 else option = WS_WRITE_REQUIRED_VALUE;
1969 switch (desc->mapping)
1971 case WS_ATTRIBUTE_FIELD_MAPPING:
1972 if (!desc->localName || !desc->ns) return E_INVALIDARG;
1973 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
1974 return hr;
1975 writer->state = WRITER_STATE_STARTATTRIBUTE;
1977 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1978 break;
1980 case WS_ELEMENT_FIELD_MAPPING:
1981 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
1982 mapping = WS_ELEMENT_TYPE_MAPPING;
1983 break;
1985 case WS_TEXT_FIELD_MAPPING:
1986 switch (writer->state)
1988 case WRITER_STATE_STARTELEMENT:
1989 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
1990 break;
1992 case WRITER_STATE_STARTATTRIBUTE:
1993 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1994 break;
1996 default:
1997 FIXME( "unhandled writer state %u\n", writer->state );
1998 return E_NOTIMPL;
2000 break;
2002 default:
2003 FIXME( "field mapping %u not supported\n", desc->mapping );
2004 return E_NOTIMPL;
2007 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK)
2008 return hr;
2010 switch (mapping)
2012 case WS_ATTRIBUTE_TYPE_MAPPING:
2013 writer->state = WRITER_STATE_STARTELEMENT;
2014 break;
2016 case WS_ELEMENT_TYPE_MAPPING:
2017 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2018 break;
2020 default: break;
2023 return S_OK;
2026 static ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index )
2028 if (index < desc->fieldCount - 1) return desc->fields[index + 1]->offset - desc->fields[index]->offset;
2029 return desc->size - desc->fields[index]->offset;
2032 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
2033 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
2034 const void *value, ULONG size )
2036 ULONG i, field_size;
2037 const void *ptr, *field_ptr;
2038 HRESULT hr;
2040 if (!desc) return E_INVALIDARG;
2041 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
2043 if ((hr = get_value_ptr( option, value, size, desc->size, (const void **)&ptr )) != S_OK) return hr;
2045 for (i = 0; i < desc->fieldCount; i++)
2047 field_ptr = (const char *)ptr + desc->fields[i]->offset;
2048 field_size = get_field_size( desc, i );
2049 if ((hr = write_type_struct_field( writer, desc->fields[i], field_ptr, field_size )) != S_OK)
2050 return hr;
2053 return S_OK;
2057 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
2058 const void *desc, WS_WRITE_OPTION option, const void *value,
2059 ULONG size )
2061 switch (type)
2063 case WS_BOOL_TYPE:
2064 return write_type_bool( writer, mapping, desc, option, value, size );
2066 case WS_INT8_TYPE:
2067 return write_type_int8( writer, mapping, desc, option, value, size );
2069 case WS_INT16_TYPE:
2070 return write_type_int16( writer, mapping, desc, option, value, size );
2072 case WS_INT32_TYPE:
2073 return write_type_int32( writer, mapping, desc, option, value, size );
2075 case WS_INT64_TYPE:
2076 return write_type_int64( writer, mapping, desc, option, value, size );
2078 case WS_UINT8_TYPE:
2079 return write_type_uint8( writer, mapping, desc, option, value, size );
2081 case WS_UINT16_TYPE:
2082 return write_type_uint16( writer, mapping, desc, option, value, size );
2084 case WS_UINT32_TYPE:
2085 return write_type_uint32( writer, mapping, desc, option, value, size );
2087 case WS_UINT64_TYPE:
2088 return write_type_uint64( writer, mapping, desc, option, value, size );
2090 case WS_DATETIME_TYPE:
2091 return write_type_datetime( writer, mapping, desc, option, value, size );
2093 case WS_GUID_TYPE:
2094 return write_type_guid( writer, mapping, desc, option, value, size );
2096 case WS_STRING_TYPE:
2097 return write_type_string( writer, mapping, desc, option, value, size );
2099 case WS_WSZ_TYPE:
2100 return write_type_wsz( writer, mapping, desc, option, value, size );
2102 case WS_BYTES_TYPE:
2103 return write_type_bytes( writer, mapping, desc, option, value, size );
2105 case WS_XML_STRING_TYPE:
2106 return write_type_xml_string( writer, mapping, desc, option, value, size );
2108 case WS_STRUCT_TYPE:
2109 return write_type_struct( writer, mapping, desc, option, value, size );
2111 default:
2112 FIXME( "type %u not supported\n", type );
2113 return E_NOTIMPL;
2117 /**************************************************************************
2118 * WsWriteAttribute [webservices.@]
2120 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
2121 WS_WRITE_OPTION option, const void *value, ULONG size,
2122 WS_ERROR *error )
2124 struct writer *writer = (struct writer *)handle;
2125 HRESULT hr;
2127 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2128 if (error) FIXME( "ignoring error parameter\n" );
2130 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
2131 return E_INVALIDARG;
2133 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
2135 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs,
2136 FALSE )) != S_OK) return hr;
2137 writer->state = WRITER_STATE_STARTATTRIBUTE;
2139 return write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription,
2140 option, value, size );
2143 /**************************************************************************
2144 * WsWriteElement [webservices.@]
2146 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
2147 WS_WRITE_OPTION option, const void *value, ULONG size,
2148 WS_ERROR *error )
2150 struct writer *writer = (struct writer *)handle;
2151 HRESULT hr;
2153 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2154 if (error) FIXME( "ignoring error parameter\n" );
2156 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
2157 return E_INVALIDARG;
2159 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
2161 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
2162 option, value, size )) != S_OK) return hr;
2164 return write_endelement_node( writer );
2167 /**************************************************************************
2168 * WsWriteType [webservices.@]
2170 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
2171 const void *desc, WS_WRITE_OPTION option, const void *value,
2172 ULONG size, WS_ERROR *error )
2174 struct writer *writer = (struct writer *)handle;
2175 HRESULT hr;
2177 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
2178 size, error );
2179 if (error) FIXME( "ignoring error parameter\n" );
2181 if (!writer || !value) return E_INVALIDARG;
2183 switch (mapping)
2185 case WS_ATTRIBUTE_TYPE_MAPPING:
2186 if (writer->state != WRITER_STATE_STARTATTRIBUTE) return WS_E_INVALID_FORMAT;
2187 hr = write_type( writer, mapping, type, desc, option, value, size );
2188 break;
2190 case WS_ELEMENT_TYPE_MAPPING:
2191 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2192 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_FORMAT;
2193 hr = write_type( writer, mapping, type, desc, option, value, size );
2194 break;
2196 case WS_ANY_ELEMENT_TYPE_MAPPING:
2197 hr = write_type( writer, mapping, type, desc, option, value, size );
2198 break;
2200 default:
2201 FIXME( "mapping %u not implemented\n", mapping );
2202 return E_NOTIMPL;
2205 return hr;
2208 WS_TYPE map_value_type( WS_VALUE_TYPE type )
2210 switch (type)
2212 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
2213 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
2214 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
2215 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
2216 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
2217 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
2218 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
2219 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
2220 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
2221 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
2222 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
2223 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
2224 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
2225 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
2226 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
2227 default:
2228 FIXME( "unhandled type %u\n", type );
2229 return ~0u;
2233 /**************************************************************************
2234 * WsWriteValue [webservices.@]
2236 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
2237 ULONG size, WS_ERROR *error )
2239 struct writer *writer = (struct writer *)handle;
2240 WS_TYPE_MAPPING mapping;
2241 WS_TYPE type;
2243 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
2244 if (error) FIXME( "ignoring error parameter\n" );
2246 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
2248 switch (writer->state)
2250 case WRITER_STATE_STARTATTRIBUTE:
2251 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2252 break;
2254 case WRITER_STATE_STARTELEMENT:
2255 mapping = WS_ELEMENT_TYPE_MAPPING;
2256 break;
2258 default:
2259 return WS_E_INVALID_FORMAT;
2262 return write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
2265 /**************************************************************************
2266 * WsWriteArray [webservices.@]
2268 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2269 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
2270 ULONG count, WS_ERROR *error )
2272 struct writer *writer = (struct writer *)handle;
2273 WS_TYPE type;
2274 ULONG type_size, i;
2275 HRESULT hr;
2277 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
2278 value_type, array, size, offset, count, error );
2279 if (error) FIXME( "ignoring error parameter\n" );
2281 if (!writer) return E_INVALIDARG;
2282 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2283 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
2285 type_size = get_type_size( type, NULL );
2286 if (size % type_size || (offset + count) * type_size > size || (count && !array)) return E_INVALIDARG;
2288 for (i = offset; i < count; i++)
2290 const char *ptr = (const char *)array + (offset + i) * type_size;
2291 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) return hr;
2292 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
2293 &ptr, sizeof(ptr) )) != S_OK) return hr;
2294 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2297 return S_OK;
2300 /**************************************************************************
2301 * WsWriteXmlBuffer [webservices.@]
2303 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
2305 struct writer *writer = (struct writer *)handle;
2306 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
2307 HRESULT hr;
2309 TRACE( "%p %p %p\n", handle, buffer, error );
2310 if (error) FIXME( "ignoring error parameter\n" );
2312 if (!writer || !xmlbuf) return E_INVALIDARG;
2314 if ((hr = write_flush( writer )) != S_OK) return hr;
2315 if ((hr = write_grow_buffer( writer, xmlbuf->size )) != S_OK) return hr;
2316 write_bytes( writer, xmlbuf->ptr, xmlbuf->size );
2317 return S_OK;
2320 /**************************************************************************
2321 * WsWriteXmlBufferToBytes [webservices.@]
2323 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
2324 const WS_XML_WRITER_ENCODING *encoding,
2325 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
2326 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
2328 struct writer *writer = (struct writer *)handle;
2329 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
2330 HRESULT hr;
2331 char *buf;
2332 ULONG i;
2334 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
2335 bytes, size, error );
2336 if (error) FIXME( "ignoring error parameter\n" );
2338 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
2340 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
2342 FIXME( "encoding type %u not supported\n", encoding->encodingType );
2343 return E_NOTIMPL;
2346 for (i = 0; i < count; i++)
2348 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
2349 properties[i].valueSize );
2350 if (hr != S_OK) return hr;
2353 if (!(buf = ws_alloc( heap, xmlbuf->size ))) return WS_E_QUOTA_EXCEEDED;
2354 memcpy( buf, xmlbuf->ptr, xmlbuf->size );
2355 *bytes = buf;
2356 *size = xmlbuf->size;
2357 return S_OK;
2360 /**************************************************************************
2361 * WsWriteXmlnsAttribute [webservices.@]
2363 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2364 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
2366 struct writer *writer = (struct writer *)handle;
2368 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
2369 single, error );
2370 if (error) FIXME( "ignoring error parameter\n" );
2372 if (!writer || !ns) return E_INVALIDARG;
2373 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
2375 if (namespace_in_scope( &writer->current->hdr, prefix, ns )) return S_OK;
2376 return write_add_namespace_attribute( writer, prefix, ns, single );
2379 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
2381 BOOL success = FALSE;
2382 struct node *node = writer->current;
2384 switch (move)
2386 case WS_MOVE_TO_ROOT_ELEMENT:
2387 success = move_to_root_element( writer->root, &node );
2388 break;
2390 case WS_MOVE_TO_NEXT_ELEMENT:
2391 success = move_to_next_element( &node );
2392 break;
2394 case WS_MOVE_TO_PREVIOUS_ELEMENT:
2395 success = move_to_prev_element( &node );
2396 break;
2398 case WS_MOVE_TO_CHILD_ELEMENT:
2399 success = move_to_child_element( &node );
2400 break;
2402 case WS_MOVE_TO_END_ELEMENT:
2403 success = move_to_end_element( &node );
2404 break;
2406 case WS_MOVE_TO_PARENT_ELEMENT:
2407 success = move_to_parent_element( &node );
2408 break;
2410 case WS_MOVE_TO_FIRST_NODE:
2411 success = move_to_first_node( &node );
2412 break;
2414 case WS_MOVE_TO_NEXT_NODE:
2415 success = move_to_next_node( &node );
2416 break;
2418 case WS_MOVE_TO_PREVIOUS_NODE:
2419 success = move_to_prev_node( &node );
2420 break;
2422 case WS_MOVE_TO_CHILD_NODE:
2423 success = move_to_child_node( &node );
2424 break;
2426 case WS_MOVE_TO_BOF:
2427 success = move_to_bof( writer->root, &node );
2428 break;
2430 case WS_MOVE_TO_EOF:
2431 success = move_to_eof( writer->root, &node );
2432 break;
2434 default:
2435 FIXME( "unhandled move %u\n", move );
2436 return E_NOTIMPL;
2439 if (success && node == writer->root) return E_INVALIDARG;
2440 writer->current = node;
2442 if (found)
2444 *found = success;
2445 return S_OK;
2447 return success ? S_OK : WS_E_INVALID_FORMAT;
2450 /**************************************************************************
2451 * WsMoveWriter [webservices.@]
2453 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2455 struct writer *writer = (struct writer *)handle;
2457 TRACE( "%p %u %p %p\n", handle, move, found, error );
2458 if (error) FIXME( "ignoring error parameter\n" );
2460 if (!writer) return E_INVALIDARG;
2461 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2463 return write_move_to( writer, move, found );
2466 /**************************************************************************
2467 * WsGetWriterPosition [webservices.@]
2469 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2471 struct writer *writer = (struct writer *)handle;
2473 TRACE( "%p %p %p\n", handle, pos, error );
2474 if (error) FIXME( "ignoring error parameter\n" );
2476 if (!writer || !pos) return E_INVALIDARG;
2477 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2479 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
2480 pos->node = writer->current;
2481 return S_OK;
2484 /**************************************************************************
2485 * WsSetWriterPosition [webservices.@]
2487 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2489 struct writer *writer = (struct writer *)handle;
2491 TRACE( "%p %p %p\n", handle, pos, error );
2492 if (error) FIXME( "ignoring error parameter\n" );
2494 if (!writer || !pos || (struct xmlbuf *)pos->buffer != writer->output_buf) return E_INVALIDARG;
2495 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2497 writer->current = pos->node;
2498 return S_OK;
2501 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
2503 struct node *node, *parent;
2504 WS_XML_COMMENT_NODE *comment;
2506 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2507 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2508 comment = (WS_XML_COMMENT_NODE *)node;
2510 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
2512 free_node( node );
2513 return E_OUTOFMEMORY;
2515 memcpy( comment->value.bytes, value->bytes, value->length );
2516 comment->value.length = value->length;
2518 write_insert_node( writer, parent, node );
2519 return S_OK;
2522 static HRESULT write_comment( struct writer *writer )
2524 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
2525 HRESULT hr;
2527 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
2528 write_bytes( writer, (const BYTE *)"<!--", 4 );
2529 write_bytes( writer, comment->value.bytes, comment->value.length );
2530 write_bytes( writer, (const BYTE *)"-->", 3 );
2531 return S_OK;
2534 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
2536 HRESULT hr;
2537 if ((hr = write_flush( writer )) != S_OK) return hr;
2538 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
2539 if ((hr = write_comment( writer )) != S_OK) return hr;
2540 writer->state = WRITER_STATE_COMMENT;
2541 return S_OK;
2544 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
2546 ULONG i;
2547 HRESULT hr;
2549 for (i = 0; i < count; i++)
2551 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
2552 attrs[i]->singleQuote )) != S_OK) return hr;
2553 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
2555 return S_OK;
2558 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
2560 HRESULT hr;
2562 switch (node->nodeType)
2564 case WS_XML_NODE_TYPE_ELEMENT:
2566 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
2567 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
2568 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
2570 case WS_XML_NODE_TYPE_TEXT:
2572 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
2573 return write_text_node( writer, text->text );
2575 case WS_XML_NODE_TYPE_END_ELEMENT:
2576 return write_endelement_node( writer );
2578 case WS_XML_NODE_TYPE_COMMENT:
2580 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
2581 return write_comment_node( writer, &comment->value );
2583 case WS_XML_NODE_TYPE_CDATA:
2584 return write_cdata_node( writer );
2586 case WS_XML_NODE_TYPE_END_CDATA:
2587 return write_endcdata_node( writer );
2589 case WS_XML_NODE_TYPE_EOF:
2590 case WS_XML_NODE_TYPE_BOF:
2591 return S_OK;
2593 default:
2594 WARN( "unknown node type %u\n", node->nodeType );
2595 return E_INVALIDARG;
2599 /**************************************************************************
2600 * WsWriteNode [webservices.@]
2602 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
2604 struct writer *writer = (struct writer *)handle;
2606 TRACE( "%p %p %p\n", handle, node, error );
2607 if (error) FIXME( "ignoring error parameter\n" );
2609 if (!writer || !node) return E_INVALIDARG;
2610 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2612 return write_node( writer, node );
2615 static HRESULT write_tree_node( struct writer *writer )
2617 HRESULT hr;
2619 switch (node_type( writer->current ))
2621 case WS_XML_NODE_TYPE_ELEMENT:
2622 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2623 return hr;
2624 if ((hr = write_startelement( writer )) != S_OK) return hr;
2625 writer->state = WRITER_STATE_STARTELEMENT;
2626 return S_OK;
2628 case WS_XML_NODE_TYPE_TEXT:
2629 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2630 return hr;
2631 if ((hr = write_text( writer )) != S_OK) return hr;
2632 writer->state = WRITER_STATE_TEXT;
2633 return S_OK;
2635 case WS_XML_NODE_TYPE_END_ELEMENT:
2636 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
2637 writer->state = WRITER_STATE_ENDELEMENT;
2638 return S_OK;
2640 case WS_XML_NODE_TYPE_COMMENT:
2641 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2642 return hr;
2643 if ((hr = write_comment( writer )) != S_OK) return hr;
2644 writer->state = WRITER_STATE_COMMENT;
2645 return S_OK;
2647 case WS_XML_NODE_TYPE_CDATA:
2648 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2649 return hr;
2650 if ((hr = write_cdata( writer )) != S_OK) return hr;
2651 writer->state = WRITER_STATE_STARTCDATA;
2652 return S_OK;
2654 case WS_XML_NODE_TYPE_END_CDATA:
2655 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2656 writer->state = WRITER_STATE_ENDCDATA;
2657 return S_OK;
2659 case WS_XML_NODE_TYPE_EOF:
2660 case WS_XML_NODE_TYPE_BOF:
2661 return S_OK;
2663 default:
2664 ERR( "unknown node type %u\n", node_type(writer->current) );
2665 return E_INVALIDARG;
2669 static HRESULT write_tree( struct writer *writer )
2671 HRESULT hr;
2673 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2674 for (;;)
2676 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
2677 if (move_to_child_node( &writer->current ))
2679 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2680 continue;
2682 if (move_to_next_node( &writer->current ))
2684 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2685 continue;
2687 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
2689 ERR( "invalid tree\n" );
2690 return WS_E_INVALID_FORMAT;
2692 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2694 return S_OK;
2697 static void write_rewind( struct writer *writer )
2699 writer->write_pos = 0;
2700 writer->current = writer->root;
2701 writer->state = WRITER_STATE_INITIAL;
2704 /**************************************************************************
2705 * WsCopyNode [webservices.@]
2707 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
2709 struct writer *writer = (struct writer *)handle;
2710 struct node *parent, *current = writer->current, *node = NULL;
2711 HRESULT hr;
2713 TRACE( "%p %p %p\n", handle, reader, error );
2714 if (error) FIXME( "ignoring error parameter\n" );
2716 if (!writer) return E_INVALIDARG;
2717 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2719 if ((hr = copy_node( reader, &node )) != S_OK) return hr;
2720 write_insert_node( writer, parent, node );
2722 write_rewind( writer );
2723 if ((hr = write_tree( writer )) != S_OK) return hr;
2725 writer->current = current;
2726 return S_OK;