explorerframe: A spelling fix in a comment.
[wine.git] / dlls / webservices / writer.c
blob1ccac533b424122d0a0e3b2a901c9f5d346f22c4
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 struct node *find_parent( struct writer *writer )
135 if (is_valid_parent( writer->current )) return writer->current;
136 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
137 return NULL;
140 static HRESULT write_init_state( struct writer *writer )
142 struct node *node;
144 heap_free( writer->current_ns );
145 writer->current_ns = NULL;
146 destroy_nodes( writer->root );
147 writer->root = NULL;
149 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
150 write_insert_eof( writer, node );
151 writer->state = WRITER_STATE_INITIAL;
152 return S_OK;
155 /**************************************************************************
156 * WsCreateWriter [webservices.@]
158 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
159 WS_XML_WRITER **handle, WS_ERROR *error )
161 struct writer *writer;
162 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
163 WS_CHARSET charset = WS_CHARSET_UTF8;
164 HRESULT hr;
166 TRACE( "%p %u %p %p\n", properties, count, handle, error );
167 if (error) FIXME( "ignoring error parameter\n" );
169 if (!handle) return E_INVALIDARG;
170 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
172 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
173 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
174 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
175 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
176 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
177 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
178 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
180 for (i = 0; i < count; i++)
182 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
183 properties[i].valueSize );
184 if (hr != S_OK)
186 free_writer( writer );
187 return hr;
191 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
192 &max_size, sizeof(max_size) );
193 if (hr != S_OK)
195 free_writer( writer );
196 return hr;
199 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
200 if (hr != S_OK)
202 free_writer( writer );
203 return hr;
206 hr = write_init_state( writer );
207 if (hr != S_OK)
209 free_writer( writer );
210 return hr;
213 *handle = (WS_XML_WRITER *)writer;
214 return S_OK;
217 /**************************************************************************
218 * WsFreeWriter [webservices.@]
220 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
222 struct writer *writer = (struct writer *)handle;
224 TRACE( "%p\n", handle );
225 free_writer( writer );
228 #define XML_BUFFER_INITIAL_ALLOCATED_SIZE 256
229 static struct xmlbuf *alloc_xmlbuf( WS_HEAP *heap )
231 struct xmlbuf *ret;
233 if (!(ret = ws_alloc( heap, sizeof(*ret) ))) return NULL;
234 if (!(ret->ptr = ws_alloc( heap, XML_BUFFER_INITIAL_ALLOCATED_SIZE )))
236 ws_free( heap, ret );
237 return NULL;
239 ret->heap = heap;
240 ret->size_allocated = XML_BUFFER_INITIAL_ALLOCATED_SIZE;
241 ret->size = 0;
242 return ret;
245 static void free_xmlbuf( struct xmlbuf *xmlbuf )
247 if (!xmlbuf) return;
248 ws_free( xmlbuf->heap, xmlbuf->ptr );
249 ws_free( xmlbuf->heap, xmlbuf );
252 /**************************************************************************
253 * WsCreateXmlBuffer [webservices.@]
255 HRESULT WINAPI WsCreateXmlBuffer( WS_HEAP *heap, const WS_XML_BUFFER_PROPERTY *properties,
256 ULONG count, WS_XML_BUFFER **handle, WS_ERROR *error )
258 struct xmlbuf *xmlbuf;
260 if (!heap || !handle) return E_INVALIDARG;
261 if (count) FIXME( "properties not implemented\n" );
263 if (!(xmlbuf = alloc_xmlbuf( heap ))) return E_OUTOFMEMORY;
265 *handle = (WS_XML_BUFFER *)xmlbuf;
266 return S_OK;
269 /**************************************************************************
270 * WsGetWriterProperty [webservices.@]
272 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
273 void *buf, ULONG size, WS_ERROR *error )
275 struct writer *writer = (struct writer *)handle;
277 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
278 if (error) FIXME( "ignoring error parameter\n" );
280 if (!writer->output_type) return WS_E_INVALID_OPERATION;
282 switch (id)
284 case WS_XML_WRITER_PROPERTY_BYTES:
286 WS_BYTES *bytes = buf;
287 if (size != sizeof(*bytes)) return E_INVALIDARG;
288 bytes->bytes = writer->output_buf->ptr;
289 bytes->length = writer->output_buf->size;
290 return S_OK;
292 default:
293 return prop_get( writer->prop, writer->prop_count, id, buf, size );
297 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
299 /* free current buffer if it's ours */
300 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
302 free_xmlbuf( writer->output_buf );
304 writer->output_buf = xmlbuf;
305 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
306 writer->write_bufptr = xmlbuf->ptr;
307 writer->write_pos = 0;
310 /**************************************************************************
311 * WsSetOutput [webservices.@]
313 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
314 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
315 ULONG count, WS_ERROR *error )
317 struct writer *writer = (struct writer *)handle;
318 struct node *node;
319 HRESULT hr;
320 ULONG i;
322 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
323 if (error) FIXME( "ignoring error parameter\n" );
325 if (!writer) return E_INVALIDARG;
327 for (i = 0; i < count; i++)
329 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
330 properties[i].valueSize );
331 if (hr != S_OK) return hr;
334 if ((hr = write_init_state( writer )) != S_OK) return hr;
336 switch (encoding->encodingType)
338 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
340 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
341 if (text->charSet != WS_CHARSET_UTF8)
343 FIXME( "charset %u not supported\n", text->charSet );
344 return E_NOTIMPL;
346 break;
348 default:
349 FIXME( "encoding type %u not supported\n", encoding->encodingType );
350 return E_NOTIMPL;
352 switch (output->outputType)
354 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
356 struct xmlbuf *xmlbuf;
358 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap ))) return E_OUTOFMEMORY;
359 set_output_buffer( writer, xmlbuf );
360 break;
362 default:
363 FIXME( "output type %u not supported\n", output->outputType );
364 return E_NOTIMPL;
367 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
368 write_insert_bof( writer, node );
369 return S_OK;
372 /**************************************************************************
373 * WsSetOutputToBuffer [webservices.@]
375 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
376 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
377 WS_ERROR *error )
379 struct writer *writer = (struct writer *)handle;
380 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
381 struct node *node;
382 HRESULT hr;
383 ULONG i;
385 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
386 if (error) FIXME( "ignoring error parameter\n" );
388 if (!writer || !xmlbuf) return E_INVALIDARG;
390 for (i = 0; i < count; i++)
392 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
393 properties[i].valueSize );
394 if (hr != S_OK) return hr;
397 if ((hr = write_init_state( writer )) != S_OK) return hr;
398 set_output_buffer( writer, xmlbuf );
400 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
401 write_insert_bof( writer, node );
402 return S_OK;
405 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
407 struct xmlbuf *buf = writer->output_buf;
408 SIZE_T new_size;
409 void *tmp;
411 if (buf->size_allocated >= writer->write_pos + size)
413 buf->size = writer->write_pos + size;
414 return S_OK;
416 new_size = max( buf->size_allocated * 2, writer->write_pos + size );
417 if (!(tmp = ws_realloc( buf->heap, buf->ptr, new_size ))) return E_OUTOFMEMORY;
418 writer->write_bufptr = buf->ptr = tmp;
419 buf->size_allocated = new_size;
420 buf->size = writer->write_pos + size;
421 return S_OK;
424 static inline void write_char( struct writer *writer, unsigned char ch )
426 writer->write_bufptr[writer->write_pos++] = ch;
429 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
431 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
432 writer->write_pos += len;
435 struct escape
437 char ch;
438 const char *entity;
439 ULONG len;
441 static const struct escape escape_lt = { '<', "&lt;", 4 };
442 static const struct escape escape_gt = { '>', "&gt;", 4 };
443 static const struct escape escape_amp = { '&', "&amp;", 5 };
444 static const struct escape escape_apos = { '\'', "&apos;", 6 };
445 static const struct escape escape_quot = { '"', "&quot;", 6 };
447 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
448 const struct escape **escapes, ULONG nb_escapes )
450 ULONG i, j, size;
451 const BYTE *ptr;
452 HRESULT hr;
454 for (i = 0; i < len; i++)
456 ptr = &bytes[i];
457 size = 1;
458 for (j = 0; j < nb_escapes; j++)
460 if (bytes[i] == escapes[j]->ch)
462 ptr = (const BYTE *)escapes[j]->entity;
463 size = escapes[j]->len;
464 break;
467 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
468 write_bytes( writer, ptr, size );
471 return S_OK;
474 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
476 WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
477 unsigned char quote = attr->singleQuote ? '\'' : '"';
478 const WS_XML_STRING *prefix;
479 ULONG size;
480 HRESULT hr;
482 if (attr->prefix) prefix = attr->prefix;
483 else prefix = writer->current->hdr.prefix;
485 /* ' prefix:attr="value"' */
487 size = attr->localName->length + 4 /* ' =""' */;
488 if (prefix) size += prefix->length + 1 /* ':' */;
489 if (text) size += text->value.length;
490 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
492 write_char( writer, ' ' );
493 if (prefix)
495 write_bytes( writer, prefix->bytes, prefix->length );
496 write_char( writer, ':' );
498 write_bytes( writer, attr->localName->bytes, attr->localName->length );
499 write_char( writer, '=' );
500 write_char( writer, quote );
501 if (text)
503 const struct escape *escapes[3];
504 escapes[0] = attr->singleQuote ? &escape_apos : &escape_quot;
505 escapes[1] = &escape_lt;
506 escapes[2] = &escape_amp;
507 hr = write_bytes_escape( writer, text->value.bytes, text->value.length, escapes, 3 );
509 write_char( writer, quote );
511 return hr;
514 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
516 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
519 /**************************************************************************
520 * WsGetPrefixFromNamespace [webservices.@]
522 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
523 BOOL required, const WS_XML_STRING **prefix,
524 WS_ERROR *error )
526 struct writer *writer = (struct writer *)handle;
527 WS_XML_ELEMENT_NODE *elem;
528 BOOL found = FALSE;
530 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
531 if (error) FIXME( "ignoring error parameter\n" );
533 if (!writer || !ns || !prefix) return E_INVALIDARG;
535 elem = &writer->current->hdr;
536 if (elem->prefix && is_current_namespace( writer, ns ))
538 *prefix = elem->prefix;
539 found = TRUE;
541 if (!found)
543 if (required) return WS_E_INVALID_FORMAT;
544 *prefix = NULL;
545 return S_FALSE;
547 return S_OK;
550 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
552 WS_XML_STRING *str;
553 if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
554 heap_free( writer->current_ns );
555 writer->current_ns = str;
556 return S_OK;
559 static HRESULT write_namespace_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
561 unsigned char quote = attr->singleQuote ? '\'' : '"';
562 ULONG size;
563 HRESULT hr;
565 /* ' xmlns:prefix="namespace"' */
567 size = attr->ns->length + 9 /* ' xmlns=""' */;
568 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
569 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
571 write_bytes( writer, (const BYTE *)" xmlns", 6 );
572 if (attr->prefix)
574 write_char( writer, ':' );
575 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
577 write_char( writer, '=' );
578 write_char( writer, quote );
579 write_bytes( writer, attr->ns->bytes, attr->ns->length );
580 write_char( writer, quote );
582 return S_OK;
585 static HRESULT write_add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
586 const WS_XML_STRING *ns, BOOL single )
588 WS_XML_ATTRIBUTE *attr;
589 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
590 HRESULT hr;
592 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
594 attr->singleQuote = !!single;
595 attr->isXmlNs = 1;
596 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
598 free_attribute( attr );
599 return E_OUTOFMEMORY;
601 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
603 free_attribute( attr );
604 return E_OUTOFMEMORY;
606 if ((hr = append_attribute( elem, attr )) != S_OK)
608 free_attribute( attr );
609 return hr;
611 return S_OK;
614 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
616 if (!str1 && !str2) return TRUE;
617 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
620 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
621 const WS_XML_STRING *ns )
623 ULONG i;
624 const struct node *node;
626 for (node = (const struct node *)elem; node; node = node->parent)
628 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
630 elem = &node->hdr;
631 for (i = 0; i < elem->attributeCount; i++)
633 if (!elem->attributes[i]->isXmlNs) continue;
634 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
635 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
638 return FALSE;
641 static HRESULT write_set_element_namespace( struct writer *writer )
643 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
644 HRESULT hr;
646 if (!elem->ns->length || namespace_in_scope( elem, elem->prefix, elem->ns )) return S_OK;
648 if ((hr = write_add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK)
649 return hr;
651 return set_current_namespace( writer, elem->ns );
654 /**************************************************************************
655 * WsWriteEndAttribute [webservices.@]
657 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
659 struct writer *writer = (struct writer *)handle;
661 TRACE( "%p %p\n", handle, error );
662 if (error) FIXME( "ignoring error parameter\n" );
664 if (!writer) return E_INVALIDARG;
666 writer->state = WRITER_STATE_STARTELEMENT;
667 return S_OK;
670 static HRESULT write_startelement( struct writer *writer )
672 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
673 ULONG size, i;
674 HRESULT hr;
676 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
678 size = elem->localName->length + 1 /* '<' */;
679 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
680 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
682 write_char( writer, '<' );
683 if (elem->prefix)
685 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
686 write_char( writer, ':' );
688 write_bytes( writer, elem->localName->bytes, elem->localName->length );
689 for (i = 0; i < elem->attributeCount; i++)
691 if (elem->attributes[i]->isXmlNs) continue;
692 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
694 for (i = 0; i < elem->attributeCount; i++)
696 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
697 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
699 for (i = 0; i < elem->attributeCount; i++)
701 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
702 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
704 return S_OK;
707 static struct node *write_find_startelement( struct writer *writer )
709 struct node *node;
710 for (node = writer->current; node; node = node->parent)
712 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
714 return NULL;
717 static inline BOOL is_empty_element( const struct node *node )
719 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
720 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
723 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
725 ULONG size;
726 HRESULT hr;
728 /* '/>' */
730 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
732 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
733 write_char( writer, '/' );
734 write_char( writer, '>' );
735 return S_OK;
738 /* '</prefix:localname>' */
740 size = elem->localName->length + 3 /* '</>' */;
741 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
742 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
744 write_char( writer, '<' );
745 write_char( writer, '/' );
746 if (elem->prefix)
748 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
749 write_char( writer, ':' );
751 write_bytes( writer, elem->localName->bytes, elem->localName->length );
752 write_char( writer, '>' );
753 return S_OK;
756 static HRESULT write_close_element( struct writer *writer, struct node *node )
758 WS_XML_ELEMENT_NODE *elem = &node->hdr;
759 elem->isEmpty = is_empty_element( node );
760 return write_endelement( writer, elem );
763 static HRESULT write_endelement_node( struct writer *writer )
765 struct node *node;
766 HRESULT hr;
768 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
769 if (writer->state == WRITER_STATE_STARTELEMENT)
771 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
772 if ((hr = write_startelement( writer )) != S_OK) return hr;
774 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
775 writer->current = node->parent;
776 writer->state = WRITER_STATE_ENDELEMENT;
777 return S_OK;
780 /**************************************************************************
781 * WsWriteEndElement [webservices.@]
783 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
785 struct writer *writer = (struct writer *)handle;
787 TRACE( "%p %p\n", handle, error );
788 if (error) FIXME( "ignoring error parameter\n" );
790 if (!writer) return E_INVALIDARG;
791 return write_endelement_node( writer );
794 static HRESULT write_endstartelement( struct writer *writer )
796 HRESULT hr;
797 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
798 write_char( writer, '>' );
799 return S_OK;
802 /**************************************************************************
803 * WsWriteEndStartElement [webservices.@]
805 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
807 struct writer *writer = (struct writer *)handle;
808 HRESULT hr;
810 TRACE( "%p %p\n", handle, error );
811 if (error) FIXME( "ignoring error parameter\n" );
813 if (!writer) return E_INVALIDARG;
814 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
816 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
817 if ((hr = write_startelement( writer )) != S_OK) return hr;
818 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
820 writer->state = WRITER_STATE_ENDSTARTELEMENT;
821 return S_OK;
824 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
825 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
826 BOOL single )
828 WS_XML_ATTRIBUTE *attr;
829 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
830 HRESULT hr;
832 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
834 if (!prefix) prefix = elem->prefix;
836 attr->singleQuote = !!single;
837 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
839 free_attribute( attr );
840 return E_OUTOFMEMORY;
842 if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
844 free_attribute( attr );
845 return E_OUTOFMEMORY;
847 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
849 free_attribute( attr );
850 return E_OUTOFMEMORY;
852 if ((hr = append_attribute( elem, attr )) != S_OK)
854 free_attribute( attr );
855 return hr;
857 return S_OK;
860 /**************************************************************************
861 * WsWriteStartAttribute [webservices.@]
863 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
864 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
865 BOOL single, WS_ERROR *error )
867 struct writer *writer = (struct writer *)handle;
868 HRESULT hr;
870 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
871 debugstr_xmlstr(ns), single, error );
872 if (error) FIXME( "ignoring error parameter\n" );
874 if (!writer || !localname || !ns) return E_INVALIDARG;
876 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
878 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
879 writer->state = WRITER_STATE_STARTATTRIBUTE;
880 return S_OK;
883 /* flush current start element if necessary */
884 static HRESULT write_flush( struct writer *writer )
886 if (writer->state == WRITER_STATE_STARTELEMENT)
888 HRESULT hr;
889 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
890 if ((hr = write_startelement( writer )) != S_OK) return hr;
891 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
892 writer->state = WRITER_STATE_ENDSTARTELEMENT;
894 return S_OK;
897 static HRESULT write_add_cdata_node( struct writer *writer )
899 struct node *node, *parent;
900 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
901 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
902 write_insert_node( writer, parent, node );
903 return S_OK;
906 static HRESULT write_add_endcdata_node( struct writer *writer )
908 struct node *node;
909 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
910 node->parent = writer->current;
911 list_add_tail( &node->parent->children, &node->entry );
912 return S_OK;
915 static HRESULT write_cdata( struct writer *writer )
917 HRESULT hr;
918 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
919 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
920 return S_OK;
923 static HRESULT write_cdata_node( struct writer *writer )
925 HRESULT hr;
926 if ((hr = write_flush( writer )) != S_OK) return hr;
927 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
928 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
929 if ((hr = write_cdata( writer )) != S_OK) return hr;
930 writer->state = WRITER_STATE_STARTCDATA;
931 return S_OK;
934 /**************************************************************************
935 * WsWriteStartCData [webservices.@]
937 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
939 struct writer *writer = (struct writer *)handle;
941 TRACE( "%p %p\n", handle, error );
942 if (error) FIXME( "ignoring error parameter\n" );
944 if (!writer) return E_INVALIDARG;
945 return write_cdata_node( writer );
948 static HRESULT write_endcdata( struct writer *writer )
950 HRESULT hr;
951 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
952 write_bytes( writer, (const BYTE *)"]]>", 3 );
953 return S_OK;
956 static HRESULT write_endcdata_node( struct writer *writer )
958 HRESULT hr;
959 if ((hr = write_endcdata( writer )) != S_OK) return hr;
960 writer->current = writer->current->parent;
961 writer->state = WRITER_STATE_ENDCDATA;
962 return S_OK;
965 /**************************************************************************
966 * WsWriteEndCData [webservices.@]
968 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
970 struct writer *writer = (struct writer *)handle;
972 TRACE( "%p %p\n", handle, error );
973 if (error) FIXME( "ignoring error parameter\n" );
975 if (!writer) return E_INVALIDARG;
976 if (writer->state != WRITER_STATE_TEXT) return WS_E_INVALID_OPERATION;
978 return write_endcdata_node( writer );
981 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
982 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
984 struct node *node, *parent;
985 WS_XML_ELEMENT_NODE *elem;
987 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
989 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
991 elem = &parent->hdr;
992 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
995 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
996 elem = &node->hdr;
998 if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
1000 free_node( node );
1001 return E_OUTOFMEMORY;
1003 if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
1005 free_node( node );
1006 return E_OUTOFMEMORY;
1008 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
1010 free_node( node );
1011 return E_OUTOFMEMORY;
1013 write_insert_node( writer, parent, node );
1014 return S_OK;
1017 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1019 struct node *node;
1020 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1021 node->parent = parent;
1022 list_add_tail( &parent->children, &node->entry );
1023 return S_OK;
1026 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1027 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1029 HRESULT hr;
1030 if ((hr = write_flush( writer )) != S_OK) return hr;
1031 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1032 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1033 writer->state = WRITER_STATE_STARTELEMENT;
1034 return S_OK;
1037 /**************************************************************************
1038 * WsWriteStartElement [webservices.@]
1040 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1041 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1042 WS_ERROR *error )
1044 struct writer *writer = (struct writer *)handle;
1046 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1047 debugstr_xmlstr(ns), error );
1048 if (error) FIXME( "ignoring error parameter\n" );
1050 if (!writer || !localname || !ns) return E_INVALIDARG;
1051 return write_element_node( writer, prefix, localname, ns );
1054 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1056 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1057 if (*ptr)
1059 memcpy( buf, bool_true, sizeof(bool_true) );
1060 return sizeof(bool_true);
1062 memcpy( buf, bool_false, sizeof(bool_false) );
1063 return sizeof(bool_false);
1066 static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
1068 return wsprintfA( (char *)buf, "%d", *ptr );
1071 static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
1073 return wsprintfA( (char *)buf, "%d", *ptr );
1076 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1078 return wsprintfA( (char *)buf, "%d", *ptr );
1081 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1083 return wsprintfA( (char *)buf, "%I64d", *ptr );
1086 static ULONG format_uint8( const UINT8 *ptr, unsigned char *buf )
1088 return wsprintfA( (char *)buf, "%u", *ptr );
1091 static ULONG format_uint16( const UINT16 *ptr, unsigned char *buf )
1093 return wsprintfA( (char *)buf, "%u", *ptr );
1096 static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
1098 return wsprintfA( (char *)buf, "%u", *ptr );
1101 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1103 return wsprintfA( (char *)buf, "%I64u", *ptr );
1106 static ULONG format_double( const double *ptr, unsigned char *buf )
1108 #ifdef HAVE_POWL
1109 static const long double precision = 0.0000000000000001;
1110 unsigned char *p = buf;
1111 long double val = *ptr;
1112 int neg, mag, mag2, use_exp;
1114 if (isnan( val ))
1116 memcpy( buf, "NaN", 3 );
1117 return 3;
1119 if (isinf( val ))
1121 if (val < 0)
1123 memcpy( buf, "-INF", 4 );
1124 return 4;
1126 memcpy( buf, "INF", 3 );
1127 return 3;
1129 if (val == 0.0)
1131 *p = '0';
1132 return 1;
1135 if ((neg = val < 0))
1137 *p++ = '-';
1138 val = -val;
1141 mag = log10l( val );
1142 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1143 if (use_exp)
1145 if (mag < 0) mag -= 1;
1146 val = val / powl( 10.0, mag );
1147 mag2 = mag;
1148 mag = 0;
1150 else if (mag < 1) mag = 0;
1152 while (val > precision || mag >= 0)
1154 long double weight = powl( 10.0, mag );
1155 if (weight > 0 && !isinf( weight ))
1157 int digit = floorl( val / weight );
1158 val -= digit * weight;
1159 *(p++) = '0' + digit;
1161 if (!mag && val > precision) *(p++) = '.';
1162 mag--;
1165 if (use_exp)
1167 int i, j;
1168 *(p++) = 'E';
1169 if (mag2 > 0) *(p++) = '+';
1170 else
1172 *(p++) = '-';
1173 mag2 = -mag2;
1175 mag = 0;
1176 while (mag2 > 0)
1178 *(p++) = '0' + mag2 % 10;
1179 mag2 /= 10;
1180 mag++;
1182 for (i = -mag, j = -1; i < j; i++, j--)
1184 p[i] ^= p[j];
1185 p[j] ^= p[i];
1186 p[i] ^= p[j];
1190 return p - buf;
1191 #else
1192 FIXME( "powl not found at build time\n" );
1193 return 0;
1194 #endif
1197 static inline int year_size( int year )
1199 return leap_year( year ) ? 366 : 365;
1202 #define TZ_OFFSET 8
1203 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1205 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1206 int day, hour, min, sec, sec_frac, month = 1, year = 1, tz_hour;
1207 unsigned __int64 ticks, day_ticks;
1208 ULONG len;
1210 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1211 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1213 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1214 tz_hour = TZ_OFFSET;
1216 else
1218 ticks = ptr->ticks;
1219 tz_hour = 0;
1221 day = ticks / TICKS_PER_DAY;
1222 day_ticks = ticks % TICKS_PER_DAY;
1223 hour = day_ticks / TICKS_PER_HOUR;
1224 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1225 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1226 sec_frac = day_ticks % TICKS_PER_SEC;
1228 while (day >= year_size( year ))
1230 day -= year_size( year );
1231 year++;
1233 while (day >= month_days[leap_year( year )][month])
1235 day -= month_days[leap_year( year )][month];
1236 month++;
1238 day++;
1240 len = sprintf( (char *)buf, fmt, year, month, day, hour, min, sec );
1241 if (sec_frac)
1243 static const char fmt_frac[] = ".%07u";
1244 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1245 while (buf[len - 1] == '0') len--;
1247 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1249 buf[len++] = 'Z';
1251 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1253 static const char fmt_tz[] = "%c%02u:00";
1254 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1257 return len;
1260 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1262 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1263 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1264 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1265 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1268 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1270 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1271 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1272 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1273 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1276 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1278 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1279 ULONG i = 0, x;
1281 while (len > 0)
1283 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1284 x = (bin[0] & 3) << 4;
1285 if (len == 1)
1287 buf[i++] = base64[x];
1288 buf[i++] = '=';
1289 buf[i++] = '=';
1290 break;
1292 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1293 x = (bin[1] & 0x0f) << 2;
1294 if (len == 2)
1296 buf[i++] = base64[x];
1297 buf[i++] = '=';
1298 break;
1300 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1301 buf[i++] = base64[bin[2] & 0x3f];
1302 bin += 3;
1303 len -= 3;
1305 return i;
1308 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret )
1310 switch (text->textType)
1312 case WS_XML_TEXT_TYPE_UTF8:
1314 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1315 if (!(*ret = alloc_utf8_text( src->value.bytes, src->value.length ))) return E_OUTOFMEMORY;
1316 return S_OK;
1318 case WS_XML_TEXT_TYPE_UTF16:
1320 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1321 const WCHAR *str = (const WCHAR *)src->bytes;
1322 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1324 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1325 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1326 if (!(*ret = alloc_utf8_text( NULL, len_utf8 ))) return E_OUTOFMEMORY;
1327 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes, (*ret)->value.length, NULL, NULL );
1328 return S_OK;
1330 case WS_XML_TEXT_TYPE_BASE64:
1332 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1333 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1334 if (!(*ret = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY;
1335 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes );
1336 return S_OK;
1338 case WS_XML_TEXT_TYPE_BOOL:
1340 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1341 if (!(*ret = alloc_utf8_text( NULL, 5 ))) return E_OUTOFMEMORY;
1342 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes );
1343 return S_OK;
1345 case WS_XML_TEXT_TYPE_INT32:
1347 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1348 unsigned char buf[12]; /* "-2147483648" */
1349 ULONG len = format_int32( &int32_text->value, buf );
1350 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1351 return S_OK;
1353 case WS_XML_TEXT_TYPE_INT64:
1355 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1356 unsigned char buf[21]; /* "-9223372036854775808" */
1357 ULONG len = format_int64( &int64_text->value, buf );
1358 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1359 return S_OK;
1361 case WS_XML_TEXT_TYPE_UINT64:
1363 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1364 unsigned char buf[21]; /* "18446744073709551615" */
1365 ULONG len = format_uint64( &uint64_text->value, buf );
1366 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1367 return S_OK;
1369 case WS_XML_TEXT_TYPE_DOUBLE:
1371 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1372 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1373 unsigned short fpword;
1374 ULONG len;
1376 if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
1377 len = format_double( &double_text->value, buf );
1378 restore_fp_rounding( fpword );
1379 if (!len) return E_NOTIMPL;
1380 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1381 return S_OK;
1383 case WS_XML_TEXT_TYPE_GUID:
1385 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1386 if (!(*ret = alloc_utf8_text( NULL, 37 ))) return E_OUTOFMEMORY;
1387 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes );
1388 return S_OK;
1390 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1392 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1393 if (!(*ret = alloc_utf8_text( NULL, 46 ))) return E_OUTOFMEMORY;
1394 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes );
1395 return S_OK;
1397 case WS_XML_TEXT_TYPE_DATETIME:
1399 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1400 if (!(*ret = alloc_utf8_text( NULL, 34 ))) return E_OUTOFMEMORY;
1401 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes );
1402 return S_OK;
1404 default:
1405 FIXME( "unhandled text type %u\n", text->textType );
1406 return E_NOTIMPL;
1410 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
1412 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1413 WS_XML_UTF8_TEXT *utf8;
1414 HRESULT hr;
1416 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK) return hr;
1417 elem->attributes[elem->attributeCount - 1]->value = &utf8->text;
1418 return S_OK;
1421 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
1423 struct node *node;
1424 WS_XML_TEXT_NODE *text;
1425 WS_XML_UTF8_TEXT *utf8;
1426 HRESULT hr;
1428 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
1429 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
1430 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
1432 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1433 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK)
1435 heap_free( node );
1436 return hr;
1438 text = (WS_XML_TEXT_NODE *)node;
1439 text->text = &utf8->text;
1441 write_insert_node( writer, writer->current, node );
1442 return S_OK;
1445 static HRESULT write_text( struct writer *writer )
1447 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)writer->current;
1448 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
1449 HRESULT hr;
1451 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
1452 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
1454 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
1455 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
1457 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
1459 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
1460 write_bytes( writer, utf8->value.bytes, utf8->value.length );
1461 return S_OK;
1464 return WS_E_INVALID_FORMAT;
1467 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
1469 HRESULT hr;
1470 if ((hr = write_flush( writer )) != S_OK) return hr;
1471 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
1472 if ((hr = write_text( writer )) != S_OK) return hr;
1473 writer->state = WRITER_STATE_TEXT;
1474 return S_OK;
1477 /**************************************************************************
1478 * WsWriteText [webservices.@]
1480 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
1482 struct writer *writer = (struct writer *)handle;
1484 TRACE( "%p %p %p\n", handle, text, error );
1486 if (!writer || !text) return E_INVALIDARG;
1488 if (writer->state == WRITER_STATE_STARTATTRIBUTE) return write_set_attribute_value( writer, text );
1489 return write_text_node( writer, text );
1492 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
1494 switch (mapping)
1496 case WS_ELEMENT_TYPE_MAPPING:
1497 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1498 return write_text_node( writer, text );
1500 case WS_ATTRIBUTE_TYPE_MAPPING:
1501 return write_set_attribute_value( writer, text );
1503 case WS_ANY_ELEMENT_TYPE_MAPPING:
1504 switch (writer->state)
1506 case WRITER_STATE_STARTATTRIBUTE:
1507 return write_set_attribute_value( writer, text );
1509 case WRITER_STATE_STARTELEMENT:
1510 return write_text_node( writer, text );
1512 default:
1513 FIXME( "writer state %u not handled\n", writer->state );
1514 return E_NOTIMPL;
1517 default:
1518 FIXME( "mapping %u not implemented\n", mapping );
1519 return E_NOTIMPL;
1523 static HRESULT write_add_nil_attribute( struct writer *writer )
1525 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
1526 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
1527 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
1528 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
1529 HRESULT hr;
1531 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
1532 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
1533 return write_add_namespace_attribute( writer, &prefix, &ns, FALSE );
1536 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
1537 const void **ptr )
1539 switch (option)
1541 case WS_WRITE_REQUIRED_VALUE:
1542 case WS_WRITE_NILLABLE_VALUE:
1543 if (!value || size != expected_size) return E_INVALIDARG;
1544 *ptr = value;
1545 return S_OK;
1547 case WS_WRITE_REQUIRED_POINTER:
1548 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
1549 return S_OK;
1551 case WS_WRITE_NILLABLE_POINTER:
1552 if (size != sizeof(const void *)) return E_INVALIDARG;
1553 *ptr = *(const void **)value;
1554 return S_OK;
1556 default:
1557 return E_INVALIDARG;
1561 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
1562 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
1563 const BOOL *value, ULONG size )
1565 WS_XML_UTF8_TEXT utf8;
1566 unsigned char buf[6]; /* "false" */
1567 const BOOL *ptr;
1568 HRESULT hr;
1570 if (desc)
1572 FIXME( "description not supported\n" );
1573 return E_NOTIMPL;
1576 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1577 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
1578 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1580 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1581 utf8.value.bytes = buf;
1582 utf8.value.length = format_bool( ptr, buf );
1583 return write_type_text( writer, mapping, &utf8.text );
1586 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
1587 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
1588 const BOOL *value, ULONG size )
1590 WS_XML_UTF8_TEXT utf8;
1591 unsigned char buf[5]; /* "-128" */
1592 const INT8 *ptr;
1593 HRESULT hr;
1595 if (desc)
1597 FIXME( "description not supported\n" );
1598 return E_NOTIMPL;
1601 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1602 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
1603 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1605 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1606 utf8.value.bytes = buf;
1607 utf8.value.length = format_int8( ptr, buf );
1608 return write_type_text( writer, mapping, &utf8.text );
1611 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
1612 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
1613 const BOOL *value, ULONG size )
1615 WS_XML_UTF8_TEXT utf8;
1616 unsigned char buf[7]; /* "-32768" */
1617 const INT16 *ptr;
1618 HRESULT hr;
1620 if (desc)
1622 FIXME( "description not supported\n" );
1623 return E_NOTIMPL;
1626 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1627 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
1628 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1630 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1631 utf8.value.bytes = buf;
1632 utf8.value.length = format_int16( ptr, buf );
1633 return write_type_text( writer, mapping, &utf8.text );
1636 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
1637 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
1638 const void *value, ULONG size )
1640 WS_XML_UTF8_TEXT utf8;
1641 unsigned char buf[12]; /* "-2147483648" */
1642 const INT32 *ptr;
1643 HRESULT hr;
1645 if (desc)
1647 FIXME( "description not supported\n" );
1648 return E_NOTIMPL;
1651 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1652 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
1653 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1655 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1656 utf8.value.bytes = buf;
1657 utf8.value.length = format_int32( ptr, buf );
1658 return write_type_text( writer, mapping, &utf8.text );
1661 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
1662 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
1663 const void *value, ULONG size )
1665 WS_XML_UTF8_TEXT utf8;
1666 unsigned char buf[21]; /* "-9223372036854775808" */
1667 const INT64 *ptr;
1668 HRESULT hr;
1670 if (desc)
1672 FIXME( "description not supported\n" );
1673 return E_NOTIMPL;
1676 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1677 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
1678 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1680 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1681 utf8.value.bytes = buf;
1682 utf8.value.length = format_int64( ptr, buf );
1683 return write_type_text( writer, mapping, &utf8.text );
1686 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
1687 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
1688 const void *value, ULONG size )
1690 WS_XML_UTF8_TEXT utf8;
1691 unsigned char buf[4]; /* "255" */
1692 const UINT8 *ptr;
1693 HRESULT hr;
1695 if (desc)
1697 FIXME( "description not supported\n" );
1698 return E_NOTIMPL;
1701 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1702 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
1703 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1705 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1706 utf8.value.bytes = buf;
1707 utf8.value.length = format_uint8( ptr, buf );
1708 return write_type_text( writer, mapping, &utf8.text );
1711 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
1712 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
1713 const void *value, ULONG size )
1715 WS_XML_UTF8_TEXT utf8;
1716 unsigned char buf[6]; /* "65535" */
1717 const UINT16 *ptr;
1718 HRESULT hr;
1720 if (desc)
1722 FIXME( "description not supported\n" );
1723 return E_NOTIMPL;
1726 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1727 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
1728 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1730 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1731 utf8.value.bytes = buf;
1732 utf8.value.length = format_uint16( ptr, buf );
1733 return write_type_text( writer, mapping, &utf8.text );
1736 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
1737 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
1738 const void *value, ULONG size )
1740 WS_XML_UTF8_TEXT utf8;
1741 unsigned char buf[11]; /* "4294967295" */
1742 const UINT32 *ptr;
1743 HRESULT hr;
1745 if (desc)
1747 FIXME( "description not supported\n" );
1748 return E_NOTIMPL;
1751 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1752 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
1753 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1755 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1756 utf8.value.bytes = buf;
1757 utf8.value.length = format_uint32( ptr, buf );
1758 return write_type_text( writer, mapping, &utf8.text );
1761 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
1762 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
1763 const void *value, ULONG size )
1765 WS_XML_UTF8_TEXT utf8;
1766 unsigned char buf[21]; /* "18446744073709551615" */
1767 const UINT64 *ptr;
1768 HRESULT hr;
1770 if (desc)
1772 FIXME( "description not supported\n" );
1773 return E_NOTIMPL;
1776 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1777 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
1778 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1780 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1781 utf8.value.bytes = buf;
1782 utf8.value.length = format_uint64( ptr, buf );
1783 return write_type_text( writer, mapping, &utf8.text );
1786 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
1787 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
1788 const void *value, ULONG size )
1790 WS_XML_UTF8_TEXT utf8;
1791 unsigned char buf[34]; /* "0000-00-00T00:00:00.0000000-00:00" */
1792 const WS_DATETIME *ptr;
1793 HRESULT hr;
1795 if (desc)
1797 FIXME( "description not supported\n" );
1798 return E_NOTIMPL;
1801 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1802 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
1803 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1804 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
1806 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1807 utf8.value.bytes = buf;
1808 utf8.value.length = format_datetime( ptr, buf );
1809 return write_type_text( writer, mapping, &utf8.text );
1812 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
1813 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
1814 const void *value, ULONG size )
1816 WS_XML_UTF8_TEXT utf8;
1817 unsigned char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
1818 const GUID *ptr;
1819 HRESULT hr;
1821 if (desc)
1823 FIXME( "description not supported\n" );
1824 return E_NOTIMPL;
1827 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1828 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
1829 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1831 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1832 utf8.value.bytes = buf;
1833 utf8.value.length = format_guid( ptr, buf );
1834 return write_type_text( writer, mapping, &utf8.text );
1837 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
1838 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
1839 const void *value, ULONG size )
1841 WS_XML_UTF16_TEXT utf16;
1842 const WS_STRING *ptr;
1843 HRESULT hr;
1845 if (desc)
1847 FIXME( "description not supported\n" );
1848 return E_NOTIMPL;
1851 if (!option) return E_INVALIDARG;
1852 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
1853 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1854 if (!ptr->length) return S_OK;
1856 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1857 utf16.bytes = (BYTE *)ptr->chars;
1858 utf16.byteCount = ptr->length * sizeof(WCHAR);
1859 return write_type_text( writer, mapping, &utf16.text );
1862 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
1863 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
1864 const void *value, ULONG size )
1866 WS_XML_UTF16_TEXT utf16;
1867 const WCHAR *ptr;
1868 HRESULT hr;
1869 int len;
1871 if (desc)
1873 FIXME( "description not supported\n" );
1874 return E_NOTIMPL;
1877 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
1878 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
1879 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1880 if (!(len = strlenW( ptr ))) return S_OK;
1882 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1883 utf16.bytes = (BYTE *)ptr;
1884 utf16.byteCount = len * sizeof(WCHAR);
1885 return write_type_text( writer, mapping, &utf16.text );
1888 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
1889 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
1890 const void *value, ULONG size )
1892 WS_XML_BASE64_TEXT base64;
1893 const WS_BYTES *ptr;
1894 HRESULT hr;
1896 if (desc)
1898 FIXME( "description not supported\n" );
1899 return E_NOTIMPL;
1902 if (!option) return E_INVALIDARG;
1903 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
1904 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
1905 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
1906 if (!ptr->length) return S_OK;
1908 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
1909 base64.bytes = ptr->bytes;
1910 base64.length = ptr->length;
1911 return write_type_text( writer, mapping, &base64.text );
1914 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
1915 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
1916 const void *value, ULONG size )
1918 WS_XML_UTF8_TEXT utf8;
1919 const WS_XML_STRING *ptr;
1920 HRESULT hr;
1922 if (desc)
1924 FIXME( "description not supported\n" );
1925 return E_NOTIMPL;
1928 if (!option) return E_INVALIDARG;
1929 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
1930 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
1931 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
1932 if (!ptr->length) return S_OK;
1934 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1935 utf8.value.bytes = ptr->bytes;
1936 utf8.value.length = ptr->length;
1937 return write_type_text( writer, mapping, &utf8.text );
1940 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
1942 if (options & WS_FIELD_POINTER)
1944 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
1945 return WS_WRITE_REQUIRED_POINTER;
1948 switch (type)
1950 case WS_BOOL_TYPE:
1951 case WS_INT8_TYPE:
1952 case WS_INT16_TYPE:
1953 case WS_INT32_TYPE:
1954 case WS_INT64_TYPE:
1955 case WS_UINT8_TYPE:
1956 case WS_UINT16_TYPE:
1957 case WS_UINT32_TYPE:
1958 case WS_UINT64_TYPE:
1959 case WS_DOUBLE_TYPE:
1960 case WS_DATETIME_TYPE:
1961 case WS_GUID_TYPE:
1962 case WS_STRING_TYPE:
1963 case WS_BYTES_TYPE:
1964 case WS_XML_STRING_TYPE:
1965 case WS_STRUCT_TYPE:
1966 case WS_ENUM_TYPE:
1967 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
1968 return WS_WRITE_REQUIRED_VALUE;
1970 case WS_WSZ_TYPE:
1971 case WS_DESCRIPTION_TYPE:
1972 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
1973 return WS_WRITE_REQUIRED_POINTER;
1975 default:
1976 FIXME( "unhandled type %u\n", type );
1977 return 0;
1981 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
1982 const void *, ULONG );
1984 static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
1985 const char *buf, ULONG count )
1987 HRESULT hr = S_OK;
1988 ULONG i, size, offset = 0;
1989 WS_WRITE_OPTION option;
1991 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
1993 /* wrapper element */
1994 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
1995 return hr;
1997 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
1998 size = get_type_size( desc->type, desc->typeDescription );
1999 else
2000 size = sizeof(const void *);
2002 for (i = 0; i < count; i++)
2004 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
2005 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
2006 buf + offset, size )) != S_OK) return hr;
2007 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2008 offset += size;
2011 if (desc->localName) hr = write_endelement_node( writer );
2012 return hr;
2015 static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
2016 const char *buf, ULONG offset )
2018 HRESULT hr;
2019 WS_TYPE_MAPPING mapping;
2020 WS_WRITE_OPTION option;
2021 ULONG count, size, field_options = desc->options;
2022 const char *ptr = buf + offset;
2024 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
2026 FIXME( "options 0x%x not supported\n", desc->options );
2027 return E_NOTIMPL;
2030 /* zero-terminated strings are always pointers */
2031 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
2033 if (field_options & WS_FIELD_POINTER)
2034 size = sizeof(const void *);
2035 else
2036 size = get_type_size( desc->type, desc->typeDescription );
2038 if (is_nil_value( ptr, size ))
2040 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
2041 if (field_options & WS_FIELD_NILLABLE)
2043 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
2044 else option = WS_WRITE_NILLABLE_VALUE;
2046 else return E_INVALIDARG;
2048 else
2050 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
2051 else option = WS_WRITE_REQUIRED_VALUE;
2054 switch (desc->mapping)
2056 case WS_ATTRIBUTE_FIELD_MAPPING:
2057 if (!desc->localName || !desc->ns) return E_INVALIDARG;
2058 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
2059 return hr;
2060 writer->state = WRITER_STATE_STARTATTRIBUTE;
2062 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2063 break;
2065 case WS_ELEMENT_FIELD_MAPPING:
2066 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
2067 mapping = WS_ELEMENT_TYPE_MAPPING;
2068 break;
2070 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
2071 count = *(const ULONG *)(buf + desc->countOffset);
2072 return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
2074 case WS_TEXT_FIELD_MAPPING:
2075 switch (writer->state)
2077 case WRITER_STATE_STARTELEMENT:
2078 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
2079 break;
2081 case WRITER_STATE_STARTATTRIBUTE:
2082 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2083 break;
2085 default:
2086 FIXME( "unhandled writer state %u\n", writer->state );
2087 return E_NOTIMPL;
2089 break;
2091 default:
2092 FIXME( "field mapping %u not supported\n", desc->mapping );
2093 return E_NOTIMPL;
2096 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
2097 return hr;
2099 switch (mapping)
2101 case WS_ATTRIBUTE_TYPE_MAPPING:
2102 writer->state = WRITER_STATE_STARTELEMENT;
2103 break;
2105 case WS_ELEMENT_TYPE_MAPPING:
2106 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2107 break;
2109 default: break;
2112 return S_OK;
2115 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
2116 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
2117 const void *value, ULONG size )
2119 ULONG i, offset;
2120 const void *ptr;
2121 HRESULT hr;
2123 if (!desc) return E_INVALIDARG;
2124 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
2126 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
2128 for (i = 0; i < desc->fieldCount; i++)
2130 offset = desc->fields[i]->offset;
2131 if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, offset )) != S_OK)
2132 return hr;
2135 return S_OK;
2139 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
2140 const void *desc, WS_WRITE_OPTION option, const void *value,
2141 ULONG size )
2143 switch (type)
2145 case WS_BOOL_TYPE:
2146 return write_type_bool( writer, mapping, desc, option, value, size );
2148 case WS_INT8_TYPE:
2149 return write_type_int8( writer, mapping, desc, option, value, size );
2151 case WS_INT16_TYPE:
2152 return write_type_int16( writer, mapping, desc, option, value, size );
2154 case WS_INT32_TYPE:
2155 return write_type_int32( writer, mapping, desc, option, value, size );
2157 case WS_INT64_TYPE:
2158 return write_type_int64( writer, mapping, desc, option, value, size );
2160 case WS_UINT8_TYPE:
2161 return write_type_uint8( writer, mapping, desc, option, value, size );
2163 case WS_UINT16_TYPE:
2164 return write_type_uint16( writer, mapping, desc, option, value, size );
2166 case WS_UINT32_TYPE:
2167 return write_type_uint32( writer, mapping, desc, option, value, size );
2169 case WS_UINT64_TYPE:
2170 return write_type_uint64( writer, mapping, desc, option, value, size );
2172 case WS_DATETIME_TYPE:
2173 return write_type_datetime( writer, mapping, desc, option, value, size );
2175 case WS_GUID_TYPE:
2176 return write_type_guid( writer, mapping, desc, option, value, size );
2178 case WS_STRING_TYPE:
2179 return write_type_string( writer, mapping, desc, option, value, size );
2181 case WS_WSZ_TYPE:
2182 return write_type_wsz( writer, mapping, desc, option, value, size );
2184 case WS_BYTES_TYPE:
2185 return write_type_bytes( writer, mapping, desc, option, value, size );
2187 case WS_XML_STRING_TYPE:
2188 return write_type_xml_string( writer, mapping, desc, option, value, size );
2190 case WS_STRUCT_TYPE:
2191 return write_type_struct( writer, mapping, desc, option, value, size );
2193 default:
2194 FIXME( "type %u not supported\n", type );
2195 return E_NOTIMPL;
2199 /**************************************************************************
2200 * WsWriteAttribute [webservices.@]
2202 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
2203 WS_WRITE_OPTION option, const void *value, ULONG size,
2204 WS_ERROR *error )
2206 struct writer *writer = (struct writer *)handle;
2207 HRESULT hr;
2209 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2210 if (error) FIXME( "ignoring error parameter\n" );
2212 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
2213 return E_INVALIDARG;
2215 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
2217 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs,
2218 FALSE )) != S_OK) return hr;
2219 writer->state = WRITER_STATE_STARTATTRIBUTE;
2221 return write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription,
2222 option, value, size );
2225 /**************************************************************************
2226 * WsWriteElement [webservices.@]
2228 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
2229 WS_WRITE_OPTION option, const void *value, ULONG size,
2230 WS_ERROR *error )
2232 struct writer *writer = (struct writer *)handle;
2233 HRESULT hr;
2235 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
2236 if (error) FIXME( "ignoring error parameter\n" );
2238 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
2239 return E_INVALIDARG;
2241 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
2243 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
2244 option, value, size )) != S_OK) return hr;
2246 return write_endelement_node( writer );
2249 /**************************************************************************
2250 * WsWriteType [webservices.@]
2252 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
2253 const void *desc, WS_WRITE_OPTION option, const void *value,
2254 ULONG size, WS_ERROR *error )
2256 struct writer *writer = (struct writer *)handle;
2257 HRESULT hr;
2259 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
2260 size, error );
2261 if (error) FIXME( "ignoring error parameter\n" );
2263 if (!writer || !value) return E_INVALIDARG;
2265 switch (mapping)
2267 case WS_ATTRIBUTE_TYPE_MAPPING:
2268 if (writer->state != WRITER_STATE_STARTATTRIBUTE) return WS_E_INVALID_FORMAT;
2269 hr = write_type( writer, mapping, type, desc, option, value, size );
2270 break;
2272 case WS_ELEMENT_TYPE_MAPPING:
2273 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2274 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_FORMAT;
2275 hr = write_type( writer, mapping, type, desc, option, value, size );
2276 break;
2278 case WS_ANY_ELEMENT_TYPE_MAPPING:
2279 hr = write_type( writer, mapping, type, desc, option, value, size );
2280 break;
2282 default:
2283 FIXME( "mapping %u not implemented\n", mapping );
2284 return E_NOTIMPL;
2287 return hr;
2290 WS_TYPE map_value_type( WS_VALUE_TYPE type )
2292 switch (type)
2294 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
2295 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
2296 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
2297 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
2298 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
2299 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
2300 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
2301 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
2302 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
2303 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
2304 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
2305 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
2306 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
2307 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
2308 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
2309 default:
2310 FIXME( "unhandled type %u\n", type );
2311 return ~0u;
2315 /**************************************************************************
2316 * WsWriteValue [webservices.@]
2318 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
2319 ULONG size, WS_ERROR *error )
2321 struct writer *writer = (struct writer *)handle;
2322 WS_TYPE_MAPPING mapping;
2323 WS_TYPE type;
2325 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
2326 if (error) FIXME( "ignoring error parameter\n" );
2328 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
2330 switch (writer->state)
2332 case WRITER_STATE_STARTATTRIBUTE:
2333 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
2334 break;
2336 case WRITER_STATE_STARTELEMENT:
2337 mapping = WS_ELEMENT_TYPE_MAPPING;
2338 break;
2340 default:
2341 return WS_E_INVALID_FORMAT;
2344 return write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
2347 /**************************************************************************
2348 * WsWriteArray [webservices.@]
2350 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2351 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
2352 ULONG count, WS_ERROR *error )
2354 struct writer *writer = (struct writer *)handle;
2355 WS_TYPE type;
2356 ULONG type_size, i;
2357 HRESULT hr;
2359 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
2360 value_type, array, size, offset, count, error );
2361 if (error) FIXME( "ignoring error parameter\n" );
2363 if (!writer) return E_INVALIDARG;
2364 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2365 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
2367 type_size = get_type_size( type, NULL );
2368 if (size % type_size || (offset + count) * type_size > size || (count && !array)) return E_INVALIDARG;
2370 for (i = offset; i < count; i++)
2372 const char *ptr = (const char *)array + (offset + i) * type_size;
2373 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) return hr;
2374 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
2375 &ptr, sizeof(ptr) )) != S_OK) return hr;
2376 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
2379 return S_OK;
2382 /**************************************************************************
2383 * WsWriteXmlBuffer [webservices.@]
2385 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
2387 struct writer *writer = (struct writer *)handle;
2388 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
2389 HRESULT hr;
2391 TRACE( "%p %p %p\n", handle, buffer, error );
2392 if (error) FIXME( "ignoring error parameter\n" );
2394 if (!writer || !xmlbuf) return E_INVALIDARG;
2396 if ((hr = write_flush( writer )) != S_OK) return hr;
2397 if ((hr = write_grow_buffer( writer, xmlbuf->size )) != S_OK) return hr;
2398 write_bytes( writer, xmlbuf->ptr, xmlbuf->size );
2399 return S_OK;
2402 /**************************************************************************
2403 * WsWriteXmlBufferToBytes [webservices.@]
2405 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
2406 const WS_XML_WRITER_ENCODING *encoding,
2407 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
2408 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
2410 struct writer *writer = (struct writer *)handle;
2411 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
2412 HRESULT hr;
2413 char *buf;
2414 ULONG i;
2416 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
2417 bytes, size, error );
2418 if (error) FIXME( "ignoring error parameter\n" );
2420 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
2422 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
2424 FIXME( "encoding type %u not supported\n", encoding->encodingType );
2425 return E_NOTIMPL;
2428 for (i = 0; i < count; i++)
2430 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
2431 properties[i].valueSize );
2432 if (hr != S_OK) return hr;
2435 if (!(buf = ws_alloc( heap, xmlbuf->size ))) return WS_E_QUOTA_EXCEEDED;
2436 memcpy( buf, xmlbuf->ptr, xmlbuf->size );
2437 *bytes = buf;
2438 *size = xmlbuf->size;
2439 return S_OK;
2442 /**************************************************************************
2443 * WsWriteXmlnsAttribute [webservices.@]
2445 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2446 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
2448 struct writer *writer = (struct writer *)handle;
2450 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
2451 single, error );
2452 if (error) FIXME( "ignoring error parameter\n" );
2454 if (!writer || !ns) return E_INVALIDARG;
2455 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
2457 if (namespace_in_scope( &writer->current->hdr, prefix, ns )) return S_OK;
2458 return write_add_namespace_attribute( writer, prefix, ns, single );
2461 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
2463 BOOL success = FALSE;
2464 struct node *node = writer->current;
2466 switch (move)
2468 case WS_MOVE_TO_ROOT_ELEMENT:
2469 success = move_to_root_element( writer->root, &node );
2470 break;
2472 case WS_MOVE_TO_NEXT_ELEMENT:
2473 success = move_to_next_element( &node );
2474 break;
2476 case WS_MOVE_TO_PREVIOUS_ELEMENT:
2477 success = move_to_prev_element( &node );
2478 break;
2480 case WS_MOVE_TO_CHILD_ELEMENT:
2481 success = move_to_child_element( &node );
2482 break;
2484 case WS_MOVE_TO_END_ELEMENT:
2485 success = move_to_end_element( &node );
2486 break;
2488 case WS_MOVE_TO_PARENT_ELEMENT:
2489 success = move_to_parent_element( &node );
2490 break;
2492 case WS_MOVE_TO_FIRST_NODE:
2493 success = move_to_first_node( &node );
2494 break;
2496 case WS_MOVE_TO_NEXT_NODE:
2497 success = move_to_next_node( &node );
2498 break;
2500 case WS_MOVE_TO_PREVIOUS_NODE:
2501 success = move_to_prev_node( &node );
2502 break;
2504 case WS_MOVE_TO_CHILD_NODE:
2505 success = move_to_child_node( &node );
2506 break;
2508 case WS_MOVE_TO_BOF:
2509 success = move_to_bof( writer->root, &node );
2510 break;
2512 case WS_MOVE_TO_EOF:
2513 success = move_to_eof( writer->root, &node );
2514 break;
2516 default:
2517 FIXME( "unhandled move %u\n", move );
2518 return E_NOTIMPL;
2521 if (success && node == writer->root) return E_INVALIDARG;
2522 writer->current = node;
2524 if (found)
2526 *found = success;
2527 return S_OK;
2529 return success ? S_OK : WS_E_INVALID_FORMAT;
2532 /**************************************************************************
2533 * WsMoveWriter [webservices.@]
2535 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2537 struct writer *writer = (struct writer *)handle;
2539 TRACE( "%p %u %p %p\n", handle, move, found, error );
2540 if (error) FIXME( "ignoring error parameter\n" );
2542 if (!writer) return E_INVALIDARG;
2543 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2545 return write_move_to( writer, move, found );
2548 /**************************************************************************
2549 * WsGetWriterPosition [webservices.@]
2551 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2553 struct writer *writer = (struct writer *)handle;
2555 TRACE( "%p %p %p\n", handle, pos, error );
2556 if (error) FIXME( "ignoring error parameter\n" );
2558 if (!writer || !pos) return E_INVALIDARG;
2559 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2561 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
2562 pos->node = writer->current;
2563 return S_OK;
2566 /**************************************************************************
2567 * WsSetWriterPosition [webservices.@]
2569 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2571 struct writer *writer = (struct writer *)handle;
2573 TRACE( "%p %p %p\n", handle, pos, error );
2574 if (error) FIXME( "ignoring error parameter\n" );
2576 if (!writer || !pos || (struct xmlbuf *)pos->buffer != writer->output_buf) return E_INVALIDARG;
2577 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2579 writer->current = pos->node;
2580 return S_OK;
2583 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
2585 struct node *node, *parent;
2586 WS_XML_COMMENT_NODE *comment;
2588 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2589 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2590 comment = (WS_XML_COMMENT_NODE *)node;
2592 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
2594 free_node( node );
2595 return E_OUTOFMEMORY;
2597 memcpy( comment->value.bytes, value->bytes, value->length );
2598 comment->value.length = value->length;
2600 write_insert_node( writer, parent, node );
2601 return S_OK;
2604 static HRESULT write_comment( struct writer *writer )
2606 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
2607 HRESULT hr;
2609 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
2610 write_bytes( writer, (const BYTE *)"<!--", 4 );
2611 write_bytes( writer, comment->value.bytes, comment->value.length );
2612 write_bytes( writer, (const BYTE *)"-->", 3 );
2613 return S_OK;
2616 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
2618 HRESULT hr;
2619 if ((hr = write_flush( writer )) != S_OK) return hr;
2620 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
2621 if ((hr = write_comment( writer )) != S_OK) return hr;
2622 writer->state = WRITER_STATE_COMMENT;
2623 return S_OK;
2626 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
2628 ULONG i;
2629 HRESULT hr;
2631 for (i = 0; i < count; i++)
2633 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
2634 attrs[i]->singleQuote )) != S_OK) return hr;
2635 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
2637 return S_OK;
2640 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
2642 HRESULT hr;
2644 switch (node->nodeType)
2646 case WS_XML_NODE_TYPE_ELEMENT:
2648 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
2649 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
2650 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
2652 case WS_XML_NODE_TYPE_TEXT:
2654 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
2655 return write_text_node( writer, text->text );
2657 case WS_XML_NODE_TYPE_END_ELEMENT:
2658 return write_endelement_node( writer );
2660 case WS_XML_NODE_TYPE_COMMENT:
2662 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
2663 return write_comment_node( writer, &comment->value );
2665 case WS_XML_NODE_TYPE_CDATA:
2666 return write_cdata_node( writer );
2668 case WS_XML_NODE_TYPE_END_CDATA:
2669 return write_endcdata_node( writer );
2671 case WS_XML_NODE_TYPE_EOF:
2672 case WS_XML_NODE_TYPE_BOF:
2673 return S_OK;
2675 default:
2676 WARN( "unknown node type %u\n", node->nodeType );
2677 return E_INVALIDARG;
2681 /**************************************************************************
2682 * WsWriteNode [webservices.@]
2684 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
2686 struct writer *writer = (struct writer *)handle;
2688 TRACE( "%p %p %p\n", handle, node, error );
2689 if (error) FIXME( "ignoring error parameter\n" );
2691 if (!writer || !node) return E_INVALIDARG;
2692 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2694 return write_node( writer, node );
2697 static HRESULT write_tree_node( struct writer *writer )
2699 HRESULT hr;
2701 switch (node_type( writer->current ))
2703 case WS_XML_NODE_TYPE_ELEMENT:
2704 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2705 return hr;
2706 if ((hr = write_startelement( writer )) != S_OK) return hr;
2707 writer->state = WRITER_STATE_STARTELEMENT;
2708 return S_OK;
2710 case WS_XML_NODE_TYPE_TEXT:
2711 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2712 return hr;
2713 if ((hr = write_text( writer )) != S_OK) return hr;
2714 writer->state = WRITER_STATE_TEXT;
2715 return S_OK;
2717 case WS_XML_NODE_TYPE_END_ELEMENT:
2718 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
2719 writer->state = WRITER_STATE_ENDELEMENT;
2720 return S_OK;
2722 case WS_XML_NODE_TYPE_COMMENT:
2723 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2724 return hr;
2725 if ((hr = write_comment( writer )) != S_OK) return hr;
2726 writer->state = WRITER_STATE_COMMENT;
2727 return S_OK;
2729 case WS_XML_NODE_TYPE_CDATA:
2730 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2731 return hr;
2732 if ((hr = write_cdata( writer )) != S_OK) return hr;
2733 writer->state = WRITER_STATE_STARTCDATA;
2734 return S_OK;
2736 case WS_XML_NODE_TYPE_END_CDATA:
2737 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2738 writer->state = WRITER_STATE_ENDCDATA;
2739 return S_OK;
2741 case WS_XML_NODE_TYPE_EOF:
2742 case WS_XML_NODE_TYPE_BOF:
2743 return S_OK;
2745 default:
2746 ERR( "unknown node type %u\n", node_type(writer->current) );
2747 return E_INVALIDARG;
2751 static HRESULT write_tree( struct writer *writer )
2753 HRESULT hr;
2755 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2756 for (;;)
2758 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
2759 if (move_to_child_node( &writer->current ))
2761 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2762 continue;
2764 if (move_to_next_node( &writer->current ))
2766 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2767 continue;
2769 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
2771 ERR( "invalid tree\n" );
2772 return WS_E_INVALID_FORMAT;
2774 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2776 return S_OK;
2779 static void write_rewind( struct writer *writer )
2781 writer->write_pos = 0;
2782 writer->current = writer->root;
2783 writer->state = WRITER_STATE_INITIAL;
2786 /**************************************************************************
2787 * WsCopyNode [webservices.@]
2789 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
2791 struct writer *writer = (struct writer *)handle;
2792 struct node *parent, *current = writer->current, *node = NULL;
2793 HRESULT hr;
2795 TRACE( "%p %p %p\n", handle, reader, error );
2796 if (error) FIXME( "ignoring error parameter\n" );
2798 if (!writer) return E_INVALIDARG;
2799 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2801 if ((hr = copy_node( reader, &node )) != S_OK) return hr;
2802 write_insert_node( writer, parent, node );
2804 write_rewind( writer );
2805 if ((hr = write_tree( writer )) != S_OK) return hr;
2807 writer->current = current;
2808 return S_OK;
2811 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
2813 return write_type_struct_field( writer, desc, value, 0 );
2816 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
2818 ULONG i, ret = 0;
2819 for (i = 0; i < count; i++)
2821 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
2822 continue;
2823 if (args[i]) ret = *(const ULONG *)args[i];
2824 break;
2826 return ret;
2829 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
2830 ULONG len )
2832 return write_type_repeating_element( writer, desc, value, len );
2835 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
2836 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
2838 struct writer *writer = (struct writer *)handle;
2839 const WS_STRUCT_DESCRIPTION *desc_struct;
2840 const WS_FIELD_DESCRIPTION *desc_field;
2841 HRESULT hr;
2842 ULONG i;
2844 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
2846 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
2848 for (i = 0; i < count; i++)
2850 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
2851 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
2853 FIXME( "messages type not supported\n" );
2854 return E_NOTIMPL;
2856 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) return hr;
2857 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
2859 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) return hr;
2861 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
2863 const void *ptr = *(const void **)args[i];
2864 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
2865 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) return hr;
2869 return write_endelement_node( writer );