server: Send WM_WINE_SETCURSOR with the thread input cursor handle.
[wine.git] / dlls / webservices / writer.c
blob6923035f00c226df64de1decc55c5fcebe4f0141
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 <assert.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <float.h>
24 #include <math.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "webservices.h"
32 #include "wine/debug.h"
33 #include "wine/list.h"
34 #include "webservices_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
38 static const struct prop_desc writer_props[] =
40 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
41 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
42 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES */
43 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
44 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
45 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
46 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
47 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
48 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
49 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
50 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
51 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
52 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
53 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
54 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
55 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
56 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
57 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
58 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
61 enum writer_state
63 WRITER_STATE_INITIAL,
64 WRITER_STATE_STARTELEMENT,
65 WRITER_STATE_STARTATTRIBUTE,
66 WRITER_STATE_STARTCDATA,
67 WRITER_STATE_ENDSTARTELEMENT,
68 WRITER_STATE_TEXT,
69 WRITER_STATE_COMMENT,
70 WRITER_STATE_ENDELEMENT,
71 WRITER_STATE_ENDCDATA
74 struct writer
76 ULONG magic;
77 CRITICAL_SECTION cs;
78 ULONG write_pos;
79 unsigned char *write_bufptr;
80 enum writer_state state;
81 struct node *root;
82 struct node *current;
83 WS_XML_STRING *current_ns;
84 WS_XML_WRITER_ENCODING_TYPE output_enc;
85 WS_CHARSET output_charset;
86 WS_XML_WRITER_OUTPUT_TYPE output_type;
87 WS_WRITE_CALLBACK output_cb;
88 void *output_cb_state;
89 struct xmlbuf *output_buf;
90 BOOL output_buf_user;
91 WS_HEAP *output_heap;
92 unsigned char *stream_buf;
93 const WS_XML_DICTIONARY *dict;
94 BOOL dict_do_lookup;
95 WS_DYNAMIC_STRING_CALLBACK dict_cb;
96 void *dict_cb_state;
97 ULONG prop_count;
98 struct prop prop[ARRAY_SIZE( writer_props )];
101 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
103 static struct writer *alloc_writer(void)
105 static const ULONG count = ARRAY_SIZE( writer_props );
106 struct writer *ret;
107 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
109 if (!(ret = calloc( 1, size ))) return NULL;
111 ret->magic = WRITER_MAGIC;
112 InitializeCriticalSection( &ret->cs );
113 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
115 prop_init( writer_props, count, ret->prop, &ret[1] );
116 ret->prop_count = count;
117 return ret;
120 static void free_writer( struct writer *writer )
122 destroy_nodes( writer->root );
123 free_xml_string( writer->current_ns );
124 WsFreeHeap( writer->output_heap );
125 free( writer->stream_buf );
127 writer->cs.DebugInfo->Spare[0] = 0;
128 DeleteCriticalSection( &writer->cs );
129 free( writer );
132 static void write_insert_eof( struct writer *writer, struct node *eof )
134 if (!writer->root) writer->root = eof;
135 else
137 eof->parent = writer->root;
138 list_add_tail( &writer->root->children, &eof->entry );
140 writer->current = eof;
143 static void write_insert_bof( struct writer *writer, struct node *bof )
145 writer->root->parent = bof;
146 list_add_tail( &bof->children, &writer->root->entry );
147 writer->current = writer->root = bof;
150 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
152 node->parent = parent;
153 list_add_before( list_tail( &parent->children ), &node->entry );
154 writer->current = node;
157 static struct node *find_parent( struct writer *writer )
159 if (is_valid_parent( writer->current )) return writer->current;
160 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
161 return NULL;
164 static HRESULT init_writer( struct writer *writer )
166 struct node *node;
168 writer->write_pos = 0;
169 writer->write_bufptr = NULL;
170 destroy_nodes( writer->root );
171 writer->root = writer->current = NULL;
172 free_xml_string( writer->current_ns );
173 writer->current_ns = NULL;
175 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
176 write_insert_eof( writer, node );
177 writer->state = WRITER_STATE_INITIAL;
178 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
179 writer->output_charset = WS_CHARSET_UTF8;
180 writer->dict = NULL;
181 writer->dict_do_lookup = FALSE;
182 writer->dict_cb = NULL;
183 writer->dict_cb_state = NULL;
184 return S_OK;
187 /**************************************************************************
188 * WsCreateWriter [webservices.@]
190 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
191 WS_XML_WRITER **handle, WS_ERROR *error )
193 struct writer *writer;
194 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
195 WS_CHARSET charset = WS_CHARSET_UTF8;
196 HRESULT hr;
198 TRACE( "%p %lu %p %p\n", properties, count, handle, error );
199 if (error) FIXME( "ignoring error parameter\n" );
201 if (!handle) return E_INVALIDARG;
202 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
204 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
205 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
206 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
207 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
208 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
209 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
210 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
212 for (i = 0; i < count; i++)
214 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
215 properties[i].valueSize );
216 if (hr != S_OK)
218 free_writer( writer );
219 return hr;
223 hr = WsCreateHeap( 1 << 20, 0, NULL, 0, &writer->output_heap, NULL );
224 if (hr != S_OK)
226 free_writer( writer );
227 return hr;
230 hr = init_writer( writer );
231 if (hr != S_OK)
233 free_writer( writer );
234 return hr;
237 TRACE( "created %p\n", writer );
238 *handle = (WS_XML_WRITER *)writer;
239 return S_OK;
242 /**************************************************************************
243 * WsFreeWriter [webservices.@]
245 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
247 struct writer *writer = (struct writer *)handle;
249 TRACE( "%p\n", handle );
251 if (!writer) return;
253 EnterCriticalSection( &writer->cs );
255 if (writer->magic != WRITER_MAGIC)
257 LeaveCriticalSection( &writer->cs );
258 return;
261 writer->magic = 0;
263 LeaveCriticalSection( &writer->cs );
264 free_writer( writer );
267 /**************************************************************************
268 * WsGetWriterProperty [webservices.@]
270 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
271 void *buf, ULONG size, WS_ERROR *error )
273 struct writer *writer = (struct writer *)handle;
274 HRESULT hr = S_OK;
276 TRACE( "%p %u %p %lu %p\n", handle, id, buf, size, error );
277 if (error) FIXME( "ignoring error parameter\n" );
279 if (!writer) return E_INVALIDARG;
281 EnterCriticalSection( &writer->cs );
283 if (writer->magic != WRITER_MAGIC)
285 LeaveCriticalSection( &writer->cs );
286 return E_INVALIDARG;
289 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
290 else
292 switch (id)
294 case WS_XML_WRITER_PROPERTY_BYTES:
296 WS_BYTES *bytes = buf;
297 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
298 else
300 bytes->bytes = writer->output_buf->bytes.bytes;
301 bytes->length = writer->output_buf->bytes.length;
303 break;
305 case WS_XML_WRITER_PROPERTY_BUFFERS:
306 if (writer->output_buf->bytes.length)
308 WS_BUFFERS *buffers = buf;
309 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
310 else
312 buffers->bufferCount = 1;
313 buffers->buffers = &writer->output_buf->bytes;
315 break;
317 /* fall through */
318 default:
319 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
323 LeaveCriticalSection( &writer->cs );
324 TRACE( "returning %#lx\n", hr );
325 return hr;
328 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
330 /* free current buffer if it's ours */
331 if (writer->output_buf && !writer->output_buf_user)
333 free_xmlbuf( writer->output_buf );
335 writer->output_buf = xmlbuf;
336 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
337 writer->write_bufptr = xmlbuf->bytes.bytes;
338 writer->write_pos = 0;
341 static void set_output_stream( struct writer *writer, WS_WRITE_CALLBACK callback, void *state )
343 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
344 writer->output_cb = callback;
345 writer->output_cb_state = state;
346 writer->write_bufptr = writer->stream_buf;
347 writer->write_pos = 0;
350 /**************************************************************************
351 * WsSetOutput [webservices.@]
353 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
354 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
355 ULONG count, WS_ERROR *error )
357 struct writer *writer = (struct writer *)handle;
358 struct node *node;
359 HRESULT hr;
360 ULONG i;
362 TRACE( "%p %p %p %p %lu %p\n", handle, encoding, output, properties, count, error );
363 if (error) FIXME( "ignoring error parameter\n" );
365 if (!writer) return E_INVALIDARG;
367 EnterCriticalSection( &writer->cs );
369 if (writer->magic != WRITER_MAGIC)
371 LeaveCriticalSection( &writer->cs );
372 return E_INVALIDARG;
375 for (i = 0; i < count; i++)
377 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
378 properties[i].valueSize );
379 if (hr != S_OK) goto done;
382 if ((hr = init_writer( writer )) != S_OK) goto done;
384 switch (encoding->encodingType)
386 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
388 const WS_XML_WRITER_TEXT_ENCODING *text = (const WS_XML_WRITER_TEXT_ENCODING *)encoding;
389 if (text->charSet != WS_CHARSET_UTF8)
391 FIXME( "charset %u not supported\n", text->charSet );
392 hr = E_NOTIMPL;
393 goto done;
395 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
396 writer->output_charset = WS_CHARSET_UTF8;
397 break;
399 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
401 const WS_XML_WRITER_BINARY_ENCODING *bin = (const WS_XML_WRITER_BINARY_ENCODING *)encoding;
402 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
403 writer->output_charset = 0;
404 writer->dict = bin->staticDictionary;
405 writer->dict_cb = bin->dynamicStringCallback;
406 writer->dict_cb_state = bin->dynamicStringCallbackState;
407 break;
409 default:
410 FIXME( "encoding type %u not supported\n", encoding->encodingType );
411 hr = E_NOTIMPL;
412 goto done;
415 switch (output->outputType)
417 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
419 struct xmlbuf *xmlbuf;
420 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, 0, writer->output_enc, writer->output_charset,
421 writer->dict, NULL )))
423 hr = WS_E_QUOTA_EXCEEDED;
424 goto done;
426 set_output_buffer( writer, xmlbuf );
427 writer->output_buf_user = FALSE;
428 break;
430 case WS_XML_WRITER_OUTPUT_TYPE_STREAM:
432 const WS_XML_WRITER_STREAM_OUTPUT *stream = (const WS_XML_WRITER_STREAM_OUTPUT *)output;
433 if (!writer->stream_buf && !(writer->stream_buf = malloc( STREAM_BUFSIZE )))
435 hr = E_OUTOFMEMORY;
436 goto done;
438 set_output_stream( writer, stream->writeCallback, stream->writeCallbackState );
439 break;
442 default:
443 FIXME( "output type %u not supported\n", output->outputType );
444 hr = E_NOTIMPL;
445 goto done;
448 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
449 else write_insert_bof( writer, node );
451 done:
452 LeaveCriticalSection( &writer->cs );
453 TRACE( "returning %#lx\n", hr );
454 return hr;
457 /**************************************************************************
458 * WsSetOutputToBuffer [webservices.@]
460 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
461 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
462 WS_ERROR *error )
464 struct writer *writer = (struct writer *)handle;
465 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
466 struct node *node;
467 HRESULT hr;
468 ULONG i;
470 TRACE( "%p %p %p %lu %p\n", handle, buffer, properties, count, error );
471 if (error) FIXME( "ignoring error parameter\n" );
473 if (!writer || !xmlbuf) return E_INVALIDARG;
475 EnterCriticalSection( &writer->cs );
477 if (writer->magic != WRITER_MAGIC)
479 LeaveCriticalSection( &writer->cs );
480 return E_INVALIDARG;
483 for (i = 0; i < count; i++)
485 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
486 properties[i].valueSize );
487 if (hr != S_OK) goto done;
490 if ((hr = init_writer( writer )) != S_OK) goto done;
491 writer->output_enc = xmlbuf->encoding;
492 writer->output_charset = xmlbuf->charset;
493 set_output_buffer( writer, xmlbuf );
494 writer->output_buf_user = TRUE;
496 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
497 else write_insert_bof( writer, node );
499 done:
500 LeaveCriticalSection( &writer->cs );
501 TRACE( "returning %#lx\n", hr );
502 return hr;
505 static HRESULT flush_writer( struct writer *writer, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
506 WS_ERROR *error )
508 WS_BYTES buf;
510 if (writer->write_pos < min_size) return S_OK;
512 buf.bytes = writer->write_bufptr;
513 buf.length = writer->write_pos;
514 writer->output_cb( writer->output_cb_state, &buf, 1, ctx, error );
515 writer->write_pos = 0;
516 return S_OK;
519 /**************************************************************************
520 * WsFlushWriter [webservices.@]
522 HRESULT WINAPI WsFlushWriter( WS_XML_WRITER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
523 WS_ERROR *error )
525 struct writer *writer = (struct writer *)handle;
526 HRESULT hr;
528 TRACE( "%p %lu %p %p\n", handle, min_size, ctx, error );
529 if (error) FIXME( "ignoring error parameter\n" );
530 if (ctx) FIXME( "ignoring ctx parameter\n" );
532 if (!writer) return E_INVALIDARG;
534 EnterCriticalSection( &writer->cs );
536 if (writer->magic != WRITER_MAGIC)
538 LeaveCriticalSection( &writer->cs );
539 return E_INVALIDARG;
542 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_STREAM) hr = WS_E_INVALID_OPERATION;
543 else hr = flush_writer( writer, min_size, ctx, error );
545 LeaveCriticalSection( &writer->cs );
546 TRACE( "returning %#lx\n", hr );
547 return hr;
550 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
552 struct xmlbuf *buf = writer->output_buf;
553 SIZE_T new_size;
554 void *tmp;
556 if (writer->output_type == WS_XML_WRITER_OUTPUT_TYPE_STREAM)
558 if (size > STREAM_BUFSIZE) return WS_E_QUOTA_EXCEEDED;
559 return flush_writer( writer, STREAM_BUFSIZE - size, NULL, NULL );
562 if (buf->size >= writer->write_pos + size)
564 buf->bytes.length = writer->write_pos + size;
565 return S_OK;
567 new_size = max( buf->size * 2, writer->write_pos + size );
568 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
569 writer->write_bufptr = buf->bytes.bytes = tmp;
570 buf->size = new_size;
571 buf->bytes.length = writer->write_pos + size;
572 return S_OK;
575 static inline void write_char( struct writer *writer, unsigned char ch )
577 writer->write_bufptr[writer->write_pos++] = ch;
580 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
582 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
583 writer->write_pos += len;
586 struct escape
588 char ch;
589 const char *entity;
590 ULONG len;
592 static const struct escape escape_lt = { '<', "&lt;", 4 };
593 static const struct escape escape_gt = { '>', "&gt;", 4 };
594 static const struct escape escape_amp = { '&', "&amp;", 5 };
595 static const struct escape escape_apos = { '\'', "&apos;", 6 };
596 static const struct escape escape_quot = { '"', "&quot;", 6 };
598 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
599 const struct escape **escapes, ULONG nb_escapes )
601 ULONG i, j, size;
602 const BYTE *ptr;
603 HRESULT hr;
605 for (i = 0; i < len; i++)
607 ptr = &bytes[i];
608 size = 1;
609 for (j = 0; j < nb_escapes; j++)
611 if (bytes[i] == escapes[j]->ch)
613 ptr = (const BYTE *)escapes[j]->entity;
614 size = escapes[j]->len;
615 break;
618 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
619 write_bytes( writer, ptr, size );
622 return S_OK;
625 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
627 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
628 const struct escape *escapes[3];
630 escapes[0] = single ? &escape_apos : &escape_quot;
631 escapes[1] = &escape_lt;
632 escapes[2] = &escape_amp;
633 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
636 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
638 unsigned char quote = attr->singleQuote ? '\'' : '"';
639 const WS_XML_STRING *prefix = NULL;
640 ULONG size;
641 HRESULT hr;
643 if (attr->prefix) prefix = attr->prefix;
645 /* ' prefix:attr="value"' */
647 size = attr->localName->length + 4 /* ' =""' */;
648 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
649 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
651 write_char( writer, ' ' );
652 if (prefix && prefix->length)
654 write_bytes( writer, prefix->bytes, prefix->length );
655 write_char( writer, ':' );
657 write_bytes( writer, attr->localName->bytes, attr->localName->length );
658 write_char( writer, '=' );
659 write_char( writer, quote );
660 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
661 write_char( writer, quote );
663 return hr;
666 static HRESULT write_int31( struct writer *writer, ULONG len )
668 HRESULT hr;
670 if (len > 0x7fffffff) return E_INVALIDARG;
672 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
673 if (len < 0x80)
675 write_char( writer, len );
676 return S_OK;
678 write_char( writer, (len & 0x7f) | 0x80 );
680 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
681 if ((len >>= 7) < 0x80)
683 write_char( writer, len );
684 return S_OK;
686 write_char( writer, (len & 0x7f) | 0x80 );
688 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
689 if ((len >>= 7) < 0x80)
691 write_char( writer, len );
692 return S_OK;
694 write_char( writer, (len & 0x7f) | 0x80 );
696 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
697 if ((len >>= 7) < 0x80)
699 write_char( writer, len );
700 return S_OK;
702 write_char( writer, (len & 0x7f) | 0x80 );
704 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
705 if ((len >>= 7) < 0x08)
707 write_char( writer, len );
708 return S_OK;
710 return WS_E_INVALID_FORMAT;
713 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
715 HRESULT hr;
716 if ((hr = write_int31( writer, len )) != S_OK) return hr;
717 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
718 write_bytes( writer, bytes, len );
719 return S_OK;
722 static HRESULT write_dict_string( struct writer *writer, ULONG id )
724 if (id > 0x7fffffff) return E_INVALIDARG;
725 return write_int31( writer, id );
728 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
730 if (!text) return RECORD_CHARS8_TEXT;
731 switch (text->textType)
733 case WS_XML_TEXT_TYPE_UTF8:
735 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
736 if (use_dict) return RECORD_DICTIONARY_TEXT;
737 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
738 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
739 return RECORD_CHARS32_TEXT;
741 case WS_XML_TEXT_TYPE_UTF16:
743 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
744 int len = text_utf16->byteCount / sizeof(WCHAR);
745 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
746 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT;
747 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT;
748 return RECORD_CHARS32_TEXT;
750 case WS_XML_TEXT_TYPE_BASE64:
752 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
753 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
754 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
755 return RECORD_BYTES32_TEXT;
757 case WS_XML_TEXT_TYPE_BOOL:
759 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
760 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
762 case WS_XML_TEXT_TYPE_INT32:
764 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
765 if (!text_int32->value) return RECORD_ZERO_TEXT;
766 if (text_int32->value == 1) return RECORD_ONE_TEXT;
767 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
768 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
769 return RECORD_INT32_TEXT;
771 case WS_XML_TEXT_TYPE_INT64:
773 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
774 if (!text_int64->value) return RECORD_ZERO_TEXT;
775 if (text_int64->value == 1) return RECORD_ONE_TEXT;
776 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
777 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
778 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
779 return RECORD_INT64_TEXT;
781 case WS_XML_TEXT_TYPE_UINT64:
783 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
784 if (!text_uint64->value) return RECORD_ZERO_TEXT;
785 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
786 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
787 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
788 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
789 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
790 return RECORD_UINT64_TEXT;
792 case WS_XML_TEXT_TYPE_DOUBLE:
794 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
795 if (!text_double->value) return RECORD_ZERO_TEXT;
796 if (text_double->value == 1) return RECORD_ONE_TEXT;
797 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
798 return RECORD_DOUBLE_TEXT;
799 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
800 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
801 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
802 return RECORD_INT64_TEXT;
804 case WS_XML_TEXT_TYPE_GUID:
805 return RECORD_GUID_TEXT;
807 case WS_XML_TEXT_TYPE_UNIQUE_ID:
808 return RECORD_UNIQUE_ID_TEXT;
810 case WS_XML_TEXT_TYPE_DATETIME:
811 return RECORD_DATETIME_TEXT;
813 default:
814 FIXME( "unhandled text type %u\n", text->textType );
815 return 0;
819 static INT64 get_text_value_int( const WS_XML_TEXT *text )
821 switch (text->textType)
823 case WS_XML_TEXT_TYPE_INT32:
825 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
826 return text_int32->value;
828 case WS_XML_TEXT_TYPE_INT64:
830 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
831 return text_int64->value;
833 case WS_XML_TEXT_TYPE_UINT64:
835 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
836 return text_uint64->value;
838 case WS_XML_TEXT_TYPE_DOUBLE:
840 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
841 return text_double->value;
843 default:
844 ERR( "unhandled text type %u\n", text->textType );
845 assert(0);
846 return 0;
850 static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
852 if (writer->dict && str->dictionary == writer->dict)
854 *id = str->id << 1;
855 return TRUE;
857 if (writer->dict_cb)
859 BOOL found = FALSE;
860 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
861 if (found) *id = (*id << 1) | 1;
862 return found;
864 return FALSE;
867 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
869 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
870 if (*ptr)
872 memcpy( buf, bool_true, sizeof(bool_true) );
873 return sizeof(bool_true);
875 memcpy( buf, bool_false, sizeof(bool_false) );
876 return sizeof(bool_false);
879 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
881 return wsprintfA( (char *)buf, "%d", *ptr );
884 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
886 return wsprintfA( (char *)buf, "%I64d", *ptr );
889 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
891 return wsprintfA( (char *)buf, "%I64u", *ptr );
894 static ULONG format_double( const double *ptr, unsigned char *buf )
896 static const double precision = 0.0000000000000001;
897 unsigned char *p = buf;
898 double val = *ptr;
899 int neg, mag, mag2 = 0, use_exp;
901 if (isnan( val ))
903 memcpy( buf, "NaN", 3 );
904 return 3;
906 if (isinf( val ))
908 if (val < 0)
910 memcpy( buf, "-INF", 4 );
911 return 4;
913 memcpy( buf, "INF", 3 );
914 return 3;
916 if (val == 0.0)
918 *p = '0';
919 return 1;
922 if ((neg = val < 0))
924 *p++ = '-';
925 val = -val;
928 mag = log10( val );
929 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
930 if (use_exp)
932 if (mag < 0) mag -= 1;
933 val = val / pow( 10.0, mag );
934 mag2 = mag;
935 mag = 0;
937 else if (mag < 1) mag = 0;
939 while (val > precision || mag >= 0)
941 double weight = pow( 10.0, mag );
942 if (weight > 0 && !isinf( weight ))
944 int digit = floor( val / weight );
945 val -= digit * weight;
946 *(p++) = '0' + digit;
948 if (!mag && val > precision) *(p++) = '.';
949 mag--;
952 if (use_exp)
954 int i, j;
955 *(p++) = 'E';
956 if (mag2 > 0) *(p++) = '+';
957 else
959 *(p++) = '-';
960 mag2 = -mag2;
962 mag = 0;
963 while (mag2 > 0)
965 *(p++) = '0' + mag2 % 10;
966 mag2 /= 10;
967 mag++;
969 for (i = -mag, j = -1; i < j; i++, j--)
971 p[i] ^= p[j];
972 p[j] ^= p[i];
973 p[i] ^= p[j];
977 return p - buf;
980 static inline int year_size( int year )
982 return leap_year( year ) ? 366 : 365;
985 #define TZ_OFFSET 8
986 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
988 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
989 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
990 unsigned __int64 ticks, day_ticks;
991 ULONG len;
993 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
994 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
996 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
997 tz_hour = TZ_OFFSET;
999 else
1001 ticks = ptr->ticks;
1002 tz_hour = 0;
1004 day = ticks / TICKS_PER_DAY;
1005 day_ticks = ticks % TICKS_PER_DAY;
1006 hour = day_ticks / TICKS_PER_HOUR;
1007 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1008 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1009 sec_frac = day_ticks % TICKS_PER_SEC;
1011 while (day >= year_size( year ))
1013 day -= year_size( year );
1014 year++;
1016 while (day >= month_days[leap_year( year )][month])
1018 day -= month_days[leap_year( year )][month];
1019 month++;
1022 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1023 if (sec_frac)
1025 static const char fmt_frac[] = ".%07u";
1026 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1027 while (buf[len - 1] == '0') len--;
1029 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1031 buf[len++] = 'Z';
1033 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1035 static const char fmt_tz[] = "%c%02u:00";
1036 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1039 return len;
1042 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1044 static const char fmt[] = "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1045 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1046 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1047 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1050 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1052 static const char fmt[] = "urn:uuid:%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1053 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1054 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1055 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1058 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
1060 ULONG len = 0;
1061 if (prefix && prefix->length)
1063 memcpy( buf, prefix->bytes, prefix->length );
1064 len += prefix->length;
1065 buf[len++] = ':';
1067 memcpy( buf + len, localname->bytes, localname->length );
1068 return len + localname->length;
1071 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1073 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1074 ULONG i = 0, x;
1076 while (len > 0)
1078 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1079 x = (bin[0] & 3) << 4;
1080 if (len == 1)
1082 buf[i++] = base64[x];
1083 buf[i++] = '=';
1084 buf[i++] = '=';
1085 break;
1087 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1088 x = (bin[1] & 0x0f) << 2;
1089 if (len == 2)
1091 buf[i++] = base64[x];
1092 buf[i++] = '=';
1093 break;
1095 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1096 buf[i++] = base64[bin[2] & 0x3f];
1097 bin += 3;
1098 len -= 3;
1100 return i;
1103 HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
1104 WS_XML_UTF8_TEXT **ret )
1106 ULONG len_old = old ? old->value.length : 0;
1107 if (offset) *offset = len_old;
1109 switch (text->textType)
1111 case WS_XML_TEXT_TYPE_UTF8:
1113 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1115 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
1116 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1117 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
1118 return S_OK;
1120 case WS_XML_TEXT_TYPE_UTF16:
1122 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1123 const WCHAR *str = (const WCHAR *)src->bytes;
1124 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1126 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1127 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1128 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
1129 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1130 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
1131 return S_OK;
1133 case WS_XML_TEXT_TYPE_BASE64:
1135 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1136 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1138 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1139 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1140 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
1141 return S_OK;
1143 case WS_XML_TEXT_TYPE_BOOL:
1145 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1147 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
1148 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1149 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
1150 return S_OK;
1152 case WS_XML_TEXT_TYPE_INT32:
1154 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1155 unsigned char buf[12]; /* "-2147483648" */
1156 ULONG len = format_int32( &int32_text->value, buf );
1158 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1159 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1160 memcpy( (*ret)->value.bytes + len_old, buf, len );
1161 return S_OK;
1163 case WS_XML_TEXT_TYPE_INT64:
1165 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1166 unsigned char buf[21]; /* "-9223372036854775808" */
1167 ULONG len = format_int64( &int64_text->value, buf );
1169 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1170 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1171 memcpy( (*ret)->value.bytes + len_old, buf, len );
1172 return S_OK;
1174 case WS_XML_TEXT_TYPE_UINT64:
1176 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1177 unsigned char buf[21]; /* "18446744073709551615" */
1178 ULONG len = format_uint64( &uint64_text->value, buf );
1180 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1181 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1182 memcpy( (*ret)->value.bytes + len_old, buf, len );
1183 return S_OK;
1185 case WS_XML_TEXT_TYPE_DOUBLE:
1187 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1188 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1189 unsigned int fpword = _control87( 0, 0 );
1190 ULONG len;
1192 _control87( _MCW_EM | _RC_NEAR | _PC_64, _MCW_EM | _MCW_RC | _MCW_PC );
1193 len = format_double( &double_text->value, buf );
1194 _control87( fpword, _MCW_EM | _MCW_RC | _MCW_PC );
1195 if (!len) return E_NOTIMPL;
1197 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1198 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1199 memcpy( (*ret)->value.bytes + len_old, buf, len );
1200 return S_OK;
1202 case WS_XML_TEXT_TYPE_GUID:
1204 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1206 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
1207 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1208 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1209 return S_OK;
1211 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1213 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1215 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
1216 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1217 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1218 return S_OK;
1220 case WS_XML_TEXT_TYPE_DATETIME:
1222 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1224 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
1225 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1226 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
1227 return S_OK;
1229 case WS_XML_TEXT_TYPE_QNAME:
1231 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
1232 ULONG len = qn->localName->length;
1234 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
1235 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1236 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1237 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
1238 return S_OK;
1240 default:
1241 FIXME( "unhandled text type %u\n", text->textType );
1242 return E_NOTIMPL;
1246 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
1248 enum record_type type;
1249 BOOL use_dict = FALSE;
1250 HRESULT hr;
1251 ULONG id;
1253 if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
1255 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1256 use_dict = get_string_id( writer, &utf8->value, &id );
1258 type = get_attr_text_record_type( text, use_dict );
1260 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1261 write_char( writer, type );
1263 switch (type)
1265 case RECORD_CHARS8_TEXT:
1267 const WS_XML_UTF8_TEXT *text_utf8;
1268 WS_XML_UTF8_TEXT *new = NULL;
1269 UINT8 len;
1271 if (!text)
1273 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1274 write_char( writer, 0 );
1275 return S_OK;
1277 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1278 else
1280 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1281 text_utf8 = new;
1283 len = text_utf8->value.length;
1284 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1286 free( new );
1287 return hr;
1289 write_char( writer, len );
1290 write_bytes( writer, text_utf8->value.bytes, len );
1291 free( new );
1292 return S_OK;
1294 case RECORD_CHARS16_TEXT:
1296 const WS_XML_UTF8_TEXT *text_utf8;
1297 WS_XML_UTF8_TEXT *new = NULL;
1298 UINT16 len;
1300 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1301 else
1303 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1304 text_utf8 = new;
1306 len = text_utf8->value.length;
1307 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1309 free( new );
1310 return hr;
1312 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1313 write_bytes( writer, text_utf8->value.bytes, len );
1314 free( new );
1315 return S_OK;
1317 case RECORD_BYTES8_TEXT:
1319 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1320 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
1321 write_char( writer, text_base64->length );
1322 write_bytes( writer, text_base64->bytes, text_base64->length );
1323 return S_OK;
1325 case RECORD_BYTES16_TEXT:
1327 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1328 UINT16 len = text_base64->length;
1329 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
1330 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1331 write_bytes( writer, text_base64->bytes, len );
1332 return S_OK;
1334 case RECORD_ZERO_TEXT:
1335 case RECORD_ONE_TEXT:
1336 case RECORD_FALSE_TEXT:
1337 case RECORD_TRUE_TEXT:
1338 return S_OK;
1340 case RECORD_INT8_TEXT:
1342 INT8 val = get_text_value_int( text );
1343 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1344 write_char( writer, val );
1345 return S_OK;
1347 case RECORD_INT16_TEXT:
1349 INT16 val = get_text_value_int( text );
1350 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1351 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1352 return S_OK;
1354 case RECORD_INT32_TEXT:
1356 INT32 val = get_text_value_int( text );
1357 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1358 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1359 return S_OK;
1361 case RECORD_INT64_TEXT:
1363 INT64 val = get_text_value_int( text );
1364 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1365 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1366 return S_OK;
1368 case RECORD_UINT64_TEXT:
1370 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
1371 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
1372 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
1373 return S_OK;
1375 case RECORD_DOUBLE_TEXT:
1377 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
1378 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
1379 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
1380 return S_OK;
1382 case RECORD_GUID_TEXT:
1384 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
1385 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
1386 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
1387 return S_OK;
1389 case RECORD_UNIQUE_ID_TEXT:
1391 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
1392 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
1393 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
1394 return S_OK;
1396 case RECORD_DATETIME_TEXT:
1398 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
1399 UINT64 val = text_datetime->value.ticks;
1401 assert( val <= TICKS_MAX );
1402 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
1403 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
1405 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1406 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1407 return S_OK;
1409 default:
1410 FIXME( "unhandled record type %02x\n", type );
1411 return E_NOTIMPL;
1415 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1417 if (!attr->prefix || !attr->prefix->length)
1419 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
1420 return RECORD_SHORT_ATTRIBUTE;
1422 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
1424 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1425 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1427 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
1428 return RECORD_ATTRIBUTE;
1431 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1433 ULONG id;
1434 enum record_type type = get_attr_record_type( attr, get_string_id(writer, attr->localName, &id) );
1435 HRESULT hr;
1437 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1438 write_char( writer, type );
1440 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
1442 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1443 return write_attribute_value_bin( writer, attr->value );
1445 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
1447 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1448 return write_attribute_value_bin( writer, attr->value );
1451 switch (type)
1453 case RECORD_SHORT_ATTRIBUTE:
1454 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1455 break;
1457 case RECORD_ATTRIBUTE:
1458 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1459 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1460 break;
1462 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
1463 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1464 break;
1466 case RECORD_DICTIONARY_ATTRIBUTE:
1467 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1468 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1469 break;
1471 default:
1472 ERR( "unhandled record type %02x\n", type );
1473 return WS_E_NOT_SUPPORTED;
1476 return write_attribute_value_bin( writer, attr->value );
1479 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1481 switch (writer->output_enc)
1483 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
1484 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
1485 default:
1486 ERR( "unhandled encoding %u\n", writer->output_enc );
1487 return WS_E_NOT_SUPPORTED;
1491 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1493 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
1496 /**************************************************************************
1497 * WsGetPrefixFromNamespace [webservices.@]
1499 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
1500 BOOL required, const WS_XML_STRING **prefix,
1501 WS_ERROR *error )
1503 struct writer *writer = (struct writer *)handle;
1504 WS_XML_ELEMENT_NODE *elem;
1505 BOOL found = FALSE;
1506 HRESULT hr = S_OK;
1508 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1509 if (error) FIXME( "ignoring error parameter\n" );
1511 if (!writer || !ns || !prefix) return E_INVALIDARG;
1513 EnterCriticalSection( &writer->cs );
1515 if (writer->magic != WRITER_MAGIC)
1517 LeaveCriticalSection( &writer->cs );
1518 return E_INVALIDARG;
1521 elem = &writer->current->hdr;
1522 if (elem->prefix && is_current_namespace( writer, ns ))
1524 *prefix = elem->prefix;
1525 found = TRUE;
1528 if (!found)
1530 if (required) hr = WS_E_INVALID_FORMAT;
1531 else
1533 *prefix = NULL;
1534 hr = S_FALSE;
1538 LeaveCriticalSection( &writer->cs );
1539 TRACE( "returning %#lx\n", hr );
1540 return hr;
1543 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1545 unsigned char quote = attr->singleQuote ? '\'' : '"';
1546 ULONG size;
1547 HRESULT hr;
1549 /* ' xmlns:prefix="namespace"' */
1551 size = attr->ns->length + 9 /* ' xmlns=""' */;
1552 if (attr->prefix && attr->prefix->length) size += attr->prefix->length + 1 /* ':' */;
1553 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1555 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1556 if (attr->prefix && attr->prefix->length)
1558 write_char( writer, ':' );
1559 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1561 write_char( writer, '=' );
1562 write_char( writer, quote );
1563 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1564 write_char( writer, quote );
1566 return S_OK;
1569 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1571 if (!attr->prefix || !attr->prefix->length)
1573 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1574 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1576 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1577 return RECORD_XMLNS_ATTRIBUTE;
1580 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1582 ULONG id;
1583 enum record_type type = get_xmlns_record_type( attr, get_string_id(writer, attr->ns, &id) );
1584 HRESULT hr;
1586 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1587 write_char( writer, type );
1589 switch (type)
1591 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1592 break;
1594 case RECORD_XMLNS_ATTRIBUTE:
1595 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1596 break;
1598 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1599 return write_dict_string( writer, id );
1601 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1602 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1603 return write_dict_string( writer, id );
1605 default:
1606 ERR( "unhandled record type %02x\n", type );
1607 return WS_E_NOT_SUPPORTED;
1610 return write_string( writer, attr->ns->bytes, attr->ns->length );
1613 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1615 switch (writer->output_enc)
1617 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1618 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1619 default:
1620 ERR( "unhandled encoding %u\n", writer->output_enc );
1621 return WS_E_NOT_SUPPORTED;
1625 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1626 const WS_XML_STRING *ns, BOOL single )
1628 WS_XML_ATTRIBUTE *attr;
1629 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1630 HRESULT hr;
1632 if (!(attr = calloc( 1, sizeof(*attr) ))) return E_OUTOFMEMORY;
1634 attr->singleQuote = !!single;
1635 attr->isXmlNs = 1;
1636 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1638 free_attribute( attr );
1639 return E_OUTOFMEMORY;
1641 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1643 free_attribute( attr );
1644 return E_OUTOFMEMORY;
1646 if ((hr = append_attribute( elem, attr )) != S_OK)
1648 free_attribute( attr );
1649 return hr;
1651 return S_OK;
1654 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1656 if (!str1 && !str2) return TRUE;
1657 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1660 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1661 const WS_XML_STRING *ns )
1663 ULONG i;
1664 const struct node *node;
1666 for (node = (const struct node *)elem; node; node = node->parent)
1668 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1670 elem = &node->hdr;
1671 for (i = 0; i < elem->attributeCount; i++)
1673 if (!elem->attributes[i]->isXmlNs) continue;
1674 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1675 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1678 return FALSE;
1681 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1683 WS_XML_STRING *str;
1684 if (!(str = dup_xml_string( ns, writer->dict_do_lookup ))) return E_OUTOFMEMORY;
1685 free_xml_string( writer->current_ns );
1686 writer->current_ns = str;
1687 return S_OK;
1690 static HRESULT set_namespaces( struct writer *writer )
1692 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1693 HRESULT hr;
1694 ULONG i;
1696 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1698 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1699 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1702 for (i = 0; i < elem->attributeCount; i++)
1704 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1705 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1706 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1709 return S_OK;
1712 /**************************************************************************
1713 * WsWriteEndAttribute [webservices.@]
1715 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1717 struct writer *writer = (struct writer *)handle;
1718 HRESULT hr = S_OK;
1720 TRACE( "%p %p\n", handle, error );
1721 if (error) FIXME( "ignoring error parameter\n" );
1723 if (!writer) return E_INVALIDARG;
1725 EnterCriticalSection( &writer->cs );
1727 if (writer->magic != WRITER_MAGIC)
1729 LeaveCriticalSection( &writer->cs );
1730 return E_INVALIDARG;
1733 writer->state = WRITER_STATE_STARTELEMENT;
1735 LeaveCriticalSection( &writer->cs );
1736 TRACE( "returning %#lx\n", hr );
1737 return hr;
1740 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1742 ULONG i;
1743 HRESULT hr;
1744 for (i = 0; i < elem->attributeCount; i++)
1746 if (elem->attributes[i]->isXmlNs) continue;
1747 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1749 for (i = 0; i < elem->attributeCount; i++)
1751 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1752 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1754 for (i = 0; i < elem->attributeCount; i++)
1756 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1757 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1759 return S_OK;
1762 static HRESULT write_startelement_text( struct writer *writer )
1764 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1765 ULONG size;
1766 HRESULT hr;
1768 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1770 size = elem->localName->length + 1 /* '<' */;
1771 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1772 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1774 write_char( writer, '<' );
1775 if (elem->prefix && elem->prefix->length)
1777 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1778 write_char( writer, ':' );
1780 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1781 return write_attributes( writer, elem );
1784 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1786 if (!elem->prefix || !elem->prefix->length)
1788 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1789 return RECORD_SHORT_ELEMENT;
1791 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1793 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1794 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1796 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1797 return RECORD_ELEMENT;
1800 static HRESULT write_startelement_bin( struct writer *writer )
1802 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1803 ULONG id;
1804 enum record_type type = get_elem_record_type( elem, get_string_id(writer, elem->localName, &id) );
1805 HRESULT hr;
1807 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1808 write_char( writer, type );
1810 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1812 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1813 return write_attributes( writer, elem );
1815 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1817 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1818 return write_attributes( writer, elem );
1821 switch (type)
1823 case RECORD_SHORT_ELEMENT:
1824 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1825 break;
1827 case RECORD_ELEMENT:
1828 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1829 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1830 break;
1832 case RECORD_SHORT_DICTIONARY_ELEMENT:
1833 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1834 break;
1836 case RECORD_DICTIONARY_ELEMENT:
1837 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1838 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1839 break;
1841 default:
1842 ERR( "unhandled record type %02x\n", type );
1843 return WS_E_NOT_SUPPORTED;
1846 return write_attributes( writer, elem );
1849 static HRESULT write_startelement( struct writer *writer )
1851 switch (writer->output_enc)
1853 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1854 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1855 default:
1856 ERR( "unhandled encoding %u\n", writer->output_enc );
1857 return WS_E_NOT_SUPPORTED;
1861 static struct node *write_find_startelement( struct writer *writer )
1863 struct node *node;
1864 for (node = writer->current; node; node = node->parent)
1866 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1868 return NULL;
1871 static inline BOOL is_empty_element( const struct node *node )
1873 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1874 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1877 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1879 ULONG size;
1880 HRESULT hr;
1882 /* '/>' */
1884 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1886 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1887 write_char( writer, '/' );
1888 write_char( writer, '>' );
1889 return S_OK;
1892 /* '</prefix:localname>' */
1894 size = elem->localName->length + 3 /* '</>' */;
1895 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1896 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1898 write_char( writer, '<' );
1899 write_char( writer, '/' );
1900 if (elem->prefix && elem->prefix->length)
1902 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1903 write_char( writer, ':' );
1905 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1906 write_char( writer, '>' );
1907 return S_OK;
1910 static HRESULT write_endelement_bin( struct writer *writer )
1912 HRESULT hr;
1913 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1914 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1915 write_char( writer, RECORD_ENDELEMENT );
1916 return S_OK;
1919 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1921 switch (writer->output_enc)
1923 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1924 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1925 default:
1926 ERR( "unhandled encoding %u\n", writer->output_enc );
1927 return WS_E_NOT_SUPPORTED;
1931 static HRESULT write_close_element( struct writer *writer, struct node *node )
1933 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1934 elem->isEmpty = is_empty_element( node );
1935 return write_endelement( writer, elem );
1938 static HRESULT write_endelement_node( struct writer *writer )
1940 struct node *node;
1941 HRESULT hr;
1943 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1944 if (writer->state == WRITER_STATE_STARTELEMENT)
1946 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1947 if ((hr = write_startelement( writer )) != S_OK) return hr;
1949 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1950 writer->current = node->parent;
1951 writer->state = WRITER_STATE_ENDELEMENT;
1952 return S_OK;
1955 /**************************************************************************
1956 * WsWriteEndElement [webservices.@]
1958 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1960 struct writer *writer = (struct writer *)handle;
1961 HRESULT hr;
1963 TRACE( "%p %p\n", handle, error );
1964 if (error) FIXME( "ignoring error parameter\n" );
1966 if (!writer) return E_INVALIDARG;
1968 EnterCriticalSection( &writer->cs );
1970 if (writer->magic != WRITER_MAGIC)
1972 LeaveCriticalSection( &writer->cs );
1973 return E_INVALIDARG;
1976 hr = write_endelement_node( writer );
1978 LeaveCriticalSection( &writer->cs );
1979 TRACE( "returning %#lx\n", hr );
1980 return hr;
1983 static HRESULT write_endstartelement_text( struct writer *writer )
1985 HRESULT hr;
1986 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1987 write_char( writer, '>' );
1988 return S_OK;
1991 static HRESULT write_endstartelement( struct writer *writer )
1993 switch (writer->output_enc)
1995 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1996 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1997 default:
1998 ERR( "unhandled encoding %u\n", writer->output_enc );
1999 return WS_E_NOT_SUPPORTED;
2003 /**************************************************************************
2004 * WsWriteEndStartElement [webservices.@]
2006 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
2008 struct writer *writer = (struct writer *)handle;
2009 HRESULT hr;
2011 TRACE( "%p %p\n", handle, error );
2012 if (error) FIXME( "ignoring error parameter\n" );
2014 if (!writer) return E_INVALIDARG;
2016 EnterCriticalSection( &writer->cs );
2018 if (writer->magic != WRITER_MAGIC)
2020 LeaveCriticalSection( &writer->cs );
2021 return E_INVALIDARG;
2024 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2025 else
2027 if ((hr = set_namespaces( writer )) != S_OK) goto done;
2028 if ((hr = write_startelement( writer )) != S_OK) goto done;
2029 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
2030 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2033 done:
2034 LeaveCriticalSection( &writer->cs );
2035 TRACE( "returning %#lx\n", hr );
2036 return hr;
2039 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
2040 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2041 BOOL single )
2043 WS_XML_ATTRIBUTE *attr;
2044 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2045 HRESULT hr;
2047 if (!(attr = calloc( 1, sizeof(*attr) ))) return E_OUTOFMEMORY;
2049 if (!prefix && ns->length) prefix = elem->prefix;
2051 attr->singleQuote = !!single;
2052 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2054 free_attribute( attr );
2055 return E_OUTOFMEMORY;
2057 if (!(attr->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2059 free_attribute( attr );
2060 return E_OUTOFMEMORY;
2062 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2064 free_attribute( attr );
2065 return E_OUTOFMEMORY;
2067 if ((hr = append_attribute( elem, attr )) != S_OK)
2069 free_attribute( attr );
2070 return hr;
2072 return S_OK;
2075 /**************************************************************************
2076 * WsWriteStartAttribute [webservices.@]
2078 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2079 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2080 BOOL single, WS_ERROR *error )
2082 struct writer *writer = (struct writer *)handle;
2083 HRESULT hr;
2085 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2086 debugstr_xmlstr(ns), single, error );
2087 if (error) FIXME( "ignoring error parameter\n" );
2089 if (!writer || !localname || !ns) return E_INVALIDARG;
2091 EnterCriticalSection( &writer->cs );
2093 if (writer->magic != WRITER_MAGIC)
2095 LeaveCriticalSection( &writer->cs );
2096 return E_INVALIDARG;
2099 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2100 else if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
2101 writer->state = WRITER_STATE_STARTATTRIBUTE;
2103 LeaveCriticalSection( &writer->cs );
2104 TRACE( "returning %#lx\n", hr );
2105 return hr;
2108 /* flush current start element if necessary */
2109 static HRESULT write_commit( struct writer *writer )
2111 if (writer->state == WRITER_STATE_STARTELEMENT)
2113 HRESULT hr;
2114 if ((hr = set_namespaces( writer )) != S_OK) return hr;
2115 if ((hr = write_startelement( writer )) != S_OK) return hr;
2116 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
2117 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2119 return S_OK;
2122 static HRESULT write_add_cdata_node( struct writer *writer )
2124 struct node *node, *parent;
2125 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2126 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2127 write_insert_node( writer, parent, node );
2128 return S_OK;
2131 static HRESULT write_add_endcdata_node( struct writer *writer )
2133 struct node *node;
2134 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
2135 node->parent = writer->current;
2136 list_add_tail( &node->parent->children, &node->entry );
2137 return S_OK;
2140 static HRESULT write_cdata( struct writer *writer )
2142 HRESULT hr;
2143 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
2144 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
2145 return S_OK;
2148 static HRESULT write_cdata_node( struct writer *writer )
2150 HRESULT hr;
2151 if ((hr = write_commit( writer )) != S_OK) return hr;
2152 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
2153 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
2154 if ((hr = write_cdata( writer )) != S_OK) return hr;
2155 writer->state = WRITER_STATE_STARTCDATA;
2156 return S_OK;
2159 /**************************************************************************
2160 * WsWriteStartCData [webservices.@]
2162 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
2164 struct writer *writer = (struct writer *)handle;
2165 HRESULT hr;
2167 TRACE( "%p %p\n", handle, error );
2168 if (error) FIXME( "ignoring error parameter\n" );
2170 if (!writer) return E_INVALIDARG;
2172 EnterCriticalSection( &writer->cs );
2174 if (writer->magic != WRITER_MAGIC)
2176 LeaveCriticalSection( &writer->cs );
2177 return E_INVALIDARG;
2180 hr = write_cdata_node( writer );
2182 LeaveCriticalSection( &writer->cs );
2183 TRACE( "returning %#lx\n", hr );
2184 return hr;
2187 static HRESULT write_endcdata( struct writer *writer )
2189 HRESULT hr;
2190 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2191 write_bytes( writer, (const BYTE *)"]]>", 3 );
2192 return S_OK;
2195 static HRESULT write_endcdata_node( struct writer *writer )
2197 HRESULT hr;
2198 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2199 writer->current = writer->current->parent;
2200 writer->state = WRITER_STATE_ENDCDATA;
2201 return S_OK;
2204 /**************************************************************************
2205 * WsWriteEndCData [webservices.@]
2207 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
2209 struct writer *writer = (struct writer *)handle;
2210 HRESULT hr;
2212 TRACE( "%p %p\n", handle, error );
2213 if (error) FIXME( "ignoring error parameter\n" );
2215 if (!writer) return E_INVALIDARG;
2217 EnterCriticalSection( &writer->cs );
2219 if (writer->magic != WRITER_MAGIC)
2221 LeaveCriticalSection( &writer->cs );
2222 return E_INVALIDARG;
2225 if (writer->state != WRITER_STATE_TEXT) hr = WS_E_INVALID_OPERATION;
2226 else hr = write_endcdata_node( writer );
2228 LeaveCriticalSection( &writer->cs );
2229 TRACE( "returning %#lx\n", hr );
2230 return hr;
2233 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2234 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2236 struct node *node, *parent;
2237 WS_XML_ELEMENT_NODE *elem;
2239 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2241 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
2243 elem = &parent->hdr;
2244 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
2247 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
2248 elem = &node->hdr;
2250 if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2252 free_node( node );
2253 return E_OUTOFMEMORY;
2255 if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2257 free_node( node );
2258 return E_OUTOFMEMORY;
2260 if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2262 free_node( node );
2263 return E_OUTOFMEMORY;
2265 write_insert_node( writer, parent, node );
2266 return S_OK;
2269 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
2271 struct node *node;
2272 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
2273 node->parent = parent;
2274 list_add_tail( &parent->children, &node->entry );
2275 return S_OK;
2278 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2279 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2281 HRESULT hr;
2282 if ((hr = write_commit( writer )) != S_OK) return hr;
2283 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
2284 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
2285 writer->state = WRITER_STATE_STARTELEMENT;
2286 return S_OK;
2289 /**************************************************************************
2290 * WsWriteStartElement [webservices.@]
2292 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2293 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2294 WS_ERROR *error )
2296 struct writer *writer = (struct writer *)handle;
2297 HRESULT hr;
2299 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2300 debugstr_xmlstr(ns), error );
2301 if (error) FIXME( "ignoring error parameter\n" );
2303 if (!writer || !localname || !ns) return E_INVALIDARG;
2305 EnterCriticalSection( &writer->cs );
2307 if (writer->magic != WRITER_MAGIC)
2309 LeaveCriticalSection( &writer->cs );
2310 return E_INVALIDARG;
2313 hr = write_element_node( writer, prefix, localname, ns );
2315 LeaveCriticalSection( &writer->cs );
2316 TRACE( "returning %#lx\n", hr );
2317 return hr;
2320 HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2322 if (offset) *offset = 0;
2323 switch (text->textType)
2325 case WS_XML_TEXT_TYPE_UTF8:
2327 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2328 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2329 WS_XML_UTF8_TEXT *new;
2330 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2332 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2333 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2334 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2335 if (offset) *offset = len_old;
2336 *ret = &new->text;
2337 return S_OK;
2339 case WS_XML_TEXT_TYPE_UTF16:
2341 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2342 const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
2343 WS_XML_UTF16_TEXT *new;
2344 ULONG len = utf16->byteCount, len_old = utf16_old ? utf16_old->byteCount : 0;
2346 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2347 if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2348 if (utf16_old) memcpy( new->bytes, utf16_old->bytes, len_old );
2349 memcpy( new->bytes + len_old, utf16->bytes, len );
2350 if (offset) *offset = len_old;
2351 *ret = &new->text;
2352 return S_OK;
2354 case WS_XML_TEXT_TYPE_BASE64:
2356 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2357 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2358 WS_XML_BASE64_TEXT *new;
2359 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2361 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2362 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2363 memcpy( new->bytes + len_old, base64->bytes, len );
2364 if (offset) *offset = len_old;
2365 *ret = &new->text;
2366 return S_OK;
2368 case WS_XML_TEXT_TYPE_BOOL:
2370 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2371 WS_XML_BOOL_TEXT *new;
2373 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2374 *ret = &new->text;
2375 return S_OK;
2377 case WS_XML_TEXT_TYPE_INT32:
2379 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2380 WS_XML_INT32_TEXT *new;
2382 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2383 *ret = &new->text;
2384 return S_OK;
2386 case WS_XML_TEXT_TYPE_INT64:
2388 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2389 WS_XML_INT64_TEXT *new;
2391 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2392 *ret = &new->text;
2393 return S_OK;
2395 case WS_XML_TEXT_TYPE_UINT64:
2397 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2398 WS_XML_UINT64_TEXT *new;
2400 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2401 *ret = &new->text;
2402 return S_OK;
2404 case WS_XML_TEXT_TYPE_DOUBLE:
2406 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2407 WS_XML_DOUBLE_TEXT *new;
2409 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2410 *ret = &new->text;
2411 return S_OK;
2413 case WS_XML_TEXT_TYPE_GUID:
2415 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2416 WS_XML_GUID_TEXT *new;
2418 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2419 *ret = &new->text;
2420 return S_OK;
2422 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2424 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2425 WS_XML_UNIQUE_ID_TEXT *new;
2427 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2428 *ret = &new->text;
2429 return S_OK;
2431 case WS_XML_TEXT_TYPE_DATETIME:
2433 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2434 WS_XML_DATETIME_TEXT *new;
2436 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2437 *ret = &new->text;
2438 return S_OK;
2440 default:
2441 FIXME( "unhandled text type %u\n", text->textType );
2442 return E_NOTIMPL;
2446 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2448 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2449 HRESULT hr;
2451 switch (value->textType)
2453 case WS_XML_TEXT_TYPE_UTF8:
2454 case WS_XML_TEXT_TYPE_UTF16:
2455 case WS_XML_TEXT_TYPE_BASE64:
2456 break;
2458 case WS_XML_TEXT_TYPE_BOOL:
2459 case WS_XML_TEXT_TYPE_INT32:
2460 case WS_XML_TEXT_TYPE_INT64:
2461 case WS_XML_TEXT_TYPE_UINT64:
2462 case WS_XML_TEXT_TYPE_DOUBLE:
2463 case WS_XML_TEXT_TYPE_GUID:
2464 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2465 case WS_XML_TEXT_TYPE_DATETIME:
2466 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2467 break;
2469 default:
2470 FIXME( "unhandled text type %u\n", value->textType );
2471 return E_NOTIMPL;
2474 switch (writer->output_enc)
2476 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2478 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2479 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2480 free( old );
2481 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2482 break;
2484 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2486 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2487 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2488 free( old );
2489 elem->attributes[elem->attributeCount - 1]->value = new;
2490 break;
2492 default:
2493 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2494 return E_NOTIMPL;
2497 return S_OK;
2500 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2502 struct node *node;
2503 WS_XML_TEXT_NODE *text;
2504 HRESULT hr;
2506 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2507 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2508 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2510 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2511 text = (WS_XML_TEXT_NODE *)node;
2513 switch (writer->output_enc)
2515 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2517 WS_XML_UTF8_TEXT *new;
2518 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2520 free( node );
2521 return hr;
2523 text->text = &new->text;
2524 break;
2526 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2528 WS_XML_TEXT *new;
2529 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2531 free( node );
2532 return hr;
2534 text->text = new;
2535 break;
2537 default:
2538 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2539 free( node );
2540 return E_NOTIMPL;
2543 write_insert_node( writer, writer->current, node );
2544 return S_OK;
2547 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2549 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2550 HRESULT hr;
2552 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2554 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2555 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2557 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2559 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2560 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2561 return S_OK;
2564 return WS_E_INVALID_FORMAT;
2567 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
2569 switch (text->textType)
2571 case WS_XML_TEXT_TYPE_UTF8:
2573 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2574 if (use_dict) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT;
2575 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2576 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2577 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2579 case WS_XML_TEXT_TYPE_UTF16:
2581 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
2582 int len = text_utf16->byteCount / sizeof(WCHAR);
2583 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
2584 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2585 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2586 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2588 case WS_XML_TEXT_TYPE_BASE64:
2590 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2591 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2592 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2593 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2594 return RECORD_BYTES32_TEXT;
2596 case WS_XML_TEXT_TYPE_BOOL:
2598 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2599 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2601 case WS_XML_TEXT_TYPE_INT32:
2603 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2604 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2605 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2606 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2607 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2608 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2610 case WS_XML_TEXT_TYPE_INT64:
2612 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2613 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2614 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2615 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2616 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2617 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2618 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2620 case WS_XML_TEXT_TYPE_UINT64:
2622 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2623 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2624 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2625 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2626 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2627 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2628 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2629 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2631 case WS_XML_TEXT_TYPE_DOUBLE:
2633 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2634 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2635 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2636 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2637 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2638 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2639 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2640 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2641 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2643 case WS_XML_TEXT_TYPE_GUID:
2644 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2646 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2647 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2649 case WS_XML_TEXT_TYPE_DATETIME:
2650 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2652 default:
2653 FIXME( "unhandled text type %u\n", text->textType );
2654 return 0;
2658 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2660 enum record_type type;
2661 BOOL use_dict = FALSE;
2662 HRESULT hr;
2663 ULONG id;
2665 if (offset)
2667 FIXME( "no support for appending text in binary mode\n" );
2668 return E_NOTIMPL;
2671 if (text->textType == WS_XML_TEXT_TYPE_UTF8)
2673 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2674 use_dict = get_string_id( writer, &utf8->value, &id );
2677 switch ((type = get_text_record_type( text, use_dict )))
2679 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2681 const WS_XML_UTF8_TEXT *text_utf8;
2682 WS_XML_UTF8_TEXT *new = NULL;
2683 UINT8 len;
2685 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2686 else
2688 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2689 text_utf8 = new;
2691 len = text_utf8->value.length;
2692 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2694 free( new );
2695 return hr;
2697 write_char( writer, type );
2698 write_char( writer, len );
2699 write_bytes( writer, text_utf8->value.bytes, len );
2700 free( new );
2701 return S_OK;
2703 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2705 const WS_XML_UTF8_TEXT *text_utf8;
2706 WS_XML_UTF8_TEXT *new = NULL;
2707 UINT16 len;
2709 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2710 else
2712 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2713 text_utf8 = new;
2715 len = text_utf8->value.length;
2716 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2718 free( new );
2719 return hr;
2721 write_char( writer, type );
2722 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2723 write_bytes( writer, text_utf8->value.bytes, len );
2724 free( new );
2725 return S_OK;
2727 case RECORD_BYTES8_TEXT:
2729 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2730 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2732 if (len)
2734 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2735 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2736 write_char( writer, len );
2737 write_bytes( writer, text_base64->bytes, len );
2739 if (rem)
2741 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2742 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2743 write_char( writer, rem );
2744 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2746 return S_OK;
2748 case RECORD_BYTES16_TEXT:
2750 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2751 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2753 if (len)
2755 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2756 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2757 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2758 write_bytes( writer, text_base64->bytes, len );
2760 if (rem)
2762 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2763 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2764 write_char( writer, rem );
2765 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2767 return S_OK;
2769 case RECORD_BYTES32_TEXT:
2771 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2772 UINT32 rem = text_base64->length % 3, len = text_base64->length - rem;
2773 if (len)
2775 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2776 write_char( writer, rem ? RECORD_BYTES32_TEXT : RECORD_BYTES32_TEXT_WITH_ENDELEMENT );
2777 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2778 write_bytes( writer, text_base64->bytes, len );
2780 if (rem)
2782 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2783 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2784 write_char( writer, rem );
2785 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2787 return S_OK;
2789 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2790 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2791 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2792 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2794 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2795 write_char( writer, type );
2796 return S_OK;
2798 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2800 INT8 val = get_text_value_int( text );
2801 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2802 write_char( writer, type );
2803 write_char( writer, val );
2804 return S_OK;
2806 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2808 INT16 val = get_text_value_int( text );
2809 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2810 write_char( writer, type );
2811 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2812 return S_OK;
2814 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2816 INT32 val = get_text_value_int( text );
2817 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2818 write_char( writer, type );
2819 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2820 return S_OK;
2822 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2824 INT64 val = get_text_value_int( text );
2825 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2826 write_char( writer, type );
2827 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2828 return S_OK;
2830 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2832 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2833 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2834 write_char( writer, type );
2835 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2836 return S_OK;
2838 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2840 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2841 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2842 write_char( writer, type );
2843 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2844 return S_OK;
2846 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2848 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2849 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2850 write_char( writer, type );
2851 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2852 return S_OK;
2854 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2856 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2857 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2858 write_char( writer, type );
2859 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2860 return S_OK;
2862 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2864 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2865 UINT64 val = text_datetime->value.ticks;
2867 assert( val <= TICKS_MAX );
2868 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2869 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2871 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2872 write_char( writer, type );
2873 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2874 return S_OK;
2876 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
2878 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2879 write_char( writer, type );
2880 return write_dict_string( writer, id );
2882 default:
2883 FIXME( "unhandled record type %02x\n", type );
2884 return E_NOTIMPL;
2888 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2890 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2892 switch (writer->output_enc)
2894 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2895 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2896 default:
2897 ERR( "unhandled encoding %u\n", writer->output_enc );
2898 return WS_E_NOT_SUPPORTED;
2902 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2904 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2905 ULONG offset = 0;
2906 HRESULT hr;
2908 if ((hr = write_commit( writer )) != S_OK) return hr;
2909 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2911 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2912 node = (WS_XML_TEXT_NODE *)writer->current;
2914 else
2916 switch (writer->output_enc)
2918 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2920 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2921 offset = old->value.length;
2922 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2923 free( old );
2924 node->text = &new->text;
2925 break;
2927 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2929 WS_XML_TEXT *new, *old = node->text;
2930 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2931 free( old );
2932 node->text = new;
2933 break;
2935 default:
2936 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2937 return E_NOTIMPL;
2941 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2943 writer->state = WRITER_STATE_TEXT;
2944 return S_OK;
2947 /**************************************************************************
2948 * WsWriteText [webservices.@]
2950 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2952 struct writer *writer = (struct writer *)handle;
2953 HRESULT hr;
2955 TRACE( "%p %p %p\n", handle, text, error );
2956 if (error) FIXME( "ignoring error parameter\n" );
2958 if (!writer || !text) return E_INVALIDARG;
2960 EnterCriticalSection( &writer->cs );
2962 if (writer->magic != WRITER_MAGIC)
2964 LeaveCriticalSection( &writer->cs );
2965 return E_INVALIDARG;
2968 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2969 else hr = write_text_node( writer, text );
2971 LeaveCriticalSection( &writer->cs );
2972 TRACE( "returning %#lx\n", hr );
2973 return hr;
2976 /**************************************************************************
2977 * WsWriteBytes [webservices.@]
2979 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2981 struct writer *writer = (struct writer *)handle;
2982 WS_XML_BASE64_TEXT base64;
2983 HRESULT hr;
2985 TRACE( "%p %p %lu %p\n", handle, bytes, count, error );
2986 if (error) FIXME( "ignoring error parameter\n" );
2988 if (!writer) return E_INVALIDARG;
2990 EnterCriticalSection( &writer->cs );
2992 if (writer->magic != WRITER_MAGIC)
2994 LeaveCriticalSection( &writer->cs );
2995 return E_INVALIDARG;
2998 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
2999 else
3001 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3002 base64.bytes = (BYTE *)bytes;
3003 base64.length = count;
3005 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
3006 else hr = write_text_node( writer, &base64.text );
3009 LeaveCriticalSection( &writer->cs );
3010 TRACE( "returning %#lx\n", hr );
3011 return hr;
3014 /**************************************************************************
3015 * WsWriteChars [webservices.@]
3017 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
3019 struct writer *writer = (struct writer *)handle;
3020 WS_XML_UTF16_TEXT utf16;
3021 HRESULT hr;
3023 TRACE( "%p %s %lu %p\n", handle, debugstr_wn(chars, count), count, error );
3024 if (error) FIXME( "ignoring error parameter\n" );
3026 if (!writer) return E_INVALIDARG;
3028 EnterCriticalSection( &writer->cs );
3030 if (writer->magic != WRITER_MAGIC)
3032 LeaveCriticalSection( &writer->cs );
3033 return E_INVALIDARG;
3036 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3037 else
3039 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3040 utf16.bytes = (BYTE *)chars;
3041 utf16.byteCount = count * sizeof(WCHAR);
3043 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
3044 else hr = write_text_node( writer, &utf16.text );
3047 LeaveCriticalSection( &writer->cs );
3048 TRACE( "returning %#lx\n", hr );
3049 return hr;
3052 /**************************************************************************
3053 * WsWriteCharsUtf8 [webservices.@]
3055 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
3057 struct writer *writer = (struct writer *)handle;
3058 WS_XML_UTF8_TEXT utf8;
3059 HRESULT hr;
3061 TRACE( "%p %s %lu %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
3062 if (error) FIXME( "ignoring error parameter\n" );
3064 if (!writer) return E_INVALIDARG;
3066 EnterCriticalSection( &writer->cs );
3068 if (writer->magic != WRITER_MAGIC)
3070 LeaveCriticalSection( &writer->cs );
3071 return E_INVALIDARG;
3074 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3075 else
3077 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3078 utf8.value.bytes = (BYTE *)bytes;
3079 utf8.value.length = count;
3081 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
3082 else hr = write_text_node( writer, &utf8.text );
3085 LeaveCriticalSection( &writer->cs );
3086 TRACE( "returning %#lx\n", hr );
3087 return hr;
3090 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
3092 switch (mapping)
3094 case WS_ELEMENT_TYPE_MAPPING:
3095 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3096 return write_text_node( writer, text );
3098 case WS_ATTRIBUTE_TYPE_MAPPING:
3099 return write_set_attribute_value( writer, text );
3101 case WS_ANY_ELEMENT_TYPE_MAPPING:
3102 switch (writer->state)
3104 case WRITER_STATE_STARTATTRIBUTE:
3105 return write_set_attribute_value( writer, text );
3107 case WRITER_STATE_STARTELEMENT:
3108 return write_text_node( writer, text );
3110 default:
3111 FIXME( "writer state %u not handled\n", writer->state );
3112 return E_NOTIMPL;
3115 default:
3116 FIXME( "mapping %u not implemented\n", mapping );
3117 return E_NOTIMPL;
3121 static HRESULT write_add_nil_attribute( struct writer *writer )
3123 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
3124 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
3125 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
3126 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
3127 HRESULT hr;
3129 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
3130 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
3131 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
3134 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
3135 const void **ptr )
3137 switch (option)
3139 case WS_WRITE_REQUIRED_VALUE:
3140 case WS_WRITE_NILLABLE_VALUE:
3141 if (!value || size != expected_size) return E_INVALIDARG;
3142 *ptr = value;
3143 return S_OK;
3145 case WS_WRITE_REQUIRED_POINTER:
3146 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
3147 return S_OK;
3149 case WS_WRITE_NILLABLE_POINTER:
3150 if (size != sizeof(const void *)) return E_INVALIDARG;
3151 *ptr = *(const void **)value;
3152 return S_OK;
3154 default:
3155 return E_INVALIDARG;
3159 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
3160 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
3161 const BOOL *value, ULONG size )
3163 WS_XML_BOOL_TEXT text_bool;
3164 const BOOL *ptr;
3165 HRESULT hr;
3167 if (desc)
3169 FIXME( "description not supported\n" );
3170 return E_NOTIMPL;
3173 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3174 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
3175 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3177 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
3178 text_bool.value = *ptr;
3179 return write_type_text( writer, mapping, &text_bool.text );
3182 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3183 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3184 const BOOL *value, ULONG size )
3186 WS_XML_INT32_TEXT text_int32;
3187 const INT8 *ptr;
3188 HRESULT hr;
3190 if (desc)
3192 FIXME( "description not supported\n" );
3193 return E_NOTIMPL;
3196 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3197 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3198 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3200 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3201 text_int32.value = *ptr;
3202 return write_type_text( writer, mapping, &text_int32.text );
3205 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3206 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3207 const BOOL *value, ULONG size )
3209 WS_XML_INT32_TEXT text_int32;
3210 const INT16 *ptr;
3211 HRESULT hr;
3213 if (desc)
3215 FIXME( "description not supported\n" );
3216 return E_NOTIMPL;
3219 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3220 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3221 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3223 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3224 text_int32.value = *ptr;
3225 return write_type_text( writer, mapping, &text_int32.text );
3228 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3229 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3230 const void *value, ULONG size )
3232 WS_XML_INT32_TEXT text_int32;
3233 const INT32 *ptr;
3234 HRESULT hr;
3236 if (desc)
3238 FIXME( "description not supported\n" );
3239 return E_NOTIMPL;
3242 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3243 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3244 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3246 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3247 text_int32.value = *ptr;
3248 return write_type_text( writer, mapping, &text_int32.text );
3251 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3252 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3253 const void *value, ULONG size )
3255 WS_XML_INT64_TEXT text_int64;
3256 const INT64 *ptr;
3257 HRESULT hr;
3259 if (desc)
3261 FIXME( "description not supported\n" );
3262 return E_NOTIMPL;
3265 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3266 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3267 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3269 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3270 text_int64.value = *ptr;
3271 return write_type_text( writer, mapping, &text_int64.text );
3274 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3275 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3276 const void *value, ULONG size )
3278 WS_XML_UINT64_TEXT text_uint64;
3279 const UINT8 *ptr;
3280 HRESULT hr;
3282 if (desc)
3284 FIXME( "description not supported\n" );
3285 return E_NOTIMPL;
3288 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3289 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3290 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3292 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3293 text_uint64.value = *ptr;
3294 return write_type_text( writer, mapping, &text_uint64.text );
3297 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3298 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3299 const void *value, ULONG size )
3301 WS_XML_UINT64_TEXT text_uint64;
3302 const UINT16 *ptr;
3303 HRESULT hr;
3305 if (desc)
3307 FIXME( "description not supported\n" );
3308 return E_NOTIMPL;
3311 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3312 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3313 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3315 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3316 text_uint64.value = *ptr;
3317 return write_type_text( writer, mapping, &text_uint64.text );
3320 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3321 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3322 const void *value, ULONG size )
3324 WS_XML_UINT64_TEXT text_uint64;
3325 const UINT32 *ptr;
3326 HRESULT hr;
3328 if (desc)
3330 FIXME( "description not supported\n" );
3331 return E_NOTIMPL;
3334 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3335 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3336 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3338 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3339 text_uint64.value = *ptr;
3340 return write_type_text( writer, mapping, &text_uint64.text );
3343 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3344 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3345 const void *value, ULONG size )
3347 WS_XML_UINT64_TEXT text_uint64;
3348 const UINT64 *ptr;
3349 HRESULT hr;
3351 if (desc)
3353 FIXME( "description not supported\n" );
3354 return E_NOTIMPL;
3357 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3358 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3359 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3361 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3362 text_uint64.value = *ptr;
3363 return write_type_text( writer, mapping, &text_uint64.text );
3366 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3367 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3368 const void *value, ULONG size )
3370 WS_XML_DOUBLE_TEXT text_double;
3371 const double *ptr;
3372 HRESULT hr;
3374 if (desc)
3376 FIXME( "description not supported\n" );
3377 return E_NOTIMPL;
3380 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3381 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3382 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3384 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3385 text_double.value = *ptr;
3386 return write_type_text( writer, mapping, &text_double.text );
3389 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3390 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3391 const void *value, ULONG size )
3393 WS_XML_DATETIME_TEXT text_datetime;
3394 const WS_DATETIME *ptr;
3395 HRESULT hr;
3397 if (desc)
3399 FIXME( "description not supported\n" );
3400 return E_NOTIMPL;
3403 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3404 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3405 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3406 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3408 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3409 text_datetime.value = *ptr;
3410 return write_type_text( writer, mapping, &text_datetime.text );
3413 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3414 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3415 const void *value, ULONG size )
3417 WS_XML_GUID_TEXT text_guid;
3418 const GUID *ptr;
3419 HRESULT hr;
3421 if (desc)
3423 FIXME( "description not supported\n" );
3424 return E_NOTIMPL;
3427 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3428 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3429 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3431 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3432 text_guid.value = *ptr;
3433 return write_type_text( writer, mapping, &text_guid.text );
3436 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3437 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3438 const void *value, ULONG size )
3440 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3441 WS_XML_UTF16_TEXT text_utf16;
3442 const WS_UNIQUE_ID *ptr;
3443 HRESULT hr;
3445 if (desc)
3447 FIXME( "description not supported\n" );
3448 return E_NOTIMPL;
3451 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3452 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3453 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3455 if (ptr->uri.length)
3457 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3458 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3459 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3460 return write_type_text( writer, mapping, &text_utf16.text );
3463 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3464 text_unique_id.value = ptr->guid;
3465 return write_type_text( writer, mapping, &text_unique_id.text );
3468 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3469 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3470 const void *value, ULONG size )
3472 WS_XML_UTF16_TEXT utf16;
3473 const WS_STRING *ptr;
3474 HRESULT hr;
3476 if (desc)
3478 FIXME( "description not supported\n" );
3479 return E_NOTIMPL;
3482 if (!option) return E_INVALIDARG;
3483 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3484 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3485 if (!ptr->length) return S_OK;
3487 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3488 utf16.bytes = (BYTE *)ptr->chars;
3489 utf16.byteCount = ptr->length * sizeof(WCHAR);
3490 return write_type_text( writer, mapping, &utf16.text );
3493 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3494 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3495 const void *value, ULONG size )
3497 WS_XML_UTF16_TEXT utf16;
3498 const WCHAR *ptr;
3499 HRESULT hr;
3500 int len;
3502 if (desc)
3504 FIXME( "description not supported\n" );
3505 return E_NOTIMPL;
3508 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3509 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3510 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3511 if (!(len = lstrlenW( ptr ))) return S_OK;
3513 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3514 utf16.bytes = (BYTE *)ptr;
3515 utf16.byteCount = len * sizeof(WCHAR);
3516 return write_type_text( writer, mapping, &utf16.text );
3519 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3520 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3521 const void *value, ULONG size )
3523 WS_XML_BASE64_TEXT base64;
3524 const WS_BYTES *ptr;
3525 HRESULT hr;
3527 if (desc)
3529 FIXME( "description not supported\n" );
3530 return E_NOTIMPL;
3533 if (!option) return E_INVALIDARG;
3534 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3535 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3536 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3537 if (!ptr->length) return S_OK;
3539 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3540 base64.bytes = ptr->bytes;
3541 base64.length = ptr->length;
3542 return write_type_text( writer, mapping, &base64.text );
3545 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3546 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3547 const void *value, ULONG size )
3549 WS_XML_UTF8_TEXT utf8;
3550 const WS_XML_STRING *ptr;
3551 HRESULT hr;
3553 if (desc)
3555 FIXME( "description not supported\n" );
3556 return E_NOTIMPL;
3559 if (!option) return E_INVALIDARG;
3560 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3561 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3562 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3563 if (!ptr->length) return S_OK;
3565 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3566 utf8.value.bytes = ptr->bytes;
3567 utf8.value.length = ptr->length;
3568 return write_type_text( writer, mapping, &utf8.text );
3571 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3573 const struct node *node;
3574 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3576 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3577 ULONG i;
3578 for (i = 0; i < elem->attributeCount; i++)
3580 if (!elem->attributes[i]->isXmlNs) continue;
3581 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3582 *prefix = elem->attributes[i]->prefix;
3583 return S_OK;
3586 return WS_E_INVALID_FORMAT;
3589 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3590 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3591 const void *value, ULONG size )
3593 WS_XML_QNAME_TEXT qname;
3594 const WS_XML_QNAME *ptr;
3595 const WS_XML_STRING *prefix;
3596 HRESULT hr;
3598 if (desc)
3600 FIXME( "description not supported\n" );
3601 return E_NOTIMPL;
3604 if (!option) return E_INVALIDARG;
3605 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3606 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3607 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3609 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3611 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3612 qname.prefix = (WS_XML_STRING *)prefix;
3613 qname.localName = (WS_XML_STRING *)&ptr->localName;
3614 qname.ns = (WS_XML_STRING *)&ptr->ns;
3615 return write_type_text( writer, mapping, &qname.text );
3618 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3620 if (options & WS_FIELD_POINTER)
3622 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM)) return WS_WRITE_NILLABLE_POINTER;
3623 return WS_WRITE_REQUIRED_POINTER;
3626 switch (type)
3628 case WS_BOOL_TYPE:
3629 case WS_INT8_TYPE:
3630 case WS_INT16_TYPE:
3631 case WS_INT32_TYPE:
3632 case WS_INT64_TYPE:
3633 case WS_UINT8_TYPE:
3634 case WS_UINT16_TYPE:
3635 case WS_UINT32_TYPE:
3636 case WS_UINT64_TYPE:
3637 case WS_DOUBLE_TYPE:
3638 case WS_DATETIME_TYPE:
3639 case WS_GUID_TYPE:
3640 case WS_UNIQUE_ID_TYPE:
3641 case WS_STRING_TYPE:
3642 case WS_BYTES_TYPE:
3643 case WS_XML_STRING_TYPE:
3644 case WS_XML_QNAME_TYPE:
3645 case WS_STRUCT_TYPE:
3646 case WS_ENUM_TYPE:
3647 case WS_UNION_TYPE:
3648 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3649 return WS_WRITE_REQUIRED_VALUE;
3651 case WS_WSZ_TYPE:
3652 case WS_DESCRIPTION_TYPE:
3653 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3654 return WS_WRITE_REQUIRED_POINTER;
3656 default:
3657 FIXME( "unhandled type %u\n", type );
3658 return 0;
3662 static HRESULT find_index( const WS_UNION_DESCRIPTION *desc, int value, ULONG *idx )
3664 ULONG i;
3666 if (desc->valueIndices)
3668 int c, min = 0, max = desc->fieldCount - 1;
3669 while (min <= max)
3671 i = (min + max) / 2;
3672 c = value - desc->fields[desc->valueIndices[i]]->value;
3673 if (c < 0)
3674 max = i - 1;
3675 else if (c > 0)
3676 min = i + 1;
3677 else
3679 *idx = desc->valueIndices[i];
3680 return S_OK;
3683 return WS_E_INVALID_FORMAT;
3686 /* fall back to linear search */
3687 for (i = 0; i < desc->fieldCount; i++)
3689 if (desc->fields[i]->value == value)
3691 *idx = i;
3692 return S_OK;
3695 return WS_E_INVALID_FORMAT;
3698 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3700 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3701 const void *value, ULONG size )
3703 ULONG i;
3704 const void *ptr;
3705 int enum_value;
3706 HRESULT hr;
3708 if (size < sizeof(enum_value)) return E_INVALIDARG;
3709 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3711 enum_value = *(int *)(char *)ptr + desc->enumOffset;
3712 if (enum_value == desc->noneEnumValue && option == WS_WRITE_NILLABLE_VALUE) return S_OK;
3714 if ((hr = find_index( desc, enum_value, &i )) != S_OK) return hr;
3715 return write_type_field( writer, &desc->fields[i]->field, ptr, desc->fields[i]->field.offset );
3718 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3719 const void *, ULONG );
3721 static HRESULT write_type_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3722 ULONG count )
3724 HRESULT hr = S_OK;
3725 ULONG i, size, offset = 0;
3726 WS_WRITE_OPTION option;
3728 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3730 /* wrapper element */
3731 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3732 return hr;
3734 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3735 size = get_type_size( desc->type, desc->typeDescription );
3736 else
3737 size = sizeof(const void *);
3739 for (i = 0; i < count; i++)
3741 if (desc->type == WS_UNION_TYPE)
3743 if ((hr = write_type_union( writer, desc->typeDescription, option, buf + offset, size )) != S_OK)
3744 return hr;
3746 else
3748 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3749 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3750 buf + offset, size )) != S_OK) return hr;
3751 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3753 offset += size;
3756 if (desc->localName) hr = write_endelement_node( writer );
3757 return hr;
3760 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3761 ULONG offset )
3763 HRESULT hr;
3764 WS_TYPE_MAPPING mapping;
3765 WS_WRITE_OPTION option;
3766 ULONG count, size, field_options = desc->options;
3767 const char *ptr = buf + offset;
3769 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3771 FIXME( "options %#lx not supported\n", desc->options );
3772 return E_NOTIMPL;
3775 /* zero-terminated strings and descriptions are always pointers */
3776 if (desc->type == WS_WSZ_TYPE || desc->type == WS_DESCRIPTION_TYPE) field_options |= WS_FIELD_POINTER;
3778 if (field_options & WS_FIELD_POINTER)
3779 size = sizeof(const void *);
3780 else
3781 size = get_type_size( desc->type, desc->typeDescription );
3783 if (is_nil_value( ptr, size ))
3785 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3786 if (field_options & (WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3788 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3789 else option = WS_WRITE_NILLABLE_VALUE;
3791 else
3793 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3794 else option = WS_WRITE_REQUIRED_VALUE;
3797 else
3799 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3800 else option = WS_WRITE_REQUIRED_VALUE;
3803 switch (desc->mapping)
3805 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
3806 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3807 break;
3809 case WS_ATTRIBUTE_FIELD_MAPPING:
3810 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3811 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3812 return hr;
3813 writer->state = WRITER_STATE_STARTATTRIBUTE;
3815 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3816 break;
3818 case WS_ELEMENT_FIELD_MAPPING:
3819 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3820 mapping = WS_ELEMENT_TYPE_MAPPING;
3821 break;
3823 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3824 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3825 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3826 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3828 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3829 case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING:
3830 count = *(const ULONG *)(buf + desc->countOffset);
3831 return write_type_array( writer, desc, *(const char **)ptr, count );
3833 case WS_TEXT_FIELD_MAPPING:
3834 switch (writer->state)
3836 case WRITER_STATE_STARTELEMENT:
3837 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3838 break;
3840 case WRITER_STATE_STARTATTRIBUTE:
3841 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3842 break;
3844 default:
3845 FIXME( "unhandled writer state %u\n", writer->state );
3846 return E_NOTIMPL;
3848 break;
3850 case WS_ANY_ATTRIBUTES_FIELD_MAPPING:
3851 return S_OK;
3853 default:
3854 FIXME( "field mapping %u not supported\n", desc->mapping );
3855 return E_NOTIMPL;
3858 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3859 return hr;
3861 switch (mapping)
3863 case WS_ATTRIBUTE_TYPE_MAPPING:
3864 writer->state = WRITER_STATE_STARTELEMENT;
3865 break;
3867 case WS_ELEMENT_TYPE_MAPPING:
3868 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3869 break;
3871 default: break;
3874 return S_OK;
3877 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3878 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3879 const void *value, ULONG size )
3881 ULONG i, offset;
3882 const void *ptr;
3883 HRESULT hr;
3885 if (!desc) return E_INVALIDARG;
3886 if (desc->structOptions) FIXME( "struct options %#lx not supported\n", desc->structOptions );
3888 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3889 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3891 for (i = 0; i < desc->fieldCount; i++)
3893 offset = desc->fields[i]->offset;
3894 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3897 return S_OK;
3900 static const WS_XML_STRING *get_enum_value_name( const WS_ENUM_DESCRIPTION *desc, int value )
3902 ULONG i;
3903 for (i = 0; i < desc->valueCount; i++)
3905 if (desc->values[i].value == value) return desc->values[i].name;
3907 return NULL;
3910 static HRESULT write_type_enum( struct writer *writer, WS_TYPE_MAPPING mapping,
3911 const WS_ENUM_DESCRIPTION *desc, WS_WRITE_OPTION option,
3912 const void *value, ULONG size )
3914 const WS_XML_STRING *name;
3915 WS_XML_UTF8_TEXT utf8;
3916 const int *ptr;
3917 HRESULT hr;
3919 if (!desc) return E_INVALIDARG;
3920 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3921 if (!(name = get_enum_value_name( desc, *ptr ))) return E_INVALIDARG;
3923 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3924 utf8.value.bytes = name->bytes;
3925 utf8.value.length = name->length;
3926 return write_type_text( writer, mapping, &utf8.text );
3929 static HRESULT write_type_description( struct writer *writer, WS_TYPE_MAPPING mapping,
3930 WS_WRITE_OPTION option, const void *value, ULONG size )
3932 const WS_STRUCT_DESCRIPTION *ptr;
3933 HRESULT hr;
3935 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3936 if (ptr) FIXME( "ignoring type description %p\n", ptr );
3937 return S_OK;
3940 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3941 const void *desc, WS_WRITE_OPTION option, const void *value,
3942 ULONG size )
3944 switch (type)
3946 case WS_BOOL_TYPE:
3947 return write_type_bool( writer, mapping, desc, option, value, size );
3949 case WS_INT8_TYPE:
3950 return write_type_int8( writer, mapping, desc, option, value, size );
3952 case WS_INT16_TYPE:
3953 return write_type_int16( writer, mapping, desc, option, value, size );
3955 case WS_INT32_TYPE:
3956 return write_type_int32( writer, mapping, desc, option, value, size );
3958 case WS_INT64_TYPE:
3959 return write_type_int64( writer, mapping, desc, option, value, size );
3961 case WS_UINT8_TYPE:
3962 return write_type_uint8( writer, mapping, desc, option, value, size );
3964 case WS_UINT16_TYPE:
3965 return write_type_uint16( writer, mapping, desc, option, value, size );
3967 case WS_UINT32_TYPE:
3968 return write_type_uint32( writer, mapping, desc, option, value, size );
3970 case WS_UINT64_TYPE:
3971 return write_type_uint64( writer, mapping, desc, option, value, size );
3973 case WS_DOUBLE_TYPE:
3974 return write_type_double( writer, mapping, desc, option, value, size );
3976 case WS_DATETIME_TYPE:
3977 return write_type_datetime( writer, mapping, desc, option, value, size );
3979 case WS_GUID_TYPE:
3980 return write_type_guid( writer, mapping, desc, option, value, size );
3982 case WS_UNIQUE_ID_TYPE:
3983 return write_type_unique_id( writer, mapping, desc, option, value, size );
3985 case WS_STRING_TYPE:
3986 return write_type_string( writer, mapping, desc, option, value, size );
3988 case WS_WSZ_TYPE:
3989 return write_type_wsz( writer, mapping, desc, option, value, size );
3991 case WS_BYTES_TYPE:
3992 return write_type_bytes( writer, mapping, desc, option, value, size );
3994 case WS_XML_STRING_TYPE:
3995 return write_type_xml_string( writer, mapping, desc, option, value, size );
3997 case WS_XML_QNAME_TYPE:
3998 return write_type_qname( writer, mapping, desc, option, value, size );
4000 case WS_DESCRIPTION_TYPE:
4001 return write_type_description( writer, mapping, option, value, size );
4003 case WS_STRUCT_TYPE:
4004 return write_type_struct( writer, mapping, desc, option, value, size );
4006 case WS_ENUM_TYPE:
4007 return write_type_enum( writer, mapping, desc, option, value, size );
4009 default:
4010 FIXME( "type %u not supported\n", type );
4011 return E_NOTIMPL;
4015 /**************************************************************************
4016 * WsWriteAttribute [webservices.@]
4018 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
4019 WS_WRITE_OPTION option, const void *value, ULONG size,
4020 WS_ERROR *error )
4022 struct writer *writer = (struct writer *)handle;
4023 HRESULT hr;
4025 TRACE( "%p %p %u %p %lu %p\n", handle, desc, option, value, size, error );
4026 if (error) FIXME( "ignoring error parameter\n" );
4028 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
4029 return E_INVALIDARG;
4031 EnterCriticalSection( &writer->cs );
4033 if (writer->magic != WRITER_MAGIC)
4035 LeaveCriticalSection( &writer->cs );
4036 return E_INVALIDARG;
4039 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
4040 else if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) == S_OK)
4042 writer->state = WRITER_STATE_STARTATTRIBUTE;
4043 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
4046 LeaveCriticalSection( &writer->cs );
4047 TRACE( "returning %#lx\n", hr );
4048 return hr;
4051 /**************************************************************************
4052 * WsWriteElement [webservices.@]
4054 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4055 WS_WRITE_OPTION option, const void *value, ULONG size,
4056 WS_ERROR *error )
4058 struct writer *writer = (struct writer *)handle;
4059 HRESULT hr;
4061 TRACE( "%p %p %u %p %lu %p\n", handle, desc, option, value, size, error );
4062 if (error) FIXME( "ignoring error parameter\n" );
4064 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
4065 return E_INVALIDARG;
4067 EnterCriticalSection( &writer->cs );
4069 if (writer->magic != WRITER_MAGIC)
4071 LeaveCriticalSection( &writer->cs );
4072 return E_INVALIDARG;
4075 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4077 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
4078 option, value, size )) != S_OK) goto done;
4080 hr = write_endelement_node( writer );
4082 done:
4083 LeaveCriticalSection( &writer->cs );
4084 TRACE( "returning %#lx\n", hr );
4085 return hr;
4088 /**************************************************************************
4089 * WsWriteType [webservices.@]
4091 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4092 const void *desc, WS_WRITE_OPTION option, const void *value,
4093 ULONG size, WS_ERROR *error )
4095 struct writer *writer = (struct writer *)handle;
4096 HRESULT hr;
4098 TRACE( "%p %u %u %p %u %p %lu %p\n", handle, mapping, type, desc, option, value,
4099 size, error );
4100 if (error) FIXME( "ignoring error parameter\n" );
4102 if (!writer || !value) return E_INVALIDARG;
4104 EnterCriticalSection( &writer->cs );
4106 if (writer->magic != WRITER_MAGIC)
4108 LeaveCriticalSection( &writer->cs );
4109 return E_INVALIDARG;
4112 switch (mapping)
4114 case WS_ATTRIBUTE_TYPE_MAPPING:
4115 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
4116 else hr = write_type( writer, mapping, type, desc, option, value, size );
4117 break;
4119 case WS_ELEMENT_TYPE_MAPPING:
4120 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4121 case WS_ANY_ELEMENT_TYPE_MAPPING:
4122 hr = write_type( writer, mapping, type, desc, option, value, size );
4123 break;
4125 default:
4126 FIXME( "mapping %u not implemented\n", mapping );
4127 hr = E_NOTIMPL;
4130 LeaveCriticalSection( &writer->cs );
4131 TRACE( "returning %#lx\n", hr );
4132 return hr;
4135 WS_TYPE map_value_type( WS_VALUE_TYPE type )
4137 switch (type)
4139 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
4140 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
4141 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
4142 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
4143 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
4144 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
4145 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
4146 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
4147 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
4148 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
4149 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
4150 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
4151 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
4152 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
4153 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
4154 default:
4155 FIXME( "unhandled type %u\n", type );
4156 return ~0u;
4160 /**************************************************************************
4161 * WsWriteValue [webservices.@]
4163 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
4164 ULONG size, WS_ERROR *error )
4166 struct writer *writer = (struct writer *)handle;
4167 WS_TYPE_MAPPING mapping;
4168 HRESULT hr = S_OK;
4169 WS_TYPE type;
4171 TRACE( "%p %u %p %lu %p\n", handle, value_type, value, size, error );
4172 if (error) FIXME( "ignoring error parameter\n" );
4174 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
4176 EnterCriticalSection( &writer->cs );
4178 if (writer->magic != WRITER_MAGIC)
4180 LeaveCriticalSection( &writer->cs );
4181 return E_INVALIDARG;
4184 switch (writer->state)
4186 case WRITER_STATE_STARTATTRIBUTE:
4187 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
4188 break;
4190 case WRITER_STATE_STARTELEMENT:
4191 mapping = WS_ELEMENT_TYPE_MAPPING;
4192 break;
4194 default:
4195 hr = WS_E_INVALID_FORMAT;
4198 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
4200 LeaveCriticalSection( &writer->cs );
4201 TRACE( "returning %#lx\n", hr );
4202 return hr;
4205 /**************************************************************************
4206 * WsWriteArray [webservices.@]
4208 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4209 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
4210 ULONG count, WS_ERROR *error )
4212 struct writer *writer = (struct writer *)handle;
4213 WS_TYPE type;
4214 ULONG type_size, i;
4215 HRESULT hr = S_OK;
4217 TRACE( "%p %s %s %u %p %lu %lu %lu %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
4218 value_type, array, size, offset, count, error );
4219 if (error) FIXME( "ignoring error parameter\n" );
4221 if (!writer) return E_INVALIDARG;
4223 EnterCriticalSection( &writer->cs );
4225 if (writer->magic != WRITER_MAGIC)
4227 LeaveCriticalSection( &writer->cs );
4228 return E_INVALIDARG;
4231 if (!writer->output_type)
4233 hr = WS_E_INVALID_OPERATION;
4234 goto done;
4237 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
4239 hr = E_INVALIDARG;
4240 goto done;
4243 type_size = get_type_size( type, NULL );
4244 if (size % type_size || (offset + count) * type_size > size || (count && !array))
4246 hr = E_INVALIDARG;
4247 goto done;
4250 for (i = offset; i < count; i++)
4252 const char *ptr = (const char *)array + (offset + i) * type_size;
4253 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4254 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4255 &ptr, sizeof(ptr) )) != S_OK) goto done;
4256 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4259 done:
4260 LeaveCriticalSection( &writer->cs );
4261 TRACE( "returning %#lx\n", hr );
4262 return hr;
4265 /**************************************************************************
4266 * WsWriteXmlBuffer [webservices.@]
4268 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4270 struct writer *writer = (struct writer *)handle;
4271 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4272 HRESULT hr;
4274 TRACE( "%p %p %p\n", handle, buffer, error );
4275 if (error) FIXME( "ignoring error parameter\n" );
4277 if (!writer || !xmlbuf) return E_INVALIDARG;
4279 EnterCriticalSection( &writer->cs );
4281 if (writer->magic != WRITER_MAGIC)
4283 LeaveCriticalSection( &writer->cs );
4284 return E_INVALIDARG;
4287 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4289 FIXME( "no support for different encoding and/or charset\n" );
4290 hr = E_NOTIMPL;
4291 goto done;
4294 if ((hr = write_commit( writer )) != S_OK) goto done;
4295 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4296 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4298 done:
4299 LeaveCriticalSection( &writer->cs );
4300 TRACE( "returning %#lx\n", hr );
4301 return hr;
4304 /**************************************************************************
4305 * WsWriteXmlBufferToBytes [webservices.@]
4307 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4308 const WS_XML_WRITER_ENCODING *encoding,
4309 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4310 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4312 struct writer *writer = (struct writer *)handle;
4313 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4314 HRESULT hr = S_OK;
4315 char *buf;
4316 ULONG i;
4318 TRACE( "%p %p %p %p %lu %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4319 bytes, size, error );
4320 if (error) FIXME( "ignoring error parameter\n" );
4322 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4324 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4326 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4327 return E_NOTIMPL;
4330 EnterCriticalSection( &writer->cs );
4332 if (writer->magic != WRITER_MAGIC)
4334 LeaveCriticalSection( &writer->cs );
4335 return E_INVALIDARG;
4338 for (i = 0; i < count; i++)
4340 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4341 properties[i].valueSize );
4342 if (hr != S_OK) goto done;
4345 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4346 else
4348 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4349 *bytes = buf;
4350 *size = xmlbuf->bytes.length;
4353 done:
4354 LeaveCriticalSection( &writer->cs );
4355 TRACE( "returning %#lx\n", hr );
4356 return hr;
4359 /**************************************************************************
4360 * WsWriteXmlnsAttribute [webservices.@]
4362 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4363 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4365 struct writer *writer = (struct writer *)handle;
4366 HRESULT hr = S_OK;
4368 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4369 single, error );
4370 if (error) FIXME( "ignoring error parameter\n" );
4372 if (!writer || !ns) return E_INVALIDARG;
4374 EnterCriticalSection( &writer->cs );
4376 if (writer->magic != WRITER_MAGIC)
4378 LeaveCriticalSection( &writer->cs );
4379 return E_INVALIDARG;
4382 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
4383 else if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4384 hr = add_namespace_attribute( writer, prefix, ns, single );
4386 LeaveCriticalSection( &writer->cs );
4387 TRACE( "returning %#lx\n", hr );
4388 return hr;
4391 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4392 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4394 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4395 HRESULT hr;
4397 if ((hr = write_commit( writer )) != S_OK) return hr;
4398 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4400 qname.prefix = (WS_XML_STRING *)prefix;
4401 qname.localName = (WS_XML_STRING *)localname;
4402 qname.ns = (WS_XML_STRING *)ns;
4404 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4405 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4408 /**************************************************************************
4409 * WsWriteQualifiedName [webservices.@]
4411 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4412 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4413 WS_ERROR *error )
4415 struct writer *writer = (struct writer *)handle;
4416 HRESULT hr;
4418 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4419 debugstr_xmlstr(ns), error );
4420 if (error) FIXME( "ignoring error parameter\n" );
4422 if (!writer) return E_INVALIDARG;
4424 EnterCriticalSection( &writer->cs );
4426 if (writer->magic != WRITER_MAGIC)
4428 LeaveCriticalSection( &writer->cs );
4429 return E_INVALIDARG;
4432 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4433 else if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
4434 else if (!localname || (!prefix && !ns)) hr = E_INVALIDARG;
4435 else hr = write_qualified_name( writer, prefix, localname, ns );
4437 LeaveCriticalSection( &writer->cs );
4438 TRACE( "returning %#lx\n", hr );
4439 return hr;
4442 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4444 BOOL success = FALSE;
4445 struct node *node = writer->current;
4447 switch (move)
4449 case WS_MOVE_TO_ROOT_ELEMENT:
4450 success = move_to_root_element( writer->root, &node );
4451 break;
4453 case WS_MOVE_TO_NEXT_ELEMENT:
4454 success = move_to_next_element( &node );
4455 break;
4457 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4458 success = move_to_prev_element( &node );
4459 break;
4461 case WS_MOVE_TO_CHILD_ELEMENT:
4462 success = move_to_child_element( &node );
4463 break;
4465 case WS_MOVE_TO_END_ELEMENT:
4466 success = move_to_end_element( &node );
4467 break;
4469 case WS_MOVE_TO_PARENT_ELEMENT:
4470 success = move_to_parent_element( &node );
4471 break;
4473 case WS_MOVE_TO_FIRST_NODE:
4474 success = move_to_first_node( &node );
4475 break;
4477 case WS_MOVE_TO_NEXT_NODE:
4478 success = move_to_next_node( &node );
4479 break;
4481 case WS_MOVE_TO_PREVIOUS_NODE:
4482 success = move_to_prev_node( &node );
4483 break;
4485 case WS_MOVE_TO_CHILD_NODE:
4486 success = move_to_child_node( &node );
4487 break;
4489 case WS_MOVE_TO_BOF:
4490 success = move_to_bof( writer->root, &node );
4491 break;
4493 case WS_MOVE_TO_EOF:
4494 success = move_to_eof( writer->root, &node );
4495 break;
4497 default:
4498 FIXME( "unhandled move %u\n", move );
4499 return E_NOTIMPL;
4502 if (success && node == writer->root) return E_INVALIDARG;
4503 writer->current = node;
4505 if (found)
4507 *found = success;
4508 return S_OK;
4510 return success ? S_OK : WS_E_INVALID_FORMAT;
4513 /**************************************************************************
4514 * WsMoveWriter [webservices.@]
4516 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4518 struct writer *writer = (struct writer *)handle;
4519 HRESULT hr;
4521 TRACE( "%p %u %p %p\n", handle, move, found, error );
4522 if (error) FIXME( "ignoring error parameter\n" );
4524 if (!writer) return E_INVALIDARG;
4526 EnterCriticalSection( &writer->cs );
4528 if (writer->magic != WRITER_MAGIC)
4530 LeaveCriticalSection( &writer->cs );
4531 return E_INVALIDARG;
4534 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
4535 else hr = write_move_to( writer, move, found );
4537 LeaveCriticalSection( &writer->cs );
4538 TRACE( "returning %#lx\n", hr );
4539 return hr;
4542 /**************************************************************************
4543 * WsGetWriterPosition [webservices.@]
4545 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4547 struct writer *writer = (struct writer *)handle;
4548 HRESULT hr = S_OK;
4550 TRACE( "%p %p %p\n", handle, pos, error );
4551 if (error) FIXME( "ignoring error parameter\n" );
4553 if (!writer || !pos) return E_INVALIDARG;
4555 EnterCriticalSection( &writer->cs );
4557 if (writer->magic != WRITER_MAGIC)
4559 LeaveCriticalSection( &writer->cs );
4560 return E_INVALIDARG;
4563 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4564 else
4566 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4567 pos->node = writer->current;
4570 LeaveCriticalSection( &writer->cs );
4571 TRACE( "returning %#lx\n", hr );
4572 return hr;
4575 /**************************************************************************
4576 * WsSetWriterPosition [webservices.@]
4578 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4580 struct writer *writer = (struct writer *)handle;
4581 HRESULT hr = S_OK;
4583 TRACE( "%p %p %p\n", handle, pos, error );
4584 if (error) FIXME( "ignoring error parameter\n" );
4586 if (!writer || !pos) return E_INVALIDARG;
4588 EnterCriticalSection( &writer->cs );
4590 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4592 LeaveCriticalSection( &writer->cs );
4593 return E_INVALIDARG;
4596 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4597 else writer->current = pos->node;
4599 LeaveCriticalSection( &writer->cs );
4600 TRACE( "returning %#lx\n", hr );
4601 return hr;
4604 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4606 struct node *node, *parent;
4607 WS_XML_COMMENT_NODE *comment;
4609 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4610 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4611 comment = (WS_XML_COMMENT_NODE *)node;
4613 if (value->length && !(comment->value.bytes = malloc( value->length )))
4615 free_node( node );
4616 return E_OUTOFMEMORY;
4618 memcpy( comment->value.bytes, value->bytes, value->length );
4619 comment->value.length = value->length;
4621 write_insert_node( writer, parent, node );
4622 return S_OK;
4625 static HRESULT write_comment_text( struct writer *writer )
4627 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4628 HRESULT hr;
4630 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4631 write_bytes( writer, (const BYTE *)"<!--", 4 );
4632 write_bytes( writer, comment->value.bytes, comment->value.length );
4633 write_bytes( writer, (const BYTE *)"-->", 3 );
4634 return S_OK;
4637 static HRESULT write_comment_bin( struct writer *writer )
4639 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4640 HRESULT hr;
4642 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4643 write_char( writer, RECORD_COMMENT );
4644 return write_string( writer, comment->value.bytes, comment->value.length );
4647 static HRESULT write_comment( struct writer *writer )
4649 switch (writer->output_enc)
4651 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4652 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4653 default:
4654 ERR( "unhandled encoding %u\n", writer->output_enc );
4655 return WS_E_NOT_SUPPORTED;
4659 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4661 HRESULT hr;
4662 if ((hr = write_commit( writer )) != S_OK) return hr;
4663 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4664 if ((hr = write_comment( writer )) != S_OK) return hr;
4665 writer->state = WRITER_STATE_COMMENT;
4666 return S_OK;
4669 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4671 ULONG i;
4672 HRESULT hr;
4674 for (i = 0; i < count; i++)
4676 const WS_XML_STRING *prefix = attrs[i]->prefix;
4677 const WS_XML_STRING *localname = attrs[i]->localName;
4678 const WS_XML_STRING *ns = attrs[i]->ns;
4679 BOOL single = attrs[i]->singleQuote;
4681 if (attrs[i]->isXmlNs)
4683 if ((hr = add_namespace_attribute( writer, prefix, ns, single )) != S_OK) return hr;
4685 else
4687 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
4688 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4691 return S_OK;
4694 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4696 HRESULT hr;
4698 switch (node->nodeType)
4700 case WS_XML_NODE_TYPE_ELEMENT:
4702 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4703 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4704 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4706 case WS_XML_NODE_TYPE_TEXT:
4708 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4709 return write_text_node( writer, text->text );
4711 case WS_XML_NODE_TYPE_END_ELEMENT:
4712 return write_endelement_node( writer );
4714 case WS_XML_NODE_TYPE_COMMENT:
4716 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4717 return write_comment_node( writer, &comment->value );
4719 case WS_XML_NODE_TYPE_CDATA:
4720 return write_cdata_node( writer );
4722 case WS_XML_NODE_TYPE_END_CDATA:
4723 return write_endcdata_node( writer );
4725 case WS_XML_NODE_TYPE_EOF:
4726 case WS_XML_NODE_TYPE_BOF:
4727 return S_OK;
4729 default:
4730 WARN( "unknown node type %u\n", node->nodeType );
4731 return E_INVALIDARG;
4735 /**************************************************************************
4736 * WsWriteNode [webservices.@]
4738 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4740 struct writer *writer = (struct writer *)handle;
4741 HRESULT hr;
4743 TRACE( "%p %p %p\n", handle, node, error );
4744 if (error) FIXME( "ignoring error parameter\n" );
4746 if (!writer || !node) return E_INVALIDARG;
4748 EnterCriticalSection( &writer->cs );
4750 if (writer->magic != WRITER_MAGIC)
4752 LeaveCriticalSection( &writer->cs );
4753 return E_INVALIDARG;
4756 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4757 else hr = write_node( writer, node );
4759 LeaveCriticalSection( &writer->cs );
4760 TRACE( "returning %#lx\n", hr );
4761 return hr;
4764 static HRESULT write_tree_node( struct writer *writer )
4766 HRESULT hr;
4768 switch (node_type( writer->current ))
4770 case WS_XML_NODE_TYPE_ELEMENT:
4771 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4772 return hr;
4773 if ((hr = write_startelement( writer )) != S_OK) return hr;
4774 writer->state = WRITER_STATE_STARTELEMENT;
4775 return S_OK;
4777 case WS_XML_NODE_TYPE_TEXT:
4778 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4779 return hr;
4780 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4781 writer->state = WRITER_STATE_TEXT;
4782 return S_OK;
4784 case WS_XML_NODE_TYPE_END_ELEMENT:
4785 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4786 writer->state = WRITER_STATE_ENDELEMENT;
4787 return S_OK;
4789 case WS_XML_NODE_TYPE_COMMENT:
4790 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4791 return hr;
4792 if ((hr = write_comment( writer )) != S_OK) return hr;
4793 writer->state = WRITER_STATE_COMMENT;
4794 return S_OK;
4796 case WS_XML_NODE_TYPE_CDATA:
4797 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4798 return hr;
4799 if ((hr = write_cdata( writer )) != S_OK) return hr;
4800 writer->state = WRITER_STATE_STARTCDATA;
4801 return S_OK;
4803 case WS_XML_NODE_TYPE_END_CDATA:
4804 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4805 writer->state = WRITER_STATE_ENDCDATA;
4806 return S_OK;
4808 case WS_XML_NODE_TYPE_EOF:
4809 case WS_XML_NODE_TYPE_BOF:
4810 return S_OK;
4812 default:
4813 ERR( "unknown node type %u\n", node_type(writer->current) );
4814 return E_INVALIDARG;
4818 static HRESULT write_tree( struct writer *writer )
4820 HRESULT hr;
4822 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4823 for (;;)
4825 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4826 if (move_to_child_node( &writer->current ))
4828 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4829 continue;
4831 if (move_to_next_node( &writer->current ))
4833 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4834 continue;
4836 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4838 ERR( "invalid tree\n" );
4839 return WS_E_INVALID_FORMAT;
4841 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4843 return S_OK;
4846 static void write_rewind( struct writer *writer )
4848 writer->write_pos = 0;
4849 writer->current = writer->root;
4850 writer->state = WRITER_STATE_INITIAL;
4853 /**************************************************************************
4854 * WsCopyNode [webservices.@]
4856 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4858 struct writer *writer = (struct writer *)handle;
4859 struct node *parent, *current, *node = NULL;
4860 HRESULT hr;
4862 TRACE( "%p %p %p\n", handle, reader, error );
4863 if (error) FIXME( "ignoring error parameter\n" );
4865 if (!writer) return E_INVALIDARG;
4867 EnterCriticalSection( &writer->cs );
4869 if (writer->magic != WRITER_MAGIC)
4871 LeaveCriticalSection( &writer->cs );
4872 return E_INVALIDARG;
4875 if (!(parent = find_parent( writer ))) hr = WS_E_INVALID_FORMAT;
4876 else
4878 if ((hr = copy_node( reader, writer->output_enc, &node )) != S_OK) goto done;
4879 current = writer->current;
4880 write_insert_node( writer, parent, node );
4882 write_rewind( writer );
4883 if ((hr = write_tree( writer )) != S_OK) goto done;
4884 writer->current = current;
4886 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4889 done:
4890 LeaveCriticalSection( &writer->cs );
4891 TRACE( "returning %#lx\n", hr );
4892 return hr;
4895 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4897 return write_type_field( writer, desc, value, 0 );
4900 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4902 ULONG i, ret = 0;
4903 for (i = 0; i < count; i++)
4905 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4906 continue;
4907 if (params[i].outputMessageIndex != INVALID_PARAMETER_INDEX)
4908 ret = **(const ULONG **)args[i];
4909 else
4910 ret = *(const ULONG *)args[i];
4911 break;
4913 return ret;
4916 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4917 ULONG len )
4919 return write_type_array( writer, desc, value, len );
4922 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4923 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4925 struct writer *writer = (struct writer *)handle;
4926 const WS_STRUCT_DESCRIPTION *desc_struct;
4927 const WS_FIELD_DESCRIPTION *desc_field;
4928 HRESULT hr;
4929 ULONG i;
4931 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4933 EnterCriticalSection( &writer->cs );
4935 if (writer->magic != WRITER_MAGIC)
4937 LeaveCriticalSection( &writer->cs );
4938 return E_INVALIDARG;
4941 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4943 for (i = 0; i < count; i++)
4945 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4946 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4948 FIXME( "messages type not supported\n" );
4949 hr = E_NOTIMPL;
4950 goto done;
4952 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4953 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4955 const void *ptr;
4956 if (params[i].outputMessageIndex != INVALID_PARAMETER_INDEX)
4957 ptr = *(const void **)args[i];
4958 else
4959 ptr = args[i];
4960 if ((hr = write_param( writer, desc_field, ptr )) != S_OK) goto done;
4962 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4964 const void *ptr;
4965 ULONG len;
4966 if (params[i].outputMessageIndex != INVALID_PARAMETER_INDEX)
4967 ptr = **(const void ***)args[i];
4968 else
4969 ptr = *(const void **)args[i];
4970 len = get_array_len( params, count, params[i].inputMessageIndex, args );
4971 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4975 hr = write_endelement_node( writer );
4977 done:
4978 LeaveCriticalSection( &writer->cs );
4979 return hr;
4982 HRESULT writer_set_lookup( WS_XML_WRITER *handle, BOOL enable )
4984 struct writer *writer = (struct writer *)handle;
4986 EnterCriticalSection( &writer->cs );
4988 if (writer->magic != WRITER_MAGIC)
4990 LeaveCriticalSection( &writer->cs );
4991 return E_INVALIDARG;
4994 writer->dict_do_lookup = enable;
4996 LeaveCriticalSection( &writer->cs );
4997 return S_OK;
5000 HRESULT writer_set_dict_callback( WS_XML_WRITER *handle, WS_DYNAMIC_STRING_CALLBACK cb, void *state )
5002 struct writer *writer = (struct writer *)handle;
5004 EnterCriticalSection( &writer->cs );
5006 if (writer->magic != WRITER_MAGIC)
5008 LeaveCriticalSection( &writer->cs );
5009 return E_INVALIDARG;
5012 writer->dict_cb = cb;
5013 writer->dict_cb_state = state;
5015 LeaveCriticalSection( &writer->cs );
5016 return S_OK;