Release 4.0.
[wine.git] / dlls / webservices / writer.c
blob4f6cb6019591e84484d52e22172b25389dff206f
1 /*
2 * Copyright 2015, 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "webservices.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
32 #include "wine/list.h"
33 #include "wine/unicode.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 #ifndef __MINGW32__
114 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
115 #endif
117 prop_init( writer_props, count, ret->prop, &ret[1] );
118 ret->prop_count = count;
119 return ret;
122 static void free_writer( struct writer *writer )
124 destroy_nodes( writer->root );
125 free_xml_string( writer->current_ns );
126 WsFreeHeap( writer->output_heap );
127 heap_free( writer->stream_buf );
129 #ifndef __MINGW32__
130 writer->cs.DebugInfo->Spare[0] = 0;
131 #endif
132 DeleteCriticalSection( &writer->cs );
133 heap_free( writer );
136 static void write_insert_eof( struct writer *writer, struct node *eof )
138 if (!writer->root) writer->root = eof;
139 else
141 eof->parent = writer->root;
142 list_add_tail( &writer->root->children, &eof->entry );
144 writer->current = eof;
147 static void write_insert_bof( struct writer *writer, struct node *bof )
149 writer->root->parent = bof;
150 list_add_tail( &bof->children, &writer->root->entry );
151 writer->current = writer->root = bof;
154 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
156 node->parent = parent;
157 list_add_before( list_tail( &parent->children ), &node->entry );
158 writer->current = node;
161 static struct node *find_parent( struct writer *writer )
163 if (is_valid_parent( writer->current )) return writer->current;
164 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
165 return NULL;
168 static HRESULT init_writer( struct writer *writer )
170 struct node *node;
172 writer->write_pos = 0;
173 writer->write_bufptr = NULL;
174 destroy_nodes( writer->root );
175 writer->root = writer->current = NULL;
176 free_xml_string( writer->current_ns );
177 writer->current_ns = NULL;
179 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
180 write_insert_eof( writer, node );
181 writer->state = WRITER_STATE_INITIAL;
182 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
183 writer->output_charset = WS_CHARSET_UTF8;
184 writer->dict = NULL;
185 writer->dict_do_lookup = FALSE;
186 writer->dict_cb = NULL;
187 writer->dict_cb_state = NULL;
188 return S_OK;
191 /**************************************************************************
192 * WsCreateWriter [webservices.@]
194 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
195 WS_XML_WRITER **handle, WS_ERROR *error )
197 struct writer *writer;
198 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
199 WS_CHARSET charset = WS_CHARSET_UTF8;
200 HRESULT hr;
202 TRACE( "%p %u %p %p\n", properties, count, handle, error );
203 if (error) FIXME( "ignoring error parameter\n" );
205 if (!handle) return E_INVALIDARG;
206 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
208 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
209 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
210 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
211 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
212 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
213 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
214 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
216 for (i = 0; i < count; i++)
218 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
219 properties[i].valueSize );
220 if (hr != S_OK)
222 free_writer( writer );
223 return hr;
227 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
228 &max_size, sizeof(max_size) );
229 if (hr != S_OK)
231 free_writer( writer );
232 return hr;
235 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
236 if (hr != S_OK)
238 free_writer( writer );
239 return hr;
242 hr = init_writer( writer );
243 if (hr != S_OK)
245 free_writer( writer );
246 return hr;
249 TRACE( "created %p\n", writer );
250 *handle = (WS_XML_WRITER *)writer;
251 return S_OK;
254 /**************************************************************************
255 * WsFreeWriter [webservices.@]
257 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
259 struct writer *writer = (struct writer *)handle;
261 TRACE( "%p\n", handle );
263 if (!writer) return;
265 EnterCriticalSection( &writer->cs );
267 if (writer->magic != WRITER_MAGIC)
269 LeaveCriticalSection( &writer->cs );
270 return;
273 writer->magic = 0;
275 LeaveCriticalSection( &writer->cs );
276 free_writer( writer );
279 /**************************************************************************
280 * WsGetWriterProperty [webservices.@]
282 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
283 void *buf, ULONG size, WS_ERROR *error )
285 struct writer *writer = (struct writer *)handle;
286 HRESULT hr = S_OK;
288 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
289 if (error) FIXME( "ignoring error parameter\n" );
291 if (!writer) return E_INVALIDARG;
293 EnterCriticalSection( &writer->cs );
295 if (writer->magic != WRITER_MAGIC)
297 LeaveCriticalSection( &writer->cs );
298 return E_INVALIDARG;
301 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
302 else
304 switch (id)
306 case WS_XML_WRITER_PROPERTY_BYTES:
308 WS_BYTES *bytes = buf;
309 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
310 else
312 bytes->bytes = writer->output_buf->bytes.bytes;
313 bytes->length = writer->output_buf->bytes.length;
315 break;
317 case WS_XML_WRITER_PROPERTY_BUFFERS:
318 if (writer->output_buf->bytes.length)
320 WS_BUFFERS *buffers = buf;
321 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
322 else
324 buffers->bufferCount = 1;
325 buffers->buffers = &writer->output_buf->bytes;
327 break;
329 /* fall through */
330 default:
331 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
335 LeaveCriticalSection( &writer->cs );
336 TRACE( "returning %08x\n", hr );
337 return hr;
340 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
342 /* free current buffer if it's ours */
343 if (writer->output_buf && !writer->output_buf_user)
345 free_xmlbuf( writer->output_buf );
347 writer->output_buf = xmlbuf;
348 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
349 writer->write_bufptr = xmlbuf->bytes.bytes;
350 writer->write_pos = 0;
353 static void set_output_stream( struct writer *writer, WS_WRITE_CALLBACK callback, void *state )
355 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
356 writer->output_cb = callback;
357 writer->output_cb_state = state;
358 writer->write_bufptr = writer->stream_buf;
359 writer->write_pos = 0;
362 /**************************************************************************
363 * WsSetOutput [webservices.@]
365 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
366 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
367 ULONG count, WS_ERROR *error )
369 struct writer *writer = (struct writer *)handle;
370 struct node *node;
371 HRESULT hr;
372 ULONG i;
374 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
375 if (error) FIXME( "ignoring error parameter\n" );
377 if (!writer) return E_INVALIDARG;
379 EnterCriticalSection( &writer->cs );
381 if (writer->magic != WRITER_MAGIC)
383 LeaveCriticalSection( &writer->cs );
384 return E_INVALIDARG;
387 for (i = 0; i < count; i++)
389 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
390 properties[i].valueSize );
391 if (hr != S_OK) goto done;
394 if ((hr = init_writer( writer )) != S_OK) goto done;
396 switch (encoding->encodingType)
398 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
400 const WS_XML_WRITER_TEXT_ENCODING *text = (const WS_XML_WRITER_TEXT_ENCODING *)encoding;
401 if (text->charSet != WS_CHARSET_UTF8)
403 FIXME( "charset %u not supported\n", text->charSet );
404 hr = E_NOTIMPL;
405 goto done;
407 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
408 writer->output_charset = WS_CHARSET_UTF8;
409 break;
411 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
413 const WS_XML_WRITER_BINARY_ENCODING *bin = (const WS_XML_WRITER_BINARY_ENCODING *)encoding;
414 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
415 writer->output_charset = 0;
416 writer->dict = bin->staticDictionary;
417 writer->dict_cb = bin->dynamicStringCallback;
418 writer->dict_cb_state = bin->dynamicStringCallbackState;
419 break;
421 default:
422 FIXME( "encoding type %u not supported\n", encoding->encodingType );
423 hr = E_NOTIMPL;
424 goto done;
427 switch (output->outputType)
429 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
431 struct xmlbuf *xmlbuf;
432 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, 0, writer->output_enc, writer->output_charset,
433 writer->dict, NULL )))
435 hr = WS_E_QUOTA_EXCEEDED;
436 goto done;
438 set_output_buffer( writer, xmlbuf );
439 writer->output_buf_user = FALSE;
440 break;
442 case WS_XML_WRITER_OUTPUT_TYPE_STREAM:
444 const WS_XML_WRITER_STREAM_OUTPUT *stream = (const WS_XML_WRITER_STREAM_OUTPUT *)output;
445 if (!writer->stream_buf && !(writer->stream_buf = heap_alloc( STREAM_BUFSIZE )))
447 hr = E_OUTOFMEMORY;
448 goto done;
450 set_output_stream( writer, stream->writeCallback, stream->writeCallbackState );
451 break;
454 default:
455 FIXME( "output type %u not supported\n", output->outputType );
456 hr = E_NOTIMPL;
457 goto done;
460 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
461 else write_insert_bof( writer, node );
463 done:
464 LeaveCriticalSection( &writer->cs );
465 TRACE( "returning %08x\n", hr );
466 return hr;
469 /**************************************************************************
470 * WsSetOutputToBuffer [webservices.@]
472 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
473 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
474 WS_ERROR *error )
476 struct writer *writer = (struct writer *)handle;
477 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
478 struct node *node;
479 HRESULT hr;
480 ULONG i;
482 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
483 if (error) FIXME( "ignoring error parameter\n" );
485 if (!writer || !xmlbuf) return E_INVALIDARG;
487 EnterCriticalSection( &writer->cs );
489 if (writer->magic != WRITER_MAGIC)
491 LeaveCriticalSection( &writer->cs );
492 return E_INVALIDARG;
495 for (i = 0; i < count; i++)
497 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
498 properties[i].valueSize );
499 if (hr != S_OK) goto done;
502 if ((hr = init_writer( writer )) != S_OK) goto done;
503 writer->output_enc = xmlbuf->encoding;
504 writer->output_charset = xmlbuf->charset;
505 set_output_buffer( writer, xmlbuf );
506 writer->output_buf_user = TRUE;
508 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
509 else write_insert_bof( writer, node );
511 done:
512 LeaveCriticalSection( &writer->cs );
513 TRACE( "returning %08x\n", hr );
514 return hr;
517 static HRESULT flush_writer( struct writer *writer, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
518 WS_ERROR *error )
520 WS_BYTES buf;
522 if (writer->write_pos < min_size) return S_OK;
524 buf.bytes = writer->write_bufptr;
525 buf.length = writer->write_pos;
526 writer->output_cb( writer->output_cb_state, &buf, 1, ctx, error );
527 writer->write_pos = 0;
528 return S_OK;
531 /**************************************************************************
532 * WsFlushWriter [webservices.@]
534 HRESULT WINAPI WsFlushWriter( WS_XML_WRITER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
535 WS_ERROR *error )
537 struct writer *writer = (struct writer *)handle;
538 HRESULT hr;
540 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
541 if (error) FIXME( "ignoring error parameter\n" );
542 if (ctx) FIXME( "ignoring ctx parameter\n" );
544 if (!writer) return E_INVALIDARG;
546 EnterCriticalSection( &writer->cs );
548 if (writer->magic != WRITER_MAGIC)
550 LeaveCriticalSection( &writer->cs );
551 return E_INVALIDARG;
554 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_STREAM) hr = WS_E_INVALID_OPERATION;
555 else hr = flush_writer( writer, min_size, ctx, error );
557 LeaveCriticalSection( &writer->cs );
558 TRACE( "returning %08x\n", hr );
559 return hr;
562 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
564 struct xmlbuf *buf = writer->output_buf;
565 SIZE_T new_size;
566 void *tmp;
568 if (writer->output_type == WS_XML_WRITER_OUTPUT_TYPE_STREAM)
570 if (size > STREAM_BUFSIZE) return WS_E_QUOTA_EXCEEDED;
571 return flush_writer( writer, STREAM_BUFSIZE - size, NULL, NULL );
574 if (buf->size >= writer->write_pos + size)
576 buf->bytes.length = writer->write_pos + size;
577 return S_OK;
579 new_size = max( buf->size * 2, writer->write_pos + size );
580 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
581 writer->write_bufptr = buf->bytes.bytes = tmp;
582 buf->size = new_size;
583 buf->bytes.length = writer->write_pos + size;
584 return S_OK;
587 static inline void write_char( struct writer *writer, unsigned char ch )
589 writer->write_bufptr[writer->write_pos++] = ch;
592 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
594 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
595 writer->write_pos += len;
598 struct escape
600 char ch;
601 const char *entity;
602 ULONG len;
604 static const struct escape escape_lt = { '<', "&lt;", 4 };
605 static const struct escape escape_gt = { '>', "&gt;", 4 };
606 static const struct escape escape_amp = { '&', "&amp;", 5 };
607 static const struct escape escape_apos = { '\'', "&apos;", 6 };
608 static const struct escape escape_quot = { '"', "&quot;", 6 };
610 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
611 const struct escape **escapes, ULONG nb_escapes )
613 ULONG i, j, size;
614 const BYTE *ptr;
615 HRESULT hr;
617 for (i = 0; i < len; i++)
619 ptr = &bytes[i];
620 size = 1;
621 for (j = 0; j < nb_escapes; j++)
623 if (bytes[i] == escapes[j]->ch)
625 ptr = (const BYTE *)escapes[j]->entity;
626 size = escapes[j]->len;
627 break;
630 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
631 write_bytes( writer, ptr, size );
634 return S_OK;
637 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
639 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
640 const struct escape *escapes[3];
642 escapes[0] = single ? &escape_apos : &escape_quot;
643 escapes[1] = &escape_lt;
644 escapes[2] = &escape_amp;
645 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
648 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
650 unsigned char quote = attr->singleQuote ? '\'' : '"';
651 const WS_XML_STRING *prefix = NULL;
652 ULONG size;
653 HRESULT hr;
655 if (attr->prefix) prefix = attr->prefix;
657 /* ' prefix:attr="value"' */
659 size = attr->localName->length + 4 /* ' =""' */;
660 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
661 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
663 write_char( writer, ' ' );
664 if (prefix && prefix->length)
666 write_bytes( writer, prefix->bytes, prefix->length );
667 write_char( writer, ':' );
669 write_bytes( writer, attr->localName->bytes, attr->localName->length );
670 write_char( writer, '=' );
671 write_char( writer, quote );
672 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
673 write_char( writer, quote );
675 return hr;
678 static HRESULT write_int31( struct writer *writer, ULONG len )
680 HRESULT hr;
682 if (len > 0x7fffffff) return E_INVALIDARG;
684 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
685 if (len < 0x80)
687 write_char( writer, len );
688 return S_OK;
690 write_char( writer, (len & 0x7f) | 0x80 );
692 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
693 if ((len >>= 7) < 0x80)
695 write_char( writer, len );
696 return S_OK;
698 write_char( writer, (len & 0x7f) | 0x80 );
700 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
701 if ((len >>= 7) < 0x80)
703 write_char( writer, len );
704 return S_OK;
706 write_char( writer, (len & 0x7f) | 0x80 );
708 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
709 if ((len >>= 7) < 0x80)
711 write_char( writer, len );
712 return S_OK;
714 write_char( writer, (len & 0x7f) | 0x80 );
716 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
717 if ((len >>= 7) < 0x08)
719 write_char( writer, len );
720 return S_OK;
722 return WS_E_INVALID_FORMAT;
725 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
727 HRESULT hr;
728 if ((hr = write_int31( writer, len )) != S_OK) return hr;
729 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
730 write_bytes( writer, bytes, len );
731 return S_OK;
734 static HRESULT write_dict_string( struct writer *writer, ULONG id )
736 if (id > 0x7fffffff) return E_INVALIDARG;
737 return write_int31( writer, id );
740 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
742 if (!text) return RECORD_CHARS8_TEXT;
743 switch (text->textType)
745 case WS_XML_TEXT_TYPE_UTF8:
747 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
748 if (use_dict) return RECORD_DICTIONARY_TEXT;
749 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
750 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
751 return RECORD_CHARS32_TEXT;
753 case WS_XML_TEXT_TYPE_UTF16:
755 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
756 int len = text_utf16->byteCount / sizeof(WCHAR);
757 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
758 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT;
759 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT;
760 return RECORD_CHARS32_TEXT;
762 case WS_XML_TEXT_TYPE_BASE64:
764 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
765 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
766 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
767 return RECORD_BYTES32_TEXT;
769 case WS_XML_TEXT_TYPE_BOOL:
771 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
772 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
774 case WS_XML_TEXT_TYPE_INT32:
776 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
777 if (!text_int32->value) return RECORD_ZERO_TEXT;
778 if (text_int32->value == 1) return RECORD_ONE_TEXT;
779 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
780 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
781 return RECORD_INT32_TEXT;
783 case WS_XML_TEXT_TYPE_INT64:
785 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
786 if (!text_int64->value) return RECORD_ZERO_TEXT;
787 if (text_int64->value == 1) return RECORD_ONE_TEXT;
788 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
789 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
790 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
791 return RECORD_INT64_TEXT;
793 case WS_XML_TEXT_TYPE_UINT64:
795 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
796 if (!text_uint64->value) return RECORD_ZERO_TEXT;
797 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
798 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
799 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
800 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
801 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
802 return RECORD_UINT64_TEXT;
804 case WS_XML_TEXT_TYPE_DOUBLE:
806 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
807 if (!text_double->value) return RECORD_ZERO_TEXT;
808 if (text_double->value == 1) return RECORD_ONE_TEXT;
809 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
810 return RECORD_DOUBLE_TEXT;
811 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
812 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
813 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
814 return RECORD_INT64_TEXT;
816 case WS_XML_TEXT_TYPE_GUID:
817 return RECORD_GUID_TEXT;
819 case WS_XML_TEXT_TYPE_UNIQUE_ID:
820 return RECORD_UNIQUE_ID_TEXT;
822 case WS_XML_TEXT_TYPE_DATETIME:
823 return RECORD_DATETIME_TEXT;
825 default:
826 FIXME( "unhandled text type %u\n", text->textType );
827 return 0;
831 static INT64 get_text_value_int( const WS_XML_TEXT *text )
833 switch (text->textType)
835 case WS_XML_TEXT_TYPE_INT32:
837 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
838 return text_int32->value;
840 case WS_XML_TEXT_TYPE_INT64:
842 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
843 return text_int64->value;
845 case WS_XML_TEXT_TYPE_UINT64:
847 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
848 return text_uint64->value;
850 case WS_XML_TEXT_TYPE_DOUBLE:
852 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
853 return text_double->value;
855 default:
856 ERR( "unhandled text type %u\n", text->textType );
857 assert(0);
858 return 0;
862 static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
864 if (writer->dict && str->dictionary == writer->dict)
866 *id = str->id << 1;
867 return TRUE;
869 if (writer->dict_cb)
871 BOOL found = FALSE;
872 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
873 if (found) *id = (*id << 1) | 1;
874 return found;
876 return FALSE;
879 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
881 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
882 if (*ptr)
884 memcpy( buf, bool_true, sizeof(bool_true) );
885 return sizeof(bool_true);
887 memcpy( buf, bool_false, sizeof(bool_false) );
888 return sizeof(bool_false);
891 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
893 return wsprintfA( (char *)buf, "%d", *ptr );
896 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
898 return wsprintfA( (char *)buf, "%I64d", *ptr );
901 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
903 return wsprintfA( (char *)buf, "%I64u", *ptr );
906 static ULONG format_double( const double *ptr, unsigned char *buf )
908 #ifdef HAVE_POWL
909 static const long double precision = 0.0000000000000001;
910 unsigned char *p = buf;
911 long double val = *ptr;
912 int neg, mag, mag2, use_exp;
914 if (isnan( val ))
916 memcpy( buf, "NaN", 3 );
917 return 3;
919 if (isinf( val ))
921 if (val < 0)
923 memcpy( buf, "-INF", 4 );
924 return 4;
926 memcpy( buf, "INF", 3 );
927 return 3;
929 if (val == 0.0)
931 *p = '0';
932 return 1;
935 if ((neg = val < 0))
937 *p++ = '-';
938 val = -val;
941 mag = log10l( val );
942 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
943 if (use_exp)
945 if (mag < 0) mag -= 1;
946 val = val / powl( 10.0, mag );
947 mag2 = mag;
948 mag = 0;
950 else if (mag < 1) mag = 0;
952 while (val > precision || mag >= 0)
954 long double weight = powl( 10.0, mag );
955 if (weight > 0 && !isinf( weight ))
957 int digit = floorl( val / weight );
958 val -= digit * weight;
959 *(p++) = '0' + digit;
961 if (!mag && val > precision) *(p++) = '.';
962 mag--;
965 if (use_exp)
967 int i, j;
968 *(p++) = 'E';
969 if (mag2 > 0) *(p++) = '+';
970 else
972 *(p++) = '-';
973 mag2 = -mag2;
975 mag = 0;
976 while (mag2 > 0)
978 *(p++) = '0' + mag2 % 10;
979 mag2 /= 10;
980 mag++;
982 for (i = -mag, j = -1; i < j; i++, j--)
984 p[i] ^= p[j];
985 p[j] ^= p[i];
986 p[i] ^= p[j];
990 return p - buf;
991 #else
992 FIXME( "powl not found at build time\n" );
993 return 0;
994 #endif
997 static inline int year_size( int year )
999 return leap_year( year ) ? 366 : 365;
1002 #define TZ_OFFSET 8
1003 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1005 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1006 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
1007 unsigned __int64 ticks, day_ticks;
1008 ULONG len;
1010 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1011 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1013 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1014 tz_hour = TZ_OFFSET;
1016 else
1018 ticks = ptr->ticks;
1019 tz_hour = 0;
1021 day = ticks / TICKS_PER_DAY;
1022 day_ticks = ticks % TICKS_PER_DAY;
1023 hour = day_ticks / TICKS_PER_HOUR;
1024 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1025 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1026 sec_frac = day_ticks % TICKS_PER_SEC;
1028 while (day >= year_size( year ))
1030 day -= year_size( year );
1031 year++;
1033 while (day >= month_days[leap_year( year )][month])
1035 day -= month_days[leap_year( year )][month];
1036 month++;
1039 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1040 if (sec_frac)
1042 static const char fmt_frac[] = ".%07u";
1043 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1044 while (buf[len - 1] == '0') len--;
1046 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1048 buf[len++] = 'Z';
1050 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1052 static const char fmt_tz[] = "%c%02u:00";
1053 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1056 return len;
1059 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1061 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1062 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1063 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1064 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1067 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1069 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1070 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1071 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1072 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1075 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
1077 ULONG len = 0;
1078 if (prefix && prefix->length)
1080 memcpy( buf, prefix->bytes, prefix->length );
1081 len += prefix->length;
1082 buf[len++] = ':';
1084 memcpy( buf + len, localname->bytes, localname->length );
1085 return len + localname->length;
1088 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
1090 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1091 ULONG i = 0, x;
1093 while (len > 0)
1095 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
1096 x = (bin[0] & 3) << 4;
1097 if (len == 1)
1099 buf[i++] = base64[x];
1100 buf[i++] = '=';
1101 buf[i++] = '=';
1102 break;
1104 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
1105 x = (bin[1] & 0x0f) << 2;
1106 if (len == 2)
1108 buf[i++] = base64[x];
1109 buf[i++] = '=';
1110 break;
1112 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
1113 buf[i++] = base64[bin[2] & 0x3f];
1114 bin += 3;
1115 len -= 3;
1117 return i;
1120 HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
1121 WS_XML_UTF8_TEXT **ret )
1123 ULONG len_old = old ? old->value.length : 0;
1124 if (offset) *offset = len_old;
1126 switch (text->textType)
1128 case WS_XML_TEXT_TYPE_UTF8:
1130 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
1132 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
1133 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1134 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
1135 return S_OK;
1137 case WS_XML_TEXT_TYPE_UTF16:
1139 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
1140 const WCHAR *str = (const WCHAR *)src->bytes;
1141 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
1143 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
1144 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
1145 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
1146 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1147 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
1148 return S_OK;
1150 case WS_XML_TEXT_TYPE_BASE64:
1152 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
1153 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
1155 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1156 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1157 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
1158 return S_OK;
1160 case WS_XML_TEXT_TYPE_BOOL:
1162 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
1164 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
1165 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1166 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
1167 return S_OK;
1169 case WS_XML_TEXT_TYPE_INT32:
1171 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
1172 unsigned char buf[12]; /* "-2147483648" */
1173 ULONG len = format_int32( &int32_text->value, buf );
1175 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1176 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1177 memcpy( (*ret)->value.bytes + len_old, buf, len );
1178 return S_OK;
1180 case WS_XML_TEXT_TYPE_INT64:
1182 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
1183 unsigned char buf[21]; /* "-9223372036854775808" */
1184 ULONG len = format_int64( &int64_text->value, buf );
1186 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1187 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1188 memcpy( (*ret)->value.bytes + len_old, buf, len );
1189 return S_OK;
1191 case WS_XML_TEXT_TYPE_UINT64:
1193 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
1194 unsigned char buf[21]; /* "18446744073709551615" */
1195 ULONG len = format_uint64( &uint64_text->value, buf );
1197 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1198 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1199 memcpy( (*ret)->value.bytes + len_old, buf, len );
1200 return S_OK;
1202 case WS_XML_TEXT_TYPE_DOUBLE:
1204 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
1205 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1206 unsigned short fpword;
1207 ULONG len;
1209 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
1210 len = format_double( &double_text->value, buf );
1211 restore_fpword( fpword );
1212 if (!len) return E_NOTIMPL;
1214 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1215 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1216 memcpy( (*ret)->value.bytes + len_old, buf, len );
1217 return S_OK;
1219 case WS_XML_TEXT_TYPE_GUID:
1221 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
1223 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
1224 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1225 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1226 return S_OK;
1228 case WS_XML_TEXT_TYPE_UNIQUE_ID:
1230 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
1232 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
1233 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1234 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
1235 return S_OK;
1237 case WS_XML_TEXT_TYPE_DATETIME:
1239 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
1241 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
1242 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1243 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
1244 return S_OK;
1246 case WS_XML_TEXT_TYPE_QNAME:
1248 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
1249 ULONG len = qn->localName->length;
1251 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
1252 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
1253 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
1254 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
1255 return S_OK;
1257 default:
1258 FIXME( "unhandled text type %u\n", text->textType );
1259 return E_NOTIMPL;
1263 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
1265 enum record_type type;
1266 BOOL use_dict = FALSE;
1267 HRESULT hr;
1268 ULONG id;
1270 if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
1272 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
1273 use_dict = get_string_id( writer, &utf8->value, &id );
1275 type = get_attr_text_record_type( text, use_dict );
1277 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1278 write_char( writer, type );
1280 switch (type)
1282 case RECORD_CHARS8_TEXT:
1284 const WS_XML_UTF8_TEXT *text_utf8;
1285 WS_XML_UTF8_TEXT *new = NULL;
1286 UINT8 len;
1288 if (!text)
1290 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1291 write_char( writer, 0 );
1292 return S_OK;
1294 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1295 else
1297 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1298 text_utf8 = new;
1300 len = text_utf8->value.length;
1301 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1303 heap_free( new );
1304 return hr;
1306 write_char( writer, len );
1307 write_bytes( writer, text_utf8->value.bytes, len );
1308 heap_free( new );
1309 return S_OK;
1311 case RECORD_CHARS16_TEXT:
1313 const WS_XML_UTF8_TEXT *text_utf8;
1314 WS_XML_UTF8_TEXT *new = NULL;
1315 UINT16 len;
1317 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
1318 else
1320 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
1321 text_utf8 = new;
1323 len = text_utf8->value.length;
1324 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK)
1326 heap_free( new );
1327 return hr;
1329 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1330 write_bytes( writer, text_utf8->value.bytes, len );
1331 heap_free( new );
1332 return S_OK;
1334 case RECORD_BYTES8_TEXT:
1336 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1337 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
1338 write_char( writer, text_base64->length );
1339 write_bytes( writer, text_base64->bytes, text_base64->length );
1340 return S_OK;
1342 case RECORD_BYTES16_TEXT:
1344 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
1345 UINT16 len = text_base64->length;
1346 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
1347 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
1348 write_bytes( writer, text_base64->bytes, len );
1349 return S_OK;
1351 case RECORD_ZERO_TEXT:
1352 case RECORD_ONE_TEXT:
1353 case RECORD_FALSE_TEXT:
1354 case RECORD_TRUE_TEXT:
1355 return S_OK;
1357 case RECORD_INT8_TEXT:
1359 INT8 val = get_text_value_int( text );
1360 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1361 write_char( writer, val );
1362 return S_OK;
1364 case RECORD_INT16_TEXT:
1366 INT16 val = get_text_value_int( text );
1367 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1368 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1369 return S_OK;
1371 case RECORD_INT32_TEXT:
1373 INT32 val = get_text_value_int( text );
1374 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1375 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1376 return S_OK;
1378 case RECORD_INT64_TEXT:
1380 INT64 val = get_text_value_int( text );
1381 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1382 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1383 return S_OK;
1385 case RECORD_UINT64_TEXT:
1387 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
1388 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
1389 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
1390 return S_OK;
1392 case RECORD_DOUBLE_TEXT:
1394 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
1395 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
1396 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
1397 return S_OK;
1399 case RECORD_GUID_TEXT:
1401 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
1402 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
1403 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
1404 return S_OK;
1406 case RECORD_UNIQUE_ID_TEXT:
1408 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
1409 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
1410 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
1411 return S_OK;
1413 case RECORD_DATETIME_TEXT:
1415 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
1416 UINT64 val = text_datetime->value.ticks;
1418 assert( val <= TICKS_MAX );
1419 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
1420 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
1422 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
1423 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
1424 return S_OK;
1426 default:
1427 FIXME( "unhandled record type %02x\n", type );
1428 return E_NOTIMPL;
1432 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1434 if (!attr->prefix || !attr->prefix->length)
1436 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
1437 return RECORD_SHORT_ATTRIBUTE;
1439 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
1441 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1442 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
1444 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
1445 return RECORD_ATTRIBUTE;
1448 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1450 ULONG id;
1451 enum record_type type = get_attr_record_type( attr, get_string_id(writer, attr->localName, &id) );
1452 HRESULT hr;
1454 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1455 write_char( writer, type );
1457 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
1459 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1460 return write_attribute_value_bin( writer, attr->value );
1462 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
1464 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1465 return write_attribute_value_bin( writer, attr->value );
1468 switch (type)
1470 case RECORD_SHORT_ATTRIBUTE:
1471 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1472 break;
1474 case RECORD_ATTRIBUTE:
1475 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1476 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
1477 break;
1479 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
1480 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1481 break;
1483 case RECORD_DICTIONARY_ATTRIBUTE:
1484 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1485 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1486 break;
1488 default:
1489 ERR( "unhandled record type %02x\n", type );
1490 return WS_E_NOT_SUPPORTED;
1493 return write_attribute_value_bin( writer, attr->value );
1496 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1498 switch (writer->output_enc)
1500 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
1501 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
1502 default:
1503 ERR( "unhandled encoding %u\n", writer->output_enc );
1504 return WS_E_NOT_SUPPORTED;
1508 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1510 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
1513 /**************************************************************************
1514 * WsGetPrefixFromNamespace [webservices.@]
1516 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
1517 BOOL required, const WS_XML_STRING **prefix,
1518 WS_ERROR *error )
1520 struct writer *writer = (struct writer *)handle;
1521 WS_XML_ELEMENT_NODE *elem;
1522 BOOL found = FALSE;
1523 HRESULT hr = S_OK;
1525 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1526 if (error) FIXME( "ignoring error parameter\n" );
1528 if (!writer || !ns || !prefix) return E_INVALIDARG;
1530 EnterCriticalSection( &writer->cs );
1532 if (writer->magic != WRITER_MAGIC)
1534 LeaveCriticalSection( &writer->cs );
1535 return E_INVALIDARG;
1538 elem = &writer->current->hdr;
1539 if (elem->prefix && is_current_namespace( writer, ns ))
1541 *prefix = elem->prefix;
1542 found = TRUE;
1545 if (!found)
1547 if (required) hr = WS_E_INVALID_FORMAT;
1548 else
1550 *prefix = NULL;
1551 hr = S_FALSE;
1555 LeaveCriticalSection( &writer->cs );
1556 TRACE( "returning %08x\n", hr );
1557 return hr;
1560 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1562 unsigned char quote = attr->singleQuote ? '\'' : '"';
1563 ULONG size;
1564 HRESULT hr;
1566 /* ' xmlns:prefix="namespace"' */
1568 size = attr->ns->length + 9 /* ' xmlns=""' */;
1569 if (attr->prefix && attr->prefix->length) size += attr->prefix->length + 1 /* ':' */;
1570 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1572 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1573 if (attr->prefix && attr->prefix->length)
1575 write_char( writer, ':' );
1576 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1578 write_char( writer, '=' );
1579 write_char( writer, quote );
1580 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1581 write_char( writer, quote );
1583 return S_OK;
1586 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1588 if (!attr->prefix || !attr->prefix->length)
1590 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1591 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1593 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1594 return RECORD_XMLNS_ATTRIBUTE;
1597 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1599 ULONG id;
1600 enum record_type type = get_xmlns_record_type( attr, get_string_id(writer, attr->ns, &id) );
1601 HRESULT hr;
1603 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1604 write_char( writer, type );
1606 switch (type)
1608 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1609 break;
1611 case RECORD_XMLNS_ATTRIBUTE:
1612 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1613 break;
1615 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1616 return write_dict_string( writer, id );
1618 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1619 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1620 return write_dict_string( writer, id );
1622 default:
1623 ERR( "unhandled record type %02x\n", type );
1624 return WS_E_NOT_SUPPORTED;
1627 return write_string( writer, attr->ns->bytes, attr->ns->length );
1630 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1632 switch (writer->output_enc)
1634 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1635 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1636 default:
1637 ERR( "unhandled encoding %u\n", writer->output_enc );
1638 return WS_E_NOT_SUPPORTED;
1642 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1643 const WS_XML_STRING *ns, BOOL single )
1645 WS_XML_ATTRIBUTE *attr;
1646 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1647 HRESULT hr;
1649 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1651 attr->singleQuote = !!single;
1652 attr->isXmlNs = 1;
1653 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1655 free_attribute( attr );
1656 return E_OUTOFMEMORY;
1658 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1660 free_attribute( attr );
1661 return E_OUTOFMEMORY;
1663 if ((hr = append_attribute( elem, attr )) != S_OK)
1665 free_attribute( attr );
1666 return hr;
1668 return S_OK;
1671 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1673 if (!str1 && !str2) return TRUE;
1674 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1677 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1678 const WS_XML_STRING *ns )
1680 ULONG i;
1681 const struct node *node;
1683 for (node = (const struct node *)elem; node; node = node->parent)
1685 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1687 elem = &node->hdr;
1688 for (i = 0; i < elem->attributeCount; i++)
1690 if (!elem->attributes[i]->isXmlNs) continue;
1691 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1692 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1695 return FALSE;
1698 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1700 WS_XML_STRING *str;
1701 if (!(str = dup_xml_string( ns, writer->dict_do_lookup ))) return E_OUTOFMEMORY;
1702 free_xml_string( writer->current_ns );
1703 writer->current_ns = str;
1704 return S_OK;
1707 static HRESULT set_namespaces( struct writer *writer )
1709 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1710 HRESULT hr;
1711 ULONG i;
1713 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1715 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1716 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1719 for (i = 0; i < elem->attributeCount; i++)
1721 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1722 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1723 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1726 return S_OK;
1729 /**************************************************************************
1730 * WsWriteEndAttribute [webservices.@]
1732 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1734 struct writer *writer = (struct writer *)handle;
1735 HRESULT hr = S_OK;
1737 TRACE( "%p %p\n", handle, error );
1738 if (error) FIXME( "ignoring error parameter\n" );
1740 if (!writer) return E_INVALIDARG;
1742 EnterCriticalSection( &writer->cs );
1744 if (writer->magic != WRITER_MAGIC)
1746 LeaveCriticalSection( &writer->cs );
1747 return E_INVALIDARG;
1750 writer->state = WRITER_STATE_STARTELEMENT;
1752 LeaveCriticalSection( &writer->cs );
1753 TRACE( "returning %08x\n", hr );
1754 return hr;
1757 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1759 ULONG i;
1760 HRESULT hr;
1761 for (i = 0; i < elem->attributeCount; i++)
1763 if (elem->attributes[i]->isXmlNs) continue;
1764 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1766 for (i = 0; i < elem->attributeCount; i++)
1768 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1769 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1771 for (i = 0; i < elem->attributeCount; i++)
1773 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1774 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1776 return S_OK;
1779 static HRESULT write_startelement_text( struct writer *writer )
1781 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1782 ULONG size;
1783 HRESULT hr;
1785 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1787 size = elem->localName->length + 1 /* '<' */;
1788 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1789 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1791 write_char( writer, '<' );
1792 if (elem->prefix && elem->prefix->length)
1794 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1795 write_char( writer, ':' );
1797 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1798 return write_attributes( writer, elem );
1801 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1803 if (!elem->prefix || !elem->prefix->length)
1805 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1806 return RECORD_SHORT_ELEMENT;
1808 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1810 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1811 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1813 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1814 return RECORD_ELEMENT;
1817 static HRESULT write_startelement_bin( struct writer *writer )
1819 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1820 ULONG id;
1821 enum record_type type = get_elem_record_type( elem, get_string_id(writer, elem->localName, &id) );
1822 HRESULT hr;
1824 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1825 write_char( writer, type );
1827 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1829 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1830 return write_attributes( writer, elem );
1832 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1834 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1835 return write_attributes( writer, elem );
1838 switch (type)
1840 case RECORD_SHORT_ELEMENT:
1841 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1842 break;
1844 case RECORD_ELEMENT:
1845 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1846 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1847 break;
1849 case RECORD_SHORT_DICTIONARY_ELEMENT:
1850 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1851 break;
1853 case RECORD_DICTIONARY_ELEMENT:
1854 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1855 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1856 break;
1858 default:
1859 ERR( "unhandled record type %02x\n", type );
1860 return WS_E_NOT_SUPPORTED;
1863 return write_attributes( writer, elem );
1866 static HRESULT write_startelement( struct writer *writer )
1868 switch (writer->output_enc)
1870 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1871 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1872 default:
1873 ERR( "unhandled encoding %u\n", writer->output_enc );
1874 return WS_E_NOT_SUPPORTED;
1878 static struct node *write_find_startelement( struct writer *writer )
1880 struct node *node;
1881 for (node = writer->current; node; node = node->parent)
1883 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1885 return NULL;
1888 static inline BOOL is_empty_element( const struct node *node )
1890 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1891 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1894 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1896 ULONG size;
1897 HRESULT hr;
1899 /* '/>' */
1901 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1903 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1904 write_char( writer, '/' );
1905 write_char( writer, '>' );
1906 return S_OK;
1909 /* '</prefix:localname>' */
1911 size = elem->localName->length + 3 /* '</>' */;
1912 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1913 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1915 write_char( writer, '<' );
1916 write_char( writer, '/' );
1917 if (elem->prefix && elem->prefix->length)
1919 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1920 write_char( writer, ':' );
1922 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1923 write_char( writer, '>' );
1924 return S_OK;
1927 static HRESULT write_endelement_bin( struct writer *writer )
1929 HRESULT hr;
1930 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1931 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1932 write_char( writer, RECORD_ENDELEMENT );
1933 return S_OK;
1936 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1938 switch (writer->output_enc)
1940 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1941 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1942 default:
1943 ERR( "unhandled encoding %u\n", writer->output_enc );
1944 return WS_E_NOT_SUPPORTED;
1948 static HRESULT write_close_element( struct writer *writer, struct node *node )
1950 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1951 elem->isEmpty = is_empty_element( node );
1952 return write_endelement( writer, elem );
1955 static HRESULT write_endelement_node( struct writer *writer )
1957 struct node *node;
1958 HRESULT hr;
1960 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1961 if (writer->state == WRITER_STATE_STARTELEMENT)
1963 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1964 if ((hr = write_startelement( writer )) != S_OK) return hr;
1966 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1967 writer->current = node->parent;
1968 writer->state = WRITER_STATE_ENDELEMENT;
1969 return S_OK;
1972 /**************************************************************************
1973 * WsWriteEndElement [webservices.@]
1975 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1977 struct writer *writer = (struct writer *)handle;
1978 HRESULT hr;
1980 TRACE( "%p %p\n", handle, error );
1981 if (error) FIXME( "ignoring error parameter\n" );
1983 if (!writer) return E_INVALIDARG;
1985 EnterCriticalSection( &writer->cs );
1987 if (writer->magic != WRITER_MAGIC)
1989 LeaveCriticalSection( &writer->cs );
1990 return E_INVALIDARG;
1993 hr = write_endelement_node( writer );
1995 LeaveCriticalSection( &writer->cs );
1996 TRACE( "returning %08x\n", hr );
1997 return hr;
2000 static HRESULT write_endstartelement_text( struct writer *writer )
2002 HRESULT hr;
2003 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2004 write_char( writer, '>' );
2005 return S_OK;
2008 static HRESULT write_endstartelement( struct writer *writer )
2010 switch (writer->output_enc)
2012 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
2013 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
2014 default:
2015 ERR( "unhandled encoding %u\n", writer->output_enc );
2016 return WS_E_NOT_SUPPORTED;
2020 /**************************************************************************
2021 * WsWriteEndStartElement [webservices.@]
2023 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
2025 struct writer *writer = (struct writer *)handle;
2026 HRESULT hr;
2028 TRACE( "%p %p\n", handle, error );
2029 if (error) FIXME( "ignoring error parameter\n" );
2031 if (!writer) return E_INVALIDARG;
2033 EnterCriticalSection( &writer->cs );
2035 if (writer->magic != WRITER_MAGIC)
2037 LeaveCriticalSection( &writer->cs );
2038 return E_INVALIDARG;
2041 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2042 else
2044 if ((hr = set_namespaces( writer )) != S_OK) goto done;
2045 if ((hr = write_startelement( writer )) != S_OK) goto done;
2046 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
2047 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2050 done:
2051 LeaveCriticalSection( &writer->cs );
2052 TRACE( "returning %08x\n", hr );
2053 return hr;
2056 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
2057 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2058 BOOL single )
2060 WS_XML_ATTRIBUTE *attr;
2061 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2062 HRESULT hr;
2064 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
2066 if (!prefix && ns->length) prefix = elem->prefix;
2068 attr->singleQuote = !!single;
2069 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2071 free_attribute( attr );
2072 return E_OUTOFMEMORY;
2074 if (!(attr->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2076 free_attribute( attr );
2077 return E_OUTOFMEMORY;
2079 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2081 free_attribute( attr );
2082 return E_OUTOFMEMORY;
2084 if ((hr = append_attribute( elem, attr )) != S_OK)
2086 free_attribute( attr );
2087 return hr;
2089 return S_OK;
2092 /**************************************************************************
2093 * WsWriteStartAttribute [webservices.@]
2095 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2096 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2097 BOOL single, WS_ERROR *error )
2099 struct writer *writer = (struct writer *)handle;
2100 HRESULT hr;
2102 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2103 debugstr_xmlstr(ns), single, error );
2104 if (error) FIXME( "ignoring error parameter\n" );
2106 if (!writer || !localname || !ns) return E_INVALIDARG;
2108 EnterCriticalSection( &writer->cs );
2110 if (writer->magic != WRITER_MAGIC)
2112 LeaveCriticalSection( &writer->cs );
2113 return E_INVALIDARG;
2116 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
2117 else if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
2118 writer->state = WRITER_STATE_STARTATTRIBUTE;
2120 LeaveCriticalSection( &writer->cs );
2121 TRACE( "returning %08x\n", hr );
2122 return hr;
2125 /* flush current start element if necessary */
2126 static HRESULT write_commit( struct writer *writer )
2128 if (writer->state == WRITER_STATE_STARTELEMENT)
2130 HRESULT hr;
2131 if ((hr = set_namespaces( writer )) != S_OK) return hr;
2132 if ((hr = write_startelement( writer )) != S_OK) return hr;
2133 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
2134 writer->state = WRITER_STATE_ENDSTARTELEMENT;
2136 return S_OK;
2139 static HRESULT write_add_cdata_node( struct writer *writer )
2141 struct node *node, *parent;
2142 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2143 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2144 write_insert_node( writer, parent, node );
2145 return S_OK;
2148 static HRESULT write_add_endcdata_node( struct writer *writer )
2150 struct node *node;
2151 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
2152 node->parent = writer->current;
2153 list_add_tail( &node->parent->children, &node->entry );
2154 return S_OK;
2157 static HRESULT write_cdata( struct writer *writer )
2159 HRESULT hr;
2160 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
2161 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
2162 return S_OK;
2165 static HRESULT write_cdata_node( struct writer *writer )
2167 HRESULT hr;
2168 if ((hr = write_commit( writer )) != S_OK) return hr;
2169 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
2170 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
2171 if ((hr = write_cdata( writer )) != S_OK) return hr;
2172 writer->state = WRITER_STATE_STARTCDATA;
2173 return S_OK;
2176 /**************************************************************************
2177 * WsWriteStartCData [webservices.@]
2179 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
2181 struct writer *writer = (struct writer *)handle;
2182 HRESULT hr;
2184 TRACE( "%p %p\n", handle, error );
2185 if (error) FIXME( "ignoring error parameter\n" );
2187 if (!writer) return E_INVALIDARG;
2189 EnterCriticalSection( &writer->cs );
2191 if (writer->magic != WRITER_MAGIC)
2193 LeaveCriticalSection( &writer->cs );
2194 return E_INVALIDARG;
2197 hr = write_cdata_node( writer );
2199 LeaveCriticalSection( &writer->cs );
2200 TRACE( "returning %08x\n", hr );
2201 return hr;
2204 static HRESULT write_endcdata( struct writer *writer )
2206 HRESULT hr;
2207 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2208 write_bytes( writer, (const BYTE *)"]]>", 3 );
2209 return S_OK;
2212 static HRESULT write_endcdata_node( struct writer *writer )
2214 HRESULT hr;
2215 if ((hr = write_endcdata( writer )) != S_OK) return hr;
2216 writer->current = writer->current->parent;
2217 writer->state = WRITER_STATE_ENDCDATA;
2218 return S_OK;
2221 /**************************************************************************
2222 * WsWriteEndCData [webservices.@]
2224 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
2226 struct writer *writer = (struct writer *)handle;
2227 HRESULT hr;
2229 TRACE( "%p %p\n", handle, error );
2230 if (error) FIXME( "ignoring error parameter\n" );
2232 if (!writer) return E_INVALIDARG;
2234 EnterCriticalSection( &writer->cs );
2236 if (writer->magic != WRITER_MAGIC)
2238 LeaveCriticalSection( &writer->cs );
2239 return E_INVALIDARG;
2242 if (writer->state != WRITER_STATE_TEXT) hr = WS_E_INVALID_OPERATION;
2243 else hr = write_endcdata_node( writer );
2245 LeaveCriticalSection( &writer->cs );
2246 TRACE( "returning %08x\n", hr );
2247 return hr;
2250 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2251 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2253 struct node *node, *parent;
2254 WS_XML_ELEMENT_NODE *elem;
2256 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
2258 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
2260 elem = &parent->hdr;
2261 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
2264 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
2265 elem = &node->hdr;
2267 if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
2269 free_node( node );
2270 return E_OUTOFMEMORY;
2272 if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
2274 free_node( node );
2275 return E_OUTOFMEMORY;
2277 if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
2279 free_node( node );
2280 return E_OUTOFMEMORY;
2282 write_insert_node( writer, parent, node );
2283 return S_OK;
2286 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
2288 struct node *node;
2289 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
2290 node->parent = parent;
2291 list_add_tail( &parent->children, &node->entry );
2292 return S_OK;
2295 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
2296 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
2298 HRESULT hr;
2299 if ((hr = write_commit( writer )) != S_OK) return hr;
2300 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
2301 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
2302 writer->state = WRITER_STATE_STARTELEMENT;
2303 return S_OK;
2306 /**************************************************************************
2307 * WsWriteStartElement [webservices.@]
2309 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
2310 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2311 WS_ERROR *error )
2313 struct writer *writer = (struct writer *)handle;
2314 HRESULT hr;
2316 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
2317 debugstr_xmlstr(ns), error );
2318 if (error) FIXME( "ignoring error parameter\n" );
2320 if (!writer || !localname || !ns) return E_INVALIDARG;
2322 EnterCriticalSection( &writer->cs );
2324 if (writer->magic != WRITER_MAGIC)
2326 LeaveCriticalSection( &writer->cs );
2327 return E_INVALIDARG;
2330 hr = write_element_node( writer, prefix, localname, ns );
2332 LeaveCriticalSection( &writer->cs );
2333 TRACE( "returning %08x\n", hr );
2334 return hr;
2337 HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2339 if (offset) *offset = 0;
2340 switch (text->textType)
2342 case WS_XML_TEXT_TYPE_UTF8:
2344 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2345 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2346 WS_XML_UTF8_TEXT *new;
2347 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2349 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2350 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2351 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2352 if (offset) *offset = len_old;
2353 *ret = &new->text;
2354 return S_OK;
2356 case WS_XML_TEXT_TYPE_UTF16:
2358 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2359 const WS_XML_UTF16_TEXT *utf16_old = (const WS_XML_UTF16_TEXT *)old;
2360 WS_XML_UTF16_TEXT *new;
2361 ULONG len = utf16->byteCount, len_old = utf16_old ? utf16_old->byteCount : 0;
2363 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2364 if (!(new = alloc_utf16_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2365 if (utf16_old) memcpy( new->bytes, utf16_old->bytes, len_old );
2366 memcpy( new->bytes + len_old, utf16->bytes, len );
2367 if (offset) *offset = len_old;
2368 *ret = &new->text;
2369 return S_OK;
2371 case WS_XML_TEXT_TYPE_BASE64:
2373 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2374 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2375 WS_XML_BASE64_TEXT *new;
2376 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2378 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2379 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2380 memcpy( new->bytes + len_old, base64->bytes, len );
2381 if (offset) *offset = len_old;
2382 *ret = &new->text;
2383 return S_OK;
2385 case WS_XML_TEXT_TYPE_BOOL:
2387 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2388 WS_XML_BOOL_TEXT *new;
2390 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2391 *ret = &new->text;
2392 return S_OK;
2394 case WS_XML_TEXT_TYPE_INT32:
2396 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2397 WS_XML_INT32_TEXT *new;
2399 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2400 *ret = &new->text;
2401 return S_OK;
2403 case WS_XML_TEXT_TYPE_INT64:
2405 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2406 WS_XML_INT64_TEXT *new;
2408 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2409 *ret = &new->text;
2410 return S_OK;
2412 case WS_XML_TEXT_TYPE_UINT64:
2414 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2415 WS_XML_UINT64_TEXT *new;
2417 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2418 *ret = &new->text;
2419 return S_OK;
2421 case WS_XML_TEXT_TYPE_DOUBLE:
2423 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2424 WS_XML_DOUBLE_TEXT *new;
2426 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2427 *ret = &new->text;
2428 return S_OK;
2430 case WS_XML_TEXT_TYPE_GUID:
2432 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2433 WS_XML_GUID_TEXT *new;
2435 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2436 *ret = &new->text;
2437 return S_OK;
2439 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2441 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2442 WS_XML_UNIQUE_ID_TEXT *new;
2444 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2445 *ret = &new->text;
2446 return S_OK;
2448 case WS_XML_TEXT_TYPE_DATETIME:
2450 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2451 WS_XML_DATETIME_TEXT *new;
2453 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2454 *ret = &new->text;
2455 return S_OK;
2457 default:
2458 FIXME( "unhandled text type %u\n", text->textType );
2459 return E_NOTIMPL;
2463 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2465 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2466 HRESULT hr;
2468 switch (value->textType)
2470 case WS_XML_TEXT_TYPE_UTF8:
2471 case WS_XML_TEXT_TYPE_UTF16:
2472 case WS_XML_TEXT_TYPE_BASE64:
2473 break;
2475 case WS_XML_TEXT_TYPE_BOOL:
2476 case WS_XML_TEXT_TYPE_INT32:
2477 case WS_XML_TEXT_TYPE_INT64:
2478 case WS_XML_TEXT_TYPE_UINT64:
2479 case WS_XML_TEXT_TYPE_DOUBLE:
2480 case WS_XML_TEXT_TYPE_GUID:
2481 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2482 case WS_XML_TEXT_TYPE_DATETIME:
2483 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2484 break;
2486 default:
2487 FIXME( "unhandled text type %u\n", value->textType );
2488 return E_NOTIMPL;
2491 switch (writer->output_enc)
2493 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2495 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2496 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2497 heap_free( old );
2498 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2499 break;
2501 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2503 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2504 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2505 heap_free( old );
2506 elem->attributes[elem->attributeCount - 1]->value = new;
2507 break;
2509 default:
2510 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2511 return E_NOTIMPL;
2514 return S_OK;
2517 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2519 struct node *node;
2520 WS_XML_TEXT_NODE *text;
2521 HRESULT hr;
2523 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2524 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2525 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2527 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2528 text = (WS_XML_TEXT_NODE *)node;
2530 switch (writer->output_enc)
2532 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2534 WS_XML_UTF8_TEXT *new;
2535 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2537 heap_free( node );
2538 return hr;
2540 text->text = &new->text;
2541 break;
2543 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2545 WS_XML_TEXT *new;
2546 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2548 heap_free( node );
2549 return hr;
2551 text->text = new;
2552 break;
2554 default:
2555 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2556 heap_free( node );
2557 return E_NOTIMPL;
2560 write_insert_node( writer, writer->current, node );
2561 return S_OK;
2564 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2566 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2567 HRESULT hr;
2569 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2571 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2572 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2574 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2576 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2577 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2578 return S_OK;
2581 return WS_E_INVALID_FORMAT;
2584 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
2586 switch (text->textType)
2588 case WS_XML_TEXT_TYPE_UTF8:
2590 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2591 if (use_dict) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT;
2592 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2593 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2594 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2596 case WS_XML_TEXT_TYPE_UTF16:
2598 const WS_XML_UTF16_TEXT *text_utf16 = (const WS_XML_UTF16_TEXT *)text;
2599 int len = text_utf16->byteCount / sizeof(WCHAR);
2600 int len_utf8 = WideCharToMultiByte( CP_UTF8, 0, (const WCHAR *)text_utf16->bytes, len, NULL, 0, NULL, NULL );
2601 if (len_utf8 <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2602 if (len_utf8 <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2603 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2605 case WS_XML_TEXT_TYPE_BASE64:
2607 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2608 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2609 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2610 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2611 return RECORD_BYTES32_TEXT;
2613 case WS_XML_TEXT_TYPE_BOOL:
2615 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2616 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2618 case WS_XML_TEXT_TYPE_INT32:
2620 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2621 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2622 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2623 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2624 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2625 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2627 case WS_XML_TEXT_TYPE_INT64:
2629 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2630 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2631 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2632 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2633 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2634 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2635 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2637 case WS_XML_TEXT_TYPE_UINT64:
2639 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2640 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2641 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2642 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2643 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2644 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2645 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2646 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2648 case WS_XML_TEXT_TYPE_DOUBLE:
2650 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2651 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2652 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2653 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2654 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2655 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2656 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2657 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2658 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2660 case WS_XML_TEXT_TYPE_GUID:
2661 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2663 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2664 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2666 case WS_XML_TEXT_TYPE_DATETIME:
2667 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2669 default:
2670 FIXME( "unhandled text type %u\n", text->textType );
2671 return 0;
2675 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2677 enum record_type type;
2678 BOOL use_dict = FALSE;
2679 HRESULT hr;
2680 ULONG id;
2682 if (offset)
2684 FIXME( "no support for appending text in binary mode\n" );
2685 return E_NOTIMPL;
2688 if (text->textType == WS_XML_TEXT_TYPE_UTF8)
2690 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2691 use_dict = get_string_id( writer, &utf8->value, &id );
2694 switch ((type = get_text_record_type( text, use_dict )))
2696 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2698 const WS_XML_UTF8_TEXT *text_utf8;
2699 WS_XML_UTF8_TEXT *new = NULL;
2700 UINT8 len;
2702 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2703 else
2705 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2706 text_utf8 = new;
2708 len = text_utf8->value.length;
2709 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2711 heap_free( new );
2712 return hr;
2714 write_char( writer, type );
2715 write_char( writer, len );
2716 write_bytes( writer, text_utf8->value.bytes, len );
2717 heap_free( new );
2718 return S_OK;
2720 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2722 const WS_XML_UTF8_TEXT *text_utf8;
2723 WS_XML_UTF8_TEXT *new = NULL;
2724 UINT16 len;
2726 if (text->textType == WS_XML_TEXT_TYPE_UTF8) text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2727 else
2729 if ((hr = text_to_utf8text( text, NULL, NULL, &new )) != S_OK) return hr;
2730 text_utf8 = new;
2732 len = text_utf8->value.length;
2733 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK)
2735 heap_free( new );
2736 return hr;
2738 write_char( writer, type );
2739 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2740 write_bytes( writer, text_utf8->value.bytes, len );
2741 heap_free( new );
2742 return S_OK;
2744 case RECORD_BYTES8_TEXT:
2746 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2747 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2749 if (len)
2751 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2752 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2753 write_char( writer, len );
2754 write_bytes( writer, text_base64->bytes, len );
2756 if (rem)
2758 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2759 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2760 write_char( writer, rem );
2761 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2763 return S_OK;
2765 case RECORD_BYTES16_TEXT:
2767 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2768 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2770 if (len)
2772 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2773 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2774 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2775 write_bytes( writer, text_base64->bytes, len );
2777 if (rem)
2779 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2780 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2781 write_char( writer, rem );
2782 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2784 return S_OK;
2786 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2787 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2788 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2789 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2791 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2792 write_char( writer, type );
2793 return S_OK;
2795 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2797 INT8 val = get_text_value_int( text );
2798 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2799 write_char( writer, type );
2800 write_char( writer, val );
2801 return S_OK;
2803 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2805 INT16 val = get_text_value_int( text );
2806 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2807 write_char( writer, type );
2808 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2809 return S_OK;
2811 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2813 INT32 val = get_text_value_int( text );
2814 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2815 write_char( writer, type );
2816 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2817 return S_OK;
2819 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2821 INT64 val = get_text_value_int( text );
2822 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2823 write_char( writer, type );
2824 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2825 return S_OK;
2827 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2829 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2830 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2831 write_char( writer, type );
2832 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2833 return S_OK;
2835 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2837 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2838 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2839 write_char( writer, type );
2840 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2841 return S_OK;
2843 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2845 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2846 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2847 write_char( writer, type );
2848 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2849 return S_OK;
2851 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2853 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2854 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2855 write_char( writer, type );
2856 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2857 return S_OK;
2859 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2861 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2862 UINT64 val = text_datetime->value.ticks;
2864 assert( val <= TICKS_MAX );
2865 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2866 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2868 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2869 write_char( writer, type );
2870 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2871 return S_OK;
2873 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
2875 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2876 write_char( writer, type );
2877 return write_dict_string( writer, id );
2879 default:
2880 FIXME( "unhandled record type %02x\n", type );
2881 return E_NOTIMPL;
2885 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2887 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2889 switch (writer->output_enc)
2891 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2892 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2893 default:
2894 ERR( "unhandled encoding %u\n", writer->output_enc );
2895 return WS_E_NOT_SUPPORTED;
2899 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2901 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2902 ULONG offset = 0;
2903 HRESULT hr;
2905 if ((hr = write_commit( writer )) != S_OK) return hr;
2906 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2908 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2909 node = (WS_XML_TEXT_NODE *)writer->current;
2911 else
2913 switch (writer->output_enc)
2915 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2917 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2918 offset = old->value.length;
2919 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2920 heap_free( old );
2921 node->text = &new->text;
2922 break;
2924 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2926 WS_XML_TEXT *new, *old = node->text;
2927 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2928 heap_free( old );
2929 node->text = new;
2930 break;
2932 default:
2933 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2934 return E_NOTIMPL;
2938 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2940 writer->state = WRITER_STATE_TEXT;
2941 return S_OK;
2944 /**************************************************************************
2945 * WsWriteText [webservices.@]
2947 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2949 struct writer *writer = (struct writer *)handle;
2950 HRESULT hr;
2952 TRACE( "%p %p %p\n", handle, text, error );
2953 if (error) FIXME( "ignoring error parameter\n" );
2955 if (!writer || !text) return E_INVALIDARG;
2957 EnterCriticalSection( &writer->cs );
2959 if (writer->magic != WRITER_MAGIC)
2961 LeaveCriticalSection( &writer->cs );
2962 return E_INVALIDARG;
2965 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2966 else hr = write_text_node( writer, text );
2968 LeaveCriticalSection( &writer->cs );
2969 TRACE( "returning %08x\n", hr );
2970 return hr;
2973 /**************************************************************************
2974 * WsWriteBytes [webservices.@]
2976 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2978 struct writer *writer = (struct writer *)handle;
2979 WS_XML_BASE64_TEXT base64;
2980 HRESULT hr;
2982 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2983 if (error) FIXME( "ignoring error parameter\n" );
2985 if (!writer) return E_INVALIDARG;
2987 EnterCriticalSection( &writer->cs );
2989 if (writer->magic != WRITER_MAGIC)
2991 LeaveCriticalSection( &writer->cs );
2992 return E_INVALIDARG;
2995 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
2996 else
2998 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2999 base64.bytes = (BYTE *)bytes;
3000 base64.length = count;
3002 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
3003 else hr = write_text_node( writer, &base64.text );
3006 LeaveCriticalSection( &writer->cs );
3007 TRACE( "returning %08x\n", hr );
3008 return hr;
3011 /**************************************************************************
3012 * WsWriteChars [webservices.@]
3014 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
3016 struct writer *writer = (struct writer *)handle;
3017 WS_XML_UTF16_TEXT utf16;
3018 HRESULT hr;
3020 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
3021 if (error) FIXME( "ignoring error parameter\n" );
3023 if (!writer) return E_INVALIDARG;
3025 EnterCriticalSection( &writer->cs );
3027 if (writer->magic != WRITER_MAGIC)
3029 LeaveCriticalSection( &writer->cs );
3030 return E_INVALIDARG;
3033 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3034 else
3036 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3037 utf16.bytes = (BYTE *)chars;
3038 utf16.byteCount = count * sizeof(WCHAR);
3040 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
3041 else hr = write_text_node( writer, &utf16.text );
3044 LeaveCriticalSection( &writer->cs );
3045 TRACE( "returning %08x\n", hr );
3046 return hr;
3049 /**************************************************************************
3050 * WsWriteCharsUtf8 [webservices.@]
3052 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
3054 struct writer *writer = (struct writer *)handle;
3055 WS_XML_UTF8_TEXT utf8;
3056 HRESULT hr;
3058 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
3059 if (error) FIXME( "ignoring error parameter\n" );
3061 if (!writer) return E_INVALIDARG;
3063 EnterCriticalSection( &writer->cs );
3065 if (writer->magic != WRITER_MAGIC)
3067 LeaveCriticalSection( &writer->cs );
3068 return E_INVALIDARG;
3071 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
3072 else
3074 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3075 utf8.value.bytes = (BYTE *)bytes;
3076 utf8.value.length = count;
3078 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
3079 else hr = write_text_node( writer, &utf8.text );
3082 LeaveCriticalSection( &writer->cs );
3083 TRACE( "returning %08x\n", hr );
3084 return hr;
3087 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
3089 switch (mapping)
3091 case WS_ELEMENT_TYPE_MAPPING:
3092 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3093 return write_text_node( writer, text );
3095 case WS_ATTRIBUTE_TYPE_MAPPING:
3096 return write_set_attribute_value( writer, text );
3098 case WS_ANY_ELEMENT_TYPE_MAPPING:
3099 switch (writer->state)
3101 case WRITER_STATE_STARTATTRIBUTE:
3102 return write_set_attribute_value( writer, text );
3104 case WRITER_STATE_STARTELEMENT:
3105 return write_text_node( writer, text );
3107 default:
3108 FIXME( "writer state %u not handled\n", writer->state );
3109 return E_NOTIMPL;
3112 default:
3113 FIXME( "mapping %u not implemented\n", mapping );
3114 return E_NOTIMPL;
3118 static HRESULT write_add_nil_attribute( struct writer *writer )
3120 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
3121 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
3122 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
3123 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
3124 HRESULT hr;
3126 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
3127 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
3128 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
3131 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
3132 const void **ptr )
3134 switch (option)
3136 case WS_WRITE_REQUIRED_VALUE:
3137 case WS_WRITE_NILLABLE_VALUE:
3138 if (!value || size != expected_size) return E_INVALIDARG;
3139 *ptr = value;
3140 return S_OK;
3142 case WS_WRITE_REQUIRED_POINTER:
3143 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
3144 return S_OK;
3146 case WS_WRITE_NILLABLE_POINTER:
3147 if (size != sizeof(const void *)) return E_INVALIDARG;
3148 *ptr = *(const void **)value;
3149 return S_OK;
3151 default:
3152 return E_INVALIDARG;
3156 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
3157 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
3158 const BOOL *value, ULONG size )
3160 WS_XML_BOOL_TEXT text_bool;
3161 const BOOL *ptr;
3162 HRESULT hr;
3164 if (desc)
3166 FIXME( "description not supported\n" );
3167 return E_NOTIMPL;
3170 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3171 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
3172 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3174 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
3175 text_bool.value = *ptr;
3176 return write_type_text( writer, mapping, &text_bool.text );
3179 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3180 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3181 const BOOL *value, ULONG size )
3183 WS_XML_INT32_TEXT text_int32;
3184 const INT8 *ptr;
3185 HRESULT hr;
3187 if (desc)
3189 FIXME( "description not supported\n" );
3190 return E_NOTIMPL;
3193 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3194 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3195 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3197 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3198 text_int32.value = *ptr;
3199 return write_type_text( writer, mapping, &text_int32.text );
3202 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3203 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3204 const BOOL *value, ULONG size )
3206 WS_XML_INT32_TEXT text_int32;
3207 const INT16 *ptr;
3208 HRESULT hr;
3210 if (desc)
3212 FIXME( "description not supported\n" );
3213 return E_NOTIMPL;
3216 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3217 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3218 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3220 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3221 text_int32.value = *ptr;
3222 return write_type_text( writer, mapping, &text_int32.text );
3225 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3226 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3227 const void *value, ULONG size )
3229 WS_XML_INT32_TEXT text_int32;
3230 const INT32 *ptr;
3231 HRESULT hr;
3233 if (desc)
3235 FIXME( "description not supported\n" );
3236 return E_NOTIMPL;
3239 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3240 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3241 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3243 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3244 text_int32.value = *ptr;
3245 return write_type_text( writer, mapping, &text_int32.text );
3248 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3249 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3250 const void *value, ULONG size )
3252 WS_XML_INT64_TEXT text_int64;
3253 const INT64 *ptr;
3254 HRESULT hr;
3256 if (desc)
3258 FIXME( "description not supported\n" );
3259 return E_NOTIMPL;
3262 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3263 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3264 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3266 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3267 text_int64.value = *ptr;
3268 return write_type_text( writer, mapping, &text_int64.text );
3271 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3272 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3273 const void *value, ULONG size )
3275 WS_XML_UINT64_TEXT text_uint64;
3276 const UINT8 *ptr;
3277 HRESULT hr;
3279 if (desc)
3281 FIXME( "description not supported\n" );
3282 return E_NOTIMPL;
3285 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3286 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3287 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3289 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3290 text_uint64.value = *ptr;
3291 return write_type_text( writer, mapping, &text_uint64.text );
3294 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3295 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3296 const void *value, ULONG size )
3298 WS_XML_UINT64_TEXT text_uint64;
3299 const UINT16 *ptr;
3300 HRESULT hr;
3302 if (desc)
3304 FIXME( "description not supported\n" );
3305 return E_NOTIMPL;
3308 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3309 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3310 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3312 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3313 text_uint64.value = *ptr;
3314 return write_type_text( writer, mapping, &text_uint64.text );
3317 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3318 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3319 const void *value, ULONG size )
3321 WS_XML_UINT64_TEXT text_uint64;
3322 const UINT32 *ptr;
3323 HRESULT hr;
3325 if (desc)
3327 FIXME( "description not supported\n" );
3328 return E_NOTIMPL;
3331 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3332 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3333 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3335 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3336 text_uint64.value = *ptr;
3337 return write_type_text( writer, mapping, &text_uint64.text );
3340 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3341 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3342 const void *value, ULONG size )
3344 WS_XML_UINT64_TEXT text_uint64;
3345 const UINT64 *ptr;
3346 HRESULT hr;
3348 if (desc)
3350 FIXME( "description not supported\n" );
3351 return E_NOTIMPL;
3354 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3355 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3356 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3358 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3359 text_uint64.value = *ptr;
3360 return write_type_text( writer, mapping, &text_uint64.text );
3363 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3364 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3365 const void *value, ULONG size )
3367 WS_XML_DOUBLE_TEXT text_double;
3368 const double *ptr;
3369 HRESULT hr;
3371 if (desc)
3373 FIXME( "description not supported\n" );
3374 return E_NOTIMPL;
3377 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3378 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3379 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3381 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3382 text_double.value = *ptr;
3383 return write_type_text( writer, mapping, &text_double.text );
3386 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3387 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3388 const void *value, ULONG size )
3390 WS_XML_DATETIME_TEXT text_datetime;
3391 const WS_DATETIME *ptr;
3392 HRESULT hr;
3394 if (desc)
3396 FIXME( "description not supported\n" );
3397 return E_NOTIMPL;
3400 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3401 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3402 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3403 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3405 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3406 text_datetime.value = *ptr;
3407 return write_type_text( writer, mapping, &text_datetime.text );
3410 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3411 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3412 const void *value, ULONG size )
3414 WS_XML_GUID_TEXT text_guid;
3415 const GUID *ptr;
3416 HRESULT hr;
3418 if (desc)
3420 FIXME( "description not supported\n" );
3421 return E_NOTIMPL;
3424 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3425 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3426 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3428 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3429 text_guid.value = *ptr;
3430 return write_type_text( writer, mapping, &text_guid.text );
3433 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3434 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3435 const void *value, ULONG size )
3437 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3438 WS_XML_UTF16_TEXT text_utf16;
3439 const WS_UNIQUE_ID *ptr;
3440 HRESULT hr;
3442 if (desc)
3444 FIXME( "description not supported\n" );
3445 return E_NOTIMPL;
3448 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3449 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3450 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3452 if (ptr->uri.length)
3454 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3455 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3456 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3457 return write_type_text( writer, mapping, &text_utf16.text );
3460 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3461 text_unique_id.value = ptr->guid;
3462 return write_type_text( writer, mapping, &text_unique_id.text );
3465 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3466 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3467 const void *value, ULONG size )
3469 WS_XML_UTF16_TEXT utf16;
3470 const WS_STRING *ptr;
3471 HRESULT hr;
3473 if (desc)
3475 FIXME( "description not supported\n" );
3476 return E_NOTIMPL;
3479 if (!option) return E_INVALIDARG;
3480 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3481 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3482 if (!ptr->length) return S_OK;
3484 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3485 utf16.bytes = (BYTE *)ptr->chars;
3486 utf16.byteCount = ptr->length * sizeof(WCHAR);
3487 return write_type_text( writer, mapping, &utf16.text );
3490 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3491 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3492 const void *value, ULONG size )
3494 WS_XML_UTF16_TEXT utf16;
3495 const WCHAR *ptr;
3496 HRESULT hr;
3497 int len;
3499 if (desc)
3501 FIXME( "description not supported\n" );
3502 return E_NOTIMPL;
3505 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3506 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3507 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3508 if (!(len = strlenW( ptr ))) return S_OK;
3510 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3511 utf16.bytes = (BYTE *)ptr;
3512 utf16.byteCount = len * sizeof(WCHAR);
3513 return write_type_text( writer, mapping, &utf16.text );
3516 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3517 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3518 const void *value, ULONG size )
3520 WS_XML_BASE64_TEXT base64;
3521 const WS_BYTES *ptr;
3522 HRESULT hr;
3524 if (desc)
3526 FIXME( "description not supported\n" );
3527 return E_NOTIMPL;
3530 if (!option) return E_INVALIDARG;
3531 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3532 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3533 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3534 if (!ptr->length) return S_OK;
3536 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3537 base64.bytes = ptr->bytes;
3538 base64.length = ptr->length;
3539 return write_type_text( writer, mapping, &base64.text );
3542 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3543 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3544 const void *value, ULONG size )
3546 WS_XML_UTF8_TEXT utf8;
3547 const WS_XML_STRING *ptr;
3548 HRESULT hr;
3550 if (desc)
3552 FIXME( "description not supported\n" );
3553 return E_NOTIMPL;
3556 if (!option) return E_INVALIDARG;
3557 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3558 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3559 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3560 if (!ptr->length) return S_OK;
3562 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3563 utf8.value.bytes = ptr->bytes;
3564 utf8.value.length = ptr->length;
3565 return write_type_text( writer, mapping, &utf8.text );
3568 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3570 const struct node *node;
3571 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3573 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3574 ULONG i;
3575 for (i = 0; i < elem->attributeCount; i++)
3577 if (!elem->attributes[i]->isXmlNs) continue;
3578 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3579 *prefix = elem->attributes[i]->prefix;
3580 return S_OK;
3583 return WS_E_INVALID_FORMAT;
3586 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3587 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3588 const void *value, ULONG size )
3590 WS_XML_QNAME_TEXT qname;
3591 const WS_XML_QNAME *ptr;
3592 const WS_XML_STRING *prefix;
3593 HRESULT hr;
3595 if (desc)
3597 FIXME( "description not supported\n" );
3598 return E_NOTIMPL;
3601 if (!option) return E_INVALIDARG;
3602 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3603 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3604 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3606 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3608 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3609 qname.prefix = (WS_XML_STRING *)prefix;
3610 qname.localName = (WS_XML_STRING *)&ptr->localName;
3611 qname.ns = (WS_XML_STRING *)&ptr->ns;
3612 return write_type_text( writer, mapping, &qname.text );
3615 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3617 if (options & WS_FIELD_POINTER)
3619 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3620 return WS_WRITE_REQUIRED_POINTER;
3623 switch (type)
3625 case WS_BOOL_TYPE:
3626 case WS_INT8_TYPE:
3627 case WS_INT16_TYPE:
3628 case WS_INT32_TYPE:
3629 case WS_INT64_TYPE:
3630 case WS_UINT8_TYPE:
3631 case WS_UINT16_TYPE:
3632 case WS_UINT32_TYPE:
3633 case WS_UINT64_TYPE:
3634 case WS_DOUBLE_TYPE:
3635 case WS_DATETIME_TYPE:
3636 case WS_GUID_TYPE:
3637 case WS_UNIQUE_ID_TYPE:
3638 case WS_STRING_TYPE:
3639 case WS_BYTES_TYPE:
3640 case WS_XML_STRING_TYPE:
3641 case WS_XML_QNAME_TYPE:
3642 case WS_STRUCT_TYPE:
3643 case WS_ENUM_TYPE:
3644 case WS_UNION_TYPE:
3645 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3646 return WS_WRITE_REQUIRED_VALUE;
3648 case WS_WSZ_TYPE:
3649 case WS_DESCRIPTION_TYPE:
3650 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3651 return WS_WRITE_REQUIRED_POINTER;
3653 default:
3654 FIXME( "unhandled type %u\n", type );
3655 return 0;
3659 static HRESULT find_index( const WS_UNION_DESCRIPTION *desc, int value, ULONG *idx )
3661 ULONG i;
3663 if (desc->valueIndices)
3665 int c, min = 0, max = desc->fieldCount - 1;
3666 while (min <= max)
3668 i = (min + max) / 2;
3669 c = value - desc->fields[desc->valueIndices[i]]->value;
3670 if (c < 0)
3671 max = i - 1;
3672 else if (c > 0)
3673 min = i + 1;
3674 else
3676 *idx = desc->valueIndices[i];
3677 return S_OK;
3680 return WS_E_INVALID_FORMAT;
3683 /* fall back to linear search */
3684 for (i = 0; i < desc->fieldCount; i++)
3686 if (desc->fields[i]->value == value)
3688 *idx = i;
3689 return S_OK;
3692 return WS_E_INVALID_FORMAT;
3695 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3697 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3698 const void *value, ULONG size )
3700 ULONG i;
3701 const void *ptr;
3702 int enum_value;
3703 HRESULT hr;
3705 if (size < sizeof(enum_value)) return E_INVALIDARG;
3706 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3708 enum_value = *(int *)(char *)ptr + desc->enumOffset;
3709 if (enum_value == desc->noneEnumValue && option == WS_WRITE_NILLABLE_VALUE) return S_OK;
3711 if ((hr = find_index( desc, enum_value, &i )) != S_OK) return hr;
3712 return write_type_field( writer, &desc->fields[i]->field, ptr, desc->fields[i]->field.offset );
3715 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3716 const void *, ULONG );
3718 static HRESULT write_type_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3719 ULONG count )
3721 HRESULT hr = S_OK;
3722 ULONG i, size, offset = 0;
3723 WS_WRITE_OPTION option;
3725 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3727 /* wrapper element */
3728 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3729 return hr;
3731 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3732 size = get_type_size( desc->type, desc->typeDescription );
3733 else
3734 size = sizeof(const void *);
3736 for (i = 0; i < count; i++)
3738 if (desc->type == WS_UNION_TYPE)
3740 if ((hr = write_type_union( writer, desc->typeDescription, option, buf + offset, size )) != S_OK)
3741 return hr;
3743 else
3745 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3746 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3747 buf + offset, size )) != S_OK) return hr;
3748 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3750 offset += size;
3753 if (desc->localName) hr = write_endelement_node( writer );
3754 return hr;
3757 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3758 ULONG offset )
3760 HRESULT hr;
3761 WS_TYPE_MAPPING mapping;
3762 WS_WRITE_OPTION option;
3763 ULONG count, size, field_options = desc->options;
3764 const char *ptr = buf + offset;
3766 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
3768 FIXME( "options 0x%x not supported\n", desc->options );
3769 return E_NOTIMPL;
3772 /* zero-terminated strings are always pointers */
3773 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
3775 if (field_options & WS_FIELD_POINTER)
3776 size = sizeof(const void *);
3777 else
3778 size = get_type_size( desc->type, desc->typeDescription );
3780 if (is_nil_value( ptr, size ))
3782 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3783 if (field_options & WS_FIELD_NILLABLE)
3785 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3786 else option = WS_WRITE_NILLABLE_VALUE;
3788 else
3790 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3791 else option = WS_WRITE_REQUIRED_VALUE;
3794 else
3796 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3797 else option = WS_WRITE_REQUIRED_VALUE;
3800 switch (desc->mapping)
3802 case WS_ATTRIBUTE_FIELD_MAPPING:
3803 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3804 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3805 return hr;
3806 writer->state = WRITER_STATE_STARTATTRIBUTE;
3808 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3809 break;
3811 case WS_ELEMENT_FIELD_MAPPING:
3812 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3813 mapping = WS_ELEMENT_TYPE_MAPPING;
3814 break;
3816 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3817 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3818 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3819 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3821 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3822 case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING:
3823 count = *(const ULONG *)(buf + desc->countOffset);
3824 return write_type_array( writer, desc, *(const char **)ptr, count );
3826 case WS_TEXT_FIELD_MAPPING:
3827 switch (writer->state)
3829 case WRITER_STATE_STARTELEMENT:
3830 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3831 break;
3833 case WRITER_STATE_STARTATTRIBUTE:
3834 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3835 break;
3837 default:
3838 FIXME( "unhandled writer state %u\n", writer->state );
3839 return E_NOTIMPL;
3841 break;
3843 default:
3844 FIXME( "field mapping %u not supported\n", desc->mapping );
3845 return E_NOTIMPL;
3848 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3849 return hr;
3851 switch (mapping)
3853 case WS_ATTRIBUTE_TYPE_MAPPING:
3854 writer->state = WRITER_STATE_STARTELEMENT;
3855 break;
3857 case WS_ELEMENT_TYPE_MAPPING:
3858 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3859 break;
3861 default: break;
3864 return S_OK;
3867 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3868 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3869 const void *value, ULONG size )
3871 ULONG i, offset;
3872 const void *ptr;
3873 HRESULT hr;
3875 if (!desc) return E_INVALIDARG;
3876 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3878 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3880 for (i = 0; i < desc->fieldCount; i++)
3882 offset = desc->fields[i]->offset;
3883 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3886 return S_OK;
3889 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3890 const void *desc, WS_WRITE_OPTION option, const void *value,
3891 ULONG size )
3893 switch (type)
3895 case WS_BOOL_TYPE:
3896 return write_type_bool( writer, mapping, desc, option, value, size );
3898 case WS_INT8_TYPE:
3899 return write_type_int8( writer, mapping, desc, option, value, size );
3901 case WS_INT16_TYPE:
3902 return write_type_int16( writer, mapping, desc, option, value, size );
3904 case WS_INT32_TYPE:
3905 return write_type_int32( writer, mapping, desc, option, value, size );
3907 case WS_INT64_TYPE:
3908 return write_type_int64( writer, mapping, desc, option, value, size );
3910 case WS_UINT8_TYPE:
3911 return write_type_uint8( writer, mapping, desc, option, value, size );
3913 case WS_UINT16_TYPE:
3914 return write_type_uint16( writer, mapping, desc, option, value, size );
3916 case WS_UINT32_TYPE:
3917 return write_type_uint32( writer, mapping, desc, option, value, size );
3919 case WS_UINT64_TYPE:
3920 return write_type_uint64( writer, mapping, desc, option, value, size );
3922 case WS_DOUBLE_TYPE:
3923 return write_type_double( writer, mapping, desc, option, value, size );
3925 case WS_DATETIME_TYPE:
3926 return write_type_datetime( writer, mapping, desc, option, value, size );
3928 case WS_GUID_TYPE:
3929 return write_type_guid( writer, mapping, desc, option, value, size );
3931 case WS_UNIQUE_ID_TYPE:
3932 return write_type_unique_id( writer, mapping, desc, option, value, size );
3934 case WS_STRING_TYPE:
3935 return write_type_string( writer, mapping, desc, option, value, size );
3937 case WS_WSZ_TYPE:
3938 return write_type_wsz( writer, mapping, desc, option, value, size );
3940 case WS_BYTES_TYPE:
3941 return write_type_bytes( writer, mapping, desc, option, value, size );
3943 case WS_XML_STRING_TYPE:
3944 return write_type_xml_string( writer, mapping, desc, option, value, size );
3946 case WS_XML_QNAME_TYPE:
3947 return write_type_qname( writer, mapping, desc, option, value, size );
3949 case WS_STRUCT_TYPE:
3950 return write_type_struct( writer, mapping, desc, option, value, size );
3952 default:
3953 FIXME( "type %u not supported\n", type );
3954 return E_NOTIMPL;
3958 /**************************************************************************
3959 * WsWriteAttribute [webservices.@]
3961 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
3962 WS_WRITE_OPTION option, const void *value, ULONG size,
3963 WS_ERROR *error )
3965 struct writer *writer = (struct writer *)handle;
3966 HRESULT hr;
3968 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3969 if (error) FIXME( "ignoring error parameter\n" );
3971 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
3972 return E_INVALIDARG;
3974 EnterCriticalSection( &writer->cs );
3976 if (writer->magic != WRITER_MAGIC)
3978 LeaveCriticalSection( &writer->cs );
3979 return E_INVALIDARG;
3982 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
3983 else if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) == S_OK)
3985 writer->state = WRITER_STATE_STARTATTRIBUTE;
3986 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
3989 LeaveCriticalSection( &writer->cs );
3990 TRACE( "returning %08x\n", hr );
3991 return hr;
3994 /**************************************************************************
3995 * WsWriteElement [webservices.@]
3997 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3998 WS_WRITE_OPTION option, const void *value, ULONG size,
3999 WS_ERROR *error )
4001 struct writer *writer = (struct writer *)handle;
4002 HRESULT hr;
4004 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
4005 if (error) FIXME( "ignoring error parameter\n" );
4007 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
4008 return E_INVALIDARG;
4010 EnterCriticalSection( &writer->cs );
4012 if (writer->magic != WRITER_MAGIC)
4014 LeaveCriticalSection( &writer->cs );
4015 return E_INVALIDARG;
4018 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4020 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
4021 option, value, size )) != S_OK) goto done;
4023 hr = write_endelement_node( writer );
4025 done:
4026 LeaveCriticalSection( &writer->cs );
4027 TRACE( "returning %08x\n", hr );
4028 return hr;
4031 /**************************************************************************
4032 * WsWriteType [webservices.@]
4034 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4035 const void *desc, WS_WRITE_OPTION option, const void *value,
4036 ULONG size, WS_ERROR *error )
4038 struct writer *writer = (struct writer *)handle;
4039 HRESULT hr;
4041 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
4042 size, error );
4043 if (error) FIXME( "ignoring error parameter\n" );
4045 if (!writer || !value) return E_INVALIDARG;
4047 EnterCriticalSection( &writer->cs );
4049 if (writer->magic != WRITER_MAGIC)
4051 LeaveCriticalSection( &writer->cs );
4052 return E_INVALIDARG;
4055 switch (mapping)
4057 case WS_ATTRIBUTE_TYPE_MAPPING:
4058 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
4059 else hr = write_type( writer, mapping, type, desc, option, value, size );
4060 break;
4062 case WS_ELEMENT_TYPE_MAPPING:
4063 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4064 case WS_ANY_ELEMENT_TYPE_MAPPING:
4065 hr = write_type( writer, mapping, type, desc, option, value, size );
4066 break;
4068 default:
4069 FIXME( "mapping %u not implemented\n", mapping );
4070 hr = E_NOTIMPL;
4073 LeaveCriticalSection( &writer->cs );
4074 TRACE( "returning %08x\n", hr );
4075 return hr;
4078 WS_TYPE map_value_type( WS_VALUE_TYPE type )
4080 switch (type)
4082 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
4083 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
4084 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
4085 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
4086 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
4087 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
4088 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
4089 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
4090 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
4091 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
4092 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
4093 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
4094 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
4095 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
4096 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
4097 default:
4098 FIXME( "unhandled type %u\n", type );
4099 return ~0u;
4103 /**************************************************************************
4104 * WsWriteValue [webservices.@]
4106 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
4107 ULONG size, WS_ERROR *error )
4109 struct writer *writer = (struct writer *)handle;
4110 WS_TYPE_MAPPING mapping;
4111 HRESULT hr = S_OK;
4112 WS_TYPE type;
4114 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
4115 if (error) FIXME( "ignoring error parameter\n" );
4117 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
4119 EnterCriticalSection( &writer->cs );
4121 if (writer->magic != WRITER_MAGIC)
4123 LeaveCriticalSection( &writer->cs );
4124 return E_INVALIDARG;
4127 switch (writer->state)
4129 case WRITER_STATE_STARTATTRIBUTE:
4130 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
4131 break;
4133 case WRITER_STATE_STARTELEMENT:
4134 mapping = WS_ELEMENT_TYPE_MAPPING;
4135 break;
4137 default:
4138 hr = WS_E_INVALID_FORMAT;
4141 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
4143 LeaveCriticalSection( &writer->cs );
4144 TRACE( "returning %08x\n", hr );
4145 return hr;
4148 /**************************************************************************
4149 * WsWriteArray [webservices.@]
4151 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4152 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
4153 ULONG count, WS_ERROR *error )
4155 struct writer *writer = (struct writer *)handle;
4156 WS_TYPE type;
4157 ULONG type_size, i;
4158 HRESULT hr = S_OK;
4160 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
4161 value_type, array, size, offset, count, error );
4162 if (error) FIXME( "ignoring error parameter\n" );
4164 if (!writer) return E_INVALIDARG;
4166 EnterCriticalSection( &writer->cs );
4168 if (writer->magic != WRITER_MAGIC)
4170 LeaveCriticalSection( &writer->cs );
4171 return E_INVALIDARG;
4174 if (!writer->output_type)
4176 hr = WS_E_INVALID_OPERATION;
4177 goto done;
4180 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
4182 hr = E_INVALIDARG;
4183 goto done;
4186 type_size = get_type_size( type, NULL );
4187 if (size % type_size || (offset + count) * type_size > size || (count && !array))
4189 hr = E_INVALIDARG;
4190 goto done;
4193 for (i = offset; i < count; i++)
4195 const char *ptr = (const char *)array + (offset + i) * type_size;
4196 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4197 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4198 &ptr, sizeof(ptr) )) != S_OK) goto done;
4199 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4202 done:
4203 LeaveCriticalSection( &writer->cs );
4204 TRACE( "returning %08x\n", hr );
4205 return hr;
4208 /**************************************************************************
4209 * WsWriteXmlBuffer [webservices.@]
4211 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4213 struct writer *writer = (struct writer *)handle;
4214 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4215 HRESULT hr;
4217 TRACE( "%p %p %p\n", handle, buffer, error );
4218 if (error) FIXME( "ignoring error parameter\n" );
4220 if (!writer || !xmlbuf) return E_INVALIDARG;
4222 EnterCriticalSection( &writer->cs );
4224 if (writer->magic != WRITER_MAGIC)
4226 LeaveCriticalSection( &writer->cs );
4227 return E_INVALIDARG;
4230 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4232 FIXME( "no support for different encoding and/or charset\n" );
4233 hr = E_NOTIMPL;
4234 goto done;
4237 if ((hr = write_commit( writer )) != S_OK) goto done;
4238 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4239 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4241 done:
4242 LeaveCriticalSection( &writer->cs );
4243 TRACE( "returning %08x\n", hr );
4244 return hr;
4247 /**************************************************************************
4248 * WsWriteXmlBufferToBytes [webservices.@]
4250 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4251 const WS_XML_WRITER_ENCODING *encoding,
4252 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4253 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4255 struct writer *writer = (struct writer *)handle;
4256 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4257 HRESULT hr = S_OK;
4258 char *buf;
4259 ULONG i;
4261 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4262 bytes, size, error );
4263 if (error) FIXME( "ignoring error parameter\n" );
4265 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4267 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4269 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4270 return E_NOTIMPL;
4273 EnterCriticalSection( &writer->cs );
4275 if (writer->magic != WRITER_MAGIC)
4277 LeaveCriticalSection( &writer->cs );
4278 return E_INVALIDARG;
4281 for (i = 0; i < count; i++)
4283 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4284 properties[i].valueSize );
4285 if (hr != S_OK) goto done;
4288 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4289 else
4291 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4292 *bytes = buf;
4293 *size = xmlbuf->bytes.length;
4296 done:
4297 LeaveCriticalSection( &writer->cs );
4298 TRACE( "returning %08x\n", hr );
4299 return hr;
4302 /**************************************************************************
4303 * WsWriteXmlnsAttribute [webservices.@]
4305 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4306 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4308 struct writer *writer = (struct writer *)handle;
4309 HRESULT hr = S_OK;
4311 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4312 single, error );
4313 if (error) FIXME( "ignoring error parameter\n" );
4315 if (!writer || !ns) return E_INVALIDARG;
4317 EnterCriticalSection( &writer->cs );
4319 if (writer->magic != WRITER_MAGIC)
4321 LeaveCriticalSection( &writer->cs );
4322 return E_INVALIDARG;
4325 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_OPERATION;
4326 else if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4327 hr = add_namespace_attribute( writer, prefix, ns, single );
4329 LeaveCriticalSection( &writer->cs );
4330 TRACE( "returning %08x\n", hr );
4331 return hr;
4334 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4335 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4337 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4338 HRESULT hr;
4340 if ((hr = write_commit( writer )) != S_OK) return hr;
4341 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4343 qname.prefix = (WS_XML_STRING *)prefix;
4344 qname.localName = (WS_XML_STRING *)localname;
4345 qname.ns = (WS_XML_STRING *)ns;
4347 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4348 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4351 /**************************************************************************
4352 * WsWriteQualifiedName [webservices.@]
4354 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4355 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4356 WS_ERROR *error )
4358 struct writer *writer = (struct writer *)handle;
4359 HRESULT hr;
4361 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4362 debugstr_xmlstr(ns), error );
4363 if (error) FIXME( "ignoring error parameter\n" );
4365 if (!writer) return E_INVALIDARG;
4367 EnterCriticalSection( &writer->cs );
4369 if (writer->magic != WRITER_MAGIC)
4371 LeaveCriticalSection( &writer->cs );
4372 return E_INVALIDARG;
4375 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4376 else if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
4377 else if (!localname || (!prefix && !ns)) hr = E_INVALIDARG;
4378 else hr = write_qualified_name( writer, prefix, localname, ns );
4380 LeaveCriticalSection( &writer->cs );
4381 TRACE( "returning %08x\n", hr );
4382 return hr;
4385 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4387 BOOL success = FALSE;
4388 struct node *node = writer->current;
4390 switch (move)
4392 case WS_MOVE_TO_ROOT_ELEMENT:
4393 success = move_to_root_element( writer->root, &node );
4394 break;
4396 case WS_MOVE_TO_NEXT_ELEMENT:
4397 success = move_to_next_element( &node );
4398 break;
4400 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4401 success = move_to_prev_element( &node );
4402 break;
4404 case WS_MOVE_TO_CHILD_ELEMENT:
4405 success = move_to_child_element( &node );
4406 break;
4408 case WS_MOVE_TO_END_ELEMENT:
4409 success = move_to_end_element( &node );
4410 break;
4412 case WS_MOVE_TO_PARENT_ELEMENT:
4413 success = move_to_parent_element( &node );
4414 break;
4416 case WS_MOVE_TO_FIRST_NODE:
4417 success = move_to_first_node( &node );
4418 break;
4420 case WS_MOVE_TO_NEXT_NODE:
4421 success = move_to_next_node( &node );
4422 break;
4424 case WS_MOVE_TO_PREVIOUS_NODE:
4425 success = move_to_prev_node( &node );
4426 break;
4428 case WS_MOVE_TO_CHILD_NODE:
4429 success = move_to_child_node( &node );
4430 break;
4432 case WS_MOVE_TO_BOF:
4433 success = move_to_bof( writer->root, &node );
4434 break;
4436 case WS_MOVE_TO_EOF:
4437 success = move_to_eof( writer->root, &node );
4438 break;
4440 default:
4441 FIXME( "unhandled move %u\n", move );
4442 return E_NOTIMPL;
4445 if (success && node == writer->root) return E_INVALIDARG;
4446 writer->current = node;
4448 if (found)
4450 *found = success;
4451 return S_OK;
4453 return success ? S_OK : WS_E_INVALID_FORMAT;
4456 /**************************************************************************
4457 * WsMoveWriter [webservices.@]
4459 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4461 struct writer *writer = (struct writer *)handle;
4462 HRESULT hr;
4464 TRACE( "%p %u %p %p\n", handle, move, found, error );
4465 if (error) FIXME( "ignoring error parameter\n" );
4467 if (!writer) return E_INVALIDARG;
4469 EnterCriticalSection( &writer->cs );
4471 if (writer->magic != WRITER_MAGIC)
4473 LeaveCriticalSection( &writer->cs );
4474 return E_INVALIDARG;
4477 if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
4478 else hr = write_move_to( writer, move, found );
4480 LeaveCriticalSection( &writer->cs );
4481 TRACE( "returning %08x\n", hr );
4482 return hr;
4485 /**************************************************************************
4486 * WsGetWriterPosition [webservices.@]
4488 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4490 struct writer *writer = (struct writer *)handle;
4491 HRESULT hr = S_OK;
4493 TRACE( "%p %p %p\n", handle, pos, error );
4494 if (error) FIXME( "ignoring error parameter\n" );
4496 if (!writer || !pos) return E_INVALIDARG;
4498 EnterCriticalSection( &writer->cs );
4500 if (writer->magic != WRITER_MAGIC)
4502 LeaveCriticalSection( &writer->cs );
4503 return E_INVALIDARG;
4506 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4507 else
4509 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4510 pos->node = writer->current;
4513 LeaveCriticalSection( &writer->cs );
4514 TRACE( "returning %08x\n", hr );
4515 return hr;
4518 /**************************************************************************
4519 * WsSetWriterPosition [webservices.@]
4521 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4523 struct writer *writer = (struct writer *)handle;
4524 HRESULT hr = S_OK;
4526 TRACE( "%p %p %p\n", handle, pos, error );
4527 if (error) FIXME( "ignoring error parameter\n" );
4529 if (!writer || !pos) return E_INVALIDARG;
4531 EnterCriticalSection( &writer->cs );
4533 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4535 LeaveCriticalSection( &writer->cs );
4536 return E_INVALIDARG;
4539 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4540 else writer->current = pos->node;
4542 LeaveCriticalSection( &writer->cs );
4543 TRACE( "returning %08x\n", hr );
4544 return hr;
4547 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4549 struct node *node, *parent;
4550 WS_XML_COMMENT_NODE *comment;
4552 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4553 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4554 comment = (WS_XML_COMMENT_NODE *)node;
4556 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4558 free_node( node );
4559 return E_OUTOFMEMORY;
4561 memcpy( comment->value.bytes, value->bytes, value->length );
4562 comment->value.length = value->length;
4564 write_insert_node( writer, parent, node );
4565 return S_OK;
4568 static HRESULT write_comment_text( struct writer *writer )
4570 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4571 HRESULT hr;
4573 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4574 write_bytes( writer, (const BYTE *)"<!--", 4 );
4575 write_bytes( writer, comment->value.bytes, comment->value.length );
4576 write_bytes( writer, (const BYTE *)"-->", 3 );
4577 return S_OK;
4580 static HRESULT write_comment_bin( struct writer *writer )
4582 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4583 HRESULT hr;
4585 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4586 write_char( writer, RECORD_COMMENT );
4587 return write_string( writer, comment->value.bytes, comment->value.length );
4590 static HRESULT write_comment( struct writer *writer )
4592 switch (writer->output_enc)
4594 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4595 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4596 default:
4597 ERR( "unhandled encoding %u\n", writer->output_enc );
4598 return WS_E_NOT_SUPPORTED;
4602 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4604 HRESULT hr;
4605 if ((hr = write_commit( writer )) != S_OK) return hr;
4606 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4607 if ((hr = write_comment( writer )) != S_OK) return hr;
4608 writer->state = WRITER_STATE_COMMENT;
4609 return S_OK;
4612 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4614 ULONG i;
4615 HRESULT hr;
4617 for (i = 0; i < count; i++)
4619 const WS_XML_STRING *prefix = attrs[i]->prefix;
4620 const WS_XML_STRING *localname = attrs[i]->localName;
4621 const WS_XML_STRING *ns = attrs[i]->ns;
4622 BOOL single = attrs[i]->singleQuote;
4624 if (attrs[i]->isXmlNs)
4626 if ((hr = add_namespace_attribute( writer, prefix, ns, single )) != S_OK) return hr;
4628 else
4630 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
4631 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4634 return S_OK;
4637 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4639 HRESULT hr;
4641 switch (node->nodeType)
4643 case WS_XML_NODE_TYPE_ELEMENT:
4645 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4646 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4647 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4649 case WS_XML_NODE_TYPE_TEXT:
4651 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4652 return write_text_node( writer, text->text );
4654 case WS_XML_NODE_TYPE_END_ELEMENT:
4655 return write_endelement_node( writer );
4657 case WS_XML_NODE_TYPE_COMMENT:
4659 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4660 return write_comment_node( writer, &comment->value );
4662 case WS_XML_NODE_TYPE_CDATA:
4663 return write_cdata_node( writer );
4665 case WS_XML_NODE_TYPE_END_CDATA:
4666 return write_endcdata_node( writer );
4668 case WS_XML_NODE_TYPE_EOF:
4669 case WS_XML_NODE_TYPE_BOF:
4670 return S_OK;
4672 default:
4673 WARN( "unknown node type %u\n", node->nodeType );
4674 return E_INVALIDARG;
4678 /**************************************************************************
4679 * WsWriteNode [webservices.@]
4681 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4683 struct writer *writer = (struct writer *)handle;
4684 HRESULT hr;
4686 TRACE( "%p %p %p\n", handle, node, error );
4687 if (error) FIXME( "ignoring error parameter\n" );
4689 if (!writer || !node) return E_INVALIDARG;
4691 EnterCriticalSection( &writer->cs );
4693 if (writer->magic != WRITER_MAGIC)
4695 LeaveCriticalSection( &writer->cs );
4696 return E_INVALIDARG;
4699 if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
4700 else hr = write_node( writer, node );
4702 LeaveCriticalSection( &writer->cs );
4703 TRACE( "returning %08x\n", hr );
4704 return hr;
4707 static HRESULT write_tree_node( struct writer *writer )
4709 HRESULT hr;
4711 switch (node_type( writer->current ))
4713 case WS_XML_NODE_TYPE_ELEMENT:
4714 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4715 return hr;
4716 if ((hr = write_startelement( writer )) != S_OK) return hr;
4717 writer->state = WRITER_STATE_STARTELEMENT;
4718 return S_OK;
4720 case WS_XML_NODE_TYPE_TEXT:
4721 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4722 return hr;
4723 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4724 writer->state = WRITER_STATE_TEXT;
4725 return S_OK;
4727 case WS_XML_NODE_TYPE_END_ELEMENT:
4728 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4729 writer->state = WRITER_STATE_ENDELEMENT;
4730 return S_OK;
4732 case WS_XML_NODE_TYPE_COMMENT:
4733 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4734 return hr;
4735 if ((hr = write_comment( writer )) != S_OK) return hr;
4736 writer->state = WRITER_STATE_COMMENT;
4737 return S_OK;
4739 case WS_XML_NODE_TYPE_CDATA:
4740 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4741 return hr;
4742 if ((hr = write_cdata( writer )) != S_OK) return hr;
4743 writer->state = WRITER_STATE_STARTCDATA;
4744 return S_OK;
4746 case WS_XML_NODE_TYPE_END_CDATA:
4747 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4748 writer->state = WRITER_STATE_ENDCDATA;
4749 return S_OK;
4751 case WS_XML_NODE_TYPE_EOF:
4752 case WS_XML_NODE_TYPE_BOF:
4753 return S_OK;
4755 default:
4756 ERR( "unknown node type %u\n", node_type(writer->current) );
4757 return E_INVALIDARG;
4761 static HRESULT write_tree( struct writer *writer )
4763 HRESULT hr;
4765 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4766 for (;;)
4768 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4769 if (move_to_child_node( &writer->current ))
4771 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4772 continue;
4774 if (move_to_next_node( &writer->current ))
4776 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4777 continue;
4779 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4781 ERR( "invalid tree\n" );
4782 return WS_E_INVALID_FORMAT;
4784 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4786 return S_OK;
4789 static void write_rewind( struct writer *writer )
4791 writer->write_pos = 0;
4792 writer->current = writer->root;
4793 writer->state = WRITER_STATE_INITIAL;
4796 /**************************************************************************
4797 * WsCopyNode [webservices.@]
4799 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4801 struct writer *writer = (struct writer *)handle;
4802 struct node *parent, *current, *node = NULL;
4803 HRESULT hr;
4805 TRACE( "%p %p %p\n", handle, reader, error );
4806 if (error) FIXME( "ignoring error parameter\n" );
4808 if (!writer) return E_INVALIDARG;
4810 EnterCriticalSection( &writer->cs );
4812 if (writer->magic != WRITER_MAGIC)
4814 LeaveCriticalSection( &writer->cs );
4815 return E_INVALIDARG;
4818 if (!(parent = find_parent( writer ))) hr = WS_E_INVALID_FORMAT;
4819 else
4821 if ((hr = copy_node( reader, writer->output_enc, &node )) != S_OK) goto done;
4822 current = writer->current;
4823 write_insert_node( writer, parent, node );
4825 write_rewind( writer );
4826 if ((hr = write_tree( writer )) != S_OK) goto done;
4827 writer->current = current;
4829 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4832 done:
4833 LeaveCriticalSection( &writer->cs );
4834 TRACE( "returning %08x\n", hr );
4835 return hr;
4838 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4840 return write_type_field( writer, desc, value, 0 );
4843 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4845 ULONG i, ret = 0;
4846 for (i = 0; i < count; i++)
4848 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4849 continue;
4850 if (args[i]) ret = *(const ULONG *)args[i];
4851 break;
4853 return ret;
4856 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4857 ULONG len )
4859 return write_type_array( writer, desc, value, len );
4862 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4863 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4865 struct writer *writer = (struct writer *)handle;
4866 const WS_STRUCT_DESCRIPTION *desc_struct;
4867 const WS_FIELD_DESCRIPTION *desc_field;
4868 HRESULT hr;
4869 ULONG i;
4871 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4873 EnterCriticalSection( &writer->cs );
4875 if (writer->magic != WRITER_MAGIC)
4877 LeaveCriticalSection( &writer->cs );
4878 return E_INVALIDARG;
4881 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4883 for (i = 0; i < count; i++)
4885 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4886 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4888 FIXME( "messages type not supported\n" );
4889 hr = E_NOTIMPL;
4890 goto done;
4892 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4893 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4895 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4897 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4899 const void *ptr = *(const void **)args[i];
4900 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4901 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4905 hr = write_endelement_node( writer );
4907 done:
4908 LeaveCriticalSection( &writer->cs );
4909 return hr;
4912 HRESULT writer_set_lookup( WS_XML_WRITER *handle, BOOL enable )
4914 struct writer *writer = (struct writer *)handle;
4916 EnterCriticalSection( &writer->cs );
4918 if (writer->magic != WRITER_MAGIC)
4920 LeaveCriticalSection( &writer->cs );
4921 return E_INVALIDARG;
4924 writer->dict_do_lookup = enable;
4926 LeaveCriticalSection( &writer->cs );
4927 return S_OK;
4930 HRESULT writer_set_dict_callback( WS_XML_WRITER *handle, WS_DYNAMIC_STRING_CALLBACK cb, void *state )
4932 struct writer *writer = (struct writer *)handle;
4934 EnterCriticalSection( &writer->cs );
4936 if (writer->magic != WRITER_MAGIC)
4938 LeaveCriticalSection( &writer->cs );
4939 return E_INVALIDARG;
4942 writer->dict_cb = cb;
4943 writer->dict_cb_state = state;
4945 LeaveCriticalSection( &writer->cs );
4946 return S_OK;