strmbase: Avoid a COM object to interface cast.
[wine.git] / dlls / webservices / writer.c
blob452ee46d673ab92bd9e57aff462f400c2c001469
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 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
430 WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
431 unsigned char quote = attr->singleQuote ? '\'' : '"';
432 const WS_XML_STRING *prefix;
433 ULONG size;
434 HRESULT hr;
436 if (attr->prefix) prefix = attr->prefix;
437 else prefix = writer->current->hdr.prefix;
439 /* ' prefix:attr="value"' */
441 size = attr->localName->length + 4 /* ' =""' */;
442 if (prefix) size += prefix->length + 1 /* ':' */;
443 if (text) size += text->value.length;
444 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
446 write_char( writer, ' ' );
447 if (prefix)
449 write_bytes( writer, prefix->bytes, prefix->length );
450 write_char( writer, ':' );
452 write_bytes( writer, attr->localName->bytes, attr->localName->length );
453 write_char( writer, '=' );
454 write_char( writer, quote );
455 if (text) write_bytes( writer, text->value.bytes, text->value.length );
456 write_char( writer, quote );
458 return S_OK;
461 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
463 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
466 /**************************************************************************
467 * WsGetPrefixFromNamespace [webservices.@]
469 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
470 BOOL required, const WS_XML_STRING **prefix,
471 WS_ERROR *error )
473 struct writer *writer = (struct writer *)handle;
474 WS_XML_ELEMENT_NODE *elem;
475 BOOL found = FALSE;
477 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
478 if (error) FIXME( "ignoring error parameter\n" );
480 if (!writer || !ns || !prefix) return E_INVALIDARG;
482 elem = &writer->current->hdr;
483 if (elem->prefix && is_current_namespace( writer, ns ))
485 *prefix = elem->prefix;
486 found = TRUE;
488 if (!found)
490 if (required) return WS_E_INVALID_FORMAT;
491 *prefix = NULL;
492 return S_FALSE;
494 return S_OK;
497 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
499 WS_XML_STRING *str;
500 if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
501 heap_free( writer->current_ns );
502 writer->current_ns = str;
503 return S_OK;
506 static HRESULT write_namespace_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
508 unsigned char quote = attr->singleQuote ? '\'' : '"';
509 ULONG size;
510 HRESULT hr;
512 /* ' xmlns:prefix="namespace"' */
514 size = attr->ns->length + 9 /* ' xmlns=""' */;
515 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
516 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
518 write_bytes( writer, (const BYTE *)" xmlns", 6 );
519 if (attr->prefix)
521 write_char( writer, ':' );
522 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
524 write_char( writer, '=' );
525 write_char( writer, quote );
526 write_bytes( writer, attr->ns->bytes, attr->ns->length );
527 write_char( writer, quote );
529 return S_OK;
532 static HRESULT write_add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
533 const WS_XML_STRING *ns, BOOL single )
535 WS_XML_ATTRIBUTE *attr;
536 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
537 HRESULT hr;
539 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
541 attr->singleQuote = !!single;
542 attr->isXmlNs = 1;
543 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
545 free_attribute( attr );
546 return E_OUTOFMEMORY;
548 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
550 free_attribute( attr );
551 return E_OUTOFMEMORY;
553 if ((hr = append_attribute( elem, attr )) != S_OK)
555 free_attribute( attr );
556 return hr;
558 return S_OK;
561 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
562 const WS_XML_STRING *ns )
564 ULONG i;
565 const struct node *node;
567 for (node = (const struct node *)elem; node; node = node->parent)
569 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
571 elem = &node->hdr;
572 for (i = 0; i < elem->attributeCount; i++)
574 if (!elem->attributes[i]->isXmlNs) continue;
575 if (WsXmlStringEquals( elem->attributes[i]->prefix, prefix, NULL ) == S_OK &&
576 WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) == S_OK)
578 return TRUE;
582 return FALSE;
585 static HRESULT write_set_element_namespace( struct writer *writer )
587 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
588 HRESULT hr;
590 if (!elem->ns->length || is_current_namespace( writer, elem->ns ) ||
591 namespace_in_scope( elem, elem->prefix, elem->ns )) return S_OK;
593 if ((hr = write_add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK)
594 return hr;
596 return set_current_namespace( writer, elem->ns );
599 /**************************************************************************
600 * WsWriteEndAttribute [webservices.@]
602 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
604 struct writer *writer = (struct writer *)handle;
606 TRACE( "%p %p\n", handle, error );
607 if (error) FIXME( "ignoring error parameter\n" );
609 if (!writer) return E_INVALIDARG;
611 writer->state = WRITER_STATE_STARTELEMENT;
612 return S_OK;
615 static HRESULT write_startelement( struct writer *writer )
617 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
618 ULONG size, i;
619 HRESULT hr;
621 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
623 size = elem->localName->length + 1 /* '<' */;
624 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
625 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
627 write_char( writer, '<' );
628 if (elem->prefix)
630 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
631 write_char( writer, ':' );
633 write_bytes( writer, elem->localName->bytes, elem->localName->length );
634 for (i = 0; i < elem->attributeCount; i++)
636 if (elem->attributes[i]->isXmlNs) continue;
637 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
639 for (i = 0; i < elem->attributeCount; i++)
641 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
642 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
644 for (i = 0; i < elem->attributeCount; i++)
646 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
647 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
649 return S_OK;
652 static struct node *write_find_startelement( struct writer *writer )
654 struct node *node;
655 for (node = writer->current; node; node = node->parent)
657 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
659 return NULL;
662 static inline BOOL is_empty_element( const struct node *node )
664 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
665 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
668 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
670 ULONG size;
671 HRESULT hr;
673 /* '/>' */
675 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
677 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
678 write_char( writer, '/' );
679 write_char( writer, '>' );
680 return S_OK;
683 /* '</prefix:localname>' */
685 size = elem->localName->length + 3 /* '</>' */;
686 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
687 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
689 write_char( writer, '<' );
690 write_char( writer, '/' );
691 if (elem->prefix)
693 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
694 write_char( writer, ':' );
696 write_bytes( writer, elem->localName->bytes, elem->localName->length );
697 write_char( writer, '>' );
698 return S_OK;
701 static HRESULT write_close_element( struct writer *writer, struct node *node )
703 WS_XML_ELEMENT_NODE *elem = &node->hdr;
704 elem->isEmpty = is_empty_element( node );
705 return write_endelement( writer, elem );
708 static HRESULT write_endelement_node( struct writer *writer )
710 struct node *node;
711 HRESULT hr;
713 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
714 if (writer->state == WRITER_STATE_STARTELEMENT)
716 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
717 if ((hr = write_startelement( writer )) != S_OK) return hr;
719 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
720 writer->current = node->parent;
721 writer->state = WRITER_STATE_ENDELEMENT;
722 return S_OK;
725 /**************************************************************************
726 * WsWriteEndElement [webservices.@]
728 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
730 struct writer *writer = (struct writer *)handle;
732 TRACE( "%p %p\n", handle, error );
733 if (error) FIXME( "ignoring error parameter\n" );
735 if (!writer) return E_INVALIDARG;
736 return write_endelement_node( writer );
739 static HRESULT write_endstartelement( struct writer *writer )
741 HRESULT hr;
742 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
743 write_char( writer, '>' );
744 return S_OK;
747 /**************************************************************************
748 * WsWriteEndStartElement [webservices.@]
750 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
752 struct writer *writer = (struct writer *)handle;
753 HRESULT hr;
755 TRACE( "%p %p\n", handle, error );
756 if (error) FIXME( "ignoring error parameter\n" );
758 if (!writer) return E_INVALIDARG;
759 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
761 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
762 if ((hr = write_startelement( writer )) != S_OK) return hr;
763 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
765 writer->state = WRITER_STATE_ENDSTARTELEMENT;
766 return S_OK;
769 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
770 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
771 BOOL single )
773 WS_XML_ATTRIBUTE *attr;
774 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
775 HRESULT hr;
777 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
779 if (!prefix) prefix = elem->prefix;
781 attr->singleQuote = !!single;
782 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
784 free_attribute( attr );
785 return E_OUTOFMEMORY;
787 if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
789 free_attribute( attr );
790 return E_OUTOFMEMORY;
792 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
794 free_attribute( attr );
795 return E_OUTOFMEMORY;
797 if ((hr = append_attribute( elem, attr )) != S_OK)
799 free_attribute( attr );
800 return hr;
802 return S_OK;
805 /**************************************************************************
806 * WsWriteStartAttribute [webservices.@]
808 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
809 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
810 BOOL single, WS_ERROR *error )
812 struct writer *writer = (struct writer *)handle;
813 HRESULT hr;
815 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
816 debugstr_xmlstr(ns), single, error );
817 if (error) FIXME( "ignoring error parameter\n" );
819 if (!writer || !localname || !ns) return E_INVALIDARG;
821 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
823 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
824 writer->state = WRITER_STATE_STARTATTRIBUTE;
825 return S_OK;
828 /* flush current start element if necessary */
829 static HRESULT write_flush( struct writer *writer )
831 if (writer->state == WRITER_STATE_STARTELEMENT)
833 HRESULT hr;
834 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
835 if ((hr = write_startelement( writer )) != S_OK) return hr;
836 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
837 writer->state = WRITER_STATE_ENDSTARTELEMENT;
839 return S_OK;
842 static HRESULT write_add_cdata_node( struct writer *writer )
844 struct node *node, *parent;
845 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
846 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
847 write_insert_node( writer, parent, node );
848 return S_OK;
851 static HRESULT write_add_endcdata_node( struct writer *writer )
853 struct node *node;
854 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
855 node->parent = writer->current;
856 list_add_tail( &node->parent->children, &node->entry );
857 return S_OK;
860 static HRESULT write_cdata( struct writer *writer )
862 HRESULT hr;
863 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
864 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
865 return S_OK;
868 static HRESULT write_cdata_node( struct writer *writer )
870 HRESULT hr;
871 if ((hr = write_flush( writer )) != S_OK) return hr;
872 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
873 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
874 if ((hr = write_cdata( writer )) != S_OK) return hr;
875 writer->state = WRITER_STATE_STARTCDATA;
876 return S_OK;
879 /**************************************************************************
880 * WsWriteStartCData [webservices.@]
882 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
884 struct writer *writer = (struct writer *)handle;
886 TRACE( "%p %p\n", handle, error );
887 if (error) FIXME( "ignoring error parameter\n" );
889 if (!writer) return E_INVALIDARG;
890 return write_cdata_node( writer );
893 static HRESULT write_endcdata( struct writer *writer )
895 HRESULT hr;
896 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
897 write_bytes( writer, (const BYTE *)"]]>", 3 );
898 return S_OK;
901 static HRESULT write_endcdata_node( struct writer *writer )
903 HRESULT hr;
904 if ((hr = write_endcdata( writer )) != S_OK) return hr;
905 writer->current = writer->current->parent;
906 writer->state = WRITER_STATE_ENDCDATA;
907 return S_OK;
910 /**************************************************************************
911 * WsWriteEndCData [webservices.@]
913 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
915 struct writer *writer = (struct writer *)handle;
917 TRACE( "%p %p\n", handle, error );
918 if (error) FIXME( "ignoring error parameter\n" );
920 if (!writer) return E_INVALIDARG;
921 if (writer->state != WRITER_STATE_TEXT) return WS_E_INVALID_OPERATION;
923 return write_endcdata_node( writer );
926 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
927 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
929 struct node *node, *parent;
930 WS_XML_ELEMENT_NODE *elem;
932 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
934 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
936 elem = &parent->hdr;
937 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
940 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
941 elem = &node->hdr;
943 if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
945 free_node( node );
946 return E_OUTOFMEMORY;
948 if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
950 free_node( node );
951 return E_OUTOFMEMORY;
953 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
955 free_node( node );
956 return E_OUTOFMEMORY;
958 write_insert_node( writer, parent, node );
959 return S_OK;
962 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
964 struct node *node;
965 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
966 node->parent = parent;
967 list_add_tail( &parent->children, &node->entry );
968 return S_OK;
971 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
972 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
974 HRESULT hr;
975 if ((hr = write_flush( writer )) != S_OK) return hr;
976 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
977 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
978 writer->state = WRITER_STATE_STARTELEMENT;
979 return S_OK;
982 /**************************************************************************
983 * WsWriteStartElement [webservices.@]
985 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
986 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
987 WS_ERROR *error )
989 struct writer *writer = (struct writer *)handle;
991 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
992 debugstr_xmlstr(ns), error );
993 if (error) FIXME( "ignoring error parameter\n" );
995 if (!writer || !localname || !ns) return E_INVALIDARG;
996 return write_element_node( writer, prefix, localname, ns );
999 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1001 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1002 if (*ptr)
1004 memcpy( buf, bool_true, sizeof(bool_true) );
1005 return sizeof(bool_true);
1007 memcpy( buf, bool_false, sizeof(bool_false) );
1008 return sizeof(bool_false);
1011 static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
1013 return wsprintfA( (char *)buf, "%d", *ptr );
1016 static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
1018 return wsprintfA( (char *)buf, "%d", *ptr );
1021 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1023 return wsprintfA( (char *)buf, "%d", *ptr );
1026 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1028 return wsprintfA( (char *)buf, "%I64d", *ptr );
1031 static ULONG format_uint8( const UINT8 *ptr, unsigned char *buf )
1033 return wsprintfA( (char *)buf, "%u", *ptr );
1036 static ULONG format_uint16( const UINT16 *ptr, unsigned char *buf )
1038 return wsprintfA( (char *)buf, "%u", *ptr );
1041 static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
1043 return wsprintfA( (char *)buf, "%u", *ptr );
1046 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1048 return wsprintfA( (char *)buf, "%I64u", *ptr );
1051 static ULONG format_double( const double *ptr, unsigned char *buf )
1053 #ifdef HAVE_POWL
1054 static const long double precision = 0.0000000000000001;
1055 unsigned char *p = buf;
1056 long double val = *ptr;
1057 int neg, mag, mag2, use_exp;
1059 if (isnan( val ))
1061 memcpy( buf, "NaN", 3 );
1062 return 3;
1064 if (isinf( val ))
1066 if (val < 0)
1068 memcpy( buf, "-INF", 4 );
1069 return 4;
1071 memcpy( buf, "INF", 3 );
1072 return 3;
1074 if (val == 0.0)
1076 *p = '0';
1077 return 1;
1080 if ((neg = val < 0))
1082 *p++ = '-';
1083 val = -val;
1086 mag = log10l( val );
1087 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1088 if (use_exp)
1090 if (mag < 0) mag -= 1;
1091 val = val / powl( 10.0, mag );
1092 mag2 = mag;
1093 mag = 0;
1095 else if (mag < 1) mag = 0;
1097 while (val > precision || mag >= 0)
1099 long double weight = powl( 10.0, mag );
1100 if (weight > 0 && !isinf( weight ))
1102 int digit = floorl( val / weight );
1103 val -= digit * weight;
1104 *(p++) = '0' + digit;
1106 if (!mag && val > precision) *(p++) = '.';
1107 mag--;
1110 if (use_exp)
1112 int i, j;
1113 *(p++) = 'E';
1114 if (mag2 > 0) *(p++) = '+';
1115 else
1117 *(p++) = '-';
1118 mag2 = -mag2;
1120 mag = 0;
1121 while (mag2 > 0)
1123 *(p++) = '0' + mag2 % 10;
1124 mag2 /= 10;
1125 mag++;
1127 for (i = -mag, j = -1; i < j; i++, j--)
1129 p[i] ^= p[j];
1130 p[j] ^= p[i];
1131 p[i] ^= p[j];
1135 return p - buf;
1136 #else
1137 FIXME( "powl not found at build time\n" );
1138 return 0;
1139 #endif
1142 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1144 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1145 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1146 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1147 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1150 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1152 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1153 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1154 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1155 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1158 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret )
1160 switch (text->textType)
1162 case WS_XML_TEXT_TYPE_UTF8:
1164 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1165 if (!(*ret = alloc_utf8_text( src->value.bytes, src->value.length ))) return E_OUTOFMEMORY;
1166 return S_OK;
1168 case WS_XML_TEXT_TYPE_UTF16:
1170 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1171 const WCHAR *str = (const WCHAR *)src->bytes;
1172 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1174 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1175 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1176 if (!(*ret = alloc_utf8_text( NULL, len_utf8 ))) return E_OUTOFMEMORY;
1177 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes, (*ret)->value.length, NULL, NULL );
1178 return S_OK;
1180 case WS_XML_TEXT_TYPE_BOOL:
1182 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1183 if (!(*ret = alloc_utf8_text( NULL, 5 ))) return E_OUTOFMEMORY;
1184 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes );
1185 return S_OK;
1187 case WS_XML_TEXT_TYPE_INT32:
1189 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1190 unsigned char buf[12]; /* "-2147483648" */
1191 ULONG len = format_int32( &int32_text->value, buf );
1192 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1193 return S_OK;
1195 case WS_XML_TEXT_TYPE_INT64:
1197 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1198 unsigned char buf[21]; /* "-9223372036854775808" */
1199 ULONG len = format_int64( &int64_text->value, buf );
1200 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1201 return S_OK;
1203 case WS_XML_TEXT_TYPE_UINT64:
1205 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1206 unsigned char buf[21]; /* "18446744073709551615" */
1207 ULONG len = format_uint64( &uint64_text->value, buf );
1208 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1209 return S_OK;
1211 case WS_XML_TEXT_TYPE_DOUBLE:
1213 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1214 unsigned char buf[24]; /* "-1.1111111111111111E-308" */
1215 unsigned short fpword;
1216 ULONG len;
1218 if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
1219 len = format_double( &double_text->value, buf );
1220 restore_fp_rounding( fpword );
1221 if (!len) return E_NOTIMPL;
1222 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1223 return S_OK;
1225 case WS_XML_TEXT_TYPE_GUID:
1227 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1228 if (!(*ret = alloc_utf8_text( NULL, 37 ))) return E_OUTOFMEMORY;
1229 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes );
1230 return S_OK;
1232 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1234 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1235 if (!(*ret = alloc_utf8_text( NULL, 46 ))) return E_OUTOFMEMORY;
1236 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes );
1237 return S_OK;
1239 default:
1240 FIXME( "unhandled text type %u\n", text->textType );
1241 return E_NOTIMPL;
1245 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
1247 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1248 WS_XML_UTF8_TEXT *utf8;
1249 HRESULT hr;
1251 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK) return hr;
1252 elem->attributes[elem->attributeCount - 1]->value = &utf8->text;
1253 return S_OK;
1256 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
1258 struct node *node;
1259 WS_XML_TEXT_NODE *text;
1260 WS_XML_UTF8_TEXT *utf8;
1261 HRESULT hr;
1263 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
1264 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
1265 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
1267 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1268 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK)
1270 heap_free( node );
1271 return hr;
1273 text = (WS_XML_TEXT_NODE *)node;
1274 text->text = &utf8->text;
1276 write_insert_node( writer, writer->current, node );
1277 return S_OK;
1280 static HRESULT write_text( struct writer *writer )
1282 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)writer->current;
1283 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
1284 HRESULT hr;
1286 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
1287 write_bytes( writer, utf8->value.bytes, utf8->value.length );
1288 return S_OK;
1291 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
1293 HRESULT hr;
1294 if ((hr = write_flush( writer )) != S_OK) return hr;
1295 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
1296 if ((hr = write_text( writer )) != S_OK) return hr;
1297 writer->state = WRITER_STATE_TEXT;
1298 return S_OK;
1301 /**************************************************************************
1302 * WsWriteText [webservices.@]
1304 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
1306 struct writer *writer = (struct writer *)handle;
1308 TRACE( "%p %p %p\n", handle, text, error );
1310 if (!writer || !text) return E_INVALIDARG;
1312 if (writer->state == WRITER_STATE_STARTATTRIBUTE) return write_set_attribute_value( writer, text );
1313 return write_text_node( writer, text );
1316 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
1318 switch (mapping)
1320 case WS_ELEMENT_TYPE_MAPPING:
1321 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1322 return write_text_node( writer, text );
1324 case WS_ATTRIBUTE_TYPE_MAPPING:
1325 return write_set_attribute_value( writer, text );
1327 case WS_ANY_ELEMENT_TYPE_MAPPING:
1328 switch (writer->state)
1330 case WRITER_STATE_STARTATTRIBUTE:
1331 return write_set_attribute_value( writer, text );
1333 case WRITER_STATE_STARTELEMENT:
1334 return write_text_node( writer, text );
1336 default:
1337 FIXME( "writer state %u not handled\n", writer->state );
1338 return E_NOTIMPL;
1341 default:
1342 FIXME( "mapping %u not implemented\n", mapping );
1343 return E_NOTIMPL;
1347 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
1348 const WS_BOOL_DESCRIPTION *desc, const BOOL *value )
1350 WS_XML_UTF8_TEXT utf8;
1351 unsigned char buf[6]; /* "false" */
1353 if (desc)
1355 FIXME( "description not supported\n" );
1356 return E_NOTIMPL;
1358 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1359 utf8.value.bytes = buf;
1360 utf8.value.length = format_bool( value, buf );
1361 return write_type_text( writer, mapping, &utf8.text );
1364 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
1365 const WS_INT8_DESCRIPTION *desc, const INT8 *value )
1367 WS_XML_UTF8_TEXT utf8;
1368 unsigned char buf[5]; /* "-128" */
1370 if (desc)
1372 FIXME( "description not supported\n" );
1373 return E_NOTIMPL;
1375 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1376 utf8.value.bytes = buf;
1377 utf8.value.length = format_int8( value, buf );
1378 return write_type_text( writer, mapping, &utf8.text );
1381 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
1382 const WS_INT16_DESCRIPTION *desc, const INT16 *value )
1384 WS_XML_UTF8_TEXT utf8;
1385 unsigned char buf[7]; /* "-32768" */
1387 if (desc)
1389 FIXME( "description not supported\n" );
1390 return E_NOTIMPL;
1392 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1393 utf8.value.bytes = buf;
1394 utf8.value.length = format_int16( value, buf );
1395 return write_type_text( writer, mapping, &utf8.text );
1398 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
1399 const WS_INT32_DESCRIPTION *desc, const INT32 *value )
1401 WS_XML_UTF8_TEXT utf8;
1402 unsigned char buf[12]; /* "-2147483648" */
1404 if (desc)
1406 FIXME( "description not supported\n" );
1407 return E_NOTIMPL;
1409 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1410 utf8.value.bytes = buf;
1411 utf8.value.length = format_int32( value, buf );
1412 return write_type_text( writer, mapping, &utf8.text );
1415 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
1416 const WS_INT64_DESCRIPTION *desc, const INT64 *value )
1418 WS_XML_UTF8_TEXT utf8;
1419 unsigned char buf[21]; /* "-9223372036854775808" */
1421 if (desc)
1423 FIXME( "description not supported\n" );
1424 return E_NOTIMPL;
1426 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1427 utf8.value.bytes = buf;
1428 utf8.value.length = format_int64( value, buf );
1429 return write_type_text( writer, mapping, &utf8.text );
1432 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
1433 const WS_UINT8_DESCRIPTION *desc, const UINT8 *value )
1435 WS_XML_UTF8_TEXT utf8;
1436 unsigned char buf[4]; /* "255" */
1438 if (desc)
1440 FIXME( "description not supported\n" );
1441 return E_NOTIMPL;
1443 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1444 utf8.value.bytes = buf;
1445 utf8.value.length = format_uint8( value, buf );
1446 return write_type_text( writer, mapping, &utf8.text );
1449 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
1450 const WS_UINT16_DESCRIPTION *desc, const UINT16 *value )
1452 WS_XML_UTF8_TEXT utf8;
1453 unsigned char buf[6]; /* "65535" */
1455 if (desc)
1457 FIXME( "description not supported\n" );
1458 return E_NOTIMPL;
1460 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1461 utf8.value.bytes = buf;
1462 utf8.value.length = format_uint16( value, buf );
1463 return write_type_text( writer, mapping, &utf8.text );
1466 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
1467 const WS_UINT32_DESCRIPTION *desc, const UINT32 *value )
1469 WS_XML_UTF8_TEXT utf8;
1470 unsigned char buf[11]; /* "4294967295" */
1472 if (desc)
1474 FIXME( "description not supported\n" );
1475 return E_NOTIMPL;
1477 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1478 utf8.value.bytes = buf;
1479 utf8.value.length = format_uint32( value, buf );
1480 return write_type_text( writer, mapping, &utf8.text );
1483 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
1484 const WS_UINT64_DESCRIPTION *desc, const UINT64 *value )
1486 WS_XML_UTF8_TEXT utf8;
1487 unsigned char buf[21]; /* "18446744073709551615" */
1489 if (desc)
1491 FIXME( "description not supported\n" );
1492 return E_NOTIMPL;
1494 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1495 utf8.value.bytes = buf;
1496 utf8.value.length = format_uint64( value, buf );
1497 return write_type_text( writer, mapping, &utf8.text );
1500 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
1501 const WS_WSZ_DESCRIPTION *desc, const WCHAR *value )
1503 WS_XML_UTF16_TEXT utf16;
1505 if (desc)
1507 FIXME( "description not supported\n" );
1508 return E_NOTIMPL;
1510 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1511 utf16.bytes = (BYTE *)value;
1512 utf16.byteCount = strlenW( value ) * sizeof(WCHAR);
1513 return write_type_text( writer, mapping, &utf16.text );
1516 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
1517 const void *, ULONG );
1519 static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
1520 const void *value, ULONG size )
1522 HRESULT hr;
1523 WS_TYPE_MAPPING mapping;
1524 WS_WRITE_OPTION option;
1526 if (!desc->options || desc->options == WS_FIELD_OPTIONAL) option = 0;
1527 else if (desc->options == WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
1528 else
1530 FIXME( "options 0x%x not supported\n", desc->options );
1531 return E_NOTIMPL;
1534 switch (desc->mapping)
1536 case WS_ATTRIBUTE_FIELD_MAPPING:
1537 if (!desc->localName || !desc->ns) return E_INVALIDARG;
1538 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
1539 return hr;
1540 writer->state = WRITER_STATE_STARTATTRIBUTE;
1542 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1543 break;
1545 case WS_ELEMENT_FIELD_MAPPING:
1546 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
1547 mapping = WS_ELEMENT_TYPE_MAPPING;
1548 break;
1550 case WS_TEXT_FIELD_MAPPING:
1551 switch (writer->state)
1553 case WRITER_STATE_STARTELEMENT:
1554 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
1555 break;
1557 case WRITER_STATE_STARTATTRIBUTE:
1558 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1559 break;
1561 default:
1562 FIXME( "unhandled writer state %u\n", writer->state );
1563 return E_NOTIMPL;
1565 break;
1567 default:
1568 FIXME( "field mapping %u not supported\n", desc->mapping );
1569 return E_NOTIMPL;
1572 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK)
1573 return hr;
1575 switch (mapping)
1577 case WS_ATTRIBUTE_TYPE_MAPPING:
1578 writer->state = WRITER_STATE_STARTELEMENT;
1579 break;
1581 case WS_ELEMENT_TYPE_MAPPING:
1582 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
1583 break;
1585 default: break;
1588 return S_OK;
1591 static ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index )
1593 if (index < desc->fieldCount - 1) return desc->fields[index + 1]->offset - desc->fields[index]->offset;
1594 return desc->size - desc->fields[index]->offset;
1597 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
1598 const WS_STRUCT_DESCRIPTION *desc, const void *value )
1600 ULONG i, size;
1601 HRESULT hr;
1602 const char *ptr;
1604 if (desc->structOptions)
1606 FIXME( "struct options 0x%x not supported\n", desc->structOptions );
1607 return E_NOTIMPL;
1610 for (i = 0; i < desc->fieldCount; i++)
1612 ptr = (const char *)value + desc->fields[i]->offset;
1613 size = get_field_size( desc, i );
1614 if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, size )) != S_OK)
1615 return hr;
1618 return S_OK;
1621 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, const void **ptr )
1623 switch (option)
1625 case WS_WRITE_REQUIRED_VALUE:
1626 if (!value || !size) return E_INVALIDARG;
1627 *ptr = value;
1628 return S_OK;
1630 case WS_WRITE_REQUIRED_POINTER:
1631 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
1632 return S_OK;
1634 default:
1635 FIXME( "option %08x not supported\n", option );
1636 return E_NOTIMPL;
1640 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
1641 const void *desc, WS_WRITE_OPTION option, const void *value,
1642 ULONG size )
1644 HRESULT hr;
1646 switch (type)
1648 case WS_STRUCT_TYPE:
1650 const void *ptr;
1652 if (!desc || option == WS_WRITE_REQUIRED_VALUE) return E_INVALIDARG;
1654 if (!option) option = WS_WRITE_REQUIRED_POINTER;
1655 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1656 return write_type_struct( writer, mapping, desc, ptr );
1658 case WS_BOOL_TYPE:
1660 const BOOL *ptr;
1661 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1662 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1663 return write_type_bool( writer, mapping, desc, ptr );
1665 case WS_INT8_TYPE:
1667 const INT8 *ptr = value;
1668 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1669 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1670 return write_type_int8( writer, mapping, desc, ptr );
1672 case WS_INT16_TYPE:
1674 const INT16 *ptr = value;
1675 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1676 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1677 return write_type_int16( writer, mapping, desc, ptr );
1679 case WS_INT32_TYPE:
1681 const INT32 *ptr;
1682 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1683 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1684 return write_type_int32( writer, mapping, desc, ptr );
1686 case WS_INT64_TYPE:
1688 const INT64 *ptr = value;
1689 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1690 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1691 return write_type_int64( writer, mapping, desc, ptr );
1693 case WS_UINT8_TYPE:
1695 const UINT8 *ptr = value;
1696 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1697 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1698 return write_type_uint8( writer, mapping, desc, ptr );
1700 case WS_UINT16_TYPE:
1702 const UINT16 *ptr = value;
1703 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1704 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1705 return write_type_uint16( writer, mapping, desc, ptr );
1707 case WS_UINT32_TYPE:
1709 const UINT32 *ptr = value;
1710 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1711 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1712 return write_type_uint32( writer, mapping, desc, ptr );
1714 case WS_UINT64_TYPE:
1716 const UINT64 *ptr = value;
1717 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1718 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1719 return write_type_uint64( writer, mapping, desc, ptr );
1721 case WS_WSZ_TYPE:
1723 const WCHAR *ptr;
1725 if (option == WS_WRITE_REQUIRED_VALUE) return E_INVALIDARG;
1727 if (!option) option = WS_WRITE_REQUIRED_POINTER;
1728 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1729 return write_type_wsz( writer, mapping, desc, ptr );
1731 default:
1732 FIXME( "type %u not supported\n", type );
1733 return E_NOTIMPL;
1737 /**************************************************************************
1738 * WsWriteAttribute [webservices.@]
1740 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
1741 WS_WRITE_OPTION option, const void *value, ULONG size,
1742 WS_ERROR *error )
1744 struct writer *writer = (struct writer *)handle;
1745 HRESULT hr;
1747 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
1748 if (error) FIXME( "ignoring error parameter\n" );
1750 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
1751 return E_INVALIDARG;
1753 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
1755 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs,
1756 FALSE )) != S_OK) return hr;
1757 writer->state = WRITER_STATE_STARTATTRIBUTE;
1759 return write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription,
1760 option, value, size );
1763 /**************************************************************************
1764 * WsWriteElement [webservices.@]
1766 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
1767 WS_WRITE_OPTION option, const void *value, ULONG size,
1768 WS_ERROR *error )
1770 struct writer *writer = (struct writer *)handle;
1771 HRESULT hr;
1773 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
1774 if (error) FIXME( "ignoring error parameter\n" );
1776 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
1777 return E_INVALIDARG;
1779 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
1781 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
1782 option, value, size )) != S_OK) return hr;
1784 return write_endelement_node( writer );
1787 /**************************************************************************
1788 * WsWriteType [webservices.@]
1790 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
1791 const void *desc, WS_WRITE_OPTION option, const void *value,
1792 ULONG size, WS_ERROR *error )
1794 struct writer *writer = (struct writer *)handle;
1795 HRESULT hr;
1797 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
1798 size, error );
1799 if (error) FIXME( "ignoring error parameter\n" );
1801 if (!writer || !value) return E_INVALIDARG;
1803 switch (mapping)
1805 case WS_ATTRIBUTE_TYPE_MAPPING:
1806 if (writer->state != WRITER_STATE_STARTATTRIBUTE) return WS_E_INVALID_FORMAT;
1807 hr = write_type( writer, mapping, type, desc, option, value, size );
1808 break;
1810 case WS_ELEMENT_TYPE_MAPPING:
1811 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1812 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_FORMAT;
1813 hr = write_type( writer, mapping, type, desc, option, value, size );
1814 break;
1816 case WS_ANY_ELEMENT_TYPE_MAPPING:
1817 hr = write_type( writer, mapping, type, desc, option, value, size );
1818 break;
1820 default:
1821 FIXME( "mapping %u not implemented\n", mapping );
1822 return E_NOTIMPL;
1825 return hr;
1828 WS_TYPE map_value_type( WS_VALUE_TYPE type )
1830 switch (type)
1832 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
1833 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
1834 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
1835 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
1836 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
1837 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
1838 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
1839 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
1840 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
1841 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
1842 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
1843 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
1844 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
1845 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
1846 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
1847 default:
1848 FIXME( "unhandled type %u\n", type );
1849 return ~0u;
1853 /**************************************************************************
1854 * WsWriteValue [webservices.@]
1856 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
1857 ULONG size, WS_ERROR *error )
1859 struct writer *writer = (struct writer *)handle;
1860 WS_TYPE_MAPPING mapping;
1861 WS_TYPE type;
1863 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
1864 if (error) FIXME( "ignoring error parameter\n" );
1866 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
1868 switch (writer->state)
1870 case WRITER_STATE_STARTATTRIBUTE:
1871 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1872 break;
1874 case WRITER_STATE_STARTELEMENT:
1875 mapping = WS_ELEMENT_TYPE_MAPPING;
1876 break;
1878 default:
1879 return WS_E_INVALID_FORMAT;
1882 return write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
1885 /**************************************************************************
1886 * WsWriteXmlBuffer [webservices.@]
1888 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
1890 struct writer *writer = (struct writer *)handle;
1891 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
1892 HRESULT hr;
1894 TRACE( "%p %p %p\n", handle, buffer, error );
1895 if (error) FIXME( "ignoring error parameter\n" );
1897 if (!writer || !xmlbuf) return E_INVALIDARG;
1899 if ((hr = write_grow_buffer( writer, xmlbuf->size )) != S_OK) return hr;
1900 write_bytes( writer, xmlbuf->ptr, xmlbuf->size );
1901 return S_OK;
1904 /**************************************************************************
1905 * WsWriteXmlBufferToBytes [webservices.@]
1907 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
1908 const WS_XML_WRITER_ENCODING *encoding,
1909 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
1910 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
1912 struct writer *writer = (struct writer *)handle;
1913 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
1914 HRESULT hr;
1915 char *buf;
1916 ULONG i;
1918 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
1919 bytes, size, error );
1920 if (error) FIXME( "ignoring error parameter\n" );
1922 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
1924 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
1926 FIXME( "encoding type %u not supported\n", encoding->encodingType );
1927 return E_NOTIMPL;
1930 for (i = 0; i < count; i++)
1932 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
1933 properties[i].valueSize );
1934 if (hr != S_OK) return hr;
1937 if (!(buf = ws_alloc( heap, xmlbuf->size ))) return WS_E_QUOTA_EXCEEDED;
1938 memcpy( buf, xmlbuf->ptr, xmlbuf->size );
1939 *bytes = buf;
1940 *size = xmlbuf->size;
1941 return S_OK;
1944 /**************************************************************************
1945 * WsWriteXmlnsAttribute [webservices.@]
1947 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1948 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
1950 struct writer *writer = (struct writer *)handle;
1952 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
1953 single, error );
1954 if (error) FIXME( "ignoring error parameter\n" );
1956 if (!writer || !ns) return E_INVALIDARG;
1957 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
1959 if (namespace_in_scope( &writer->current->hdr, prefix, ns )) return S_OK;
1960 return write_add_namespace_attribute( writer, prefix, ns, single );
1963 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
1965 BOOL success = FALSE;
1966 struct node *node = writer->current;
1968 switch (move)
1970 case WS_MOVE_TO_ROOT_ELEMENT:
1971 success = move_to_root_element( writer->root, &node );
1972 break;
1974 case WS_MOVE_TO_NEXT_ELEMENT:
1975 success = move_to_next_element( &node );
1976 break;
1978 case WS_MOVE_TO_PREVIOUS_ELEMENT:
1979 success = move_to_prev_element( &node );
1980 break;
1982 case WS_MOVE_TO_CHILD_ELEMENT:
1983 success = move_to_child_element( &node );
1984 break;
1986 case WS_MOVE_TO_END_ELEMENT:
1987 success = move_to_end_element( &node );
1988 break;
1990 case WS_MOVE_TO_PARENT_ELEMENT:
1991 success = move_to_parent_element( &node );
1992 break;
1994 case WS_MOVE_TO_FIRST_NODE:
1995 success = move_to_first_node( &node );
1996 break;
1998 case WS_MOVE_TO_NEXT_NODE:
1999 success = move_to_next_node( &node );
2000 break;
2002 case WS_MOVE_TO_PREVIOUS_NODE:
2003 success = move_to_prev_node( &node );
2004 break;
2006 case WS_MOVE_TO_CHILD_NODE:
2007 success = move_to_child_node( &node );
2008 break;
2010 case WS_MOVE_TO_BOF:
2011 success = move_to_bof( writer->root, &node );
2012 break;
2014 case WS_MOVE_TO_EOF:
2015 success = move_to_eof( writer->root, &node );
2016 break;
2018 default:
2019 FIXME( "unhandled move %u\n", move );
2020 return E_NOTIMPL;
2023 if (success && node == writer->root) return E_INVALIDARG;
2024 writer->current = node;
2026 if (found)
2028 *found = success;
2029 return S_OK;
2031 return success ? S_OK : WS_E_INVALID_FORMAT;
2034 /**************************************************************************
2035 * WsMoveWriter [webservices.@]
2037 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2039 struct writer *writer = (struct writer *)handle;
2041 TRACE( "%p %u %p %p\n", handle, move, found, error );
2042 if (error) FIXME( "ignoring error parameter\n" );
2044 if (!writer) return E_INVALIDARG;
2045 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2047 return write_move_to( writer, move, found );
2050 /**************************************************************************
2051 * WsGetWriterPosition [webservices.@]
2053 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2055 struct writer *writer = (struct writer *)handle;
2057 TRACE( "%p %p %p\n", handle, pos, error );
2058 if (error) FIXME( "ignoring error parameter\n" );
2060 if (!writer || !pos) return E_INVALIDARG;
2061 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2063 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
2064 pos->node = writer->current;
2065 return S_OK;
2068 /**************************************************************************
2069 * WsSetWriterPosition [webservices.@]
2071 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2073 struct writer *writer = (struct writer *)handle;
2075 TRACE( "%p %p %p\n", handle, pos, error );
2076 if (error) FIXME( "ignoring error parameter\n" );
2078 if (!writer || !pos || (struct xmlbuf *)pos->buffer != writer->output_buf) return E_INVALIDARG;
2079 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2081 writer->current = pos->node;
2082 return S_OK;
2085 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
2087 struct node *node, *parent;
2088 WS_XML_COMMENT_NODE *comment;
2090 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2091 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2092 comment = (WS_XML_COMMENT_NODE *)node;
2094 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
2096 free_node( node );
2097 return E_OUTOFMEMORY;
2099 memcpy( comment->value.bytes, value->bytes, value->length );
2100 comment->value.length = value->length;
2102 write_insert_node( writer, parent, node );
2103 return S_OK;
2106 static HRESULT write_comment( struct writer *writer )
2108 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
2109 HRESULT hr;
2111 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
2112 write_bytes( writer, (const BYTE *)"<!--", 4 );
2113 write_bytes( writer, comment->value.bytes, comment->value.length );
2114 write_bytes( writer, (const BYTE *)"-->", 3 );
2115 return S_OK;
2118 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
2120 HRESULT hr;
2121 if ((hr = write_flush( writer )) != S_OK) return hr;
2122 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
2123 if ((hr = write_comment( writer )) != S_OK) return hr;
2124 writer->state = WRITER_STATE_COMMENT;
2125 return S_OK;
2128 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
2130 ULONG i;
2131 HRESULT hr;
2133 for (i = 0; i < count; i++)
2135 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
2136 attrs[i]->singleQuote )) != S_OK) return hr;
2137 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
2139 return S_OK;
2142 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
2144 HRESULT hr;
2146 switch (node->nodeType)
2148 case WS_XML_NODE_TYPE_ELEMENT:
2150 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
2151 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
2152 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
2154 case WS_XML_NODE_TYPE_TEXT:
2156 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
2157 return write_text_node( writer, text->text );
2159 case WS_XML_NODE_TYPE_END_ELEMENT:
2160 return write_endelement_node( writer );
2162 case WS_XML_NODE_TYPE_COMMENT:
2164 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
2165 return write_comment_node( writer, &comment->value );
2167 case WS_XML_NODE_TYPE_CDATA:
2168 return write_cdata_node( writer );
2170 case WS_XML_NODE_TYPE_END_CDATA:
2171 return write_endcdata_node( writer );
2173 case WS_XML_NODE_TYPE_EOF:
2174 case WS_XML_NODE_TYPE_BOF:
2175 return S_OK;
2177 default:
2178 WARN( "unknown node type %u\n", node->nodeType );
2179 return E_INVALIDARG;
2183 /**************************************************************************
2184 * WsWriteNode [webservices.@]
2186 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
2188 struct writer *writer = (struct writer *)handle;
2190 TRACE( "%p %p %p\n", handle, node, error );
2191 if (error) FIXME( "ignoring error parameter\n" );
2193 if (!writer || !node) return E_INVALIDARG;
2194 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2196 return write_node( writer, node );
2199 static HRESULT write_tree_node( struct writer *writer )
2201 HRESULT hr;
2203 switch (node_type( writer->current ))
2205 case WS_XML_NODE_TYPE_ELEMENT:
2206 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2207 return hr;
2208 if ((hr = write_startelement( writer )) != S_OK) return hr;
2209 writer->state = WRITER_STATE_STARTELEMENT;
2210 return S_OK;
2212 case WS_XML_NODE_TYPE_TEXT:
2213 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2214 return hr;
2215 if ((hr = write_text( writer )) != S_OK) return hr;
2216 writer->state = WRITER_STATE_TEXT;
2217 return S_OK;
2219 case WS_XML_NODE_TYPE_END_ELEMENT:
2220 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
2221 writer->state = WRITER_STATE_ENDELEMENT;
2222 return S_OK;
2224 case WS_XML_NODE_TYPE_COMMENT:
2225 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2226 return hr;
2227 if ((hr = write_comment( writer )) != S_OK) return hr;
2228 writer->state = WRITER_STATE_COMMENT;
2229 return S_OK;
2231 case WS_XML_NODE_TYPE_CDATA:
2232 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2233 return hr;
2234 if ((hr = write_cdata( writer )) != S_OK) return hr;
2235 writer->state = WRITER_STATE_STARTCDATA;
2236 return S_OK;
2238 case WS_XML_NODE_TYPE_END_CDATA:
2239 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2240 writer->state = WRITER_STATE_ENDCDATA;
2241 return S_OK;
2243 case WS_XML_NODE_TYPE_EOF:
2244 case WS_XML_NODE_TYPE_BOF:
2245 return S_OK;
2247 default:
2248 ERR( "unknown node type %u\n", node_type(writer->current) );
2249 return E_INVALIDARG;
2253 static HRESULT write_tree( struct writer *writer )
2255 HRESULT hr;
2257 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2258 for (;;)
2260 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
2261 if (move_to_child_node( &writer->current ))
2263 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2264 continue;
2266 if (move_to_next_node( &writer->current ))
2268 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2269 continue;
2271 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
2273 ERR( "invalid tree\n" );
2274 return WS_E_INVALID_FORMAT;
2276 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2278 return S_OK;
2281 static void write_rewind( struct writer *writer )
2283 writer->write_pos = 0;
2284 writer->current = writer->root;
2285 writer->state = WRITER_STATE_INITIAL;
2288 /**************************************************************************
2289 * WsCopyNode [webservices.@]
2291 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
2293 struct writer *writer = (struct writer *)handle;
2294 struct node *parent, *current = writer->current, *node = NULL;
2295 HRESULT hr;
2297 TRACE( "%p %p %p\n", handle, reader, error );
2298 if (error) FIXME( "ignoring error parameter\n" );
2300 if (!writer) return E_INVALIDARG;
2301 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2303 if ((hr = copy_node( reader, &node )) != S_OK) return hr;
2304 write_insert_node( writer, parent, node );
2306 write_rewind( writer );
2307 if ((hr = write_tree( writer )) != S_OK) return hr;
2309 writer->current = current;
2310 return S_OK;