webservices: Allow integer values to be passed by pointer in WsWriteType.
[wine.git] / dlls / webservices / writer.c
blob50cd3981dae4e48e77ab9bdeb2bdbd1a6e03727c
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 <stdarg.h>
20 #include <stdio.h>
21 #include <math.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "webservices.h"
28 #include "wine/debug.h"
29 #include "wine/list.h"
30 #include "wine/unicode.h"
31 #include "webservices_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
35 static const struct prop_desc writer_props[] =
37 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
38 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
39 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
40 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
41 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
42 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
43 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
44 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
45 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
46 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
47 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
48 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
49 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
50 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
51 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
52 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
53 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
54 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
55 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
58 enum writer_state
60 WRITER_STATE_INITIAL,
61 WRITER_STATE_STARTELEMENT,
62 WRITER_STATE_STARTATTRIBUTE,
63 WRITER_STATE_STARTCDATA,
64 WRITER_STATE_ENDSTARTELEMENT,
65 WRITER_STATE_TEXT,
66 WRITER_STATE_COMMENT,
67 WRITER_STATE_ENDELEMENT,
68 WRITER_STATE_ENDCDATA
71 struct writer
73 ULONG write_pos;
74 unsigned char *write_bufptr;
75 enum writer_state state;
76 struct node *root;
77 struct node *current;
78 WS_XML_STRING *current_ns;
79 WS_XML_WRITER_OUTPUT_TYPE output_type;
80 struct xmlbuf *output_buf;
81 WS_HEAP *output_heap;
82 ULONG prop_count;
83 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
86 static struct writer *alloc_writer(void)
88 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
89 struct writer *ret;
90 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
92 if (!(ret = heap_alloc_zero( size ))) return NULL;
93 prop_init( writer_props, count, ret->prop, &ret[1] );
94 ret->prop_count = count;
95 return ret;
98 static void free_writer( struct writer *writer )
100 destroy_nodes( writer->root );
101 heap_free( writer->current_ns );
102 WsFreeHeap( writer->output_heap );
103 heap_free( writer );
106 static void write_insert_eof( struct writer *writer, struct node *eof )
108 if (!writer->root) writer->root = eof;
109 else
111 eof->parent = writer->root;
112 list_add_tail( &writer->root->children, &eof->entry );
114 writer->current = eof;
117 static void write_insert_bof( struct writer *writer, struct node *bof )
119 writer->root->parent = bof;
120 list_add_tail( &bof->children, &writer->root->entry );
121 writer->current = writer->root = bof;
124 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
126 node->parent = parent;
127 list_add_before( list_tail( &parent->children ), &node->entry );
128 writer->current = node;
131 static HRESULT write_init_state( struct writer *writer )
133 struct node *node;
135 heap_free( writer->current_ns );
136 writer->current_ns = NULL;
137 destroy_nodes( writer->root );
138 writer->root = NULL;
140 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
141 write_insert_eof( writer, node );
142 writer->state = WRITER_STATE_INITIAL;
143 return S_OK;
146 /**************************************************************************
147 * WsCreateWriter [webservices.@]
149 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
150 WS_XML_WRITER **handle, WS_ERROR *error )
152 struct writer *writer;
153 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
154 WS_CHARSET charset = WS_CHARSET_UTF8;
155 HRESULT hr;
157 TRACE( "%p %u %p %p\n", properties, count, handle, error );
158 if (error) FIXME( "ignoring error parameter\n" );
160 if (!handle) return E_INVALIDARG;
161 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
163 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
164 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
165 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
166 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
167 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
168 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
169 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
171 for (i = 0; i < count; i++)
173 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
174 properties[i].valueSize );
175 if (hr != S_OK)
177 free_writer( writer );
178 return hr;
182 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
183 &max_size, sizeof(max_size) );
184 if (hr != S_OK)
186 free_writer( writer );
187 return hr;
190 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
191 if (hr != S_OK)
193 free_writer( writer );
194 return hr;
197 hr = write_init_state( writer );
198 if (hr != S_OK)
200 free_writer( writer );
201 return hr;
204 *handle = (WS_XML_WRITER *)writer;
205 return S_OK;
208 /**************************************************************************
209 * WsFreeWriter [webservices.@]
211 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
213 struct writer *writer = (struct writer *)handle;
215 TRACE( "%p\n", handle );
216 free_writer( writer );
219 #define XML_BUFFER_INITIAL_ALLOCATED_SIZE 256
220 static struct xmlbuf *alloc_xmlbuf( WS_HEAP *heap )
222 struct xmlbuf *ret;
224 if (!(ret = ws_alloc( heap, sizeof(*ret) ))) return NULL;
225 if (!(ret->ptr = ws_alloc( heap, XML_BUFFER_INITIAL_ALLOCATED_SIZE )))
227 ws_free( heap, ret );
228 return NULL;
230 ret->heap = heap;
231 ret->size_allocated = XML_BUFFER_INITIAL_ALLOCATED_SIZE;
232 ret->size = 0;
233 return ret;
236 static void free_xmlbuf( struct xmlbuf *xmlbuf )
238 if (!xmlbuf) return;
239 ws_free( xmlbuf->heap, xmlbuf->ptr );
240 ws_free( xmlbuf->heap, xmlbuf );
243 /**************************************************************************
244 * WsCreateXmlBuffer [webservices.@]
246 HRESULT WINAPI WsCreateXmlBuffer( WS_HEAP *heap, const WS_XML_BUFFER_PROPERTY *properties,
247 ULONG count, WS_XML_BUFFER **handle, WS_ERROR *error )
249 struct xmlbuf *xmlbuf;
251 if (!heap || !handle) return E_INVALIDARG;
252 if (count) FIXME( "properties not implemented\n" );
254 if (!(xmlbuf = alloc_xmlbuf( heap ))) return E_OUTOFMEMORY;
256 *handle = (WS_XML_BUFFER *)xmlbuf;
257 return S_OK;
260 /**************************************************************************
261 * WsGetWriterProperty [webservices.@]
263 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
264 void *buf, ULONG size, WS_ERROR *error )
266 struct writer *writer = (struct writer *)handle;
268 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
269 if (error) FIXME( "ignoring error parameter\n" );
271 if (!writer->output_type) return WS_E_INVALID_OPERATION;
273 switch (id)
275 case WS_XML_WRITER_PROPERTY_BYTES:
277 WS_BYTES *bytes = buf;
278 if (size != sizeof(*bytes)) return E_INVALIDARG;
279 bytes->bytes = writer->output_buf->ptr;
280 bytes->length = writer->output_buf->size;
281 return S_OK;
283 default:
284 return prop_get( writer->prop, writer->prop_count, id, buf, size );
288 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
290 /* free current buffer if it's ours */
291 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
293 free_xmlbuf( writer->output_buf );
295 writer->output_buf = xmlbuf;
296 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
297 writer->write_bufptr = xmlbuf->ptr;
298 writer->write_pos = 0;
301 /**************************************************************************
302 * WsSetOutput [webservices.@]
304 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
305 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
306 ULONG count, WS_ERROR *error )
308 struct writer *writer = (struct writer *)handle;
309 struct node *node;
310 HRESULT hr;
311 ULONG i;
313 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
314 if (error) FIXME( "ignoring error parameter\n" );
316 if (!writer) return E_INVALIDARG;
318 for (i = 0; i < count; i++)
320 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
321 properties[i].valueSize );
322 if (hr != S_OK) return hr;
325 if ((hr = write_init_state( writer )) != S_OK) return hr;
327 switch (encoding->encodingType)
329 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
331 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
332 if (text->charSet != WS_CHARSET_UTF8)
334 FIXME( "charset %u not supported\n", text->charSet );
335 return E_NOTIMPL;
337 break;
339 default:
340 FIXME( "encoding type %u not supported\n", encoding->encodingType );
341 return E_NOTIMPL;
343 switch (output->outputType)
345 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
347 struct xmlbuf *xmlbuf;
349 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap ))) return E_OUTOFMEMORY;
350 set_output_buffer( writer, xmlbuf );
351 break;
353 default:
354 FIXME( "output type %u not supported\n", output->outputType );
355 return E_NOTIMPL;
358 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
359 write_insert_bof( writer, node );
360 return S_OK;
363 /**************************************************************************
364 * WsSetOutputToBuffer [webservices.@]
366 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
367 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
368 WS_ERROR *error )
370 struct writer *writer = (struct writer *)handle;
371 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
372 struct node *node;
373 HRESULT hr;
374 ULONG i;
376 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
377 if (error) FIXME( "ignoring error parameter\n" );
379 if (!writer || !xmlbuf) return E_INVALIDARG;
381 for (i = 0; i < count; i++)
383 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
384 properties[i].valueSize );
385 if (hr != S_OK) return hr;
388 if ((hr = write_init_state( writer )) != S_OK) return hr;
389 set_output_buffer( writer, xmlbuf );
391 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
392 write_insert_bof( writer, node );
393 return S_OK;
396 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
398 struct xmlbuf *buf = writer->output_buf;
399 SIZE_T new_size;
400 void *tmp;
402 if (buf->size_allocated >= writer->write_pos + size)
404 buf->size = writer->write_pos + size;
405 return S_OK;
407 new_size = max( buf->size_allocated * 2, writer->write_pos + size );
408 if (!(tmp = ws_realloc( buf->heap, buf->ptr, new_size ))) return E_OUTOFMEMORY;
409 writer->write_bufptr = buf->ptr = tmp;
410 buf->size_allocated = new_size;
411 buf->size = writer->write_pos + size;
412 return S_OK;
415 static inline void write_char( struct writer *writer, unsigned char ch )
417 writer->write_bufptr[writer->write_pos++] = ch;
420 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
422 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
423 writer->write_pos += len;
426 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
428 WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
429 unsigned char quote = attr->singleQuote ? '\'' : '"';
430 const WS_XML_STRING *prefix;
431 ULONG size;
432 HRESULT hr;
434 if (attr->prefix) prefix = attr->prefix;
435 else prefix = writer->current->hdr.prefix;
437 /* ' prefix:attr="value"' */
439 size = attr->localName->length + 4 /* ' =""' */;
440 if (prefix) size += prefix->length + 1 /* ':' */;
441 if (text) size += text->value.length;
442 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
444 write_char( writer, ' ' );
445 if (prefix)
447 write_bytes( writer, prefix->bytes, prefix->length );
448 write_char( writer, ':' );
450 write_bytes( writer, attr->localName->bytes, attr->localName->length );
451 write_char( writer, '=' );
452 write_char( writer, quote );
453 if (text) write_bytes( writer, text->value.bytes, text->value.length );
454 write_char( writer, quote );
456 return S_OK;
459 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
461 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
464 /**************************************************************************
465 * WsGetPrefixFromNamespace [webservices.@]
467 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
468 BOOL required, const WS_XML_STRING **prefix,
469 WS_ERROR *error )
471 struct writer *writer = (struct writer *)handle;
472 WS_XML_ELEMENT_NODE *elem;
473 BOOL found = FALSE;
475 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
476 if (error) FIXME( "ignoring error parameter\n" );
478 if (!writer || !ns || !prefix) return E_INVALIDARG;
480 elem = &writer->current->hdr;
481 if (elem->prefix && is_current_namespace( writer, ns ))
483 *prefix = elem->prefix;
484 found = TRUE;
486 if (!found)
488 if (required) return WS_E_INVALID_FORMAT;
489 *prefix = NULL;
490 return S_FALSE;
492 return S_OK;
495 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
497 WS_XML_STRING *str;
498 if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
499 heap_free( writer->current_ns );
500 writer->current_ns = str;
501 return S_OK;
504 static HRESULT write_namespace_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
506 unsigned char quote = attr->singleQuote ? '\'' : '"';
507 ULONG size;
508 HRESULT hr;
510 /* ' xmlns:prefix="namespace"' */
512 size = attr->ns->length + 9 /* ' xmlns=""' */;
513 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
514 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
516 write_bytes( writer, (const BYTE *)" xmlns", 6 );
517 if (attr->prefix)
519 write_char( writer, ':' );
520 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
522 write_char( writer, '=' );
523 write_char( writer, quote );
524 write_bytes( writer, attr->ns->bytes, attr->ns->length );
525 write_char( writer, quote );
527 return S_OK;
530 static HRESULT write_add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
531 const WS_XML_STRING *ns, BOOL single )
533 WS_XML_ATTRIBUTE *attr;
534 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
535 HRESULT hr;
537 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
539 attr->singleQuote = !!single;
540 attr->isXmlNs = 1;
541 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
543 free_attribute( attr );
544 return E_OUTOFMEMORY;
546 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
548 free_attribute( attr );
549 return E_OUTOFMEMORY;
551 if ((hr = append_attribute( elem, attr )) != S_OK)
553 free_attribute( attr );
554 return hr;
556 return S_OK;
559 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
560 const WS_XML_STRING *ns )
562 ULONG i;
563 const struct node *node;
565 for (node = (const struct node *)elem; node; node = node->parent)
567 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
569 elem = &node->hdr;
570 for (i = 0; i < elem->attributeCount; i++)
572 if (!elem->attributes[i]->isXmlNs) continue;
573 if (WsXmlStringEquals( elem->attributes[i]->prefix, prefix, NULL ) == S_OK &&
574 WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) == S_OK)
576 return TRUE;
580 return FALSE;
583 static HRESULT write_set_element_namespace( struct writer *writer )
585 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
586 HRESULT hr;
588 if (!elem->ns->length || is_current_namespace( writer, elem->ns ) ||
589 namespace_in_scope( elem, elem->prefix, elem->ns )) return S_OK;
591 if ((hr = write_add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK)
592 return hr;
594 return set_current_namespace( writer, elem->ns );
597 /**************************************************************************
598 * WsWriteEndAttribute [webservices.@]
600 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
602 struct writer *writer = (struct writer *)handle;
604 TRACE( "%p %p\n", handle, error );
605 if (error) FIXME( "ignoring error parameter\n" );
607 if (!writer) return E_INVALIDARG;
609 writer->state = WRITER_STATE_STARTELEMENT;
610 return S_OK;
613 static HRESULT write_startelement( struct writer *writer )
615 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
616 ULONG size, i;
617 HRESULT hr;
619 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
621 size = elem->localName->length + 1 /* '<' */;
622 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
623 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
625 write_char( writer, '<' );
626 if (elem->prefix)
628 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
629 write_char( writer, ':' );
631 write_bytes( writer, elem->localName->bytes, elem->localName->length );
632 for (i = 0; i < elem->attributeCount; i++)
634 if (elem->attributes[i]->isXmlNs) continue;
635 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
637 for (i = 0; i < elem->attributeCount; i++)
639 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
640 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
642 for (i = 0; i < elem->attributeCount; i++)
644 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
645 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
647 return S_OK;
650 static struct node *write_find_startelement( struct writer *writer )
652 struct node *node;
653 for (node = writer->current; node; node = node->parent)
655 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
657 return NULL;
660 static inline BOOL is_empty_element( const struct node *node )
662 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
663 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
666 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
668 ULONG size;
669 HRESULT hr;
671 /* '/>' */
673 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
675 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
676 write_char( writer, '/' );
677 write_char( writer, '>' );
678 return S_OK;
681 /* '</prefix:localname>' */
683 size = elem->localName->length + 3 /* '</>' */;
684 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
685 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
687 write_char( writer, '<' );
688 write_char( writer, '/' );
689 if (elem->prefix)
691 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
692 write_char( writer, ':' );
694 write_bytes( writer, elem->localName->bytes, elem->localName->length );
695 write_char( writer, '>' );
696 return S_OK;
699 static HRESULT write_close_element( struct writer *writer, struct node *node )
701 WS_XML_ELEMENT_NODE *elem = &node->hdr;
702 elem->isEmpty = is_empty_element( node );
703 return write_endelement( writer, elem );
706 static HRESULT write_endelement_node( struct writer *writer )
708 struct node *node;
709 HRESULT hr;
711 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
712 if (writer->state == WRITER_STATE_STARTELEMENT)
714 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
715 if ((hr = write_startelement( writer )) != S_OK) return hr;
717 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
718 writer->current = node->parent;
719 writer->state = WRITER_STATE_ENDELEMENT;
720 return S_OK;
723 /**************************************************************************
724 * WsWriteEndElement [webservices.@]
726 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
728 struct writer *writer = (struct writer *)handle;
730 TRACE( "%p %p\n", handle, error );
731 if (error) FIXME( "ignoring error parameter\n" );
733 if (!writer) return E_INVALIDARG;
734 return write_endelement_node( writer );
737 static HRESULT write_endstartelement( struct writer *writer )
739 HRESULT hr;
740 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
741 write_char( writer, '>' );
742 return S_OK;
745 /**************************************************************************
746 * WsWriteEndStartElement [webservices.@]
748 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
750 struct writer *writer = (struct writer *)handle;
751 HRESULT hr;
753 TRACE( "%p %p\n", handle, error );
754 if (error) FIXME( "ignoring error parameter\n" );
756 if (!writer) return E_INVALIDARG;
757 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
759 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
760 if ((hr = write_startelement( writer )) != S_OK) return hr;
761 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
763 writer->state = WRITER_STATE_ENDSTARTELEMENT;
764 return S_OK;
767 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
768 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
769 BOOL single )
771 WS_XML_ATTRIBUTE *attr;
772 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
773 HRESULT hr;
775 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
777 if (!prefix) prefix = elem->prefix;
779 attr->singleQuote = !!single;
780 if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
782 free_attribute( attr );
783 return E_OUTOFMEMORY;
785 if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
787 free_attribute( attr );
788 return E_OUTOFMEMORY;
790 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
792 free_attribute( attr );
793 return E_OUTOFMEMORY;
795 if ((hr = append_attribute( elem, attr )) != S_OK)
797 free_attribute( attr );
798 return hr;
800 return S_OK;
803 /**************************************************************************
804 * WsWriteStartAttribute [webservices.@]
806 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
807 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
808 BOOL single, WS_ERROR *error )
810 struct writer *writer = (struct writer *)handle;
811 HRESULT hr;
813 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
814 debugstr_xmlstr(ns), single, error );
815 if (error) FIXME( "ignoring error parameter\n" );
817 if (!writer || !localname || !ns) return E_INVALIDARG;
819 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
821 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
822 writer->state = WRITER_STATE_STARTATTRIBUTE;
823 return S_OK;
826 /* flush current start element if necessary */
827 static HRESULT write_flush( struct writer *writer )
829 if (writer->state == WRITER_STATE_STARTELEMENT)
831 HRESULT hr;
832 if ((hr = write_set_element_namespace( writer )) != S_OK) return hr;
833 if ((hr = write_startelement( writer )) != S_OK) return hr;
834 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
835 writer->state = WRITER_STATE_ENDSTARTELEMENT;
837 return S_OK;
840 static HRESULT write_add_cdata_node( struct writer *writer )
842 struct node *node, *parent;
843 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
844 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
845 write_insert_node( writer, parent, node );
846 return S_OK;
849 static HRESULT write_add_endcdata_node( struct writer *writer )
851 struct node *node;
852 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
853 node->parent = writer->current;
854 list_add_tail( &node->parent->children, &node->entry );
855 return S_OK;
858 static HRESULT write_cdata( struct writer *writer )
860 HRESULT hr;
861 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
862 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
863 return S_OK;
866 static HRESULT write_cdata_node( struct writer *writer )
868 HRESULT hr;
869 if ((hr = write_flush( writer )) != S_OK) return hr;
870 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
871 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
872 if ((hr = write_cdata( writer )) != S_OK) return hr;
873 writer->state = WRITER_STATE_STARTCDATA;
874 return S_OK;
877 /**************************************************************************
878 * WsWriteStartCData [webservices.@]
880 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
882 struct writer *writer = (struct writer *)handle;
884 TRACE( "%p %p\n", handle, error );
885 if (error) FIXME( "ignoring error parameter\n" );
887 if (!writer) return E_INVALIDARG;
888 return write_cdata_node( writer );
891 static HRESULT write_endcdata( struct writer *writer )
893 HRESULT hr;
894 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
895 write_bytes( writer, (const BYTE *)"]]>", 3 );
896 return S_OK;
899 static HRESULT write_endcdata_node( struct writer *writer )
901 HRESULT hr;
902 if ((hr = write_endcdata( writer )) != S_OK) return hr;
903 writer->current = writer->current->parent;
904 writer->state = WRITER_STATE_ENDCDATA;
905 return S_OK;
908 /**************************************************************************
909 * WsWriteEndCData [webservices.@]
911 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
913 struct writer *writer = (struct writer *)handle;
915 TRACE( "%p %p\n", handle, error );
916 if (error) FIXME( "ignoring error parameter\n" );
918 if (!writer) return E_INVALIDARG;
919 if (writer->state != WRITER_STATE_TEXT) return WS_E_INVALID_OPERATION;
921 return write_endcdata_node( writer );
924 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
925 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
927 struct node *node, *parent;
928 WS_XML_ELEMENT_NODE *elem;
930 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
932 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
934 elem = &parent->hdr;
935 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
938 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
939 elem = &node->hdr;
941 if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
943 free_node( node );
944 return E_OUTOFMEMORY;
946 if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
948 free_node( node );
949 return E_OUTOFMEMORY;
951 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
953 free_node( node );
954 return E_OUTOFMEMORY;
956 write_insert_node( writer, parent, node );
957 return S_OK;
960 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
962 struct node *node;
963 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
964 node->parent = parent;
965 list_add_tail( &parent->children, &node->entry );
966 return S_OK;
969 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
970 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
972 HRESULT hr;
973 if ((hr = write_flush( writer )) != S_OK) return hr;
974 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
975 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
976 writer->state = WRITER_STATE_STARTELEMENT;
977 return S_OK;
980 /**************************************************************************
981 * WsWriteStartElement [webservices.@]
983 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
984 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
985 WS_ERROR *error )
987 struct writer *writer = (struct writer *)handle;
989 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
990 debugstr_xmlstr(ns), error );
991 if (error) FIXME( "ignoring error parameter\n" );
993 if (!writer || !localname || !ns) return E_INVALIDARG;
994 return write_element_node( writer, prefix, localname, ns );
997 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
999 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1000 if (*ptr)
1002 memcpy( buf, bool_true, sizeof(bool_true) );
1003 return sizeof(bool_true);
1005 memcpy( buf, bool_false, sizeof(bool_false) );
1006 return sizeof(bool_false);
1009 static ULONG format_int8( const INT8 *ptr, unsigned char *buf )
1011 return wsprintfA( (char *)buf, "%d", *ptr );
1014 static ULONG format_int16( const INT16 *ptr, unsigned char *buf )
1016 return wsprintfA( (char *)buf, "%d", *ptr );
1019 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1021 return wsprintfA( (char *)buf, "%d", *ptr );
1024 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1026 return wsprintfA( (char *)buf, "%I64d", *ptr );
1029 static ULONG format_uint8( const UINT8 *ptr, unsigned char *buf )
1031 return wsprintfA( (char *)buf, "%u", *ptr );
1034 static ULONG format_uint16( const UINT16 *ptr, unsigned char *buf )
1036 return wsprintfA( (char *)buf, "%u", *ptr );
1039 static ULONG format_uint32( const UINT32 *ptr, unsigned char *buf )
1041 return wsprintfA( (char *)buf, "%u", *ptr );
1044 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1046 return wsprintfA( (char *)buf, "%I64u", *ptr );
1049 static ULONG format_double( const double *ptr, unsigned char *buf )
1051 static const double precision = 0.0000000000000001;
1052 unsigned char *p = buf;
1053 double val = *ptr; /* FIXME: use long double */
1054 int neg, mag, mag2, use_exp;
1056 if (isnan( val ))
1058 memcpy( buf, "NaN", 3 );
1059 return 3;
1061 if (isinf( val ))
1063 if (val < 0)
1065 memcpy( buf, "-INF", 4 );
1066 return 4;
1068 memcpy( buf, "INF", 3 );
1069 return 3;
1071 if (val == 0.0)
1073 *p = '0';
1074 return 1;
1077 if ((neg = val < 0))
1079 *p++ = '-';
1080 val = -val;
1083 mag = log10( val );
1084 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1085 if (use_exp)
1087 if (mag < 0) mag -= 1;
1088 val = val / pow( 10.0, mag );
1089 mag2 = mag;
1090 mag = 0;
1092 else if (mag < 1) mag = 0;
1094 while (val > precision || mag >= 0)
1096 double weight = pow( 10.0, mag );
1097 if (weight > 0 && !isinf( weight ))
1099 int digit = floor( val / weight );
1100 val -= digit * weight;
1101 *(p++) = '0' + digit;
1103 if (!mag && val > 0) *(p++) = '.';
1104 mag--;
1107 if (use_exp)
1109 int i, j;
1110 *(p++) = 'E';
1111 if (mag2 > 0) *(p++) = '+';
1112 else
1114 *(p++) = '-';
1115 mag2 = -mag2;
1117 mag = 0;
1118 while (mag2 > 0)
1120 *(p++) = '0' + mag2 % 10;
1121 mag2 /= 10;
1122 mag++;
1124 for (i = -mag, j = -1; i < j; i++, j--)
1126 p[i] ^= p[j];
1127 p[j] ^= p[i];
1128 p[i] ^= p[j];
1132 return p - buf;
1135 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1137 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1138 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1139 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1140 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1143 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1145 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1146 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1147 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1148 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1151 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret )
1153 switch (text->textType)
1155 case WS_XML_TEXT_TYPE_UTF8:
1157 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1158 if (!(*ret = alloc_utf8_text( src->value.bytes, src->value.length ))) return E_OUTOFMEMORY;
1159 return S_OK;
1161 case WS_XML_TEXT_TYPE_UTF16:
1163 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1164 const WCHAR *str = (const WCHAR *)src->bytes;
1165 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1167 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1168 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1169 if (!(*ret = alloc_utf8_text( NULL, len_utf8 ))) return E_OUTOFMEMORY;
1170 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes, (*ret)->value.length, NULL, NULL );
1171 return S_OK;
1173 case WS_XML_TEXT_TYPE_BOOL:
1175 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1176 if (!(*ret = alloc_utf8_text( NULL, 5 ))) return E_OUTOFMEMORY;
1177 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes );
1178 return S_OK;
1180 case WS_XML_TEXT_TYPE_INT32:
1182 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1183 unsigned char buf[12]; /* "-2147483648" */
1184 ULONG len = format_int32( &int32_text->value, buf );
1185 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1186 return S_OK;
1188 case WS_XML_TEXT_TYPE_INT64:
1190 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1191 unsigned char buf[21]; /* "-9223372036854775808" */
1192 ULONG len = format_int64( &int64_text->value, buf );
1193 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1194 return S_OK;
1196 case WS_XML_TEXT_TYPE_UINT64:
1198 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1199 unsigned char buf[21]; /* "18446744073709551615" */
1200 ULONG len = format_uint64( &uint64_text->value, buf );
1201 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1202 return S_OK;
1204 case WS_XML_TEXT_TYPE_DOUBLE:
1206 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1207 unsigned char buf[24]; /* "-1.1111111111111111E-308" */
1208 unsigned short fpword;
1209 ULONG len;
1211 if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
1212 len = format_double( &double_text->value, buf );
1213 restore_fp_rounding( fpword );
1214 if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
1215 return S_OK;
1217 case WS_XML_TEXT_TYPE_GUID:
1219 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1220 if (!(*ret = alloc_utf8_text( NULL, 37 ))) return E_OUTOFMEMORY;
1221 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes );
1222 return S_OK;
1224 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1226 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1227 if (!(*ret = alloc_utf8_text( NULL, 46 ))) return E_OUTOFMEMORY;
1228 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes );
1229 return S_OK;
1231 default:
1232 FIXME( "unhandled text type %u\n", text->textType );
1233 return E_NOTIMPL;
1237 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
1239 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1240 WS_XML_UTF8_TEXT *utf8;
1241 HRESULT hr;
1243 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK) return hr;
1244 elem->attributes[elem->attributeCount - 1]->value = &utf8->text;
1245 return S_OK;
1248 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
1250 struct node *node;
1251 WS_XML_TEXT_NODE *text;
1252 WS_XML_UTF8_TEXT *utf8;
1253 HRESULT hr;
1255 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
1256 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
1257 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
1259 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1260 if ((hr = text_to_utf8text( value, &utf8 )) != S_OK)
1262 heap_free( node );
1263 return hr;
1265 text = (WS_XML_TEXT_NODE *)node;
1266 text->text = &utf8->text;
1268 write_insert_node( writer, writer->current, node );
1269 return S_OK;
1272 static HRESULT write_text( struct writer *writer )
1274 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)writer->current;
1275 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
1276 HRESULT hr;
1278 if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
1279 write_bytes( writer, utf8->value.bytes, utf8->value.length );
1280 return S_OK;
1283 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
1285 HRESULT hr;
1286 if ((hr = write_flush( writer )) != S_OK) return hr;
1287 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
1288 if ((hr = write_text( writer )) != S_OK) return hr;
1289 writer->state = WRITER_STATE_TEXT;
1290 return S_OK;
1293 /**************************************************************************
1294 * WsWriteText [webservices.@]
1296 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
1298 struct writer *writer = (struct writer *)handle;
1300 TRACE( "%p %p %p\n", handle, text, error );
1302 if (!writer || !text) return E_INVALIDARG;
1304 if (writer->state == WRITER_STATE_STARTATTRIBUTE) return write_set_attribute_value( writer, text );
1305 return write_text_node( writer, text );
1308 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
1310 switch (mapping)
1312 case WS_ELEMENT_TYPE_MAPPING:
1313 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1314 return write_text_node( writer, text );
1316 case WS_ATTRIBUTE_TYPE_MAPPING:
1317 return write_set_attribute_value( writer, text );
1319 case WS_ANY_ELEMENT_TYPE_MAPPING:
1320 switch (writer->state)
1322 case WRITER_STATE_STARTATTRIBUTE:
1323 return write_set_attribute_value( writer, text );
1325 case WRITER_STATE_STARTELEMENT:
1326 return write_text_node( writer, text );
1328 default:
1329 FIXME( "writer state %u not handled\n", writer->state );
1330 return E_NOTIMPL;
1333 default:
1334 FIXME( "mapping %u not implemented\n", mapping );
1335 return E_NOTIMPL;
1339 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
1340 const WS_BOOL_DESCRIPTION *desc, const BOOL *value )
1342 WS_XML_UTF8_TEXT utf8;
1343 unsigned char buf[6]; /* "false" */
1345 if (desc)
1347 FIXME( "description not supported\n" );
1348 return E_NOTIMPL;
1350 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1351 utf8.value.bytes = buf;
1352 utf8.value.length = format_bool( value, buf );
1353 return write_type_text( writer, mapping, &utf8.text );
1356 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
1357 const WS_INT8_DESCRIPTION *desc, const INT8 *value )
1359 WS_XML_UTF8_TEXT utf8;
1360 unsigned char buf[5]; /* "-128" */
1362 if (desc)
1364 FIXME( "description not supported\n" );
1365 return E_NOTIMPL;
1367 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1368 utf8.value.bytes = buf;
1369 utf8.value.length = format_int8( value, buf );
1370 return write_type_text( writer, mapping, &utf8.text );
1373 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
1374 const WS_INT16_DESCRIPTION *desc, const INT16 *value )
1376 WS_XML_UTF8_TEXT utf8;
1377 unsigned char buf[7]; /* "-32768" */
1379 if (desc)
1381 FIXME( "description not supported\n" );
1382 return E_NOTIMPL;
1384 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1385 utf8.value.bytes = buf;
1386 utf8.value.length = format_int16( value, buf );
1387 return write_type_text( writer, mapping, &utf8.text );
1390 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
1391 const WS_INT32_DESCRIPTION *desc, const INT32 *value )
1393 WS_XML_UTF8_TEXT utf8;
1394 unsigned char buf[12]; /* "-2147483648" */
1396 if (desc)
1398 FIXME( "description not supported\n" );
1399 return E_NOTIMPL;
1401 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1402 utf8.value.bytes = buf;
1403 utf8.value.length = format_int32( value, buf );
1404 return write_type_text( writer, mapping, &utf8.text );
1407 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
1408 const WS_INT64_DESCRIPTION *desc, const INT64 *value )
1410 WS_XML_UTF8_TEXT utf8;
1411 unsigned char buf[21]; /* "-9223372036854775808" */
1413 if (desc)
1415 FIXME( "description not supported\n" );
1416 return E_NOTIMPL;
1418 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1419 utf8.value.bytes = buf;
1420 utf8.value.length = format_int64( value, buf );
1421 return write_type_text( writer, mapping, &utf8.text );
1424 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
1425 const WS_UINT8_DESCRIPTION *desc, const UINT8 *value )
1427 WS_XML_UTF8_TEXT utf8;
1428 unsigned char buf[4]; /* "255" */
1430 if (desc)
1432 FIXME( "description not supported\n" );
1433 return E_NOTIMPL;
1435 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1436 utf8.value.bytes = buf;
1437 utf8.value.length = format_uint8( value, buf );
1438 return write_type_text( writer, mapping, &utf8.text );
1441 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
1442 const WS_UINT16_DESCRIPTION *desc, const UINT16 *value )
1444 WS_XML_UTF8_TEXT utf8;
1445 unsigned char buf[6]; /* "65535" */
1447 if (desc)
1449 FIXME( "description not supported\n" );
1450 return E_NOTIMPL;
1452 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1453 utf8.value.bytes = buf;
1454 utf8.value.length = format_uint16( value, buf );
1455 return write_type_text( writer, mapping, &utf8.text );
1458 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
1459 const WS_UINT32_DESCRIPTION *desc, const UINT32 *value )
1461 WS_XML_UTF8_TEXT utf8;
1462 unsigned char buf[11]; /* "4294967295" */
1464 if (desc)
1466 FIXME( "description not supported\n" );
1467 return E_NOTIMPL;
1469 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1470 utf8.value.bytes = buf;
1471 utf8.value.length = format_uint32( value, buf );
1472 return write_type_text( writer, mapping, &utf8.text );
1475 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
1476 const WS_UINT64_DESCRIPTION *desc, const UINT64 *value )
1478 WS_XML_UTF8_TEXT utf8;
1479 unsigned char buf[21]; /* "18446744073709551615" */
1481 if (desc)
1483 FIXME( "description not supported\n" );
1484 return E_NOTIMPL;
1486 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
1487 utf8.value.bytes = buf;
1488 utf8.value.length = format_uint64( value, buf );
1489 return write_type_text( writer, mapping, &utf8.text );
1492 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
1493 const WS_WSZ_DESCRIPTION *desc, const WCHAR *value )
1495 WS_XML_UTF16_TEXT utf16;
1497 if (desc)
1499 FIXME( "description not supported\n" );
1500 return E_NOTIMPL;
1502 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
1503 utf16.bytes = (BYTE *)value;
1504 utf16.byteCount = strlenW( value ) * sizeof(WCHAR);
1505 return write_type_text( writer, mapping, &utf16.text );
1508 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
1509 const void *, ULONG );
1511 static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
1512 const void *value, ULONG size )
1514 HRESULT hr;
1515 WS_TYPE_MAPPING mapping;
1516 WS_WRITE_OPTION option;
1518 if (!desc->options || desc->options == WS_FIELD_OPTIONAL) option = 0;
1519 else if (desc->options == WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
1520 else
1522 FIXME( "options 0x%x not supported\n", desc->options );
1523 return E_NOTIMPL;
1526 switch (desc->mapping)
1528 case WS_ATTRIBUTE_FIELD_MAPPING:
1529 if (!desc->localName || !desc->ns) return E_INVALIDARG;
1530 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
1531 return hr;
1532 writer->state = WRITER_STATE_STARTATTRIBUTE;
1534 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1535 break;
1537 case WS_ELEMENT_FIELD_MAPPING:
1538 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
1539 mapping = WS_ELEMENT_TYPE_MAPPING;
1540 break;
1542 case WS_TEXT_FIELD_MAPPING:
1543 switch (writer->state)
1545 case WRITER_STATE_STARTELEMENT:
1546 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
1547 break;
1549 case WRITER_STATE_STARTATTRIBUTE:
1550 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1551 break;
1553 default:
1554 FIXME( "unhandled writer state %u\n", writer->state );
1555 return E_NOTIMPL;
1557 break;
1559 default:
1560 FIXME( "field mapping %u not supported\n", desc->mapping );
1561 return E_NOTIMPL;
1564 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK)
1565 return hr;
1567 switch (mapping)
1569 case WS_ATTRIBUTE_TYPE_MAPPING:
1570 writer->state = WRITER_STATE_STARTELEMENT;
1571 break;
1573 case WS_ELEMENT_TYPE_MAPPING:
1574 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
1575 break;
1577 default: break;
1580 return S_OK;
1583 static ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index )
1585 if (index < desc->fieldCount - 1) return desc->fields[index + 1]->offset - desc->fields[index]->offset;
1586 return desc->size - desc->fields[index]->offset;
1589 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
1590 const WS_STRUCT_DESCRIPTION *desc, const void *value )
1592 ULONG i, size;
1593 HRESULT hr;
1594 const char *ptr;
1596 if (desc->structOptions)
1598 FIXME( "struct options 0x%x not supported\n", desc->structOptions );
1599 return E_NOTIMPL;
1602 for (i = 0; i < desc->fieldCount; i++)
1604 ptr = (const char *)value + desc->fields[i]->offset;
1605 size = get_field_size( desc, i );
1606 if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, size )) != S_OK)
1607 return hr;
1610 return S_OK;
1613 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, const void **ptr )
1615 switch (option)
1617 case WS_WRITE_REQUIRED_VALUE:
1618 if (!value || !size) return E_INVALIDARG;
1619 *ptr = value;
1620 return S_OK;
1622 case WS_WRITE_REQUIRED_POINTER:
1623 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
1624 return S_OK;
1626 default:
1627 FIXME( "option %08x not supported\n", option );
1628 return E_NOTIMPL;
1632 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
1633 const void *desc, WS_WRITE_OPTION option, const void *value,
1634 ULONG size )
1636 HRESULT hr;
1638 switch (type)
1640 case WS_STRUCT_TYPE:
1642 const void *ptr;
1644 if (!desc || option == WS_WRITE_REQUIRED_VALUE) return E_INVALIDARG;
1646 if (!option) option = WS_WRITE_REQUIRED_POINTER;
1647 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1648 return write_type_struct( writer, mapping, desc, ptr );
1650 case WS_BOOL_TYPE:
1652 const BOOL *ptr;
1653 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1654 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1655 return write_type_bool( writer, mapping, desc, ptr );
1657 case WS_INT8_TYPE:
1659 const INT8 *ptr = value;
1660 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1661 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1662 return write_type_int8( writer, mapping, desc, ptr );
1664 case WS_INT16_TYPE:
1666 const INT16 *ptr = value;
1667 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1668 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1669 return write_type_int16( writer, mapping, desc, ptr );
1671 case WS_INT32_TYPE:
1673 const INT32 *ptr;
1674 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1675 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1676 return write_type_int32( writer, mapping, desc, ptr );
1678 case WS_INT64_TYPE:
1680 const INT64 *ptr = value;
1681 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1682 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1683 return write_type_int64( writer, mapping, desc, ptr );
1685 case WS_UINT8_TYPE:
1687 const UINT8 *ptr = value;
1688 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1689 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1690 return write_type_uint8( writer, mapping, desc, ptr );
1692 case WS_UINT16_TYPE:
1694 const UINT16 *ptr = value;
1695 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1696 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1697 return write_type_uint16( writer, mapping, desc, ptr );
1699 case WS_UINT32_TYPE:
1701 const UINT32 *ptr = value;
1702 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1703 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1704 return write_type_uint32( writer, mapping, desc, ptr );
1706 case WS_UINT64_TYPE:
1708 const UINT64 *ptr = value;
1709 if (!option) option = WS_WRITE_REQUIRED_VALUE;
1710 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1711 return write_type_uint64( writer, mapping, desc, ptr );
1713 case WS_WSZ_TYPE:
1715 const WCHAR *ptr;
1717 if (option == WS_WRITE_REQUIRED_VALUE) return E_INVALIDARG;
1719 if (!option) option = WS_WRITE_REQUIRED_POINTER;
1720 if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr;
1721 return write_type_wsz( writer, mapping, desc, ptr );
1723 default:
1724 FIXME( "type %u not supported\n", type );
1725 return E_NOTIMPL;
1729 /**************************************************************************
1730 * WsWriteAttribute [webservices.@]
1732 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
1733 WS_WRITE_OPTION option, const void *value, ULONG size,
1734 WS_ERROR *error )
1736 struct writer *writer = (struct writer *)handle;
1737 HRESULT hr;
1739 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
1740 if (error) FIXME( "ignoring error parameter\n" );
1742 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
1743 return E_INVALIDARG;
1745 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
1747 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs,
1748 FALSE )) != S_OK) return hr;
1749 writer->state = WRITER_STATE_STARTATTRIBUTE;
1751 return write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription,
1752 option, value, size );
1755 /**************************************************************************
1756 * WsWriteElement [webservices.@]
1758 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
1759 WS_WRITE_OPTION option, const void *value, ULONG size,
1760 WS_ERROR *error )
1762 struct writer *writer = (struct writer *)handle;
1763 HRESULT hr;
1765 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
1766 if (error) FIXME( "ignoring error parameter\n" );
1768 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
1769 return E_INVALIDARG;
1771 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) return hr;
1773 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
1774 option, value, size )) != S_OK) return hr;
1776 return write_endelement_node( writer );
1779 /**************************************************************************
1780 * WsWriteType [webservices.@]
1782 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
1783 const void *desc, WS_WRITE_OPTION option, const void *value,
1784 ULONG size, WS_ERROR *error )
1786 struct writer *writer = (struct writer *)handle;
1787 HRESULT hr;
1789 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
1790 size, error );
1791 if (error) FIXME( "ignoring error parameter\n" );
1793 if (!writer || !value) return E_INVALIDARG;
1795 switch (mapping)
1797 case WS_ATTRIBUTE_TYPE_MAPPING:
1798 if (writer->state != WRITER_STATE_STARTATTRIBUTE) return WS_E_INVALID_FORMAT;
1799 hr = write_type( writer, mapping, type, desc, option, value, size );
1800 break;
1802 case WS_ELEMENT_TYPE_MAPPING:
1803 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
1804 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_FORMAT;
1805 hr = write_type( writer, mapping, type, desc, option, value, size );
1806 break;
1808 case WS_ANY_ELEMENT_TYPE_MAPPING:
1809 hr = write_type( writer, mapping, type, desc, option, value, size );
1810 break;
1812 default:
1813 FIXME( "mapping %u not implemented\n", mapping );
1814 return E_NOTIMPL;
1817 return hr;
1820 WS_TYPE map_value_type( WS_VALUE_TYPE type )
1822 switch (type)
1824 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
1825 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
1826 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
1827 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
1828 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
1829 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
1830 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
1831 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
1832 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
1833 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
1834 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
1835 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
1836 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
1837 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
1838 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
1839 default:
1840 FIXME( "unhandled type %u\n", type );
1841 return ~0u;
1845 /**************************************************************************
1846 * WsWriteValue [webservices.@]
1848 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
1849 ULONG size, WS_ERROR *error )
1851 struct writer *writer = (struct writer *)handle;
1852 WS_TYPE_MAPPING mapping;
1853 WS_TYPE type;
1855 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
1856 if (error) FIXME( "ignoring error parameter\n" );
1858 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
1860 switch (writer->state)
1862 case WRITER_STATE_STARTATTRIBUTE:
1863 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
1864 break;
1866 case WRITER_STATE_STARTELEMENT:
1867 mapping = WS_ELEMENT_TYPE_MAPPING;
1868 break;
1870 default:
1871 return WS_E_INVALID_FORMAT;
1874 return write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
1877 /**************************************************************************
1878 * WsWriteXmlBuffer [webservices.@]
1880 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
1882 struct writer *writer = (struct writer *)handle;
1883 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
1884 HRESULT hr;
1886 TRACE( "%p %p %p\n", handle, buffer, error );
1887 if (error) FIXME( "ignoring error parameter\n" );
1889 if (!writer || !xmlbuf) return E_INVALIDARG;
1891 if ((hr = write_grow_buffer( writer, xmlbuf->size )) != S_OK) return hr;
1892 write_bytes( writer, xmlbuf->ptr, xmlbuf->size );
1893 return S_OK;
1896 /**************************************************************************
1897 * WsWriteXmlBufferToBytes [webservices.@]
1899 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
1900 const WS_XML_WRITER_ENCODING *encoding,
1901 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
1902 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
1904 struct writer *writer = (struct writer *)handle;
1905 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
1906 HRESULT hr;
1907 char *buf;
1908 ULONG i;
1910 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
1911 bytes, size, error );
1912 if (error) FIXME( "ignoring error parameter\n" );
1914 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
1916 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
1918 FIXME( "encoding type %u not supported\n", encoding->encodingType );
1919 return E_NOTIMPL;
1922 for (i = 0; i < count; i++)
1924 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
1925 properties[i].valueSize );
1926 if (hr != S_OK) return hr;
1929 if (!(buf = ws_alloc( heap, xmlbuf->size ))) return WS_E_QUOTA_EXCEEDED;
1930 memcpy( buf, xmlbuf->ptr, xmlbuf->size );
1931 *bytes = buf;
1932 return S_OK;
1935 /**************************************************************************
1936 * WsWriteXmlnsAttribute [webservices.@]
1938 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1939 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
1941 struct writer *writer = (struct writer *)handle;
1943 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
1944 single, error );
1945 if (error) FIXME( "ignoring error parameter\n" );
1947 if (!writer || !ns) return E_INVALIDARG;
1948 if (writer->state != WRITER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
1950 if (namespace_in_scope( &writer->current->hdr, prefix, ns )) return S_OK;
1951 return write_add_namespace_attribute( writer, prefix, ns, single );
1954 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
1956 BOOL success = FALSE;
1957 struct node *node = writer->current;
1959 switch (move)
1961 case WS_MOVE_TO_ROOT_ELEMENT:
1962 success = move_to_root_element( writer->root, &node );
1963 break;
1965 case WS_MOVE_TO_NEXT_ELEMENT:
1966 success = move_to_next_element( &node );
1967 break;
1969 case WS_MOVE_TO_PREVIOUS_ELEMENT:
1970 success = move_to_prev_element( &node );
1971 break;
1973 case WS_MOVE_TO_CHILD_ELEMENT:
1974 success = move_to_child_element( &node );
1975 break;
1977 case WS_MOVE_TO_END_ELEMENT:
1978 success = move_to_end_element( &node );
1979 break;
1981 case WS_MOVE_TO_PARENT_ELEMENT:
1982 success = move_to_parent_element( &node );
1983 break;
1985 case WS_MOVE_TO_FIRST_NODE:
1986 success = move_to_first_node( &node );
1987 break;
1989 case WS_MOVE_TO_NEXT_NODE:
1990 success = move_to_next_node( &node );
1991 break;
1993 case WS_MOVE_TO_PREVIOUS_NODE:
1994 success = move_to_prev_node( &node );
1995 break;
1997 case WS_MOVE_TO_CHILD_NODE:
1998 success = move_to_child_node( &node );
1999 break;
2001 case WS_MOVE_TO_BOF:
2002 success = move_to_bof( writer->root, &node );
2003 break;
2005 case WS_MOVE_TO_EOF:
2006 success = move_to_eof( writer->root, &node );
2007 break;
2009 default:
2010 FIXME( "unhandled move %u\n", move );
2011 return E_NOTIMPL;
2014 if (success && node == writer->root) return E_INVALIDARG;
2015 writer->current = node;
2017 if (found)
2019 *found = success;
2020 return S_OK;
2022 return success ? S_OK : WS_E_INVALID_FORMAT;
2025 /**************************************************************************
2026 * WsMoveWriter [webservices.@]
2028 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2030 struct writer *writer = (struct writer *)handle;
2032 TRACE( "%p %u %p %p\n", handle, move, found, error );
2033 if (error) FIXME( "ignoring error parameter\n" );
2035 if (!writer) return E_INVALIDARG;
2036 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2038 return write_move_to( writer, move, found );
2041 /**************************************************************************
2042 * WsGetWriterPosition [webservices.@]
2044 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2046 struct writer *writer = (struct writer *)handle;
2048 TRACE( "%p %p %p\n", handle, pos, error );
2049 if (error) FIXME( "ignoring error parameter\n" );
2051 if (!writer || !pos) return E_INVALIDARG;
2052 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2054 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
2055 pos->node = writer->current;
2056 return S_OK;
2059 /**************************************************************************
2060 * WsSetWriterPosition [webservices.@]
2062 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
2064 struct writer *writer = (struct writer *)handle;
2066 TRACE( "%p %p %p\n", handle, pos, error );
2067 if (error) FIXME( "ignoring error parameter\n" );
2069 if (!writer || !pos || (struct xmlbuf *)pos->buffer != writer->output_buf) return E_INVALIDARG;
2070 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2072 writer->current = pos->node;
2073 return S_OK;
2076 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
2078 struct node *node, *parent;
2079 WS_XML_COMMENT_NODE *comment;
2081 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2082 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2083 comment = (WS_XML_COMMENT_NODE *)node;
2085 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
2087 free_node( node );
2088 return E_OUTOFMEMORY;
2090 memcpy( comment->value.bytes, value->bytes, value->length );
2091 comment->value.length = value->length;
2093 write_insert_node( writer, parent, node );
2094 return S_OK;
2097 static HRESULT write_comment( struct writer *writer )
2099 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
2100 HRESULT hr;
2102 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
2103 write_bytes( writer, (const BYTE *)"<!--", 4 );
2104 write_bytes( writer, comment->value.bytes, comment->value.length );
2105 write_bytes( writer, (const BYTE *)"-->", 3 );
2106 return S_OK;
2109 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
2111 HRESULT hr;
2112 if ((hr = write_flush( writer )) != S_OK) return hr;
2113 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
2114 if ((hr = write_comment( writer )) != S_OK) return hr;
2115 writer->state = WRITER_STATE_COMMENT;
2116 return S_OK;
2119 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
2121 ULONG i;
2122 HRESULT hr;
2124 for (i = 0; i < count; i++)
2126 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
2127 attrs[i]->singleQuote )) != S_OK) return hr;
2128 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
2130 return S_OK;
2133 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
2135 HRESULT hr;
2137 switch (node->nodeType)
2139 case WS_XML_NODE_TYPE_ELEMENT:
2141 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
2142 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
2143 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
2145 case WS_XML_NODE_TYPE_TEXT:
2147 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
2148 return write_text_node( writer, text->text );
2150 case WS_XML_NODE_TYPE_END_ELEMENT:
2151 return write_endelement_node( writer );
2153 case WS_XML_NODE_TYPE_COMMENT:
2155 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
2156 return write_comment_node( writer, &comment->value );
2158 case WS_XML_NODE_TYPE_CDATA:
2159 return write_cdata_node( writer );
2161 case WS_XML_NODE_TYPE_END_CDATA:
2162 return write_endcdata_node( writer );
2164 case WS_XML_NODE_TYPE_EOF:
2165 case WS_XML_NODE_TYPE_BOF:
2166 return S_OK;
2168 default:
2169 WARN( "unknown node type %u\n", node->nodeType );
2170 return E_INVALIDARG;
2174 /**************************************************************************
2175 * WsWriteNode [webservices.@]
2177 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
2179 struct writer *writer = (struct writer *)handle;
2181 TRACE( "%p %p %p\n", handle, node, error );
2182 if (error) FIXME( "ignoring error parameter\n" );
2184 if (!writer || !node) return E_INVALIDARG;
2185 if (!writer->output_type) return WS_E_INVALID_OPERATION;
2187 return write_node( writer, node );
2190 static HRESULT write_tree_node( struct writer *writer )
2192 HRESULT hr;
2194 switch (node_type( writer->current ))
2196 case WS_XML_NODE_TYPE_ELEMENT:
2197 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2198 return hr;
2199 if ((hr = write_startelement( writer )) != S_OK) return hr;
2200 writer->state = WRITER_STATE_STARTELEMENT;
2201 return S_OK;
2203 case WS_XML_NODE_TYPE_TEXT:
2204 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2205 return hr;
2206 if ((hr = write_text( writer )) != S_OK) return hr;
2207 writer->state = WRITER_STATE_TEXT;
2208 return S_OK;
2210 case WS_XML_NODE_TYPE_END_ELEMENT:
2211 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
2212 writer->state = WRITER_STATE_ENDELEMENT;
2213 return S_OK;
2215 case WS_XML_NODE_TYPE_COMMENT:
2216 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2217 return hr;
2218 if ((hr = write_comment( writer )) != S_OK) return hr;
2219 writer->state = WRITER_STATE_COMMENT;
2220 return S_OK;
2222 case WS_XML_NODE_TYPE_CDATA:
2223 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
2224 return hr;
2225 if ((hr = write_cdata( writer )) != S_OK) return hr;
2226 writer->state = WRITER_STATE_STARTCDATA;
2227 return S_OK;
2229 case WS_XML_NODE_TYPE_END_CDATA:
2230 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2231 writer->state = WRITER_STATE_ENDCDATA;
2232 return S_OK;
2234 case WS_XML_NODE_TYPE_EOF:
2235 case WS_XML_NODE_TYPE_BOF:
2236 return S_OK;
2238 default:
2239 ERR( "unknown node type %u\n", node_type(writer->current) );
2240 return E_INVALIDARG;
2244 static HRESULT write_tree( struct writer *writer )
2246 HRESULT hr;
2248 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2249 for (;;)
2251 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
2252 if (move_to_child_node( &writer->current ))
2254 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2255 continue;
2257 if (move_to_next_node( &writer->current ))
2259 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2260 continue;
2262 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
2264 ERR( "invalid tree\n" );
2265 return WS_E_INVALID_FORMAT;
2267 if ((hr = write_tree_node( writer )) != S_OK) return hr;
2269 return S_OK;
2272 static void write_rewind( struct writer *writer )
2274 writer->write_pos = 0;
2275 writer->current = writer->root;
2276 writer->state = WRITER_STATE_INITIAL;
2279 /**************************************************************************
2280 * WsCopyNode [webservices.@]
2282 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
2284 struct writer *writer = (struct writer *)handle;
2285 struct node *parent, *current = writer->current, *node = NULL;
2286 HRESULT hr;
2288 TRACE( "%p %p %p\n", handle, reader, error );
2289 if (error) FIXME( "ignoring error parameter\n" );
2291 if (!writer) return E_INVALIDARG;
2292 if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
2294 if ((hr = copy_node( reader, &node )) != S_OK) return hr;
2295 write_insert_node( writer, parent, node );
2297 write_rewind( writer );
2298 if ((hr = write_tree( writer )) != S_OK) return hr;
2300 writer->current = current;
2301 return S_OK;