makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / webservices / writer.c
blob28df4a3c4ef45c6b9c0c468e9c87afadca5d11ab
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 <stdio.h>
22 #include <float.h>
23 #include <math.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winuser.h"
29 #include "webservices.h"
31 #include "wine/debug.h"
32 #include "wine/heap.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 = heap_alloc_zero( 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 heap_free( writer->stream_buf );
127 writer->cs.DebugInfo->Spare[0] = 0;
128 DeleteCriticalSection( &writer->cs );
129 heap_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 %u %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 = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
224 &max_size, sizeof(max_size) );
225 if (hr != S_OK)
227 free_writer( writer );
228 return hr;
231 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
232 if (hr != S_OK)
234 free_writer( writer );
235 return hr;
238 hr = init_writer( writer );
239 if (hr != S_OK)
241 free_writer( writer );
242 return hr;
245 TRACE( "created %p\n", writer );
246 *handle = (WS_XML_WRITER *)writer;
247 return S_OK;
250 /**************************************************************************
251 * WsFreeWriter [webservices.@]
253 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
255 struct writer *writer = (struct writer *)handle;
257 TRACE( "%p\n", handle );
259 if (!writer) return;
261 EnterCriticalSection( &writer->cs );
263 if (writer->magic != WRITER_MAGIC)
265 LeaveCriticalSection( &writer->cs );
266 return;
269 writer->magic = 0;
271 LeaveCriticalSection( &writer->cs );
272 free_writer( writer );
275 /**************************************************************************
276 * WsGetWriterProperty [webservices.@]
278 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
279 void *buf, ULONG size, WS_ERROR *error )
281 struct writer *writer = (struct writer *)handle;
282 HRESULT hr = S_OK;
284 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
285 if (error) FIXME( "ignoring error parameter\n" );
287 if (!writer) return E_INVALIDARG;
289 EnterCriticalSection( &writer->cs );
291 if (writer->magic != WRITER_MAGIC)
293 LeaveCriticalSection( &writer->cs );
294 return E_INVALIDARG;
297 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
298 else
300 switch (id)
302 case WS_XML_WRITER_PROPERTY_BYTES:
304 WS_BYTES *bytes = buf;
305 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
306 else
308 bytes->bytes = writer->output_buf->bytes.bytes;
309 bytes->length = writer->output_buf->bytes.length;
311 break;
313 case WS_XML_WRITER_PROPERTY_BUFFERS:
314 if (writer->output_buf->bytes.length)
316 WS_BUFFERS *buffers = buf;
317 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
318 else
320 buffers->bufferCount = 1;
321 buffers->buffers = &writer->output_buf->bytes;
323 break;
325 /* fall through */
326 default:
327 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
331 LeaveCriticalSection( &writer->cs );
332 TRACE( "returning %08x\n", hr );
333 return hr;
336 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
338 /* free current buffer if it's ours */
339 if (writer->output_buf && !writer->output_buf_user)
341 free_xmlbuf( writer->output_buf );
343 writer->output_buf = xmlbuf;
344 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
345 writer->write_bufptr = xmlbuf->bytes.bytes;
346 writer->write_pos = 0;
349 static void set_output_stream( struct writer *writer, WS_WRITE_CALLBACK callback, void *state )
351 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
352 writer->output_cb = callback;
353 writer->output_cb_state = state;
354 writer->write_bufptr = writer->stream_buf;
355 writer->write_pos = 0;
358 /**************************************************************************
359 * WsSetOutput [webservices.@]
361 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
362 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
363 ULONG count, WS_ERROR *error )
365 struct writer *writer = (struct writer *)handle;
366 struct node *node;
367 HRESULT hr;
368 ULONG i;
370 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
371 if (error) FIXME( "ignoring error parameter\n" );
373 if (!writer) return E_INVALIDARG;
375 EnterCriticalSection( &writer->cs );
377 if (writer->magic != WRITER_MAGIC)
379 LeaveCriticalSection( &writer->cs );
380 return E_INVALIDARG;
383 for (i = 0; i < count; i++)
385 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
386 properties[i].valueSize );
387 if (hr != S_OK) goto done;
390 if ((hr = init_writer( writer )) != S_OK) goto done;
392 switch (encoding->encodingType)
394 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
396 const WS_XML_WRITER_TEXT_ENCODING *text = (const WS_XML_WRITER_TEXT_ENCODING *)encoding;
397 if (text->charSet != WS_CHARSET_UTF8)
399 FIXME( "charset %u not supported\n", text->charSet );
400 hr = E_NOTIMPL;
401 goto done;
403 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
404 writer->output_charset = WS_CHARSET_UTF8;
405 break;
407 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
409 const WS_XML_WRITER_BINARY_ENCODING *bin = (const WS_XML_WRITER_BINARY_ENCODING *)encoding;
410 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
411 writer->output_charset = 0;
412 writer->dict = bin->staticDictionary;
413 writer->dict_cb = bin->dynamicStringCallback;
414 writer->dict_cb_state = bin->dynamicStringCallbackState;
415 break;
417 default:
418 FIXME( "encoding type %u not supported\n", encoding->encodingType );
419 hr = E_NOTIMPL;
420 goto done;
423 switch (output->outputType)
425 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
427 struct xmlbuf *xmlbuf;
428 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, 0, writer->output_enc, writer->output_charset,
429 writer->dict, NULL )))
431 hr = WS_E_QUOTA_EXCEEDED;
432 goto done;
434 set_output_buffer( writer, xmlbuf );
435 writer->output_buf_user = FALSE;
436 break;
438 case WS_XML_WRITER_OUTPUT_TYPE_STREAM:
440 const WS_XML_WRITER_STREAM_OUTPUT *stream = (const WS_XML_WRITER_STREAM_OUTPUT *)output;
441 if (!writer->stream_buf && !(writer->stream_buf = heap_alloc( STREAM_BUFSIZE )))
443 hr = E_OUTOFMEMORY;
444 goto done;
446 set_output_stream( writer, stream->writeCallback, stream->writeCallbackState );
447 break;
450 default:
451 FIXME( "output type %u not supported\n", output->outputType );
452 hr = E_NOTIMPL;
453 goto done;
456 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
457 else write_insert_bof( writer, node );
459 done:
460 LeaveCriticalSection( &writer->cs );
461 TRACE( "returning %08x\n", hr );
462 return hr;
465 /**************************************************************************
466 * WsSetOutputToBuffer [webservices.@]
468 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
469 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
470 WS_ERROR *error )
472 struct writer *writer = (struct writer *)handle;
473 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
474 struct node *node;
475 HRESULT hr;
476 ULONG i;
478 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
479 if (error) FIXME( "ignoring error parameter\n" );
481 if (!writer || !xmlbuf) return E_INVALIDARG;
483 EnterCriticalSection( &writer->cs );
485 if (writer->magic != WRITER_MAGIC)
487 LeaveCriticalSection( &writer->cs );
488 return E_INVALIDARG;
491 for (i = 0; i < count; i++)
493 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
494 properties[i].valueSize );
495 if (hr != S_OK) goto done;
498 if ((hr = init_writer( writer )) != S_OK) goto done;
499 writer->output_enc = xmlbuf->encoding;
500 writer->output_charset = xmlbuf->charset;
501 set_output_buffer( writer, xmlbuf );
502 writer->output_buf_user = TRUE;
504 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
505 else write_insert_bof( writer, node );
507 done:
508 LeaveCriticalSection( &writer->cs );
509 TRACE( "returning %08x\n", hr );
510 return hr;
513 static HRESULT flush_writer( struct writer *writer, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
514 WS_ERROR *error )
516 WS_BYTES buf;
518 if (writer->write_pos < min_size) return S_OK;
520 buf.bytes = writer->write_bufptr;
521 buf.length = writer->write_pos;
522 writer->output_cb( writer->output_cb_state, &buf, 1, ctx, error );
523 writer->write_pos = 0;
524 return S_OK;
527 /**************************************************************************
528 * WsFlushWriter [webservices.@]
530 HRESULT WINAPI WsFlushWriter( WS_XML_WRITER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
531 WS_ERROR *error )
533 struct writer *writer = (struct writer *)handle;
534 HRESULT hr;
536 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
537 if (error) FIXME( "ignoring error parameter\n" );
538 if (ctx) FIXME( "ignoring ctx parameter\n" );
540 if (!writer) return E_INVALIDARG;
542 EnterCriticalSection( &writer->cs );
544 if (writer->magic != WRITER_MAGIC)
546 LeaveCriticalSection( &writer->cs );
547 return E_INVALIDARG;
550 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_STREAM) hr = WS_E_INVALID_OPERATION;
551 else hr = flush_writer( writer, min_size, ctx, error );
553 LeaveCriticalSection( &writer->cs );
554 TRACE( "returning %08x\n", hr );
555 return hr;
558 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
560 struct xmlbuf *buf = writer->output_buf;
561 SIZE_T new_size;
562 void *tmp;
564 if (writer->output_type == WS_XML_WRITER_OUTPUT_TYPE_STREAM)
566 if (size > STREAM_BUFSIZE) return WS_E_QUOTA_EXCEEDED;
567 return flush_writer( writer, STREAM_BUFSIZE - size, NULL, NULL );
570 if (buf->size >= writer->write_pos + size)
572 buf->bytes.length = writer->write_pos + size;
573 return S_OK;
575 new_size = max( buf->size * 2, writer->write_pos + size );
576 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
577 writer->write_bufptr = buf->bytes.bytes = tmp;
578 buf->size = new_size;
579 buf->bytes.length = writer->write_pos + size;
580 return S_OK;
583 static inline void write_char( struct writer *writer, unsigned char ch )
585 writer->write_bufptr[writer->write_pos++] = ch;
588 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
590 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
591 writer->write_pos += len;
594 struct escape
596 char ch;
597 const char *entity;
598 ULONG len;
600 static const struct escape escape_lt = { '<', "&lt;", 4 };
601 static const struct escape escape_gt = { '>', "&gt;", 4 };
602 static const struct escape escape_amp = { '&', "&amp;", 5 };
603 static const struct escape escape_apos = { '\'', "&apos;", 6 };
604 static const struct escape escape_quot = { '"', "&quot;", 6 };
606 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
607 const struct escape **escapes, ULONG nb_escapes )
609 ULONG i, j, size;
610 const BYTE *ptr;
611 HRESULT hr;
613 for (i = 0; i < len; i++)
615 ptr = &bytes[i];
616 size = 1;
617 for (j = 0; j < nb_escapes; j++)
619 if (bytes[i] == escapes[j]->ch)
621 ptr = (const BYTE *)escapes[j]->entity;
622 size = escapes[j]->len;
623 break;
626 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
627 write_bytes( writer, ptr, size );
630 return S_OK;
633 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
635 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
636 const struct escape *escapes[3];
638 escapes[0] = single ? &escape_apos : &escape_quot;
639 escapes[1] = &escape_lt;
640 escapes[2] = &escape_amp;
641 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
644 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
646 unsigned char quote = attr->singleQuote ? '\'' : '"';
647 const WS_XML_STRING *prefix = NULL;
648 ULONG size;
649 HRESULT hr;
651 if (attr->prefix) prefix = attr->prefix;
653 /* ' prefix:attr="value"' */
655 size = attr->localName->length + 4 /* ' =""' */;
656 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
657 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
659 write_char( writer, ' ' );
660 if (prefix && prefix->length)
662 write_bytes( writer, prefix->bytes, prefix->length );
663 write_char( writer, ':' );
665 write_bytes( writer, attr->localName->bytes, attr->localName->length );
666 write_char( writer, '=' );
667 write_char( writer, quote );
668 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
669 write_char( writer, quote );
671 return hr;
674 static HRESULT write_int31( struct writer *writer, ULONG len )
676 HRESULT hr;
678 if (len > 0x7fffffff) return E_INVALIDARG;
680 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
681 if (len < 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) < 0x80)
707 write_char( writer, len );
708 return S_OK;
710 write_char( writer, (len & 0x7f) | 0x80 );
712 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
713 if ((len >>= 7) < 0x08)
715 write_char( writer, len );
716 return S_OK;
718 return WS_E_INVALID_FORMAT;
721 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
723 HRESULT hr;
724 if ((hr = write_int31( writer, len )) != S_OK) return hr;
725 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
726 write_bytes( writer, bytes, len );
727 return S_OK;
730 static HRESULT write_dict_string( struct writer *writer, ULONG id )
732 if (id > 0x7fffffff) return E_INVALIDARG;
733 return write_int31( writer, id );
736 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
738 if (!text) return RECORD_CHARS8_TEXT;
739 switch (text->textType)
741 case WS_XML_TEXT_TYPE_UTF8:
743 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
744 if (use_dict) return RECORD_DICTIONARY_TEXT;
745 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
746 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
747 return RECORD_CHARS32_TEXT;
749 case WS_XML_TEXT_TYPE_UTF16:
751 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
752 int len = text_utf16->byteCount / sizeof(WCHAR);
753 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
754 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT;
755 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT;
756 return RECORD_CHARS32_TEXT;
758 case WS_XML_TEXT_TYPE_BASE64:
760 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
761 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
762 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
763 return RECORD_BYTES32_TEXT;
765 case WS_XML_TEXT_TYPE_BOOL:
767 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
768 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
770 case WS_XML_TEXT_TYPE_INT32:
772 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
773 if (!text_int32->value) return RECORD_ZERO_TEXT;
774 if (text_int32->value == 1) return RECORD_ONE_TEXT;
775 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
776 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
777 return RECORD_INT32_TEXT;
779 case WS_XML_TEXT_TYPE_INT64:
781 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
782 if (!text_int64->value) return RECORD_ZERO_TEXT;
783 if (text_int64->value == 1) return RECORD_ONE_TEXT;
784 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
785 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
786 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
787 return RECORD_INT64_TEXT;
789 case WS_XML_TEXT_TYPE_UINT64:
791 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
792 if (!text_uint64->value) return RECORD_ZERO_TEXT;
793 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
794 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
795 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
796 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
797 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
798 return RECORD_UINT64_TEXT;
800 case WS_XML_TEXT_TYPE_DOUBLE:
802 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
803 if (!text_double->value) return RECORD_ZERO_TEXT;
804 if (text_double->value == 1) return RECORD_ONE_TEXT;
805 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
806 return RECORD_DOUBLE_TEXT;
807 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
808 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
809 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
810 return RECORD_INT64_TEXT;
812 case WS_XML_TEXT_TYPE_GUID:
813 return RECORD_GUID_TEXT;
815 case WS_XML_TEXT_TYPE_UNIQUE_ID:
816 return RECORD_UNIQUE_ID_TEXT;
818 case WS_XML_TEXT_TYPE_DATETIME:
819 return RECORD_DATETIME_TEXT;
821 default:
822 FIXME( "unhandled text type %u\n", text->textType );
823 return 0;
827 static INT64 get_text_value_int( const WS_XML_TEXT *text )
829 switch (text->textType)
831 case WS_XML_TEXT_TYPE_INT32:
833 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
834 return text_int32->value;
836 case WS_XML_TEXT_TYPE_INT64:
838 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
839 return text_int64->value;
841 case WS_XML_TEXT_TYPE_UINT64:
843 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
844 return text_uint64->value;
846 case WS_XML_TEXT_TYPE_DOUBLE:
848 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
849 return text_double->value;
851 default:
852 ERR( "unhandled text type %u\n", text->textType );
853 assert(0);
854 return 0;
858 static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
860 if (writer->dict && str->dictionary == writer->dict)
862 *id = str->id << 1;
863 return TRUE;
865 if (writer->dict_cb)
867 BOOL found = FALSE;
868 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
869 if (found) *id = (*id << 1) | 1;
870 return found;
872 return FALSE;
875 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
877 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
878 if (*ptr)
880 memcpy( buf, bool_true, sizeof(bool_true) );
881 return sizeof(bool_true);
883 memcpy( buf, bool_false, sizeof(bool_false) );
884 return sizeof(bool_false);
887 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
889 return wsprintfA( (char *)buf, "%d", *ptr );
892 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
894 return wsprintfA( (char *)buf, "%I64d", *ptr );
897 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
899 return wsprintfA( (char *)buf, "%I64u", *ptr );
902 static ULONG format_double( const double *ptr, unsigned char *buf )
904 static const double precision = 0.0000000000000001;
905 unsigned char *p = buf;
906 double val = *ptr;
907 int neg, mag, mag2, use_exp;
909 if (isnan( val ))
911 memcpy( buf, "NaN", 3 );
912 return 3;
914 if (isinf( val ))
916 if (val < 0)
918 memcpy( buf, "-INF", 4 );
919 return 4;
921 memcpy( buf, "INF", 3 );
922 return 3;
924 if (val == 0.0)
926 *p = '0';
927 return 1;
930 if ((neg = val < 0))
932 *p++ = '-';
933 val = -val;
936 mag = log10( val );
937 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
938 if (use_exp)
940 if (mag < 0) mag -= 1;
941 val = val / pow( 10.0, mag );
942 mag2 = mag;
943 mag = 0;
945 else if (mag < 1) mag = 0;
947 while (val > precision || mag >= 0)
949 double weight = pow( 10.0, mag );
950 if (weight > 0 && !isinf( weight ))
952 int digit = floor( val / weight );
953 val -= digit * weight;
954 *(p++) = '0' + digit;
956 if (!mag && val > precision) *(p++) = '.';
957 mag--;
960 if (use_exp)
962 int i, j;
963 *(p++) = 'E';
964 if (mag2 > 0) *(p++) = '+';
965 else
967 *(p++) = '-';
968 mag2 = -mag2;
970 mag = 0;
971 while (mag2 > 0)
973 *(p++) = '0' + mag2 % 10;
974 mag2 /= 10;
975 mag++;
977 for (i = -mag, j = -1; i < j; i++, j--)
979 p[i] ^= p[j];
980 p[j] ^= p[i];
981 p[i] ^= p[j];
985 return p - buf;
988 static inline int year_size( int year )
990 return leap_year( year ) ? 366 : 365;
993 #define TZ_OFFSET 8
994 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
996 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
997 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
998 unsigned __int64 ticks, day_ticks;
999 ULONG len;
1001 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1002 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1004 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1005 tz_hour = TZ_OFFSET;
1007 else
1009 ticks = ptr->ticks;
1010 tz_hour = 0;
1012 day = ticks / TICKS_PER_DAY;
1013 day_ticks = ticks % TICKS_PER_DAY;
1014 hour = day_ticks / TICKS_PER_HOUR;
1015 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1016 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1017 sec_frac = day_ticks % TICKS_PER_SEC;
1019 while (day >= year_size( year ))
1021 day -= year_size( year );
1022 year++;
1024 while (day >= month_days[leap_year( year )][month])
1026 day -= month_days[leap_year( year )][month];
1027 month++;
1030 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1031 if (sec_frac)
1033 static const char fmt_frac[] = ".%07u";
1034 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1035 while (buf[len - 1] == '0') len--;
1037 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1039 buf[len++] = 'Z';
1041 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1043 static const char fmt_tz[] = "%c%02u:00";
1044 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1047 return len;
1050 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1052 static const char fmt[] = "%08x-%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_urn( const GUID *ptr, unsigned char *buf )
1060 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1061 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1062 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1063 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1066 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
1068 ULONG len = 0;
1069 if (prefix && prefix->length)
1071 memcpy( buf, prefix->bytes, prefix->length );
1072 len += prefix->length;
1073 buf[len++] = ':';
1075 memcpy( buf + len, localname->bytes, localname->length );
1076 return len + localname->length;
1079 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1081 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1082 ULONG i = 0, x;
1084 while (len > 0)
1086 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1087 x = (bin[0] & 3) << 4;
1088 if (len == 1)
1090 buf[i++] = base64[x];
1091 buf[i++] = '=';
1092 buf[i++] = '=';
1093 break;
1095 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1096 x = (bin[1] & 0x0f) << 2;
1097 if (len == 2)
1099 buf[i++] = base64[x];
1100 buf[i++] = '=';
1101 break;
1103 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1104 buf[i++] = base64[bin[2] & 0x3f];
1105 bin += 3;
1106 len -= 3;
1108 return i;
1111 HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
1112 WS_XML_UTF8_TEXT **ret )
1114 ULONG len_old = old ? old->value.length : 0;
1115 if (offset) *offset = len_old;
1117 switch (text->textType)
1119 case WS_XML_TEXT_TYPE_UTF8:
1121 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1123 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
1124 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1125 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
1126 return S_OK;
1128 case WS_XML_TEXT_TYPE_UTF16:
1130 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1131 const WCHAR *str = (const WCHAR *)src->bytes;
1132 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1134 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1135 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1136 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
1137 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1138 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
1139 return S_OK;
1141 case WS_XML_TEXT_TYPE_BASE64:
1143 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1144 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1146 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1147 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1148 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
1149 return S_OK;
1151 case WS_XML_TEXT_TYPE_BOOL:
1153 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1155 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
1156 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1157 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
1158 return S_OK;
1160 case WS_XML_TEXT_TYPE_INT32:
1162 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1163 unsigned char buf[12]; /* "-2147483648" */
1164 ULONG len = format_int32( &int32_text->value, buf );
1166 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1167 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1168 memcpy( (*ret)->value.bytes + len_old, buf, len );
1169 return S_OK;
1171 case WS_XML_TEXT_TYPE_INT64:
1173 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1174 unsigned char buf[21]; /* "-9223372036854775808" */
1175 ULONG len = format_int64( &int64_text->value, buf );
1177 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1178 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1179 memcpy( (*ret)->value.bytes + len_old, buf, len );
1180 return S_OK;
1182 case WS_XML_TEXT_TYPE_UINT64:
1184 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1185 unsigned char buf[21]; /* "18446744073709551615" */
1186 ULONG len = format_uint64( &uint64_text->value, buf );
1188 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1189 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1190 memcpy( (*ret)->value.bytes + len_old, buf, len );
1191 return S_OK;
1193 case WS_XML_TEXT_TYPE_DOUBLE:
1195 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1196 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1197 unsigned int fpword = _control87( 0, 0 );
1198 ULONG len;
1200 _control87( _MCW_EM | _RC_NEAR | _PC_64, _MCW_EM | _MCW_RC | _MCW_PC );
1201 len = format_double( &double_text->value, buf );
1202 _control87( fpword, _MCW_EM | _MCW_RC | _MCW_PC );
1203 if (!len) return E_NOTIMPL;
1205 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1206 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1207 memcpy( (*ret)->value.bytes + len_old, buf, len );
1208 return S_OK;
1210 case WS_XML_TEXT_TYPE_GUID:
1212 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1214 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
1215 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1216 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1217 return S_OK;
1219 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1221 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1223 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
1224 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1225 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1226 return S_OK;
1228 case WS_XML_TEXT_TYPE_DATETIME:
1230 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1232 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
1233 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1234 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
1235 return S_OK;
1237 case WS_XML_TEXT_TYPE_QNAME:
1239 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
1240 ULONG len = qn->localName->length;
1242 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
1243 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1244 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1245 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
1246 return S_OK;
1248 default:
1249 FIXME( "unhandled text type %u\n", text->textType );
1250 return E_NOTIMPL;
1254 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
1256 enum record_type type;
1257 BOOL use_dict = FALSE;
1258 HRESULT hr;
1259 ULONG id;
1261 if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
1263 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1264 use_dict = get_string_id( writer, &utf8->value, &id );
1266 type = get_attr_text_record_type( text, use_dict );
1268 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1269 write_char( writer, type );
1271 switch (type)
1273 case RECORD_CHARS8_TEXT:
1275 const WS_XML_UTF8_TEXT *text_utf8;
1276 WS_XML_UTF8_TEXT *new = NULL;
1277 UINT8 len;
1279 if (!text)
1281 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1282 write_char( writer, 0 );
1283 return S_OK;
1285 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1286 else
1288 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1289 text_utf8 = new;
1291 len = text_utf8->value.length;
1292 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1294 heap_free( new );
1295 return hr;
1297 write_char( writer, len );
1298 write_bytes( writer, text_utf8->value.bytes, len );
1299 heap_free( new );
1300 return S_OK;
1302 case RECORD_CHARS16_TEXT:
1304 const WS_XML_UTF8_TEXT *text_utf8;
1305 WS_XML_UTF8_TEXT *new = NULL;
1306 UINT16 len;
1308 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1309 else
1311 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1312 text_utf8 = new;
1314 len = text_utf8->value.length;
1315 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1317 heap_free( new );
1318 return hr;
1320 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1321 write_bytes( writer, text_utf8->value.bytes, len );
1322 heap_free( new );
1323 return S_OK;
1325 case RECORD_BYTES8_TEXT:
1327 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1328 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
1329 write_char( writer, text_base64->length );
1330 write_bytes( writer, text_base64->bytes, text_base64->length );
1331 return S_OK;
1333 case RECORD_BYTES16_TEXT:
1335 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1336 UINT16 len = text_base64->length;
1337 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
1338 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1339 write_bytes( writer, text_base64->bytes, len );
1340 return S_OK;
1342 case RECORD_ZERO_TEXT:
1343 case RECORD_ONE_TEXT:
1344 case RECORD_FALSE_TEXT:
1345 case RECORD_TRUE_TEXT:
1346 return S_OK;
1348 case RECORD_INT8_TEXT:
1350 INT8 val = get_text_value_int( text );
1351 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1352 write_char( writer, val );
1353 return S_OK;
1355 case RECORD_INT16_TEXT:
1357 INT16 val = get_text_value_int( text );
1358 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1359 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1360 return S_OK;
1362 case RECORD_INT32_TEXT:
1364 INT32 val = get_text_value_int( text );
1365 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1366 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1367 return S_OK;
1369 case RECORD_INT64_TEXT:
1371 INT64 val = get_text_value_int( text );
1372 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1373 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1374 return S_OK;
1376 case RECORD_UINT64_TEXT:
1378 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
1379 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
1380 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
1381 return S_OK;
1383 case RECORD_DOUBLE_TEXT:
1385 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
1386 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
1387 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
1388 return S_OK;
1390 case RECORD_GUID_TEXT:
1392 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
1393 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
1394 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
1395 return S_OK;
1397 case RECORD_UNIQUE_ID_TEXT:
1399 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
1400 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
1401 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
1402 return S_OK;
1404 case RECORD_DATETIME_TEXT:
1406 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
1407 UINT64 val = text_datetime->value.ticks;
1409 assert( val <= TICKS_MAX );
1410 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
1411 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
1413 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1414 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1415 return S_OK;
1417 default:
1418 FIXME( "unhandled record type %02x\n", type );
1419 return E_NOTIMPL;
1423 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1425 if (!attr->prefix || !attr->prefix->length)
1427 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
1428 return RECORD_SHORT_ATTRIBUTE;
1430 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
1432 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1433 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1435 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
1436 return RECORD_ATTRIBUTE;
1439 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1441 ULONG id;
1442 enum record_type type = get_attr_record_type( attr, get_string_id(writer, attr->localName, &id) );
1443 HRESULT hr;
1445 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1446 write_char( writer, type );
1448 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
1450 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1451 return write_attribute_value_bin( writer, attr->value );
1453 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
1455 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1456 return write_attribute_value_bin( writer, attr->value );
1459 switch (type)
1461 case RECORD_SHORT_ATTRIBUTE:
1462 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1463 break;
1465 case RECORD_ATTRIBUTE:
1466 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1467 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1468 break;
1470 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
1471 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1472 break;
1474 case RECORD_DICTIONARY_ATTRIBUTE:
1475 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1476 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1477 break;
1479 default:
1480 ERR( "unhandled record type %02x\n", type );
1481 return WS_E_NOT_SUPPORTED;
1484 return write_attribute_value_bin( writer, attr->value );
1487 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1489 switch (writer->output_enc)
1491 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
1492 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
1493 default:
1494 ERR( "unhandled encoding %u\n", writer->output_enc );
1495 return WS_E_NOT_SUPPORTED;
1499 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1501 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
1504 /**************************************************************************
1505 * WsGetPrefixFromNamespace [webservices.@]
1507 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
1508 BOOL required, const WS_XML_STRING **prefix,
1509 WS_ERROR *error )
1511 struct writer *writer = (struct writer *)handle;
1512 WS_XML_ELEMENT_NODE *elem;
1513 BOOL found = FALSE;
1514 HRESULT hr = S_OK;
1516 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1517 if (error) FIXME( "ignoring error parameter\n" );
1519 if (!writer || !ns || !prefix) return E_INVALIDARG;
1521 EnterCriticalSection( &writer->cs );
1523 if (writer->magic != WRITER_MAGIC)
1525 LeaveCriticalSection( &writer->cs );
1526 return E_INVALIDARG;
1529 elem = &writer->current->hdr;
1530 if (elem->prefix && is_current_namespace( writer, ns ))
1532 *prefix = elem->prefix;
1533 found = TRUE;
1536 if (!found)
1538 if (required) hr = WS_E_INVALID_FORMAT;
1539 else
1541 *prefix = NULL;
1542 hr = S_FALSE;
1546 LeaveCriticalSection( &writer->cs );
1547 TRACE( "returning %08x\n", hr );
1548 return hr;
1551 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1553 unsigned char quote = attr->singleQuote ? '\'' : '"';
1554 ULONG size;
1555 HRESULT hr;
1557 /* ' xmlns:prefix="namespace"' */
1559 size = attr->ns->length + 9 /* ' xmlns=""' */;
1560 if (attr->prefix && attr->prefix->length) size += attr->prefix->length + 1 /* ':' */;
1561 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1563 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1564 if (attr->prefix && attr->prefix->length)
1566 write_char( writer, ':' );
1567 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1569 write_char( writer, '=' );
1570 write_char( writer, quote );
1571 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1572 write_char( writer, quote );
1574 return S_OK;
1577 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1579 if (!attr->prefix || !attr->prefix->length)
1581 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1582 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1584 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1585 return RECORD_XMLNS_ATTRIBUTE;
1588 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1590 ULONG id;
1591 enum record_type type = get_xmlns_record_type( attr, get_string_id(writer, attr->ns, &id) );
1592 HRESULT hr;
1594 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1595 write_char( writer, type );
1597 switch (type)
1599 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1600 break;
1602 case RECORD_XMLNS_ATTRIBUTE:
1603 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1604 break;
1606 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1607 return write_dict_string( writer, id );
1609 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1610 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1611 return write_dict_string( writer, id );
1613 default:
1614 ERR( "unhandled record type %02x\n", type );
1615 return WS_E_NOT_SUPPORTED;
1618 return write_string( writer, attr->ns->bytes, attr->ns->length );
1621 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1623 switch (writer->output_enc)
1625 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1626 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1627 default:
1628 ERR( "unhandled encoding %u\n", writer->output_enc );
1629 return WS_E_NOT_SUPPORTED;
1633 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1634 const WS_XML_STRING *ns, BOOL single )
1636 WS_XML_ATTRIBUTE *attr;
1637 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1638 HRESULT hr;
1640 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1642 attr->singleQuote = !!single;
1643 attr->isXmlNs = 1;
1644 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1646 free_attribute( attr );
1647 return E_OUTOFMEMORY;
1649 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1651 free_attribute( attr );
1652 return E_OUTOFMEMORY;
1654 if ((hr = append_attribute( elem, attr )) != S_OK)
1656 free_attribute( attr );
1657 return hr;
1659 return S_OK;
1662 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1664 if (!str1 && !str2) return TRUE;
1665 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1668 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1669 const WS_XML_STRING *ns )
1671 ULONG i;
1672 const struct node *node;
1674 for (node = (const struct node *)elem; node; node = node->parent)
1676 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1678 elem = &node->hdr;
1679 for (i = 0; i < elem->attributeCount; i++)
1681 if (!elem->attributes[i]->isXmlNs) continue;
1682 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1683 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1686 return FALSE;
1689 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1691 WS_XML_STRING *str;
1692 if (!(str = dup_xml_string( ns, writer->dict_do_lookup ))) return E_OUTOFMEMORY;
1693 free_xml_string( writer->current_ns );
1694 writer->current_ns = str;
1695 return S_OK;
1698 static HRESULT set_namespaces( struct writer *writer )
1700 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1701 HRESULT hr;
1702 ULONG i;
1704 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1706 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1707 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1710 for (i = 0; i < elem->attributeCount; i++)
1712 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1713 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1714 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1717 return S_OK;
1720 /**************************************************************************
1721 * WsWriteEndAttribute [webservices.@]
1723 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1725 struct writer *writer = (struct writer *)handle;
1726 HRESULT hr = S_OK;
1728 TRACE( "%p %p\n", handle, error );
1729 if (error) FIXME( "ignoring error parameter\n" );
1731 if (!writer) return E_INVALIDARG;
1733 EnterCriticalSection( &writer->cs );
1735 if (writer->magic != WRITER_MAGIC)
1737 LeaveCriticalSection( &writer->cs );
1738 return E_INVALIDARG;
1741 writer->state = WRITER_STATE_STARTELEMENT;
1743 LeaveCriticalSection( &writer->cs );
1744 TRACE( "returning %08x\n", hr );
1745 return hr;
1748 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1750 ULONG i;
1751 HRESULT hr;
1752 for (i = 0; i < elem->attributeCount; i++)
1754 if (elem->attributes[i]->isXmlNs) continue;
1755 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1757 for (i = 0; i < elem->attributeCount; i++)
1759 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1760 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1762 for (i = 0; i < elem->attributeCount; i++)
1764 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1765 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1767 return S_OK;
1770 static HRESULT write_startelement_text( struct writer *writer )
1772 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1773 ULONG size;
1774 HRESULT hr;
1776 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1778 size = elem->localName->length + 1 /* '<' */;
1779 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1780 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1782 write_char( writer, '<' );
1783 if (elem->prefix && elem->prefix->length)
1785 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1786 write_char( writer, ':' );
1788 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1789 return write_attributes( writer, elem );
1792 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1794 if (!elem->prefix || !elem->prefix->length)
1796 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1797 return RECORD_SHORT_ELEMENT;
1799 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1801 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1802 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1804 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1805 return RECORD_ELEMENT;
1808 static HRESULT write_startelement_bin( struct writer *writer )
1810 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1811 ULONG id;
1812 enum record_type type = get_elem_record_type( elem, get_string_id(writer, elem->localName, &id) );
1813 HRESULT hr;
1815 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1816 write_char( writer, type );
1818 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1820 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1821 return write_attributes( writer, elem );
1823 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1825 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1826 return write_attributes( writer, elem );
1829 switch (type)
1831 case RECORD_SHORT_ELEMENT:
1832 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1833 break;
1835 case RECORD_ELEMENT:
1836 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1837 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1838 break;
1840 case RECORD_SHORT_DICTIONARY_ELEMENT:
1841 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1842 break;
1844 case RECORD_DICTIONARY_ELEMENT:
1845 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1846 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1847 break;
1849 default:
1850 ERR( "unhandled record type %02x\n", type );
1851 return WS_E_NOT_SUPPORTED;
1854 return write_attributes( writer, elem );
1857 static HRESULT write_startelement( struct writer *writer )
1859 switch (writer->output_enc)
1861 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1862 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1863 default:
1864 ERR( "unhandled encoding %u\n", writer->output_enc );
1865 return WS_E_NOT_SUPPORTED;
1869 static struct node *write_find_startelement( struct writer *writer )
1871 struct node *node;
1872 for (node = writer->current; node; node = node->parent)
1874 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1876 return NULL;
1879 static inline BOOL is_empty_element( const struct node *node )
1881 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1882 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1885 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1887 ULONG size;
1888 HRESULT hr;
1890 /* '/>' */
1892 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1894 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1895 write_char( writer, '/' );
1896 write_char( writer, '>' );
1897 return S_OK;
1900 /* '</prefix:localname>' */
1902 size = elem->localName->length + 3 /* '</>' */;
1903 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1904 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1906 write_char( writer, '<' );
1907 write_char( writer, '/' );
1908 if (elem->prefix && elem->prefix->length)
1910 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1911 write_char( writer, ':' );
1913 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1914 write_char( writer, '>' );
1915 return S_OK;
1918 static HRESULT write_endelement_bin( struct writer *writer )
1920 HRESULT hr;
1921 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1922 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1923 write_char( writer, RECORD_ENDELEMENT );
1924 return S_OK;
1927 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1929 switch (writer->output_enc)
1931 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1932 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1933 default:
1934 ERR( "unhandled encoding %u\n", writer->output_enc );
1935 return WS_E_NOT_SUPPORTED;
1939 static HRESULT write_close_element( struct writer *writer, struct node *node )
1941 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1942 elem->isEmpty = is_empty_element( node );
1943 return write_endelement( writer, elem );
1946 static HRESULT write_endelement_node( struct writer *writer )
1948 struct node *node;
1949 HRESULT hr;
1951 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1952 if (writer->state == WRITER_STATE_STARTELEMENT)
1954 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1955 if ((hr = write_startelement( writer )) != S_OK) return hr;
1957 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1958 writer->current = node->parent;
1959 writer->state = WRITER_STATE_ENDELEMENT;
1960 return S_OK;
1963 /**************************************************************************
1964 * WsWriteEndElement [webservices.@]
1966 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1968 struct writer *writer = (struct writer *)handle;
1969 HRESULT hr;
1971 TRACE( "%p %p\n", handle, error );
1972 if (error) FIXME( "ignoring error parameter\n" );
1974 if (!writer) return E_INVALIDARG;
1976 EnterCriticalSection( &writer->cs );
1978 if (writer->magic != WRITER_MAGIC)
1980 LeaveCriticalSection( &writer->cs );
1981 return E_INVALIDARG;
1984 hr = write_endelement_node( writer );
1986 LeaveCriticalSection( &writer->cs );
1987 TRACE( "returning %08x\n", hr );
1988 return hr;
1991 static HRESULT write_endstartelement_text( struct writer *writer )
1993 HRESULT hr;
1994 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1995 write_char( writer, '>' );
1996 return S_OK;
1999 static HRESULT write_endstartelement( struct writer *writer )
2001 switch (writer->output_enc)
2003 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
2004 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
2005 default:
2006 ERR( "unhandled encoding %u\n", writer->output_enc );
2007 return WS_E_NOT_SUPPORTED;
2011 /**************************************************************************
2012 * WsWriteEndStartElement [webservices.@]
2014 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
2016 struct writer *writer = (struct writer *)handle;
2017 HRESULT hr;
2019 TRACE( "%p %p\n", handle, error );
2020 if (error) FIXME( "ignoring error parameter\n" );
2022 if (!writer) return E_INVALIDARG;
2024 EnterCriticalSection( &writer->cs );
2026 if (writer->magic != WRITER_MAGIC)
2028 LeaveCriticalSection( &writer->cs );
2029 return E_INVALIDARG;
2032 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2033 else
2035 if ((hr = set_namespaces( writer )) != S_OK) goto done;
2036 if ((hr = write_startelement( writer )) != S_OK) goto done;
2037 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
2038 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2041 done:
2042 LeaveCriticalSection( &writer->cs );
2043 TRACE( "returning %08x\n", hr );
2044 return hr;
2047 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
2048 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2049 BOOL single )
2051 WS_XML_ATTRIBUTE *attr;
2052 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2053 HRESULT hr;
2055 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
2057 if (!prefix && ns->length) prefix = elem->prefix;
2059 attr->singleQuote = !!single;
2060 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2062 free_attribute( attr );
2063 return E_OUTOFMEMORY;
2065 if (!(attr->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2067 free_attribute( attr );
2068 return E_OUTOFMEMORY;
2070 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2072 free_attribute( attr );
2073 return E_OUTOFMEMORY;
2075 if ((hr = append_attribute( elem, attr )) != S_OK)
2077 free_attribute( attr );
2078 return hr;
2080 return S_OK;
2083 /**************************************************************************
2084 * WsWriteStartAttribute [webservices.@]
2086 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2087 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2088 BOOL single, WS_ERROR *error )
2090 struct writer *writer = (struct writer *)handle;
2091 HRESULT hr;
2093 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2094 debugstr_xmlstr(ns), single, error );
2095 if (error) FIXME( "ignoring error parameter\n" );
2097 if (!writer || !localname || !ns) return E_INVALIDARG;
2099 EnterCriticalSection( &writer->cs );
2101 if (writer->magic != WRITER_MAGIC)
2103 LeaveCriticalSection( &writer->cs );
2104 return E_INVALIDARG;
2107 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2108 else if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
2109 writer->state = WRITER_STATE_STARTATTRIBUTE;
2111 LeaveCriticalSection( &writer->cs );
2112 TRACE( "returning %08x\n", hr );
2113 return hr;
2116 /* flush current start element if necessary */
2117 static HRESULT write_commit( struct writer *writer )
2119 if (writer->state == WRITER_STATE_STARTELEMENT)
2121 HRESULT hr;
2122 if ((hr = set_namespaces( writer )) != S_OK) return hr;
2123 if ((hr = write_startelement( writer )) != S_OK) return hr;
2124 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
2125 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2127 return S_OK;
2130 static HRESULT write_add_cdata_node( struct writer *writer )
2132 struct node *node, *parent;
2133 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2134 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2135 write_insert_node( writer, parent, node );
2136 return S_OK;
2139 static HRESULT write_add_endcdata_node( struct writer *writer )
2141 struct node *node;
2142 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
2143 node->parent = writer->current;
2144 list_add_tail( &node->parent->children, &node->entry );
2145 return S_OK;
2148 static HRESULT write_cdata( struct writer *writer )
2150 HRESULT hr;
2151 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
2152 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
2153 return S_OK;
2156 static HRESULT write_cdata_node( struct writer *writer )
2158 HRESULT hr;
2159 if ((hr = write_commit( writer )) != S_OK) return hr;
2160 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
2161 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
2162 if ((hr = write_cdata( writer )) != S_OK) return hr;
2163 writer->state = WRITER_STATE_STARTCDATA;
2164 return S_OK;
2167 /**************************************************************************
2168 * WsWriteStartCData [webservices.@]
2170 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
2172 struct writer *writer = (struct writer *)handle;
2173 HRESULT hr;
2175 TRACE( "%p %p\n", handle, error );
2176 if (error) FIXME( "ignoring error parameter\n" );
2178 if (!writer) return E_INVALIDARG;
2180 EnterCriticalSection( &writer->cs );
2182 if (writer->magic != WRITER_MAGIC)
2184 LeaveCriticalSection( &writer->cs );
2185 return E_INVALIDARG;
2188 hr = write_cdata_node( writer );
2190 LeaveCriticalSection( &writer->cs );
2191 TRACE( "returning %08x\n", hr );
2192 return hr;
2195 static HRESULT write_endcdata( struct writer *writer )
2197 HRESULT hr;
2198 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2199 write_bytes( writer, (const BYTE *)"]]>", 3 );
2200 return S_OK;
2203 static HRESULT write_endcdata_node( struct writer *writer )
2205 HRESULT hr;
2206 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2207 writer->current = writer->current->parent;
2208 writer->state = WRITER_STATE_ENDCDATA;
2209 return S_OK;
2212 /**************************************************************************
2213 * WsWriteEndCData [webservices.@]
2215 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
2217 struct writer *writer = (struct writer *)handle;
2218 HRESULT hr;
2220 TRACE( "%p %p\n", handle, error );
2221 if (error) FIXME( "ignoring error parameter\n" );
2223 if (!writer) return E_INVALIDARG;
2225 EnterCriticalSection( &writer->cs );
2227 if (writer->magic != WRITER_MAGIC)
2229 LeaveCriticalSection( &writer->cs );
2230 return E_INVALIDARG;
2233 if (writer->state != WRITER_STATE_TEXT) hr = WS_E_INVALID_OPERATION;
2234 else hr = write_endcdata_node( writer );
2236 LeaveCriticalSection( &writer->cs );
2237 TRACE( "returning %08x\n", hr );
2238 return hr;
2241 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2242 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2244 struct node *node, *parent;
2245 WS_XML_ELEMENT_NODE *elem;
2247 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2249 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
2251 elem = &parent->hdr;
2252 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
2255 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
2256 elem = &node->hdr;
2258 if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2260 free_node( node );
2261 return E_OUTOFMEMORY;
2263 if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2265 free_node( node );
2266 return E_OUTOFMEMORY;
2268 if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2270 free_node( node );
2271 return E_OUTOFMEMORY;
2273 write_insert_node( writer, parent, node );
2274 return S_OK;
2277 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
2279 struct node *node;
2280 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
2281 node->parent = parent;
2282 list_add_tail( &parent->children, &node->entry );
2283 return S_OK;
2286 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2287 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2289 HRESULT hr;
2290 if ((hr = write_commit( writer )) != S_OK) return hr;
2291 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
2292 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
2293 writer->state = WRITER_STATE_STARTELEMENT;
2294 return S_OK;
2297 /**************************************************************************
2298 * WsWriteStartElement [webservices.@]
2300 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2301 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2302 WS_ERROR *error )
2304 struct writer *writer = (struct writer *)handle;
2305 HRESULT hr;
2307 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2308 debugstr_xmlstr(ns), error );
2309 if (error) FIXME( "ignoring error parameter\n" );
2311 if (!writer || !localname || !ns) return E_INVALIDARG;
2313 EnterCriticalSection( &writer->cs );
2315 if (writer->magic != WRITER_MAGIC)
2317 LeaveCriticalSection( &writer->cs );
2318 return E_INVALIDARG;
2321 hr = write_element_node( writer, prefix, localname, ns );
2323 LeaveCriticalSection( &writer->cs );
2324 TRACE( "returning %08x\n", hr );
2325 return hr;
2328 HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2330 if (offset) *offset = 0;
2331 switch (text->textType)
2333 case WS_XML_TEXT_TYPE_UTF8:
2335 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2336 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2337 WS_XML_UTF8_TEXT *new;
2338 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2340 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2341 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2342 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2343 if (offset) *offset = len_old;
2344 *ret = &new->text;
2345 return S_OK;
2347 case WS_XML_TEXT_TYPE_UTF16:
2349 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2350 const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
2351 WS_XML_UTF16_TEXT *new;
2352 ULONG len = utf16->byteCount, len_old = utf16_old ? utf16_old->byteCount : 0;
2354 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2355 if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2356 if (utf16_old) memcpy( new->bytes, utf16_old->bytes, len_old );
2357 memcpy( new->bytes + len_old, utf16->bytes, len );
2358 if (offset) *offset = len_old;
2359 *ret = &new->text;
2360 return S_OK;
2362 case WS_XML_TEXT_TYPE_BASE64:
2364 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2365 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2366 WS_XML_BASE64_TEXT *new;
2367 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2369 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2370 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2371 memcpy( new->bytes + len_old, base64->bytes, len );
2372 if (offset) *offset = len_old;
2373 *ret = &new->text;
2374 return S_OK;
2376 case WS_XML_TEXT_TYPE_BOOL:
2378 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2379 WS_XML_BOOL_TEXT *new;
2381 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2382 *ret = &new->text;
2383 return S_OK;
2385 case WS_XML_TEXT_TYPE_INT32:
2387 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2388 WS_XML_INT32_TEXT *new;
2390 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2391 *ret = &new->text;
2392 return S_OK;
2394 case WS_XML_TEXT_TYPE_INT64:
2396 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2397 WS_XML_INT64_TEXT *new;
2399 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2400 *ret = &new->text;
2401 return S_OK;
2403 case WS_XML_TEXT_TYPE_UINT64:
2405 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2406 WS_XML_UINT64_TEXT *new;
2408 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2409 *ret = &new->text;
2410 return S_OK;
2412 case WS_XML_TEXT_TYPE_DOUBLE:
2414 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2415 WS_XML_DOUBLE_TEXT *new;
2417 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2418 *ret = &new->text;
2419 return S_OK;
2421 case WS_XML_TEXT_TYPE_GUID:
2423 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2424 WS_XML_GUID_TEXT *new;
2426 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2427 *ret = &new->text;
2428 return S_OK;
2430 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2432 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2433 WS_XML_UNIQUE_ID_TEXT *new;
2435 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2436 *ret = &new->text;
2437 return S_OK;
2439 case WS_XML_TEXT_TYPE_DATETIME:
2441 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2442 WS_XML_DATETIME_TEXT *new;
2444 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2445 *ret = &new->text;
2446 return S_OK;
2448 default:
2449 FIXME( "unhandled text type %u\n", text->textType );
2450 return E_NOTIMPL;
2454 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2456 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2457 HRESULT hr;
2459 switch (value->textType)
2461 case WS_XML_TEXT_TYPE_UTF8:
2462 case WS_XML_TEXT_TYPE_UTF16:
2463 case WS_XML_TEXT_TYPE_BASE64:
2464 break;
2466 case WS_XML_TEXT_TYPE_BOOL:
2467 case WS_XML_TEXT_TYPE_INT32:
2468 case WS_XML_TEXT_TYPE_INT64:
2469 case WS_XML_TEXT_TYPE_UINT64:
2470 case WS_XML_TEXT_TYPE_DOUBLE:
2471 case WS_XML_TEXT_TYPE_GUID:
2472 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2473 case WS_XML_TEXT_TYPE_DATETIME:
2474 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2475 break;
2477 default:
2478 FIXME( "unhandled text type %u\n", value->textType );
2479 return E_NOTIMPL;
2482 switch (writer->output_enc)
2484 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2486 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2487 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2488 heap_free( old );
2489 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2490 break;
2492 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2494 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2495 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2496 heap_free( old );
2497 elem->attributes[elem->attributeCount - 1]->value = new;
2498 break;
2500 default:
2501 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2502 return E_NOTIMPL;
2505 return S_OK;
2508 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2510 struct node *node;
2511 WS_XML_TEXT_NODE *text;
2512 HRESULT hr;
2514 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2515 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2516 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2518 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2519 text = (WS_XML_TEXT_NODE *)node;
2521 switch (writer->output_enc)
2523 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2525 WS_XML_UTF8_TEXT *new;
2526 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2528 heap_free( node );
2529 return hr;
2531 text->text = &new->text;
2532 break;
2534 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2536 WS_XML_TEXT *new;
2537 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2539 heap_free( node );
2540 return hr;
2542 text->text = new;
2543 break;
2545 default:
2546 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2547 heap_free( node );
2548 return E_NOTIMPL;
2551 write_insert_node( writer, writer->current, node );
2552 return S_OK;
2555 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2557 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2558 HRESULT hr;
2560 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2562 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2563 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2565 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2567 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2568 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2569 return S_OK;
2572 return WS_E_INVALID_FORMAT;
2575 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
2577 switch (text->textType)
2579 case WS_XML_TEXT_TYPE_UTF8:
2581 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2582 if (use_dict) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT;
2583 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2584 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2585 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2587 case WS_XML_TEXT_TYPE_UTF16:
2589 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
2590 int len = text_utf16->byteCount / sizeof(WCHAR);
2591 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
2592 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2593 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2594 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2596 case WS_XML_TEXT_TYPE_BASE64:
2598 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2599 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2600 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2601 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2602 return RECORD_BYTES32_TEXT;
2604 case WS_XML_TEXT_TYPE_BOOL:
2606 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2607 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2609 case WS_XML_TEXT_TYPE_INT32:
2611 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2612 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2613 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2614 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2615 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2616 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2618 case WS_XML_TEXT_TYPE_INT64:
2620 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2621 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2622 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2623 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2624 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2625 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2626 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2628 case WS_XML_TEXT_TYPE_UINT64:
2630 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2631 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2632 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2633 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2634 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2635 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2636 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2637 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2639 case WS_XML_TEXT_TYPE_DOUBLE:
2641 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2642 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2643 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2644 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2645 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2646 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2647 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2648 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2649 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2651 case WS_XML_TEXT_TYPE_GUID:
2652 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2654 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2655 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2657 case WS_XML_TEXT_TYPE_DATETIME:
2658 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2660 default:
2661 FIXME( "unhandled text type %u\n", text->textType );
2662 return 0;
2666 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2668 enum record_type type;
2669 BOOL use_dict = FALSE;
2670 HRESULT hr;
2671 ULONG id;
2673 if (offset)
2675 FIXME( "no support for appending text in binary mode\n" );
2676 return E_NOTIMPL;
2679 if (text->textType == WS_XML_TEXT_TYPE_UTF8)
2681 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2682 use_dict = get_string_id( writer, &utf8->value, &id );
2685 switch ((type = get_text_record_type( text, use_dict )))
2687 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2689 const WS_XML_UTF8_TEXT *text_utf8;
2690 WS_XML_UTF8_TEXT *new = NULL;
2691 UINT8 len;
2693 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2694 else
2696 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2697 text_utf8 = new;
2699 len = text_utf8->value.length;
2700 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2702 heap_free( new );
2703 return hr;
2705 write_char( writer, type );
2706 write_char( writer, len );
2707 write_bytes( writer, text_utf8->value.bytes, len );
2708 heap_free( new );
2709 return S_OK;
2711 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2713 const WS_XML_UTF8_TEXT *text_utf8;
2714 WS_XML_UTF8_TEXT *new = NULL;
2715 UINT16 len;
2717 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2718 else
2720 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2721 text_utf8 = new;
2723 len = text_utf8->value.length;
2724 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2726 heap_free( new );
2727 return hr;
2729 write_char( writer, type );
2730 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2731 write_bytes( writer, text_utf8->value.bytes, len );
2732 heap_free( new );
2733 return S_OK;
2735 case RECORD_BYTES8_TEXT:
2737 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2738 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2740 if (len)
2742 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2743 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2744 write_char( writer, len );
2745 write_bytes( writer, text_base64->bytes, len );
2747 if (rem)
2749 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2750 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2751 write_char( writer, rem );
2752 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2754 return S_OK;
2756 case RECORD_BYTES16_TEXT:
2758 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2759 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2761 if (len)
2763 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2764 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2765 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2766 write_bytes( writer, text_base64->bytes, len );
2768 if (rem)
2770 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2771 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2772 write_char( writer, rem );
2773 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2775 return S_OK;
2777 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2778 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2779 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2780 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2782 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2783 write_char( writer, type );
2784 return S_OK;
2786 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2788 INT8 val = get_text_value_int( text );
2789 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2790 write_char( writer, type );
2791 write_char( writer, val );
2792 return S_OK;
2794 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2796 INT16 val = get_text_value_int( text );
2797 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2798 write_char( writer, type );
2799 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2800 return S_OK;
2802 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2804 INT32 val = get_text_value_int( text );
2805 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2806 write_char( writer, type );
2807 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2808 return S_OK;
2810 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2812 INT64 val = get_text_value_int( text );
2813 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2814 write_char( writer, type );
2815 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2816 return S_OK;
2818 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2820 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2821 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2822 write_char( writer, type );
2823 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2824 return S_OK;
2826 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2828 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2829 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2830 write_char( writer, type );
2831 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2832 return S_OK;
2834 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2836 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2837 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2838 write_char( writer, type );
2839 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2840 return S_OK;
2842 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2844 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2845 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2846 write_char( writer, type );
2847 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2848 return S_OK;
2850 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2852 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2853 UINT64 val = text_datetime->value.ticks;
2855 assert( val <= TICKS_MAX );
2856 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2857 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2859 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2860 write_char( writer, type );
2861 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2862 return S_OK;
2864 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
2866 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2867 write_char( writer, type );
2868 return write_dict_string( writer, id );
2870 default:
2871 FIXME( "unhandled record type %02x\n", type );
2872 return E_NOTIMPL;
2876 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2878 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2880 switch (writer->output_enc)
2882 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2883 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2884 default:
2885 ERR( "unhandled encoding %u\n", writer->output_enc );
2886 return WS_E_NOT_SUPPORTED;
2890 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2892 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2893 ULONG offset = 0;
2894 HRESULT hr;
2896 if ((hr = write_commit( writer )) != S_OK) return hr;
2897 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2899 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2900 node = (WS_XML_TEXT_NODE *)writer->current;
2902 else
2904 switch (writer->output_enc)
2906 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2908 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2909 offset = old->value.length;
2910 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2911 heap_free( old );
2912 node->text = &new->text;
2913 break;
2915 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2917 WS_XML_TEXT *new, *old = node->text;
2918 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2919 heap_free( old );
2920 node->text = new;
2921 break;
2923 default:
2924 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2925 return E_NOTIMPL;
2929 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2931 writer->state = WRITER_STATE_TEXT;
2932 return S_OK;
2935 /**************************************************************************
2936 * WsWriteText [webservices.@]
2938 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2940 struct writer *writer = (struct writer *)handle;
2941 HRESULT hr;
2943 TRACE( "%p %p %p\n", handle, text, error );
2944 if (error) FIXME( "ignoring error parameter\n" );
2946 if (!writer || !text) return E_INVALIDARG;
2948 EnterCriticalSection( &writer->cs );
2950 if (writer->magic != WRITER_MAGIC)
2952 LeaveCriticalSection( &writer->cs );
2953 return E_INVALIDARG;
2956 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2957 else hr = write_text_node( writer, text );
2959 LeaveCriticalSection( &writer->cs );
2960 TRACE( "returning %08x\n", hr );
2961 return hr;
2964 /**************************************************************************
2965 * WsWriteBytes [webservices.@]
2967 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2969 struct writer *writer = (struct writer *)handle;
2970 WS_XML_BASE64_TEXT base64;
2971 HRESULT hr;
2973 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2974 if (error) FIXME( "ignoring error parameter\n" );
2976 if (!writer) return E_INVALIDARG;
2978 EnterCriticalSection( &writer->cs );
2980 if (writer->magic != WRITER_MAGIC)
2982 LeaveCriticalSection( &writer->cs );
2983 return E_INVALIDARG;
2986 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
2987 else
2989 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2990 base64.bytes = (BYTE *)bytes;
2991 base64.length = count;
2993 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2994 else hr = write_text_node( writer, &base64.text );
2997 LeaveCriticalSection( &writer->cs );
2998 TRACE( "returning %08x\n", hr );
2999 return hr;
3002 /**************************************************************************
3003 * WsWriteChars [webservices.@]
3005 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
3007 struct writer *writer = (struct writer *)handle;
3008 WS_XML_UTF16_TEXT utf16;
3009 HRESULT hr;
3011 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
3012 if (error) FIXME( "ignoring error parameter\n" );
3014 if (!writer) return E_INVALIDARG;
3016 EnterCriticalSection( &writer->cs );
3018 if (writer->magic != WRITER_MAGIC)
3020 LeaveCriticalSection( &writer->cs );
3021 return E_INVALIDARG;
3024 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3025 else
3027 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3028 utf16.bytes = (BYTE *)chars;
3029 utf16.byteCount = count * sizeof(WCHAR);
3031 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
3032 else hr = write_text_node( writer, &utf16.text );
3035 LeaveCriticalSection( &writer->cs );
3036 TRACE( "returning %08x\n", hr );
3037 return hr;
3040 /**************************************************************************
3041 * WsWriteCharsUtf8 [webservices.@]
3043 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
3045 struct writer *writer = (struct writer *)handle;
3046 WS_XML_UTF8_TEXT utf8;
3047 HRESULT hr;
3049 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
3050 if (error) FIXME( "ignoring error parameter\n" );
3052 if (!writer) return E_INVALIDARG;
3054 EnterCriticalSection( &writer->cs );
3056 if (writer->magic != WRITER_MAGIC)
3058 LeaveCriticalSection( &writer->cs );
3059 return E_INVALIDARG;
3062 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3063 else
3065 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3066 utf8.value.bytes = (BYTE *)bytes;
3067 utf8.value.length = count;
3069 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
3070 else hr = write_text_node( writer, &utf8.text );
3073 LeaveCriticalSection( &writer->cs );
3074 TRACE( "returning %08x\n", hr );
3075 return hr;
3078 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
3080 switch (mapping)
3082 case WS_ELEMENT_TYPE_MAPPING:
3083 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3084 return write_text_node( writer, text );
3086 case WS_ATTRIBUTE_TYPE_MAPPING:
3087 return write_set_attribute_value( writer, text );
3089 case WS_ANY_ELEMENT_TYPE_MAPPING:
3090 switch (writer->state)
3092 case WRITER_STATE_STARTATTRIBUTE:
3093 return write_set_attribute_value( writer, text );
3095 case WRITER_STATE_STARTELEMENT:
3096 return write_text_node( writer, text );
3098 default:
3099 FIXME( "writer state %u not handled\n", writer->state );
3100 return E_NOTIMPL;
3103 default:
3104 FIXME( "mapping %u not implemented\n", mapping );
3105 return E_NOTIMPL;
3109 static HRESULT write_add_nil_attribute( struct writer *writer )
3111 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
3112 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
3113 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
3114 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
3115 HRESULT hr;
3117 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
3118 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
3119 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
3122 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
3123 const void **ptr )
3125 switch (option)
3127 case WS_WRITE_REQUIRED_VALUE:
3128 case WS_WRITE_NILLABLE_VALUE:
3129 if (!value || size != expected_size) return E_INVALIDARG;
3130 *ptr = value;
3131 return S_OK;
3133 case WS_WRITE_REQUIRED_POINTER:
3134 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
3135 return S_OK;
3137 case WS_WRITE_NILLABLE_POINTER:
3138 if (size != sizeof(const void *)) return E_INVALIDARG;
3139 *ptr = *(const void **)value;
3140 return S_OK;
3142 default:
3143 return E_INVALIDARG;
3147 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
3148 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
3149 const BOOL *value, ULONG size )
3151 WS_XML_BOOL_TEXT text_bool;
3152 const BOOL *ptr;
3153 HRESULT hr;
3155 if (desc)
3157 FIXME( "description not supported\n" );
3158 return E_NOTIMPL;
3161 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3162 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
3163 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3165 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
3166 text_bool.value = *ptr;
3167 return write_type_text( writer, mapping, &text_bool.text );
3170 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3171 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3172 const BOOL *value, ULONG size )
3174 WS_XML_INT32_TEXT text_int32;
3175 const INT8 *ptr;
3176 HRESULT hr;
3178 if (desc)
3180 FIXME( "description not supported\n" );
3181 return E_NOTIMPL;
3184 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3185 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3186 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3188 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3189 text_int32.value = *ptr;
3190 return write_type_text( writer, mapping, &text_int32.text );
3193 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3194 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3195 const BOOL *value, ULONG size )
3197 WS_XML_INT32_TEXT text_int32;
3198 const INT16 *ptr;
3199 HRESULT hr;
3201 if (desc)
3203 FIXME( "description not supported\n" );
3204 return E_NOTIMPL;
3207 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3208 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3209 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3211 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3212 text_int32.value = *ptr;
3213 return write_type_text( writer, mapping, &text_int32.text );
3216 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3217 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3218 const void *value, ULONG size )
3220 WS_XML_INT32_TEXT text_int32;
3221 const INT32 *ptr;
3222 HRESULT hr;
3224 if (desc)
3226 FIXME( "description not supported\n" );
3227 return E_NOTIMPL;
3230 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3231 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3232 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3234 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3235 text_int32.value = *ptr;
3236 return write_type_text( writer, mapping, &text_int32.text );
3239 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3240 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3241 const void *value, ULONG size )
3243 WS_XML_INT64_TEXT text_int64;
3244 const INT64 *ptr;
3245 HRESULT hr;
3247 if (desc)
3249 FIXME( "description not supported\n" );
3250 return E_NOTIMPL;
3253 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3254 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3255 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3257 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3258 text_int64.value = *ptr;
3259 return write_type_text( writer, mapping, &text_int64.text );
3262 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3263 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3264 const void *value, ULONG size )
3266 WS_XML_UINT64_TEXT text_uint64;
3267 const UINT8 *ptr;
3268 HRESULT hr;
3270 if (desc)
3272 FIXME( "description not supported\n" );
3273 return E_NOTIMPL;
3276 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3277 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3278 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3280 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3281 text_uint64.value = *ptr;
3282 return write_type_text( writer, mapping, &text_uint64.text );
3285 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3286 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3287 const void *value, ULONG size )
3289 WS_XML_UINT64_TEXT text_uint64;
3290 const UINT16 *ptr;
3291 HRESULT hr;
3293 if (desc)
3295 FIXME( "description not supported\n" );
3296 return E_NOTIMPL;
3299 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3300 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3301 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3303 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3304 text_uint64.value = *ptr;
3305 return write_type_text( writer, mapping, &text_uint64.text );
3308 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3309 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3310 const void *value, ULONG size )
3312 WS_XML_UINT64_TEXT text_uint64;
3313 const UINT32 *ptr;
3314 HRESULT hr;
3316 if (desc)
3318 FIXME( "description not supported\n" );
3319 return E_NOTIMPL;
3322 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3323 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3324 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3326 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3327 text_uint64.value = *ptr;
3328 return write_type_text( writer, mapping, &text_uint64.text );
3331 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3332 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3333 const void *value, ULONG size )
3335 WS_XML_UINT64_TEXT text_uint64;
3336 const UINT64 *ptr;
3337 HRESULT hr;
3339 if (desc)
3341 FIXME( "description not supported\n" );
3342 return E_NOTIMPL;
3345 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3346 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3347 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3349 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3350 text_uint64.value = *ptr;
3351 return write_type_text( writer, mapping, &text_uint64.text );
3354 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3355 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3356 const void *value, ULONG size )
3358 WS_XML_DOUBLE_TEXT text_double;
3359 const double *ptr;
3360 HRESULT hr;
3362 if (desc)
3364 FIXME( "description not supported\n" );
3365 return E_NOTIMPL;
3368 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3369 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3370 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3372 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3373 text_double.value = *ptr;
3374 return write_type_text( writer, mapping, &text_double.text );
3377 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3378 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3379 const void *value, ULONG size )
3381 WS_XML_DATETIME_TEXT text_datetime;
3382 const WS_DATETIME *ptr;
3383 HRESULT hr;
3385 if (desc)
3387 FIXME( "description not supported\n" );
3388 return E_NOTIMPL;
3391 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3392 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3393 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3394 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3396 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3397 text_datetime.value = *ptr;
3398 return write_type_text( writer, mapping, &text_datetime.text );
3401 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3402 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3403 const void *value, ULONG size )
3405 WS_XML_GUID_TEXT text_guid;
3406 const GUID *ptr;
3407 HRESULT hr;
3409 if (desc)
3411 FIXME( "description not supported\n" );
3412 return E_NOTIMPL;
3415 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3416 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3417 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3419 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3420 text_guid.value = *ptr;
3421 return write_type_text( writer, mapping, &text_guid.text );
3424 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3425 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3426 const void *value, ULONG size )
3428 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3429 WS_XML_UTF16_TEXT text_utf16;
3430 const WS_UNIQUE_ID *ptr;
3431 HRESULT hr;
3433 if (desc)
3435 FIXME( "description not supported\n" );
3436 return E_NOTIMPL;
3439 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3440 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3441 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3443 if (ptr->uri.length)
3445 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3446 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3447 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3448 return write_type_text( writer, mapping, &text_utf16.text );
3451 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3452 text_unique_id.value = ptr->guid;
3453 return write_type_text( writer, mapping, &text_unique_id.text );
3456 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3457 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3458 const void *value, ULONG size )
3460 WS_XML_UTF16_TEXT utf16;
3461 const WS_STRING *ptr;
3462 HRESULT hr;
3464 if (desc)
3466 FIXME( "description not supported\n" );
3467 return E_NOTIMPL;
3470 if (!option) return E_INVALIDARG;
3471 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3472 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3473 if (!ptr->length) return S_OK;
3475 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3476 utf16.bytes = (BYTE *)ptr->chars;
3477 utf16.byteCount = ptr->length * sizeof(WCHAR);
3478 return write_type_text( writer, mapping, &utf16.text );
3481 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3482 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3483 const void *value, ULONG size )
3485 WS_XML_UTF16_TEXT utf16;
3486 const WCHAR *ptr;
3487 HRESULT hr;
3488 int len;
3490 if (desc)
3492 FIXME( "description not supported\n" );
3493 return E_NOTIMPL;
3496 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3497 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3498 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3499 if (!(len = lstrlenW( ptr ))) return S_OK;
3501 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3502 utf16.bytes = (BYTE *)ptr;
3503 utf16.byteCount = len * sizeof(WCHAR);
3504 return write_type_text( writer, mapping, &utf16.text );
3507 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3508 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3509 const void *value, ULONG size )
3511 WS_XML_BASE64_TEXT base64;
3512 const WS_BYTES *ptr;
3513 HRESULT hr;
3515 if (desc)
3517 FIXME( "description not supported\n" );
3518 return E_NOTIMPL;
3521 if (!option) return E_INVALIDARG;
3522 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3523 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3524 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3525 if (!ptr->length) return S_OK;
3527 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3528 base64.bytes = ptr->bytes;
3529 base64.length = ptr->length;
3530 return write_type_text( writer, mapping, &base64.text );
3533 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3534 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3535 const void *value, ULONG size )
3537 WS_XML_UTF8_TEXT utf8;
3538 const WS_XML_STRING *ptr;
3539 HRESULT hr;
3541 if (desc)
3543 FIXME( "description not supported\n" );
3544 return E_NOTIMPL;
3547 if (!option) return E_INVALIDARG;
3548 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3549 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3550 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3551 if (!ptr->length) return S_OK;
3553 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3554 utf8.value.bytes = ptr->bytes;
3555 utf8.value.length = ptr->length;
3556 return write_type_text( writer, mapping, &utf8.text );
3559 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3561 const struct node *node;
3562 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3564 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3565 ULONG i;
3566 for (i = 0; i < elem->attributeCount; i++)
3568 if (!elem->attributes[i]->isXmlNs) continue;
3569 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3570 *prefix = elem->attributes[i]->prefix;
3571 return S_OK;
3574 return WS_E_INVALID_FORMAT;
3577 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3578 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3579 const void *value, ULONG size )
3581 WS_XML_QNAME_TEXT qname;
3582 const WS_XML_QNAME *ptr;
3583 const WS_XML_STRING *prefix;
3584 HRESULT hr;
3586 if (desc)
3588 FIXME( "description not supported\n" );
3589 return E_NOTIMPL;
3592 if (!option) return E_INVALIDARG;
3593 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3594 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3595 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3597 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3599 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3600 qname.prefix = (WS_XML_STRING *)prefix;
3601 qname.localName = (WS_XML_STRING *)&ptr->localName;
3602 qname.ns = (WS_XML_STRING *)&ptr->ns;
3603 return write_type_text( writer, mapping, &qname.text );
3606 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3608 if (options & WS_FIELD_POINTER)
3610 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM)) return WS_WRITE_NILLABLE_POINTER;
3611 return WS_WRITE_REQUIRED_POINTER;
3614 switch (type)
3616 case WS_BOOL_TYPE:
3617 case WS_INT8_TYPE:
3618 case WS_INT16_TYPE:
3619 case WS_INT32_TYPE:
3620 case WS_INT64_TYPE:
3621 case WS_UINT8_TYPE:
3622 case WS_UINT16_TYPE:
3623 case WS_UINT32_TYPE:
3624 case WS_UINT64_TYPE:
3625 case WS_DOUBLE_TYPE:
3626 case WS_DATETIME_TYPE:
3627 case WS_GUID_TYPE:
3628 case WS_UNIQUE_ID_TYPE:
3629 case WS_STRING_TYPE:
3630 case WS_BYTES_TYPE:
3631 case WS_XML_STRING_TYPE:
3632 case WS_XML_QNAME_TYPE:
3633 case WS_STRUCT_TYPE:
3634 case WS_ENUM_TYPE:
3635 case WS_UNION_TYPE:
3636 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3637 return WS_WRITE_REQUIRED_VALUE;
3639 case WS_WSZ_TYPE:
3640 case WS_DESCRIPTION_TYPE:
3641 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3642 return WS_WRITE_REQUIRED_POINTER;
3644 default:
3645 FIXME( "unhandled type %u\n", type );
3646 return 0;
3650 static HRESULT find_index( const WS_UNION_DESCRIPTION *desc, int value, ULONG *idx )
3652 ULONG i;
3654 if (desc->valueIndices)
3656 int c, min = 0, max = desc->fieldCount - 1;
3657 while (min <= max)
3659 i = (min + max) / 2;
3660 c = value - desc->fields[desc->valueIndices[i]]->value;
3661 if (c < 0)
3662 max = i - 1;
3663 else if (c > 0)
3664 min = i + 1;
3665 else
3667 *idx = desc->valueIndices[i];
3668 return S_OK;
3671 return WS_E_INVALID_FORMAT;
3674 /* fall back to linear search */
3675 for (i = 0; i < desc->fieldCount; i++)
3677 if (desc->fields[i]->value == value)
3679 *idx = i;
3680 return S_OK;
3683 return WS_E_INVALID_FORMAT;
3686 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3688 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3689 const void *value, ULONG size )
3691 ULONG i;
3692 const void *ptr;
3693 int enum_value;
3694 HRESULT hr;
3696 if (size < sizeof(enum_value)) return E_INVALIDARG;
3697 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3699 enum_value = *(int *)(char *)ptr + desc->enumOffset;
3700 if (enum_value == desc->noneEnumValue && option == WS_WRITE_NILLABLE_VALUE) return S_OK;
3702 if ((hr = find_index( desc, enum_value, &i )) != S_OK) return hr;
3703 return write_type_field( writer, &desc->fields[i]->field, ptr, desc->fields[i]->field.offset );
3706 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3707 const void *, ULONG );
3709 static HRESULT write_type_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3710 ULONG count )
3712 HRESULT hr = S_OK;
3713 ULONG i, size, offset = 0;
3714 WS_WRITE_OPTION option;
3716 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3718 /* wrapper element */
3719 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3720 return hr;
3722 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3723 size = get_type_size( desc->type, desc->typeDescription );
3724 else
3725 size = sizeof(const void *);
3727 for (i = 0; i < count; i++)
3729 if (desc->type == WS_UNION_TYPE)
3731 if ((hr = write_type_union( writer, desc->typeDescription, option, buf + offset, size )) != S_OK)
3732 return hr;
3734 else
3736 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3737 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3738 buf + offset, size )) != S_OK) return hr;
3739 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3741 offset += size;
3744 if (desc->localName) hr = write_endelement_node( writer );
3745 return hr;
3748 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3749 ULONG offset )
3751 HRESULT hr;
3752 WS_TYPE_MAPPING mapping;
3753 WS_WRITE_OPTION option;
3754 ULONG count, size, field_options = desc->options;
3755 const char *ptr = buf + offset;
3757 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3759 FIXME( "options 0x%x not supported\n", desc->options );
3760 return E_NOTIMPL;
3763 /* zero-terminated strings and descriptions are always pointers */
3764 if (desc->type == WS_WSZ_TYPE || desc->type == WS_DESCRIPTION_TYPE) field_options |= WS_FIELD_POINTER;
3766 if (field_options & WS_FIELD_POINTER)
3767 size = sizeof(const void *);
3768 else
3769 size = get_type_size( desc->type, desc->typeDescription );
3771 if (is_nil_value( ptr, size ))
3773 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3774 if (field_options & (WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3776 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3777 else option = WS_WRITE_NILLABLE_VALUE;
3779 else
3781 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3782 else option = WS_WRITE_REQUIRED_VALUE;
3785 else
3787 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3788 else option = WS_WRITE_REQUIRED_VALUE;
3791 switch (desc->mapping)
3793 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
3794 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3795 break;
3797 case WS_ATTRIBUTE_FIELD_MAPPING:
3798 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3799 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3800 return hr;
3801 writer->state = WRITER_STATE_STARTATTRIBUTE;
3803 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3804 break;
3806 case WS_ELEMENT_FIELD_MAPPING:
3807 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3808 mapping = WS_ELEMENT_TYPE_MAPPING;
3809 break;
3811 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3812 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3813 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3814 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3816 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3817 case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING:
3818 count = *(const ULONG *)(buf + desc->countOffset);
3819 return write_type_array( writer, desc, *(const char **)ptr, count );
3821 case WS_TEXT_FIELD_MAPPING:
3822 switch (writer->state)
3824 case WRITER_STATE_STARTELEMENT:
3825 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3826 break;
3828 case WRITER_STATE_STARTATTRIBUTE:
3829 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3830 break;
3832 default:
3833 FIXME( "unhandled writer state %u\n", writer->state );
3834 return E_NOTIMPL;
3836 break;
3838 case WS_ANY_ATTRIBUTES_FIELD_MAPPING:
3839 return S_OK;
3841 default:
3842 FIXME( "field mapping %u not supported\n", desc->mapping );
3843 return E_NOTIMPL;
3846 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3847 return hr;
3849 switch (mapping)
3851 case WS_ATTRIBUTE_TYPE_MAPPING:
3852 writer->state = WRITER_STATE_STARTELEMENT;
3853 break;
3855 case WS_ELEMENT_TYPE_MAPPING:
3856 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3857 break;
3859 default: break;
3862 return S_OK;
3865 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3866 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3867 const void *value, ULONG size )
3869 ULONG i, offset;
3870 const void *ptr;
3871 HRESULT hr;
3873 if (!desc) return E_INVALIDARG;
3874 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3876 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3877 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3879 for (i = 0; i < desc->fieldCount; i++)
3881 offset = desc->fields[i]->offset;
3882 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3885 return S_OK;
3888 static const WS_XML_STRING *get_enum_value_name( const WS_ENUM_DESCRIPTION *desc, int value )
3890 ULONG i;
3891 for (i = 0; i < desc->valueCount; i++)
3893 if (desc->values[i].value == value) return desc->values[i].name;
3895 return NULL;
3898 static HRESULT write_type_enum( struct writer *writer, WS_TYPE_MAPPING mapping,
3899 const WS_ENUM_DESCRIPTION *desc, WS_WRITE_OPTION option,
3900 const void *value, ULONG size )
3902 const WS_XML_STRING *name;
3903 WS_XML_UTF8_TEXT utf8;
3904 const int *ptr;
3905 HRESULT hr;
3907 if (!desc) return E_INVALIDARG;
3908 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3909 if (!(name = get_enum_value_name( desc, *ptr ))) return E_INVALIDARG;
3911 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3912 utf8.value.bytes = name->bytes;
3913 utf8.value.length = name->length;
3914 return write_type_text( writer, mapping, &utf8.text );
3917 static HRESULT write_type_description( struct writer *writer, WS_TYPE_MAPPING mapping,
3918 WS_WRITE_OPTION option, const void *value, ULONG size )
3920 const WS_STRUCT_DESCRIPTION *ptr;
3921 HRESULT hr;
3923 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3924 if (ptr) FIXME( "ignoring type description %p\n", ptr );
3925 return S_OK;
3928 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3929 const void *desc, WS_WRITE_OPTION option, const void *value,
3930 ULONG size )
3932 switch (type)
3934 case WS_BOOL_TYPE:
3935 return write_type_bool( writer, mapping, desc, option, value, size );
3937 case WS_INT8_TYPE:
3938 return write_type_int8( writer, mapping, desc, option, value, size );
3940 case WS_INT16_TYPE:
3941 return write_type_int16( writer, mapping, desc, option, value, size );
3943 case WS_INT32_TYPE:
3944 return write_type_int32( writer, mapping, desc, option, value, size );
3946 case WS_INT64_TYPE:
3947 return write_type_int64( writer, mapping, desc, option, value, size );
3949 case WS_UINT8_TYPE:
3950 return write_type_uint8( writer, mapping, desc, option, value, size );
3952 case WS_UINT16_TYPE:
3953 return write_type_uint16( writer, mapping, desc, option, value, size );
3955 case WS_UINT32_TYPE:
3956 return write_type_uint32( writer, mapping, desc, option, value, size );
3958 case WS_UINT64_TYPE:
3959 return write_type_uint64( writer, mapping, desc, option, value, size );
3961 case WS_DOUBLE_TYPE:
3962 return write_type_double( writer, mapping, desc, option, value, size );
3964 case WS_DATETIME_TYPE:
3965 return write_type_datetime( writer, mapping, desc, option, value, size );
3967 case WS_GUID_TYPE:
3968 return write_type_guid( writer, mapping, desc, option, value, size );
3970 case WS_UNIQUE_ID_TYPE:
3971 return write_type_unique_id( writer, mapping, desc, option, value, size );
3973 case WS_STRING_TYPE:
3974 return write_type_string( writer, mapping, desc, option, value, size );
3976 case WS_WSZ_TYPE:
3977 return write_type_wsz( writer, mapping, desc, option, value, size );
3979 case WS_BYTES_TYPE:
3980 return write_type_bytes( writer, mapping, desc, option, value, size );
3982 case WS_XML_STRING_TYPE:
3983 return write_type_xml_string( writer, mapping, desc, option, value, size );
3985 case WS_XML_QNAME_TYPE:
3986 return write_type_qname( writer, mapping, desc, option, value, size );
3988 case WS_DESCRIPTION_TYPE:
3989 return write_type_description( writer, mapping, option, value, size );
3991 case WS_STRUCT_TYPE:
3992 return write_type_struct( writer, mapping, desc, option, value, size );
3994 case WS_ENUM_TYPE:
3995 return write_type_enum( writer, mapping, desc, option, value, size );
3997 default:
3998 FIXME( "type %u not supported\n", type );
3999 return E_NOTIMPL;
4003 /**************************************************************************
4004 * WsWriteAttribute [webservices.@]
4006 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
4007 WS_WRITE_OPTION option, const void *value, ULONG size,
4008 WS_ERROR *error )
4010 struct writer *writer = (struct writer *)handle;
4011 HRESULT hr;
4013 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
4014 if (error) FIXME( "ignoring error parameter\n" );
4016 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
4017 return E_INVALIDARG;
4019 EnterCriticalSection( &writer->cs );
4021 if (writer->magic != WRITER_MAGIC)
4023 LeaveCriticalSection( &writer->cs );
4024 return E_INVALIDARG;
4027 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
4028 else if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) == S_OK)
4030 writer->state = WRITER_STATE_STARTATTRIBUTE;
4031 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
4034 LeaveCriticalSection( &writer->cs );
4035 TRACE( "returning %08x\n", hr );
4036 return hr;
4039 /**************************************************************************
4040 * WsWriteElement [webservices.@]
4042 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4043 WS_WRITE_OPTION option, const void *value, ULONG size,
4044 WS_ERROR *error )
4046 struct writer *writer = (struct writer *)handle;
4047 HRESULT hr;
4049 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
4050 if (error) FIXME( "ignoring error parameter\n" );
4052 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
4053 return E_INVALIDARG;
4055 EnterCriticalSection( &writer->cs );
4057 if (writer->magic != WRITER_MAGIC)
4059 LeaveCriticalSection( &writer->cs );
4060 return E_INVALIDARG;
4063 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4065 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
4066 option, value, size )) != S_OK) goto done;
4068 hr = write_endelement_node( writer );
4070 done:
4071 LeaveCriticalSection( &writer->cs );
4072 TRACE( "returning %08x\n", hr );
4073 return hr;
4076 /**************************************************************************
4077 * WsWriteType [webservices.@]
4079 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4080 const void *desc, WS_WRITE_OPTION option, const void *value,
4081 ULONG size, WS_ERROR *error )
4083 struct writer *writer = (struct writer *)handle;
4084 HRESULT hr;
4086 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
4087 size, error );
4088 if (error) FIXME( "ignoring error parameter\n" );
4090 if (!writer || !value) return E_INVALIDARG;
4092 EnterCriticalSection( &writer->cs );
4094 if (writer->magic != WRITER_MAGIC)
4096 LeaveCriticalSection( &writer->cs );
4097 return E_INVALIDARG;
4100 switch (mapping)
4102 case WS_ATTRIBUTE_TYPE_MAPPING:
4103 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
4104 else hr = write_type( writer, mapping, type, desc, option, value, size );
4105 break;
4107 case WS_ELEMENT_TYPE_MAPPING:
4108 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4109 case WS_ANY_ELEMENT_TYPE_MAPPING:
4110 hr = write_type( writer, mapping, type, desc, option, value, size );
4111 break;
4113 default:
4114 FIXME( "mapping %u not implemented\n", mapping );
4115 hr = E_NOTIMPL;
4118 LeaveCriticalSection( &writer->cs );
4119 TRACE( "returning %08x\n", hr );
4120 return hr;
4123 WS_TYPE map_value_type( WS_VALUE_TYPE type )
4125 switch (type)
4127 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
4128 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
4129 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
4130 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
4131 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
4132 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
4133 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
4134 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
4135 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
4136 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
4137 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
4138 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
4139 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
4140 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
4141 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
4142 default:
4143 FIXME( "unhandled type %u\n", type );
4144 return ~0u;
4148 /**************************************************************************
4149 * WsWriteValue [webservices.@]
4151 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
4152 ULONG size, WS_ERROR *error )
4154 struct writer *writer = (struct writer *)handle;
4155 WS_TYPE_MAPPING mapping;
4156 HRESULT hr = S_OK;
4157 WS_TYPE type;
4159 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
4160 if (error) FIXME( "ignoring error parameter\n" );
4162 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
4164 EnterCriticalSection( &writer->cs );
4166 if (writer->magic != WRITER_MAGIC)
4168 LeaveCriticalSection( &writer->cs );
4169 return E_INVALIDARG;
4172 switch (writer->state)
4174 case WRITER_STATE_STARTATTRIBUTE:
4175 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
4176 break;
4178 case WRITER_STATE_STARTELEMENT:
4179 mapping = WS_ELEMENT_TYPE_MAPPING;
4180 break;
4182 default:
4183 hr = WS_E_INVALID_FORMAT;
4186 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
4188 LeaveCriticalSection( &writer->cs );
4189 TRACE( "returning %08x\n", hr );
4190 return hr;
4193 /**************************************************************************
4194 * WsWriteArray [webservices.@]
4196 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4197 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
4198 ULONG count, WS_ERROR *error )
4200 struct writer *writer = (struct writer *)handle;
4201 WS_TYPE type;
4202 ULONG type_size, i;
4203 HRESULT hr = S_OK;
4205 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
4206 value_type, array, size, offset, count, error );
4207 if (error) FIXME( "ignoring error parameter\n" );
4209 if (!writer) return E_INVALIDARG;
4211 EnterCriticalSection( &writer->cs );
4213 if (writer->magic != WRITER_MAGIC)
4215 LeaveCriticalSection( &writer->cs );
4216 return E_INVALIDARG;
4219 if (!writer->output_type)
4221 hr = WS_E_INVALID_OPERATION;
4222 goto done;
4225 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
4227 hr = E_INVALIDARG;
4228 goto done;
4231 type_size = get_type_size( type, NULL );
4232 if (size % type_size || (offset + count) * type_size > size || (count && !array))
4234 hr = E_INVALIDARG;
4235 goto done;
4238 for (i = offset; i < count; i++)
4240 const char *ptr = (const char *)array + (offset + i) * type_size;
4241 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4242 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4243 &ptr, sizeof(ptr) )) != S_OK) goto done;
4244 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4247 done:
4248 LeaveCriticalSection( &writer->cs );
4249 TRACE( "returning %08x\n", hr );
4250 return hr;
4253 /**************************************************************************
4254 * WsWriteXmlBuffer [webservices.@]
4256 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4258 struct writer *writer = (struct writer *)handle;
4259 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4260 HRESULT hr;
4262 TRACE( "%p %p %p\n", handle, buffer, error );
4263 if (error) FIXME( "ignoring error parameter\n" );
4265 if (!writer || !xmlbuf) return E_INVALIDARG;
4267 EnterCriticalSection( &writer->cs );
4269 if (writer->magic != WRITER_MAGIC)
4271 LeaveCriticalSection( &writer->cs );
4272 return E_INVALIDARG;
4275 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4277 FIXME( "no support for different encoding and/or charset\n" );
4278 hr = E_NOTIMPL;
4279 goto done;
4282 if ((hr = write_commit( writer )) != S_OK) goto done;
4283 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4284 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4286 done:
4287 LeaveCriticalSection( &writer->cs );
4288 TRACE( "returning %08x\n", hr );
4289 return hr;
4292 /**************************************************************************
4293 * WsWriteXmlBufferToBytes [webservices.@]
4295 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4296 const WS_XML_WRITER_ENCODING *encoding,
4297 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4298 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4300 struct writer *writer = (struct writer *)handle;
4301 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4302 HRESULT hr = S_OK;
4303 char *buf;
4304 ULONG i;
4306 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4307 bytes, size, error );
4308 if (error) FIXME( "ignoring error parameter\n" );
4310 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4312 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4314 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4315 return E_NOTIMPL;
4318 EnterCriticalSection( &writer->cs );
4320 if (writer->magic != WRITER_MAGIC)
4322 LeaveCriticalSection( &writer->cs );
4323 return E_INVALIDARG;
4326 for (i = 0; i < count; i++)
4328 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4329 properties[i].valueSize );
4330 if (hr != S_OK) goto done;
4333 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4334 else
4336 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4337 *bytes = buf;
4338 *size = xmlbuf->bytes.length;
4341 done:
4342 LeaveCriticalSection( &writer->cs );
4343 TRACE( "returning %08x\n", hr );
4344 return hr;
4347 /**************************************************************************
4348 * WsWriteXmlnsAttribute [webservices.@]
4350 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4351 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4353 struct writer *writer = (struct writer *)handle;
4354 HRESULT hr = S_OK;
4356 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4357 single, error );
4358 if (error) FIXME( "ignoring error parameter\n" );
4360 if (!writer || !ns) return E_INVALIDARG;
4362 EnterCriticalSection( &writer->cs );
4364 if (writer->magic != WRITER_MAGIC)
4366 LeaveCriticalSection( &writer->cs );
4367 return E_INVALIDARG;
4370 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
4371 else if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4372 hr = add_namespace_attribute( writer, prefix, ns, single );
4374 LeaveCriticalSection( &writer->cs );
4375 TRACE( "returning %08x\n", hr );
4376 return hr;
4379 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4380 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4382 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4383 HRESULT hr;
4385 if ((hr = write_commit( writer )) != S_OK) return hr;
4386 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4388 qname.prefix = (WS_XML_STRING *)prefix;
4389 qname.localName = (WS_XML_STRING *)localname;
4390 qname.ns = (WS_XML_STRING *)ns;
4392 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4393 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4396 /**************************************************************************
4397 * WsWriteQualifiedName [webservices.@]
4399 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4400 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4401 WS_ERROR *error )
4403 struct writer *writer = (struct writer *)handle;
4404 HRESULT hr;
4406 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4407 debugstr_xmlstr(ns), error );
4408 if (error) FIXME( "ignoring error parameter\n" );
4410 if (!writer) return E_INVALIDARG;
4412 EnterCriticalSection( &writer->cs );
4414 if (writer->magic != WRITER_MAGIC)
4416 LeaveCriticalSection( &writer->cs );
4417 return E_INVALIDARG;
4420 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4421 else if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
4422 else if (!localname || (!prefix && !ns)) hr = E_INVALIDARG;
4423 else hr = write_qualified_name( writer, prefix, localname, ns );
4425 LeaveCriticalSection( &writer->cs );
4426 TRACE( "returning %08x\n", hr );
4427 return hr;
4430 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4432 BOOL success = FALSE;
4433 struct node *node = writer->current;
4435 switch (move)
4437 case WS_MOVE_TO_ROOT_ELEMENT:
4438 success = move_to_root_element( writer->root, &node );
4439 break;
4441 case WS_MOVE_TO_NEXT_ELEMENT:
4442 success = move_to_next_element( &node );
4443 break;
4445 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4446 success = move_to_prev_element( &node );
4447 break;
4449 case WS_MOVE_TO_CHILD_ELEMENT:
4450 success = move_to_child_element( &node );
4451 break;
4453 case WS_MOVE_TO_END_ELEMENT:
4454 success = move_to_end_element( &node );
4455 break;
4457 case WS_MOVE_TO_PARENT_ELEMENT:
4458 success = move_to_parent_element( &node );
4459 break;
4461 case WS_MOVE_TO_FIRST_NODE:
4462 success = move_to_first_node( &node );
4463 break;
4465 case WS_MOVE_TO_NEXT_NODE:
4466 success = move_to_next_node( &node );
4467 break;
4469 case WS_MOVE_TO_PREVIOUS_NODE:
4470 success = move_to_prev_node( &node );
4471 break;
4473 case WS_MOVE_TO_CHILD_NODE:
4474 success = move_to_child_node( &node );
4475 break;
4477 case WS_MOVE_TO_BOF:
4478 success = move_to_bof( writer->root, &node );
4479 break;
4481 case WS_MOVE_TO_EOF:
4482 success = move_to_eof( writer->root, &node );
4483 break;
4485 default:
4486 FIXME( "unhandled move %u\n", move );
4487 return E_NOTIMPL;
4490 if (success && node == writer->root) return E_INVALIDARG;
4491 writer->current = node;
4493 if (found)
4495 *found = success;
4496 return S_OK;
4498 return success ? S_OK : WS_E_INVALID_FORMAT;
4501 /**************************************************************************
4502 * WsMoveWriter [webservices.@]
4504 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4506 struct writer *writer = (struct writer *)handle;
4507 HRESULT hr;
4509 TRACE( "%p %u %p %p\n", handle, move, found, error );
4510 if (error) FIXME( "ignoring error parameter\n" );
4512 if (!writer) return E_INVALIDARG;
4514 EnterCriticalSection( &writer->cs );
4516 if (writer->magic != WRITER_MAGIC)
4518 LeaveCriticalSection( &writer->cs );
4519 return E_INVALIDARG;
4522 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
4523 else hr = write_move_to( writer, move, found );
4525 LeaveCriticalSection( &writer->cs );
4526 TRACE( "returning %08x\n", hr );
4527 return hr;
4530 /**************************************************************************
4531 * WsGetWriterPosition [webservices.@]
4533 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4535 struct writer *writer = (struct writer *)handle;
4536 HRESULT hr = S_OK;
4538 TRACE( "%p %p %p\n", handle, pos, error );
4539 if (error) FIXME( "ignoring error parameter\n" );
4541 if (!writer || !pos) return E_INVALIDARG;
4543 EnterCriticalSection( &writer->cs );
4545 if (writer->magic != WRITER_MAGIC)
4547 LeaveCriticalSection( &writer->cs );
4548 return E_INVALIDARG;
4551 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4552 else
4554 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4555 pos->node = writer->current;
4558 LeaveCriticalSection( &writer->cs );
4559 TRACE( "returning %08x\n", hr );
4560 return hr;
4563 /**************************************************************************
4564 * WsSetWriterPosition [webservices.@]
4566 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4568 struct writer *writer = (struct writer *)handle;
4569 HRESULT hr = S_OK;
4571 TRACE( "%p %p %p\n", handle, pos, error );
4572 if (error) FIXME( "ignoring error parameter\n" );
4574 if (!writer || !pos) return E_INVALIDARG;
4576 EnterCriticalSection( &writer->cs );
4578 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4580 LeaveCriticalSection( &writer->cs );
4581 return E_INVALIDARG;
4584 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4585 else writer->current = pos->node;
4587 LeaveCriticalSection( &writer->cs );
4588 TRACE( "returning %08x\n", hr );
4589 return hr;
4592 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4594 struct node *node, *parent;
4595 WS_XML_COMMENT_NODE *comment;
4597 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4598 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4599 comment = (WS_XML_COMMENT_NODE *)node;
4601 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4603 free_node( node );
4604 return E_OUTOFMEMORY;
4606 memcpy( comment->value.bytes, value->bytes, value->length );
4607 comment->value.length = value->length;
4609 write_insert_node( writer, parent, node );
4610 return S_OK;
4613 static HRESULT write_comment_text( struct writer *writer )
4615 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4616 HRESULT hr;
4618 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4619 write_bytes( writer, (const BYTE *)"<!--", 4 );
4620 write_bytes( writer, comment->value.bytes, comment->value.length );
4621 write_bytes( writer, (const BYTE *)"-->", 3 );
4622 return S_OK;
4625 static HRESULT write_comment_bin( 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, 1 )) != S_OK) return hr;
4631 write_char( writer, RECORD_COMMENT );
4632 return write_string( writer, comment->value.bytes, comment->value.length );
4635 static HRESULT write_comment( struct writer *writer )
4637 switch (writer->output_enc)
4639 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4640 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4641 default:
4642 ERR( "unhandled encoding %u\n", writer->output_enc );
4643 return WS_E_NOT_SUPPORTED;
4647 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4649 HRESULT hr;
4650 if ((hr = write_commit( writer )) != S_OK) return hr;
4651 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4652 if ((hr = write_comment( writer )) != S_OK) return hr;
4653 writer->state = WRITER_STATE_COMMENT;
4654 return S_OK;
4657 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4659 ULONG i;
4660 HRESULT hr;
4662 for (i = 0; i < count; i++)
4664 const WS_XML_STRING *prefix = attrs[i]->prefix;
4665 const WS_XML_STRING *localname = attrs[i]->localName;
4666 const WS_XML_STRING *ns = attrs[i]->ns;
4667 BOOL single = attrs[i]->singleQuote;
4669 if (attrs[i]->isXmlNs)
4671 if ((hr = add_namespace_attribute( writer, prefix, ns, single )) != S_OK) return hr;
4673 else
4675 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
4676 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4679 return S_OK;
4682 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4684 HRESULT hr;
4686 switch (node->nodeType)
4688 case WS_XML_NODE_TYPE_ELEMENT:
4690 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4691 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4692 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4694 case WS_XML_NODE_TYPE_TEXT:
4696 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4697 return write_text_node( writer, text->text );
4699 case WS_XML_NODE_TYPE_END_ELEMENT:
4700 return write_endelement_node( writer );
4702 case WS_XML_NODE_TYPE_COMMENT:
4704 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4705 return write_comment_node( writer, &comment->value );
4707 case WS_XML_NODE_TYPE_CDATA:
4708 return write_cdata_node( writer );
4710 case WS_XML_NODE_TYPE_END_CDATA:
4711 return write_endcdata_node( writer );
4713 case WS_XML_NODE_TYPE_EOF:
4714 case WS_XML_NODE_TYPE_BOF:
4715 return S_OK;
4717 default:
4718 WARN( "unknown node type %u\n", node->nodeType );
4719 return E_INVALIDARG;
4723 /**************************************************************************
4724 * WsWriteNode [webservices.@]
4726 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4728 struct writer *writer = (struct writer *)handle;
4729 HRESULT hr;
4731 TRACE( "%p %p %p\n", handle, node, error );
4732 if (error) FIXME( "ignoring error parameter\n" );
4734 if (!writer || !node) return E_INVALIDARG;
4736 EnterCriticalSection( &writer->cs );
4738 if (writer->magic != WRITER_MAGIC)
4740 LeaveCriticalSection( &writer->cs );
4741 return E_INVALIDARG;
4744 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4745 else hr = write_node( writer, node );
4747 LeaveCriticalSection( &writer->cs );
4748 TRACE( "returning %08x\n", hr );
4749 return hr;
4752 static HRESULT write_tree_node( struct writer *writer )
4754 HRESULT hr;
4756 switch (node_type( writer->current ))
4758 case WS_XML_NODE_TYPE_ELEMENT:
4759 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4760 return hr;
4761 if ((hr = write_startelement( writer )) != S_OK) return hr;
4762 writer->state = WRITER_STATE_STARTELEMENT;
4763 return S_OK;
4765 case WS_XML_NODE_TYPE_TEXT:
4766 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4767 return hr;
4768 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4769 writer->state = WRITER_STATE_TEXT;
4770 return S_OK;
4772 case WS_XML_NODE_TYPE_END_ELEMENT:
4773 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4774 writer->state = WRITER_STATE_ENDELEMENT;
4775 return S_OK;
4777 case WS_XML_NODE_TYPE_COMMENT:
4778 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4779 return hr;
4780 if ((hr = write_comment( writer )) != S_OK) return hr;
4781 writer->state = WRITER_STATE_COMMENT;
4782 return S_OK;
4784 case WS_XML_NODE_TYPE_CDATA:
4785 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4786 return hr;
4787 if ((hr = write_cdata( writer )) != S_OK) return hr;
4788 writer->state = WRITER_STATE_STARTCDATA;
4789 return S_OK;
4791 case WS_XML_NODE_TYPE_END_CDATA:
4792 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4793 writer->state = WRITER_STATE_ENDCDATA;
4794 return S_OK;
4796 case WS_XML_NODE_TYPE_EOF:
4797 case WS_XML_NODE_TYPE_BOF:
4798 return S_OK;
4800 default:
4801 ERR( "unknown node type %u\n", node_type(writer->current) );
4802 return E_INVALIDARG;
4806 static HRESULT write_tree( struct writer *writer )
4808 HRESULT hr;
4810 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4811 for (;;)
4813 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4814 if (move_to_child_node( &writer->current ))
4816 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4817 continue;
4819 if (move_to_next_node( &writer->current ))
4821 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4822 continue;
4824 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4826 ERR( "invalid tree\n" );
4827 return WS_E_INVALID_FORMAT;
4829 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4831 return S_OK;
4834 static void write_rewind( struct writer *writer )
4836 writer->write_pos = 0;
4837 writer->current = writer->root;
4838 writer->state = WRITER_STATE_INITIAL;
4841 /**************************************************************************
4842 * WsCopyNode [webservices.@]
4844 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4846 struct writer *writer = (struct writer *)handle;
4847 struct node *parent, *current, *node = NULL;
4848 HRESULT hr;
4850 TRACE( "%p %p %p\n", handle, reader, error );
4851 if (error) FIXME( "ignoring error parameter\n" );
4853 if (!writer) return E_INVALIDARG;
4855 EnterCriticalSection( &writer->cs );
4857 if (writer->magic != WRITER_MAGIC)
4859 LeaveCriticalSection( &writer->cs );
4860 return E_INVALIDARG;
4863 if (!(parent = find_parent( writer ))) hr = WS_E_INVALID_FORMAT;
4864 else
4866 if ((hr = copy_node( reader, writer->output_enc, &node )) != S_OK) goto done;
4867 current = writer->current;
4868 write_insert_node( writer, parent, node );
4870 write_rewind( writer );
4871 if ((hr = write_tree( writer )) != S_OK) goto done;
4872 writer->current = current;
4874 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4877 done:
4878 LeaveCriticalSection( &writer->cs );
4879 TRACE( "returning %08x\n", hr );
4880 return hr;
4883 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4885 return write_type_field( writer, desc, value, 0 );
4888 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4890 ULONG i, ret = 0;
4891 for (i = 0; i < count; i++)
4893 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4894 continue;
4895 if (args[i]) ret = *(const ULONG *)args[i];
4896 break;
4898 return ret;
4901 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4902 ULONG len )
4904 return write_type_array( writer, desc, value, len );
4907 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4908 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4910 struct writer *writer = (struct writer *)handle;
4911 const WS_STRUCT_DESCRIPTION *desc_struct;
4912 const WS_FIELD_DESCRIPTION *desc_field;
4913 HRESULT hr;
4914 ULONG i;
4916 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4918 EnterCriticalSection( &writer->cs );
4920 if (writer->magic != WRITER_MAGIC)
4922 LeaveCriticalSection( &writer->cs );
4923 return E_INVALIDARG;
4926 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4928 for (i = 0; i < count; i++)
4930 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4931 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4933 FIXME( "messages type not supported\n" );
4934 hr = E_NOTIMPL;
4935 goto done;
4937 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4938 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4940 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4942 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4944 const void *ptr = *(const void **)args[i];
4945 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4946 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4950 hr = write_endelement_node( writer );
4952 done:
4953 LeaveCriticalSection( &writer->cs );
4954 return hr;
4957 HRESULT writer_set_lookup( WS_XML_WRITER *handle, BOOL enable )
4959 struct writer *writer = (struct writer *)handle;
4961 EnterCriticalSection( &writer->cs );
4963 if (writer->magic != WRITER_MAGIC)
4965 LeaveCriticalSection( &writer->cs );
4966 return E_INVALIDARG;
4969 writer->dict_do_lookup = enable;
4971 LeaveCriticalSection( &writer->cs );
4972 return S_OK;
4975 HRESULT writer_set_dict_callback( WS_XML_WRITER *handle, WS_DYNAMIC_STRING_CALLBACK cb, void *state )
4977 struct writer *writer = (struct writer *)handle;
4979 EnterCriticalSection( &writer->cs );
4981 if (writer->magic != WRITER_MAGIC)
4983 LeaveCriticalSection( &writer->cs );
4984 return E_INVALIDARG;
4987 writer->dict_cb = cb;
4988 writer->dict_cb_state = state;
4990 LeaveCriticalSection( &writer->cs );
4991 return S_OK;