gphoto2.ds: Set supported groups.
[wine.git] / dlls / webservices / writer.c
blobf6917c6ae3db860c8fcd231c6fd91f9cad27fa6f
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/list.h"
32 #include "wine/unicode.h"
33 #include "webservices_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
37 static const struct prop_desc writer_props[] =
39 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
40 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
41 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
42 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
43 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
44 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
45 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
46 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
47 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
48 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
49 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
50 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
51 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
52 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
53 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
54 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
55 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
56 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
57 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
60 enum writer_state
62 WRITER_STATE_INITIAL,
63 WRITER_STATE_STARTELEMENT,
64 WRITER_STATE_STARTATTRIBUTE,
65 WRITER_STATE_STARTCDATA,
66 WRITER_STATE_ENDSTARTELEMENT,
67 WRITER_STATE_TEXT,
68 WRITER_STATE_COMMENT,
69 WRITER_STATE_ENDELEMENT,
70 WRITER_STATE_ENDCDATA
73 struct writer
75 ULONG magic;
76 CRITICAL_SECTION cs;
77 ULONG write_pos;
78 unsigned char *write_bufptr;
79 enum writer_state state;
80 struct node *root;
81 struct node *current;
82 WS_XML_STRING *current_ns;
83 WS_XML_WRITER_ENCODING_TYPE output_enc;
84 WS_CHARSET output_charset;
85 WS_XML_WRITER_OUTPUT_TYPE output_type;
86 struct xmlbuf *output_buf;
87 WS_HEAP *output_heap;
88 const WS_XML_DICTIONARY *dict;
89 BOOL dict_do_lookup;
90 WS_DYNAMIC_STRING_CALLBACK dict_cb;
91 void *dict_cb_state;
92 ULONG prop_count;
93 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
96 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
98 static struct writer *alloc_writer(void)
100 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
101 struct writer *ret;
102 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
104 if (!(ret = heap_alloc_zero( size ))) return NULL;
106 ret->magic = WRITER_MAGIC;
107 InitializeCriticalSection( &ret->cs );
108 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
110 prop_init( writer_props, count, ret->prop, &ret[1] );
111 ret->prop_count = count;
112 return ret;
115 static void free_writer( struct writer *writer )
117 destroy_nodes( writer->root );
118 free_xml_string( writer->current_ns );
119 WsFreeHeap( writer->output_heap );
121 writer->cs.DebugInfo->Spare[0] = 0;
122 DeleteCriticalSection( &writer->cs );
123 heap_free( writer );
126 static void write_insert_eof( struct writer *writer, struct node *eof )
128 if (!writer->root) writer->root = eof;
129 else
131 eof->parent = writer->root;
132 list_add_tail( &writer->root->children, &eof->entry );
134 writer->current = eof;
137 static void write_insert_bof( struct writer *writer, struct node *bof )
139 writer->root->parent = bof;
140 list_add_tail( &bof->children, &writer->root->entry );
141 writer->current = writer->root = bof;
144 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
146 node->parent = parent;
147 list_add_before( list_tail( &parent->children ), &node->entry );
148 writer->current = node;
151 static struct node *find_parent( struct writer *writer )
153 if (is_valid_parent( writer->current )) return writer->current;
154 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
155 return NULL;
158 static HRESULT init_writer( struct writer *writer )
160 struct node *node;
162 writer->write_pos = 0;
163 writer->write_bufptr = NULL;
164 destroy_nodes( writer->root );
165 writer->root = writer->current = NULL;
166 free_xml_string( writer->current_ns );
167 writer->current_ns = NULL;
169 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
170 write_insert_eof( writer, node );
171 writer->state = WRITER_STATE_INITIAL;
172 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
173 writer->output_charset = WS_CHARSET_UTF8;
174 writer->dict = NULL;
175 writer->dict_do_lookup = FALSE;
176 writer->dict_cb = NULL;
177 writer->dict_cb_state = NULL;
178 return S_OK;
181 /**************************************************************************
182 * WsCreateWriter [webservices.@]
184 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
185 WS_XML_WRITER **handle, WS_ERROR *error )
187 struct writer *writer;
188 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
189 WS_CHARSET charset = WS_CHARSET_UTF8;
190 HRESULT hr;
192 TRACE( "%p %u %p %p\n", properties, count, handle, error );
193 if (error) FIXME( "ignoring error parameter\n" );
195 if (!handle) return E_INVALIDARG;
196 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
198 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
199 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
200 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
201 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
202 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
203 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
204 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
206 for (i = 0; i < count; i++)
208 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
209 properties[i].valueSize );
210 if (hr != S_OK)
212 free_writer( writer );
213 return hr;
217 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
218 &max_size, sizeof(max_size) );
219 if (hr != S_OK)
221 free_writer( writer );
222 return hr;
225 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
226 if (hr != S_OK)
228 free_writer( writer );
229 return hr;
232 hr = init_writer( writer );
233 if (hr != S_OK)
235 free_writer( writer );
236 return hr;
239 TRACE( "created %p\n", writer );
240 *handle = (WS_XML_WRITER *)writer;
241 return S_OK;
244 /**************************************************************************
245 * WsFreeWriter [webservices.@]
247 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
249 struct writer *writer = (struct writer *)handle;
251 TRACE( "%p\n", handle );
253 if (!writer) return;
255 EnterCriticalSection( &writer->cs );
257 if (writer->magic != WRITER_MAGIC)
259 LeaveCriticalSection( &writer->cs );
260 return;
263 writer->magic = 0;
265 LeaveCriticalSection( &writer->cs );
266 free_writer( writer );
269 /**************************************************************************
270 * WsGetWriterProperty [webservices.@]
272 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
273 void *buf, ULONG size, WS_ERROR *error )
275 struct writer *writer = (struct writer *)handle;
276 HRESULT hr = S_OK;
278 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
279 if (error) FIXME( "ignoring error parameter\n" );
281 if (!writer) return E_INVALIDARG;
283 EnterCriticalSection( &writer->cs );
285 if (writer->magic != WRITER_MAGIC)
287 LeaveCriticalSection( &writer->cs );
288 return E_INVALIDARG;
291 if (!writer->output_type)
293 LeaveCriticalSection( &writer->cs );
294 return WS_E_INVALID_OPERATION;
297 switch (id)
299 case WS_XML_WRITER_PROPERTY_BYTES:
301 WS_BYTES *bytes = buf;
302 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
303 else
305 bytes->bytes = writer->output_buf->bytes.bytes;
306 bytes->length = writer->output_buf->bytes.length;
308 break;
310 case WS_XML_WRITER_PROPERTY_BUFFERS:
311 if (writer->output_buf->bytes.length)
313 WS_BUFFERS *buffers = buf;
314 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
315 else
317 buffers->bufferCount = 1;
318 buffers->buffers = &writer->output_buf->bytes;
320 break;
322 /* fall through */
323 default:
324 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
327 LeaveCriticalSection( &writer->cs );
328 return hr;
331 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
333 /* free current buffer if it's ours */
334 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
336 free_xmlbuf( writer->output_buf );
338 writer->output_buf = xmlbuf;
339 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
340 writer->write_bufptr = xmlbuf->bytes.bytes;
341 writer->write_pos = 0;
344 /**************************************************************************
345 * WsSetOutput [webservices.@]
347 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
348 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
349 ULONG count, WS_ERROR *error )
351 struct writer *writer = (struct writer *)handle;
352 struct node *node;
353 HRESULT hr;
354 ULONG i;
356 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
357 if (error) FIXME( "ignoring error parameter\n" );
359 if (!writer) return E_INVALIDARG;
361 EnterCriticalSection( &writer->cs );
363 if (writer->magic != WRITER_MAGIC)
365 LeaveCriticalSection( &writer->cs );
366 return E_INVALIDARG;
369 for (i = 0; i < count; i++)
371 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
372 properties[i].valueSize );
373 if (hr != S_OK) goto done;
376 if ((hr = init_writer( writer )) != S_OK) goto done;
378 switch (encoding->encodingType)
380 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
382 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
383 if (text->charSet != WS_CHARSET_UTF8)
385 FIXME( "charset %u not supported\n", text->charSet );
386 hr = E_NOTIMPL;
387 goto done;
389 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
390 writer->output_charset = WS_CHARSET_UTF8;
391 break;
393 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
395 WS_XML_WRITER_BINARY_ENCODING *bin = (WS_XML_WRITER_BINARY_ENCODING *)encoding;
396 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
397 writer->output_charset = 0;
398 writer->dict = bin->staticDictionary;
399 writer->dict_cb = bin->dynamicStringCallback;
400 writer->dict_cb_state = bin->dynamicStringCallbackState;
401 break;
403 default:
404 FIXME( "encoding type %u not supported\n", encoding->encodingType );
405 hr = E_NOTIMPL;
406 goto done;
409 switch (output->outputType)
411 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
413 struct xmlbuf *xmlbuf;
414 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, 0, writer->output_enc, writer->output_charset,
415 writer->dict, NULL )))
417 hr = WS_E_QUOTA_EXCEEDED;
418 goto done;
420 set_output_buffer( writer, xmlbuf );
421 break;
423 default:
424 FIXME( "output type %u not supported\n", output->outputType );
425 hr = E_NOTIMPL;
426 goto done;
429 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
430 else write_insert_bof( writer, node );
432 done:
433 LeaveCriticalSection( &writer->cs );
434 return hr;
437 /**************************************************************************
438 * WsSetOutputToBuffer [webservices.@]
440 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
441 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
442 WS_ERROR *error )
444 struct writer *writer = (struct writer *)handle;
445 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
446 struct node *node;
447 HRESULT hr;
448 ULONG i;
450 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
451 if (error) FIXME( "ignoring error parameter\n" );
453 if (!writer || !xmlbuf) return E_INVALIDARG;
455 EnterCriticalSection( &writer->cs );
457 if (writer->magic != WRITER_MAGIC)
459 LeaveCriticalSection( &writer->cs );
460 return E_INVALIDARG;
463 for (i = 0; i < count; i++)
465 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
466 properties[i].valueSize );
467 if (hr != S_OK) goto done;
470 if ((hr = init_writer( writer )) != S_OK) goto done;
471 writer->output_enc = xmlbuf->encoding;
472 writer->output_charset = xmlbuf->charset;
473 set_output_buffer( writer, xmlbuf );
475 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
476 else write_insert_bof( writer, node );
478 done:
479 LeaveCriticalSection( &writer->cs );
480 return hr;
483 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
485 struct xmlbuf *buf = writer->output_buf;
486 SIZE_T new_size;
487 void *tmp;
489 if (buf->size >= writer->write_pos + size)
491 buf->bytes.length = writer->write_pos + size;
492 return S_OK;
494 new_size = max( buf->size * 2, writer->write_pos + size );
495 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
496 writer->write_bufptr = buf->bytes.bytes = tmp;
497 buf->size = new_size;
498 buf->bytes.length = writer->write_pos + size;
499 return S_OK;
502 static inline void write_char( struct writer *writer, unsigned char ch )
504 writer->write_bufptr[writer->write_pos++] = ch;
507 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
509 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
510 writer->write_pos += len;
513 struct escape
515 char ch;
516 const char *entity;
517 ULONG len;
519 static const struct escape escape_lt = { '<', "&lt;", 4 };
520 static const struct escape escape_gt = { '>', "&gt;", 4 };
521 static const struct escape escape_amp = { '&', "&amp;", 5 };
522 static const struct escape escape_apos = { '\'', "&apos;", 6 };
523 static const struct escape escape_quot = { '"', "&quot;", 6 };
525 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
526 const struct escape **escapes, ULONG nb_escapes )
528 ULONG i, j, size;
529 const BYTE *ptr;
530 HRESULT hr;
532 for (i = 0; i < len; i++)
534 ptr = &bytes[i];
535 size = 1;
536 for (j = 0; j < nb_escapes; j++)
538 if (bytes[i] == escapes[j]->ch)
540 ptr = (const BYTE *)escapes[j]->entity;
541 size = escapes[j]->len;
542 break;
545 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
546 write_bytes( writer, ptr, size );
549 return S_OK;
552 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
554 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
555 const struct escape *escapes[3];
557 escapes[0] = single ? &escape_apos : &escape_quot;
558 escapes[1] = &escape_lt;
559 escapes[2] = &escape_amp;
560 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
563 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
565 unsigned char quote = attr->singleQuote ? '\'' : '"';
566 const WS_XML_STRING *prefix = NULL;
567 ULONG size;
568 HRESULT hr;
570 if (attr->prefix) prefix = attr->prefix;
572 /* ' prefix:attr="value"' */
574 size = attr->localName->length + 4 /* ' =""' */;
575 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
576 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
578 write_char( writer, ' ' );
579 if (prefix && prefix->length)
581 write_bytes( writer, prefix->bytes, prefix->length );
582 write_char( writer, ':' );
584 write_bytes( writer, attr->localName->bytes, attr->localName->length );
585 write_char( writer, '=' );
586 write_char( writer, quote );
587 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
588 write_char( writer, quote );
590 return hr;
593 static HRESULT write_int31( struct writer *writer, ULONG len )
595 HRESULT hr;
597 if (len > 0x7fffffff) return E_INVALIDARG;
599 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
600 if (len < 0x80)
602 write_char( writer, len );
603 return S_OK;
605 write_char( writer, (len & 0x7f) | 0x80 );
607 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
608 if ((len >>= 7) < 0x80)
610 write_char( writer, len );
611 return S_OK;
613 write_char( writer, (len & 0x7f) | 0x80 );
615 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
616 if ((len >>= 7) < 0x80)
618 write_char( writer, len );
619 return S_OK;
621 write_char( writer, (len & 0x7f) | 0x80 );
623 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
624 if ((len >>= 7) < 0x80)
626 write_char( writer, len );
627 return S_OK;
629 write_char( writer, (len & 0x7f) | 0x80 );
631 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
632 if ((len >>= 7) < 0x08)
634 write_char( writer, len );
635 return S_OK;
637 return WS_E_INVALID_FORMAT;
640 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
642 HRESULT hr;
643 if ((hr = write_int31( writer, len )) != S_OK) return hr;
644 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
645 write_bytes( writer, bytes, len );
646 return S_OK;
649 static HRESULT write_dict_string( struct writer *writer, ULONG id )
651 HRESULT hr;
652 if (id > 0x7fffffff) return E_INVALIDARG;
653 if ((hr = write_int31( writer, id )) != S_OK) return hr;
654 return S_OK;
657 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
659 if (!text) return RECORD_CHARS8_TEXT;
660 switch (text->textType)
662 case WS_XML_TEXT_TYPE_UTF8:
664 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
665 if (use_dict) return RECORD_DICTIONARY_TEXT;
666 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
667 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
668 return RECORD_CHARS32_TEXT;
670 case WS_XML_TEXT_TYPE_BASE64:
672 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
673 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
674 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
675 return RECORD_BYTES32_TEXT;
677 case WS_XML_TEXT_TYPE_BOOL:
679 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
680 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
682 case WS_XML_TEXT_TYPE_INT32:
684 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
685 if (!text_int32->value) return RECORD_ZERO_TEXT;
686 if (text_int32->value == 1) return RECORD_ONE_TEXT;
687 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
688 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
689 return RECORD_INT32_TEXT;
691 case WS_XML_TEXT_TYPE_INT64:
693 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
694 if (!text_int64->value) return RECORD_ZERO_TEXT;
695 if (text_int64->value == 1) return RECORD_ONE_TEXT;
696 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
697 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
698 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
699 return RECORD_INT64_TEXT;
701 case WS_XML_TEXT_TYPE_UINT64:
703 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
704 if (!text_uint64->value) return RECORD_ZERO_TEXT;
705 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
706 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
707 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
708 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
709 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
710 return RECORD_UINT64_TEXT;
712 case WS_XML_TEXT_TYPE_DOUBLE:
714 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
715 if (!text_double->value) return RECORD_ZERO_TEXT;
716 if (text_double->value == 1) return RECORD_ONE_TEXT;
717 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
718 return RECORD_DOUBLE_TEXT;
719 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
720 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
721 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
722 return RECORD_INT64_TEXT;
724 case WS_XML_TEXT_TYPE_GUID:
725 return RECORD_GUID_TEXT;
727 case WS_XML_TEXT_TYPE_UNIQUE_ID:
728 return RECORD_UNIQUE_ID_TEXT;
730 case WS_XML_TEXT_TYPE_DATETIME:
731 return RECORD_DATETIME_TEXT;
733 default:
734 FIXME( "unhandled text type %u\n", text->textType );
735 return 0;
739 static INT64 get_text_value_int( const WS_XML_TEXT *text )
741 switch (text->textType)
743 case WS_XML_TEXT_TYPE_INT32:
745 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
746 return text_int32->value;
748 case WS_XML_TEXT_TYPE_INT64:
750 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
751 return text_int64->value;
753 case WS_XML_TEXT_TYPE_UINT64:
755 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
756 return text_uint64->value;
758 case WS_XML_TEXT_TYPE_DOUBLE:
760 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
761 return text_double->value;
763 default:
764 ERR( "unhandled text type %u\n", text->textType );
765 assert(0);
766 return 0;
770 static BOOL get_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
772 if (writer->dict && str->dictionary == writer->dict)
774 *id = str->id << 1;
775 return TRUE;
777 if (writer->dict_cb)
779 BOOL found = FALSE;
780 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
781 if (found) *id = (*id << 1) | 1;
782 return found;
784 return FALSE;
787 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
789 enum record_type type;
790 BOOL use_dict = FALSE;
791 HRESULT hr;
792 ULONG id;
794 if (text && text->textType == WS_XML_TEXT_TYPE_UTF8)
796 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
797 use_dict = get_string_id( writer, &utf8->value, &id );
799 type = get_attr_text_record_type( text, use_dict );
801 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
802 write_char( writer, type );
804 switch (type)
806 case RECORD_CHARS8_TEXT:
808 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
809 if (!text_utf8)
811 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
812 write_char( writer, 0 );
813 return S_OK;
815 if ((hr = write_grow_buffer( writer, 1 + text_utf8->value.length )) != S_OK) return hr;
816 write_char( writer, text_utf8->value.length );
817 write_bytes( writer, text_utf8->value.bytes, text_utf8->value.length );
818 return S_OK;
820 case RECORD_CHARS16_TEXT:
822 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
823 UINT16 len = text_utf8->value.length;
824 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
825 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
826 write_bytes( writer, text_utf8->value.bytes, len );
827 return S_OK;
829 case RECORD_BYTES8_TEXT:
831 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
832 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
833 write_char( writer, text_base64->length );
834 write_bytes( writer, text_base64->bytes, text_base64->length );
835 return S_OK;
837 case RECORD_BYTES16_TEXT:
839 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
840 UINT16 len = text_base64->length;
841 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
842 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
843 write_bytes( writer, text_base64->bytes, len );
844 return S_OK;
846 case RECORD_ZERO_TEXT:
847 case RECORD_ONE_TEXT:
848 case RECORD_FALSE_TEXT:
849 case RECORD_TRUE_TEXT:
850 return S_OK;
852 case RECORD_INT8_TEXT:
854 INT8 val = get_text_value_int( text );
855 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
856 write_char( writer, val );
857 return S_OK;
859 case RECORD_INT16_TEXT:
861 INT16 val = get_text_value_int( text );
862 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
863 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
864 return S_OK;
866 case RECORD_INT32_TEXT:
868 INT32 val = get_text_value_int( text );
869 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
870 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
871 return S_OK;
873 case RECORD_INT64_TEXT:
875 INT64 val = get_text_value_int( text );
876 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
877 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
878 return S_OK;
880 case RECORD_UINT64_TEXT:
882 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
883 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
884 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
885 return S_OK;
887 case RECORD_DOUBLE_TEXT:
889 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
890 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
891 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
892 return S_OK;
894 case RECORD_GUID_TEXT:
896 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
897 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
898 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
899 return S_OK;
901 case RECORD_UNIQUE_ID_TEXT:
903 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
904 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
905 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
906 return S_OK;
908 case RECORD_DATETIME_TEXT:
910 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
911 UINT64 val = text_datetime->value.ticks;
913 assert( val <= TICKS_MAX );
914 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
915 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
917 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
918 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
919 return S_OK;
921 default:
922 FIXME( "unhandled record type %02x\n", type );
923 return E_NOTIMPL;
927 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
929 if (!attr->prefix || !attr->prefix->length)
931 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
932 return RECORD_SHORT_ATTRIBUTE;
934 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
936 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
937 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
939 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
940 return RECORD_ATTRIBUTE;
943 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
945 ULONG id;
946 enum record_type type = get_attr_record_type( attr, get_string_id(writer, attr->localName, &id) );
947 HRESULT hr;
949 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
950 write_char( writer, type );
952 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
954 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
955 return write_attribute_value_bin( writer, attr->value );
957 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
959 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
960 return write_attribute_value_bin( writer, attr->value );
963 switch (type)
965 case RECORD_SHORT_ATTRIBUTE:
966 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
967 break;
969 case RECORD_ATTRIBUTE:
970 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
971 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
972 break;
974 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
975 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
976 break;
978 case RECORD_DICTIONARY_ATTRIBUTE:
979 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
980 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
981 break;
983 default:
984 ERR( "unhandled record type %02x\n", type );
985 return WS_E_NOT_SUPPORTED;
988 return write_attribute_value_bin( writer, attr->value );
991 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
993 switch (writer->output_enc)
995 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
996 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
997 default:
998 ERR( "unhandled encoding %u\n", writer->output_enc );
999 return WS_E_NOT_SUPPORTED;
1003 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1005 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
1008 /**************************************************************************
1009 * WsGetPrefixFromNamespace [webservices.@]
1011 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
1012 BOOL required, const WS_XML_STRING **prefix,
1013 WS_ERROR *error )
1015 struct writer *writer = (struct writer *)handle;
1016 WS_XML_ELEMENT_NODE *elem;
1017 BOOL found = FALSE;
1018 HRESULT hr = S_OK;
1020 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1021 if (error) FIXME( "ignoring error parameter\n" );
1023 if (!writer || !ns || !prefix) return E_INVALIDARG;
1025 EnterCriticalSection( &writer->cs );
1027 if (writer->magic != WRITER_MAGIC)
1029 LeaveCriticalSection( &writer->cs );
1030 return E_INVALIDARG;
1033 elem = &writer->current->hdr;
1034 if (elem->prefix && is_current_namespace( writer, ns ))
1036 *prefix = elem->prefix;
1037 found = TRUE;
1040 if (!found)
1042 if (required) hr = WS_E_INVALID_FORMAT;
1043 else
1045 *prefix = NULL;
1046 hr = S_FALSE;
1050 LeaveCriticalSection( &writer->cs );
1051 return hr;
1054 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1056 unsigned char quote = attr->singleQuote ? '\'' : '"';
1057 ULONG size;
1058 HRESULT hr;
1060 /* ' xmlns:prefix="namespace"' */
1062 size = attr->ns->length + 9 /* ' xmlns=""' */;
1063 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
1064 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1066 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1067 if (attr->prefix)
1069 write_char( writer, ':' );
1070 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1072 write_char( writer, '=' );
1073 write_char( writer, quote );
1074 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1075 write_char( writer, quote );
1077 return S_OK;
1080 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1082 if (!attr->prefix || !attr->prefix->length)
1084 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1085 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1087 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1088 return RECORD_XMLNS_ATTRIBUTE;
1091 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1093 ULONG id;
1094 enum record_type type = get_xmlns_record_type( attr, get_string_id(writer, attr->ns, &id) );
1095 HRESULT hr;
1097 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1098 write_char( writer, type );
1100 switch (type)
1102 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1103 break;
1105 case RECORD_XMLNS_ATTRIBUTE:
1106 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1107 break;
1109 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1110 return write_dict_string( writer, id );
1112 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1113 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1114 return write_dict_string( writer, id );
1116 default:
1117 ERR( "unhandled record type %02x\n", type );
1118 return WS_E_NOT_SUPPORTED;
1121 return write_string( writer, attr->ns->bytes, attr->ns->length );
1124 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1126 switch (writer->output_enc)
1128 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1129 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1130 default:
1131 ERR( "unhandled encoding %u\n", writer->output_enc );
1132 return WS_E_NOT_SUPPORTED;
1136 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1137 const WS_XML_STRING *ns, BOOL single )
1139 WS_XML_ATTRIBUTE *attr;
1140 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1141 HRESULT hr;
1143 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1145 attr->singleQuote = !!single;
1146 attr->isXmlNs = 1;
1147 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1149 free_attribute( attr );
1150 return E_OUTOFMEMORY;
1152 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1154 free_attribute( attr );
1155 return E_OUTOFMEMORY;
1157 if ((hr = append_attribute( elem, attr )) != S_OK)
1159 free_attribute( attr );
1160 return hr;
1162 return S_OK;
1165 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1167 if (!str1 && !str2) return TRUE;
1168 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1171 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1172 const WS_XML_STRING *ns )
1174 ULONG i;
1175 const struct node *node;
1177 for (node = (const struct node *)elem; node; node = node->parent)
1179 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1181 elem = &node->hdr;
1182 for (i = 0; i < elem->attributeCount; i++)
1184 if (!elem->attributes[i]->isXmlNs) continue;
1185 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1186 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1189 return FALSE;
1192 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1194 WS_XML_STRING *str;
1195 if (!(str = dup_xml_string( ns, writer->dict_do_lookup ))) return E_OUTOFMEMORY;
1196 free_xml_string( writer->current_ns );
1197 writer->current_ns = str;
1198 return S_OK;
1201 static HRESULT set_namespaces( struct writer *writer )
1203 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1204 HRESULT hr;
1205 ULONG i;
1207 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1209 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1210 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1213 for (i = 0; i < elem->attributeCount; i++)
1215 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1216 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1217 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1220 return S_OK;
1223 /**************************************************************************
1224 * WsWriteEndAttribute [webservices.@]
1226 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1228 struct writer *writer = (struct writer *)handle;
1230 TRACE( "%p %p\n", handle, error );
1231 if (error) FIXME( "ignoring error parameter\n" );
1233 if (!writer) return E_INVALIDARG;
1235 EnterCriticalSection( &writer->cs );
1237 if (writer->magic != WRITER_MAGIC)
1239 LeaveCriticalSection( &writer->cs );
1240 return E_INVALIDARG;
1243 writer->state = WRITER_STATE_STARTELEMENT;
1245 LeaveCriticalSection( &writer->cs );
1246 return S_OK;
1249 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1251 ULONG i;
1252 HRESULT hr;
1253 for (i = 0; i < elem->attributeCount; i++)
1255 if (elem->attributes[i]->isXmlNs) continue;
1256 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1258 for (i = 0; i < elem->attributeCount; i++)
1260 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1261 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1263 for (i = 0; i < elem->attributeCount; i++)
1265 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1266 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1268 return S_OK;
1271 static HRESULT write_startelement_text( struct writer *writer )
1273 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1274 ULONG size;
1275 HRESULT hr;
1277 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1279 size = elem->localName->length + 1 /* '<' */;
1280 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1281 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1283 write_char( writer, '<' );
1284 if (elem->prefix && elem->prefix->length)
1286 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1287 write_char( writer, ':' );
1289 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1290 return write_attributes( writer, elem );
1293 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1295 if (!elem->prefix || !elem->prefix->length)
1297 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1298 return RECORD_SHORT_ELEMENT;
1300 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1302 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1303 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1305 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1306 return RECORD_ELEMENT;
1309 static HRESULT write_startelement_bin( struct writer *writer )
1311 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1312 ULONG id;
1313 enum record_type type = get_elem_record_type( elem, get_string_id(writer, elem->localName, &id) );
1314 HRESULT hr;
1316 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1317 write_char( writer, type );
1319 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1321 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1322 return write_attributes( writer, elem );
1324 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1326 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1327 return write_attributes( writer, elem );
1330 switch (type)
1332 case RECORD_SHORT_ELEMENT:
1333 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1334 break;
1336 case RECORD_ELEMENT:
1337 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1338 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1339 break;
1341 case RECORD_SHORT_DICTIONARY_ELEMENT:
1342 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1343 break;
1345 case RECORD_DICTIONARY_ELEMENT:
1346 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1347 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1348 break;
1350 default:
1351 ERR( "unhandled record type %02x\n", type );
1352 return WS_E_NOT_SUPPORTED;
1355 return write_attributes( writer, elem );
1358 static HRESULT write_startelement( struct writer *writer )
1360 switch (writer->output_enc)
1362 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1363 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1364 default:
1365 ERR( "unhandled encoding %u\n", writer->output_enc );
1366 return WS_E_NOT_SUPPORTED;
1370 static struct node *write_find_startelement( struct writer *writer )
1372 struct node *node;
1373 for (node = writer->current; node; node = node->parent)
1375 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1377 return NULL;
1380 static inline BOOL is_empty_element( const struct node *node )
1382 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1383 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1386 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1388 ULONG size;
1389 HRESULT hr;
1391 /* '/>' */
1393 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1395 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1396 write_char( writer, '/' );
1397 write_char( writer, '>' );
1398 return S_OK;
1401 /* '</prefix:localname>' */
1403 size = elem->localName->length + 3 /* '</>' */;
1404 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1405 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1407 write_char( writer, '<' );
1408 write_char( writer, '/' );
1409 if (elem->prefix && elem->prefix->length)
1411 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1412 write_char( writer, ':' );
1414 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1415 write_char( writer, '>' );
1416 return S_OK;
1419 static HRESULT write_endelement_bin( struct writer *writer )
1421 HRESULT hr;
1422 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1423 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1424 write_char( writer, RECORD_ENDELEMENT );
1425 return S_OK;
1428 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1430 switch (writer->output_enc)
1432 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1433 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1434 default:
1435 ERR( "unhandled encoding %u\n", writer->output_enc );
1436 return WS_E_NOT_SUPPORTED;
1440 static HRESULT write_close_element( struct writer *writer, struct node *node )
1442 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1443 elem->isEmpty = is_empty_element( node );
1444 return write_endelement( writer, elem );
1447 static HRESULT write_endelement_node( struct writer *writer )
1449 struct node *node;
1450 HRESULT hr;
1452 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1453 if (writer->state == WRITER_STATE_STARTELEMENT)
1455 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1456 if ((hr = write_startelement( writer )) != S_OK) return hr;
1458 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1459 writer->current = node->parent;
1460 writer->state = WRITER_STATE_ENDELEMENT;
1461 return S_OK;
1464 /**************************************************************************
1465 * WsWriteEndElement [webservices.@]
1467 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1469 struct writer *writer = (struct writer *)handle;
1470 HRESULT hr;
1472 TRACE( "%p %p\n", handle, error );
1473 if (error) FIXME( "ignoring error parameter\n" );
1475 if (!writer) return E_INVALIDARG;
1477 EnterCriticalSection( &writer->cs );
1479 if (writer->magic != WRITER_MAGIC)
1481 LeaveCriticalSection( &writer->cs );
1482 return E_INVALIDARG;
1485 hr = write_endelement_node( writer );
1487 LeaveCriticalSection( &writer->cs );
1488 return hr;
1491 static HRESULT write_endstartelement_text( struct writer *writer )
1493 HRESULT hr;
1494 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1495 write_char( writer, '>' );
1496 return S_OK;
1499 static HRESULT write_endstartelement( struct writer *writer )
1501 switch (writer->output_enc)
1503 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1504 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1505 default:
1506 ERR( "unhandled encoding %u\n", writer->output_enc );
1507 return WS_E_NOT_SUPPORTED;
1511 /**************************************************************************
1512 * WsWriteEndStartElement [webservices.@]
1514 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
1516 struct writer *writer = (struct writer *)handle;
1517 HRESULT hr;
1519 TRACE( "%p %p\n", handle, error );
1520 if (error) FIXME( "ignoring error parameter\n" );
1522 if (!writer) return E_INVALIDARG;
1524 EnterCriticalSection( &writer->cs );
1526 if (writer->magic != WRITER_MAGIC)
1528 LeaveCriticalSection( &writer->cs );
1529 return E_INVALIDARG;
1532 if (writer->state != WRITER_STATE_STARTELEMENT)
1534 LeaveCriticalSection( &writer->cs );
1535 return WS_E_INVALID_OPERATION;
1538 if ((hr = set_namespaces( writer )) != S_OK) goto done;
1539 if ((hr = write_startelement( writer )) != S_OK) goto done;
1540 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
1541 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1543 done:
1544 LeaveCriticalSection( &writer->cs );
1545 return hr;
1548 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1549 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1550 BOOL single )
1552 WS_XML_ATTRIBUTE *attr;
1553 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1554 HRESULT hr;
1556 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1558 if (!prefix && ns->length) prefix = elem->prefix;
1560 attr->singleQuote = !!single;
1561 if (prefix && !(attr->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1563 free_attribute( attr );
1564 return E_OUTOFMEMORY;
1566 if (!(attr->localName = dup_xml_string( localname, writer->dict_do_lookup )))
1568 free_attribute( attr );
1569 return E_OUTOFMEMORY;
1571 if (!(attr->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1573 free_attribute( attr );
1574 return E_OUTOFMEMORY;
1576 if ((hr = append_attribute( elem, attr )) != S_OK)
1578 free_attribute( attr );
1579 return hr;
1581 return S_OK;
1584 /**************************************************************************
1585 * WsWriteStartAttribute [webservices.@]
1587 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1588 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1589 BOOL single, WS_ERROR *error )
1591 struct writer *writer = (struct writer *)handle;
1592 HRESULT hr;
1594 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1595 debugstr_xmlstr(ns), single, error );
1596 if (error) FIXME( "ignoring error parameter\n" );
1598 if (!writer || !localname || !ns) return E_INVALIDARG;
1600 EnterCriticalSection( &writer->cs );
1602 if (writer->magic != WRITER_MAGIC)
1604 LeaveCriticalSection( &writer->cs );
1605 return E_INVALIDARG;
1608 if (writer->state != WRITER_STATE_STARTELEMENT)
1610 LeaveCriticalSection( &writer->cs );
1611 return WS_E_INVALID_OPERATION;
1614 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
1615 writer->state = WRITER_STATE_STARTATTRIBUTE;
1617 LeaveCriticalSection( &writer->cs );
1618 return hr;
1621 /* flush current start element if necessary */
1622 static HRESULT write_flush( struct writer *writer )
1624 if (writer->state == WRITER_STATE_STARTELEMENT)
1626 HRESULT hr;
1627 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1628 if ((hr = write_startelement( writer )) != S_OK) return hr;
1629 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
1630 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1632 return S_OK;
1635 static HRESULT write_add_cdata_node( struct writer *writer )
1637 struct node *node, *parent;
1638 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1639 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1640 write_insert_node( writer, parent, node );
1641 return S_OK;
1644 static HRESULT write_add_endcdata_node( struct writer *writer )
1646 struct node *node;
1647 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
1648 node->parent = writer->current;
1649 list_add_tail( &node->parent->children, &node->entry );
1650 return S_OK;
1653 static HRESULT write_cdata( struct writer *writer )
1655 HRESULT hr;
1656 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
1657 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
1658 return S_OK;
1661 static HRESULT write_cdata_node( struct writer *writer )
1663 HRESULT hr;
1664 if ((hr = write_flush( writer )) != S_OK) return hr;
1665 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
1666 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
1667 if ((hr = write_cdata( writer )) != S_OK) return hr;
1668 writer->state = WRITER_STATE_STARTCDATA;
1669 return S_OK;
1672 /**************************************************************************
1673 * WsWriteStartCData [webservices.@]
1675 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
1677 struct writer *writer = (struct writer *)handle;
1678 HRESULT hr;
1680 TRACE( "%p %p\n", handle, error );
1681 if (error) FIXME( "ignoring error parameter\n" );
1683 if (!writer) return E_INVALIDARG;
1685 EnterCriticalSection( &writer->cs );
1687 if (writer->magic != WRITER_MAGIC)
1689 LeaveCriticalSection( &writer->cs );
1690 return E_INVALIDARG;
1693 hr = write_cdata_node( writer );
1695 LeaveCriticalSection( &writer->cs );
1696 return hr;
1699 static HRESULT write_endcdata( struct writer *writer )
1701 HRESULT hr;
1702 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
1703 write_bytes( writer, (const BYTE *)"]]>", 3 );
1704 return S_OK;
1707 static HRESULT write_endcdata_node( struct writer *writer )
1709 HRESULT hr;
1710 if ((hr = write_endcdata( writer )) != S_OK) return hr;
1711 writer->current = writer->current->parent;
1712 writer->state = WRITER_STATE_ENDCDATA;
1713 return S_OK;
1716 /**************************************************************************
1717 * WsWriteEndCData [webservices.@]
1719 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
1721 struct writer *writer = (struct writer *)handle;
1722 HRESULT hr;
1724 TRACE( "%p %p\n", handle, error );
1725 if (error) FIXME( "ignoring error parameter\n" );
1727 if (!writer) return E_INVALIDARG;
1729 EnterCriticalSection( &writer->cs );
1731 if (writer->magic != WRITER_MAGIC)
1733 LeaveCriticalSection( &writer->cs );
1734 return E_INVALIDARG;
1737 if (writer->state != WRITER_STATE_TEXT)
1739 LeaveCriticalSection( &writer->cs );
1740 return WS_E_INVALID_OPERATION;
1743 hr = write_endcdata_node( writer );
1745 LeaveCriticalSection( &writer->cs );
1746 return hr;
1749 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1750 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1752 struct node *node, *parent;
1753 WS_XML_ELEMENT_NODE *elem;
1755 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1757 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1759 elem = &parent->hdr;
1760 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
1763 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
1764 elem = &node->hdr;
1766 if (prefix && !(elem->prefix = dup_xml_string( prefix, writer->dict_do_lookup )))
1768 free_node( node );
1769 return E_OUTOFMEMORY;
1771 if (!(elem->localName = dup_xml_string( localname, writer->dict_do_lookup )))
1773 free_node( node );
1774 return E_OUTOFMEMORY;
1776 if (!(elem->ns = dup_xml_string( ns, writer->dict_do_lookup )))
1778 free_node( node );
1779 return E_OUTOFMEMORY;
1781 write_insert_node( writer, parent, node );
1782 return S_OK;
1785 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1787 struct node *node;
1788 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1789 node->parent = parent;
1790 list_add_tail( &parent->children, &node->entry );
1791 return S_OK;
1794 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1795 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1797 HRESULT hr;
1798 if ((hr = write_flush( writer )) != S_OK) return hr;
1799 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1800 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1801 writer->state = WRITER_STATE_STARTELEMENT;
1802 return S_OK;
1805 /**************************************************************************
1806 * WsWriteStartElement [webservices.@]
1808 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1809 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1810 WS_ERROR *error )
1812 struct writer *writer = (struct writer *)handle;
1813 HRESULT hr;
1815 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1816 debugstr_xmlstr(ns), error );
1817 if (error) FIXME( "ignoring error parameter\n" );
1819 if (!writer || !localname || !ns) return E_INVALIDARG;
1821 EnterCriticalSection( &writer->cs );
1823 if (writer->magic != WRITER_MAGIC)
1825 LeaveCriticalSection( &writer->cs );
1826 return E_INVALIDARG;
1829 hr = write_element_node( writer, prefix, localname, ns );
1831 LeaveCriticalSection( &writer->cs );
1832 return hr;
1835 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1837 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1838 if (*ptr)
1840 memcpy( buf, bool_true, sizeof(bool_true) );
1841 return sizeof(bool_true);
1843 memcpy( buf, bool_false, sizeof(bool_false) );
1844 return sizeof(bool_false);
1847 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1849 return wsprintfA( (char *)buf, "%d", *ptr );
1852 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1854 return wsprintfA( (char *)buf, "%I64d", *ptr );
1857 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1859 return wsprintfA( (char *)buf, "%I64u", *ptr );
1862 static ULONG format_double( const double *ptr, unsigned char *buf )
1864 #ifdef HAVE_POWL
1865 static const long double precision = 0.0000000000000001;
1866 unsigned char *p = buf;
1867 long double val = *ptr;
1868 int neg, mag, mag2, use_exp;
1870 if (isnan( val ))
1872 memcpy( buf, "NaN", 3 );
1873 return 3;
1875 if (isinf( val ))
1877 if (val < 0)
1879 memcpy( buf, "-INF", 4 );
1880 return 4;
1882 memcpy( buf, "INF", 3 );
1883 return 3;
1885 if (val == 0.0)
1887 *p = '0';
1888 return 1;
1891 if ((neg = val < 0))
1893 *p++ = '-';
1894 val = -val;
1897 mag = log10l( val );
1898 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1899 if (use_exp)
1901 if (mag < 0) mag -= 1;
1902 val = val / powl( 10.0, mag );
1903 mag2 = mag;
1904 mag = 0;
1906 else if (mag < 1) mag = 0;
1908 while (val > precision || mag >= 0)
1910 long double weight = powl( 10.0, mag );
1911 if (weight > 0 && !isinf( weight ))
1913 int digit = floorl( val / weight );
1914 val -= digit * weight;
1915 *(p++) = '0' + digit;
1917 if (!mag && val > precision) *(p++) = '.';
1918 mag--;
1921 if (use_exp)
1923 int i, j;
1924 *(p++) = 'E';
1925 if (mag2 > 0) *(p++) = '+';
1926 else
1928 *(p++) = '-';
1929 mag2 = -mag2;
1931 mag = 0;
1932 while (mag2 > 0)
1934 *(p++) = '0' + mag2 % 10;
1935 mag2 /= 10;
1936 mag++;
1938 for (i = -mag, j = -1; i < j; i++, j--)
1940 p[i] ^= p[j];
1941 p[j] ^= p[i];
1942 p[i] ^= p[j];
1946 return p - buf;
1947 #else
1948 FIXME( "powl not found at build time\n" );
1949 return 0;
1950 #endif
1953 static inline int year_size( int year )
1955 return leap_year( year ) ? 366 : 365;
1958 #define TZ_OFFSET 8
1959 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1961 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1962 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
1963 unsigned __int64 ticks, day_ticks;
1964 ULONG len;
1966 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1967 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1969 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1970 tz_hour = TZ_OFFSET;
1972 else
1974 ticks = ptr->ticks;
1975 tz_hour = 0;
1977 day = ticks / TICKS_PER_DAY;
1978 day_ticks = ticks % TICKS_PER_DAY;
1979 hour = day_ticks / TICKS_PER_HOUR;
1980 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1981 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1982 sec_frac = day_ticks % TICKS_PER_SEC;
1984 while (day >= year_size( year ))
1986 day -= year_size( year );
1987 year++;
1989 while (day >= month_days[leap_year( year )][month])
1991 day -= month_days[leap_year( year )][month];
1992 month++;
1995 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1996 if (sec_frac)
1998 static const char fmt_frac[] = ".%07u";
1999 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
2000 while (buf[len - 1] == '0') len--;
2002 if (ptr->format == WS_DATETIME_FORMAT_UTC)
2004 buf[len++] = 'Z';
2006 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
2008 static const char fmt_tz[] = "%c%02u:00";
2009 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
2012 return len;
2015 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
2017 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
2018 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
2019 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
2020 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
2023 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
2025 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
2026 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
2027 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
2028 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
2031 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
2033 ULONG len = 0;
2034 if (prefix && prefix->length)
2036 memcpy( buf, prefix->bytes, prefix->length );
2037 len += prefix->length;
2038 buf[len++] = ':';
2040 memcpy( buf + len, localname->bytes, localname->length );
2041 return len + localname->length;
2044 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
2046 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2047 ULONG i = 0, x;
2049 while (len > 0)
2051 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
2052 x = (bin[0] & 3) << 4;
2053 if (len == 1)
2055 buf[i++] = base64[x];
2056 buf[i++] = '=';
2057 buf[i++] = '=';
2058 break;
2060 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
2061 x = (bin[1] & 0x0f) << 2;
2062 if (len == 2)
2064 buf[i++] = base64[x];
2065 buf[i++] = '=';
2066 break;
2068 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
2069 buf[i++] = base64[bin[2] & 0x3f];
2070 bin += 3;
2071 len -= 3;
2073 return i;
2076 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
2077 WS_XML_UTF8_TEXT **ret )
2079 ULONG len_old = old ? old->value.length : 0;
2080 if (offset) *offset = len_old;
2082 switch (text->textType)
2084 case WS_XML_TEXT_TYPE_UTF8:
2086 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
2088 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
2089 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2090 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
2091 return S_OK;
2093 case WS_XML_TEXT_TYPE_UTF16:
2095 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
2096 const WCHAR *str = (const WCHAR *)src->bytes;
2097 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
2099 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2100 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2101 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2102 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2103 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
2104 return S_OK;
2106 case WS_XML_TEXT_TYPE_BASE64:
2108 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2109 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
2111 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2112 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2113 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
2114 return S_OK;
2116 case WS_XML_TEXT_TYPE_BOOL:
2118 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2120 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
2121 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2122 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
2123 return S_OK;
2125 case WS_XML_TEXT_TYPE_INT32:
2127 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2128 unsigned char buf[12]; /* "-2147483648" */
2129 ULONG len = format_int32( &int32_text->value, buf );
2131 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2132 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2133 memcpy( (*ret)->value.bytes + len_old, buf, len );
2134 return S_OK;
2136 case WS_XML_TEXT_TYPE_INT64:
2138 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2139 unsigned char buf[21]; /* "-9223372036854775808" */
2140 ULONG len = format_int64( &int64_text->value, buf );
2142 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2143 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2144 memcpy( (*ret)->value.bytes + len_old, buf, len );
2145 return S_OK;
2147 case WS_XML_TEXT_TYPE_UINT64:
2149 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2150 unsigned char buf[21]; /* "18446744073709551615" */
2151 ULONG len = format_uint64( &uint64_text->value, buf );
2153 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2154 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2155 memcpy( (*ret)->value.bytes + len_old, buf, len );
2156 return S_OK;
2158 case WS_XML_TEXT_TYPE_DOUBLE:
2160 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2161 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
2162 unsigned short fpword;
2163 ULONG len;
2165 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
2166 len = format_double( &double_text->value, buf );
2167 restore_fpword( fpword );
2168 if (!len) return E_NOTIMPL;
2170 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2171 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2172 memcpy( (*ret)->value.bytes + len_old, buf, len );
2173 return S_OK;
2175 case WS_XML_TEXT_TYPE_GUID:
2177 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2179 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
2180 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2181 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2182 return S_OK;
2184 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2186 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2188 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
2189 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2190 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2191 return S_OK;
2193 case WS_XML_TEXT_TYPE_DATETIME:
2195 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2197 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
2198 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2199 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
2200 return S_OK;
2202 case WS_XML_TEXT_TYPE_QNAME:
2204 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
2205 ULONG len = qn->localName->length;
2207 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
2208 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2209 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2210 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
2211 return S_OK;
2213 default:
2214 FIXME( "unhandled text type %u\n", text->textType );
2215 return E_NOTIMPL;
2219 static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2221 if (offset) *offset = 0;
2222 switch (text->textType)
2224 case WS_XML_TEXT_TYPE_UTF8:
2226 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2227 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2228 WS_XML_UTF8_TEXT *new;
2229 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2231 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2232 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2233 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2234 if (offset) *offset = len_old;
2235 *ret = &new->text;
2236 return S_OK;
2238 case WS_XML_TEXT_TYPE_UTF16:
2240 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2241 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2242 WS_XML_UTF8_TEXT *new;
2243 const WCHAR *str = (const WCHAR *)utf16->bytes;
2244 ULONG len = utf16->byteCount / sizeof(WCHAR), len_utf8, len_old = utf8_old ? utf8_old->value.length : 0;
2246 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2247 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2248 if (!(new = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2249 if (old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2250 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)new->value.bytes + len_old, len_utf8, NULL, NULL );
2251 if (offset) *offset = len_old;
2252 *ret = &new->text;
2253 return S_OK;
2255 case WS_XML_TEXT_TYPE_BASE64:
2257 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2258 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2259 WS_XML_BASE64_TEXT *new;
2260 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2262 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2263 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2264 memcpy( new->bytes + len_old, base64->bytes, len );
2265 if (offset) *offset = len_old;
2266 *ret = &new->text;
2267 return S_OK;
2269 case WS_XML_TEXT_TYPE_BOOL:
2271 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2272 WS_XML_BOOL_TEXT *new;
2274 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2275 *ret = &new->text;
2276 return S_OK;
2278 case WS_XML_TEXT_TYPE_INT32:
2280 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2281 WS_XML_INT32_TEXT *new;
2283 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2284 *ret = &new->text;
2285 return S_OK;
2287 case WS_XML_TEXT_TYPE_INT64:
2289 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2290 WS_XML_INT64_TEXT *new;
2292 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2293 *ret = &new->text;
2294 return S_OK;
2296 case WS_XML_TEXT_TYPE_UINT64:
2298 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2299 WS_XML_UINT64_TEXT *new;
2301 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2302 *ret = &new->text;
2303 return S_OK;
2305 case WS_XML_TEXT_TYPE_DOUBLE:
2307 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2308 WS_XML_DOUBLE_TEXT *new;
2310 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2311 *ret = &new->text;
2312 return S_OK;
2314 case WS_XML_TEXT_TYPE_GUID:
2316 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2317 WS_XML_GUID_TEXT *new;
2319 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2320 *ret = &new->text;
2321 return S_OK;
2323 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2325 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2326 WS_XML_UNIQUE_ID_TEXT *new;
2328 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2329 *ret = &new->text;
2330 return S_OK;
2332 case WS_XML_TEXT_TYPE_DATETIME:
2334 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2335 WS_XML_DATETIME_TEXT *new;
2337 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2338 *ret = &new->text;
2339 return S_OK;
2341 default:
2342 FIXME( "unhandled text type %u\n", text->textType );
2343 return E_NOTIMPL;
2347 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2349 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2350 HRESULT hr;
2352 switch (value->textType)
2354 case WS_XML_TEXT_TYPE_UTF8:
2355 case WS_XML_TEXT_TYPE_UTF16:
2356 case WS_XML_TEXT_TYPE_BASE64:
2357 break;
2359 case WS_XML_TEXT_TYPE_BOOL:
2360 case WS_XML_TEXT_TYPE_INT32:
2361 case WS_XML_TEXT_TYPE_INT64:
2362 case WS_XML_TEXT_TYPE_UINT64:
2363 case WS_XML_TEXT_TYPE_DOUBLE:
2364 case WS_XML_TEXT_TYPE_GUID:
2365 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2366 case WS_XML_TEXT_TYPE_DATETIME:
2367 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2368 break;
2370 default:
2371 FIXME( "unhandled text type %u\n", value->textType );
2372 return E_NOTIMPL;
2375 switch (writer->output_enc)
2377 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2379 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2380 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2381 heap_free( old );
2382 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2383 break;
2385 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2387 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2388 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2389 heap_free( old );
2390 elem->attributes[elem->attributeCount - 1]->value = new;
2391 break;
2393 default:
2394 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2395 return E_NOTIMPL;
2398 return S_OK;
2401 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2403 struct node *node;
2404 WS_XML_TEXT_NODE *text;
2405 HRESULT hr;
2407 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2408 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2409 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2411 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2412 text = (WS_XML_TEXT_NODE *)node;
2414 switch (writer->output_enc)
2416 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2418 WS_XML_UTF8_TEXT *new;
2419 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2421 heap_free( node );
2422 return hr;
2424 text->text = &new->text;
2425 break;
2427 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2429 WS_XML_TEXT *new;
2430 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2432 heap_free( node );
2433 return hr;
2435 text->text = new;
2436 break;
2438 default:
2439 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2440 heap_free( node );
2441 return E_NOTIMPL;
2444 write_insert_node( writer, writer->current, node );
2445 return S_OK;
2448 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2450 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2451 HRESULT hr;
2453 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2455 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2456 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2458 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2460 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2461 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2462 return S_OK;
2465 return WS_E_INVALID_FORMAT;
2468 static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL use_dict )
2470 switch (text->textType)
2472 case WS_XML_TEXT_TYPE_UTF8:
2474 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2475 if (use_dict) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT;
2476 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2477 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2478 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2480 case WS_XML_TEXT_TYPE_BASE64:
2482 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2483 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2484 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2485 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2486 return RECORD_BYTES32_TEXT;
2488 case WS_XML_TEXT_TYPE_BOOL:
2490 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2491 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2493 case WS_XML_TEXT_TYPE_INT32:
2495 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2496 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2497 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2498 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2499 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2500 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2502 case WS_XML_TEXT_TYPE_INT64:
2504 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2505 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2506 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2507 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2508 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2509 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2510 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2512 case WS_XML_TEXT_TYPE_UINT64:
2514 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2515 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2516 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2517 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2518 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2519 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2520 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2521 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2523 case WS_XML_TEXT_TYPE_DOUBLE:
2525 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2526 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2527 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2528 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2529 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2530 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2531 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2532 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2533 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2535 case WS_XML_TEXT_TYPE_GUID:
2536 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2538 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2539 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2541 case WS_XML_TEXT_TYPE_DATETIME:
2542 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2544 default:
2545 FIXME( "unhandled text type %u\n", text->textType );
2546 return 0;
2550 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2552 enum record_type type;
2553 BOOL use_dict = FALSE;
2554 HRESULT hr;
2555 ULONG id;
2557 if (offset)
2559 FIXME( "no support for appending text in binary mode\n" );
2560 return E_NOTIMPL;
2563 if (text->textType == WS_XML_TEXT_TYPE_UTF8)
2565 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2566 use_dict = get_string_id( writer, &utf8->value, &id );
2569 switch ((type = get_text_record_type( text, use_dict )))
2571 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2573 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2574 UINT8 len = text_utf8->value.length;
2576 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2577 write_char( writer, type );
2578 write_char( writer, len );
2579 write_bytes( writer, text_utf8->value.bytes, len );
2580 return S_OK;
2582 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2584 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2585 UINT16 len = text_utf8->value.length;
2587 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2588 write_char( writer, type );
2589 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2590 write_bytes( writer, text_utf8->value.bytes, len );
2591 return S_OK;
2593 case RECORD_BYTES8_TEXT:
2595 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2596 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2598 if (len)
2600 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2601 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2602 write_char( writer, len );
2603 write_bytes( writer, text_base64->bytes, len );
2605 if (rem)
2607 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2608 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2609 write_char( writer, rem );
2610 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2612 return S_OK;
2614 case RECORD_BYTES16_TEXT:
2616 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2617 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2619 if (len)
2621 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2622 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2623 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2624 write_bytes( writer, text_base64->bytes, len );
2626 if (rem)
2628 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2629 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2630 write_char( writer, rem );
2631 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2633 return S_OK;
2635 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2636 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2637 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2638 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2640 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2641 write_char( writer, type );
2642 return S_OK;
2644 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2646 INT8 val = get_text_value_int( text );
2647 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2648 write_char( writer, type );
2649 write_char( writer, val );
2650 return S_OK;
2652 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2654 INT16 val = get_text_value_int( text );
2655 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2656 write_char( writer, type );
2657 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2658 return S_OK;
2660 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2662 INT32 val = get_text_value_int( text );
2663 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2664 write_char( writer, type );
2665 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2666 return S_OK;
2668 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2670 INT64 val = get_text_value_int( text );
2671 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2672 write_char( writer, type );
2673 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2674 return S_OK;
2676 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2678 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2679 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2680 write_char( writer, type );
2681 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2682 return S_OK;
2684 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2686 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2687 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2688 write_char( writer, type );
2689 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2690 return S_OK;
2692 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2694 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2695 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2696 write_char( writer, type );
2697 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2698 return S_OK;
2700 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2702 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2703 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2704 write_char( writer, type );
2705 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2706 return S_OK;
2708 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2710 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2711 UINT64 val = text_datetime->value.ticks;
2713 assert( val <= TICKS_MAX );
2714 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2715 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2717 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2718 write_char( writer, type );
2719 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2720 return S_OK;
2722 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT:
2724 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2725 write_char( writer, type );
2726 return write_dict_string( writer, id );
2728 default:
2729 FIXME( "unhandled record type %02x\n", type );
2730 return E_NOTIMPL;
2734 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2736 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2738 switch (writer->output_enc)
2740 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2741 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2742 default:
2743 ERR( "unhandled encoding %u\n", writer->output_enc );
2744 return WS_E_NOT_SUPPORTED;
2748 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2750 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2751 ULONG offset = 0;
2752 HRESULT hr;
2754 if ((hr = write_flush( writer )) != S_OK) return hr;
2755 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2757 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2758 node = (WS_XML_TEXT_NODE *)writer->current;
2760 else
2762 switch (writer->output_enc)
2764 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2766 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2767 offset = old->value.length;
2768 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2769 heap_free( old );
2770 node->text = &new->text;
2771 break;
2773 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2775 WS_XML_TEXT *new, *old = node->text;
2776 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2777 heap_free( old );
2778 node->text = new;
2779 break;
2781 default:
2782 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2783 return E_NOTIMPL;
2787 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2789 writer->state = WRITER_STATE_TEXT;
2790 return S_OK;
2793 /**************************************************************************
2794 * WsWriteText [webservices.@]
2796 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2798 struct writer *writer = (struct writer *)handle;
2799 HRESULT hr;
2801 TRACE( "%p %p %p\n", handle, text, error );
2802 if (error) FIXME( "ignoring error parameter\n" );
2804 if (!writer || !text) return E_INVALIDARG;
2806 EnterCriticalSection( &writer->cs );
2808 if (writer->magic != WRITER_MAGIC)
2810 LeaveCriticalSection( &writer->cs );
2811 return E_INVALIDARG;
2814 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2815 else hr = write_text_node( writer, text );
2817 LeaveCriticalSection( &writer->cs );
2818 return hr;
2821 /**************************************************************************
2822 * WsWriteBytes [webservices.@]
2824 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2826 struct writer *writer = (struct writer *)handle;
2827 WS_XML_BASE64_TEXT base64;
2828 HRESULT hr;
2830 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2831 if (error) FIXME( "ignoring error parameter\n" );
2833 if (!writer) return E_INVALIDARG;
2835 EnterCriticalSection( &writer->cs );
2837 if (writer->magic != WRITER_MAGIC)
2839 LeaveCriticalSection( &writer->cs );
2840 return E_INVALIDARG;
2843 if (!writer->output_type)
2845 LeaveCriticalSection( &writer->cs );
2846 return WS_E_INVALID_OPERATION;
2849 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2850 base64.bytes = (BYTE *)bytes;
2851 base64.length = count;
2853 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2854 else hr = write_text_node( writer, &base64.text );
2856 LeaveCriticalSection( &writer->cs );
2857 return hr;
2860 /**************************************************************************
2861 * WsWriteChars [webservices.@]
2863 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
2865 struct writer *writer = (struct writer *)handle;
2866 WS_XML_UTF16_TEXT utf16;
2867 HRESULT hr;
2869 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
2870 if (error) FIXME( "ignoring error parameter\n" );
2872 if (!writer) return E_INVALIDARG;
2874 EnterCriticalSection( &writer->cs );
2876 if (writer->magic != WRITER_MAGIC)
2878 LeaveCriticalSection( &writer->cs );
2879 return E_INVALIDARG;
2882 if (!writer->output_type)
2884 LeaveCriticalSection( &writer->cs );
2885 return WS_E_INVALID_OPERATION;
2888 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2889 utf16.bytes = (BYTE *)chars;
2890 utf16.byteCount = count * sizeof(WCHAR);
2892 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
2893 else hr = write_text_node( writer, &utf16.text );
2895 LeaveCriticalSection( &writer->cs );
2896 return hr;
2899 /**************************************************************************
2900 * WsWriteCharsUtf8 [webservices.@]
2902 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
2904 struct writer *writer = (struct writer *)handle;
2905 WS_XML_UTF8_TEXT utf8;
2906 HRESULT hr;
2908 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
2909 if (error) FIXME( "ignoring error parameter\n" );
2911 if (!writer) return E_INVALIDARG;
2913 EnterCriticalSection( &writer->cs );
2915 if (writer->magic != WRITER_MAGIC)
2917 LeaveCriticalSection( &writer->cs );
2918 return E_INVALIDARG;
2921 if (!writer->output_type)
2923 LeaveCriticalSection( &writer->cs );
2924 return WS_E_INVALID_OPERATION;
2927 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2928 utf8.value.bytes = (BYTE *)bytes;
2929 utf8.value.length = count;
2931 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
2932 else hr = write_text_node( writer, &utf8.text );
2934 LeaveCriticalSection( &writer->cs );
2935 return hr;
2938 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
2940 switch (mapping)
2942 case WS_ELEMENT_TYPE_MAPPING:
2943 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2944 return write_text_node( writer, text );
2946 case WS_ATTRIBUTE_TYPE_MAPPING:
2947 return write_set_attribute_value( writer, text );
2949 case WS_ANY_ELEMENT_TYPE_MAPPING:
2950 switch (writer->state)
2952 case WRITER_STATE_STARTATTRIBUTE:
2953 return write_set_attribute_value( writer, text );
2955 case WRITER_STATE_STARTELEMENT:
2956 return write_text_node( writer, text );
2958 default:
2959 FIXME( "writer state %u not handled\n", writer->state );
2960 return E_NOTIMPL;
2963 default:
2964 FIXME( "mapping %u not implemented\n", mapping );
2965 return E_NOTIMPL;
2969 static HRESULT write_add_nil_attribute( struct writer *writer )
2971 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
2972 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
2973 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
2974 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
2975 HRESULT hr;
2977 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
2978 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
2979 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
2982 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
2983 const void **ptr )
2985 switch (option)
2987 case WS_WRITE_REQUIRED_VALUE:
2988 case WS_WRITE_NILLABLE_VALUE:
2989 if (!value || size != expected_size) return E_INVALIDARG;
2990 *ptr = value;
2991 return S_OK;
2993 case WS_WRITE_REQUIRED_POINTER:
2994 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
2995 return S_OK;
2997 case WS_WRITE_NILLABLE_POINTER:
2998 if (size != sizeof(const void *)) return E_INVALIDARG;
2999 *ptr = *(const void **)value;
3000 return S_OK;
3002 default:
3003 return E_INVALIDARG;
3007 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
3008 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
3009 const BOOL *value, ULONG size )
3011 WS_XML_BOOL_TEXT text_bool;
3012 const BOOL *ptr;
3013 HRESULT hr;
3015 if (desc)
3017 FIXME( "description not supported\n" );
3018 return E_NOTIMPL;
3021 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3022 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
3023 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3025 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
3026 text_bool.value = *ptr;
3027 return write_type_text( writer, mapping, &text_bool.text );
3030 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3031 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3032 const BOOL *value, ULONG size )
3034 WS_XML_INT32_TEXT text_int32;
3035 const INT8 *ptr;
3036 HRESULT hr;
3038 if (desc)
3040 FIXME( "description not supported\n" );
3041 return E_NOTIMPL;
3044 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3045 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3046 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3048 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3049 text_int32.value = *ptr;
3050 return write_type_text( writer, mapping, &text_int32.text );
3053 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3054 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3055 const BOOL *value, ULONG size )
3057 WS_XML_INT32_TEXT text_int32;
3058 const INT16 *ptr;
3059 HRESULT hr;
3061 if (desc)
3063 FIXME( "description not supported\n" );
3064 return E_NOTIMPL;
3067 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3068 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3069 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3071 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3072 text_int32.value = *ptr;
3073 return write_type_text( writer, mapping, &text_int32.text );
3076 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3077 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3078 const void *value, ULONG size )
3080 WS_XML_INT32_TEXT text_int32;
3081 const INT32 *ptr;
3082 HRESULT hr;
3084 if (desc)
3086 FIXME( "description not supported\n" );
3087 return E_NOTIMPL;
3090 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3091 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3092 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3094 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3095 text_int32.value = *ptr;
3096 return write_type_text( writer, mapping, &text_int32.text );
3099 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3100 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3101 const void *value, ULONG size )
3103 WS_XML_INT64_TEXT text_int64;
3104 const INT64 *ptr;
3105 HRESULT hr;
3107 if (desc)
3109 FIXME( "description not supported\n" );
3110 return E_NOTIMPL;
3113 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3114 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3115 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3117 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3118 text_int64.value = *ptr;
3119 return write_type_text( writer, mapping, &text_int64.text );
3122 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3123 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3124 const void *value, ULONG size )
3126 WS_XML_UINT64_TEXT text_uint64;
3127 const UINT8 *ptr;
3128 HRESULT hr;
3130 if (desc)
3132 FIXME( "description not supported\n" );
3133 return E_NOTIMPL;
3136 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3137 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3138 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3140 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3141 text_uint64.value = *ptr;
3142 return write_type_text( writer, mapping, &text_uint64.text );
3145 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3146 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3147 const void *value, ULONG size )
3149 WS_XML_UINT64_TEXT text_uint64;
3150 const UINT16 *ptr;
3151 HRESULT hr;
3153 if (desc)
3155 FIXME( "description not supported\n" );
3156 return E_NOTIMPL;
3159 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3160 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3161 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3163 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3164 text_uint64.value = *ptr;
3165 return write_type_text( writer, mapping, &text_uint64.text );
3168 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3169 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3170 const void *value, ULONG size )
3172 WS_XML_UINT64_TEXT text_uint64;
3173 const UINT32 *ptr;
3174 HRESULT hr;
3176 if (desc)
3178 FIXME( "description not supported\n" );
3179 return E_NOTIMPL;
3182 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3183 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3184 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3186 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3187 text_uint64.value = *ptr;
3188 return write_type_text( writer, mapping, &text_uint64.text );
3191 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3192 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3193 const void *value, ULONG size )
3195 WS_XML_UINT64_TEXT text_uint64;
3196 const UINT64 *ptr;
3197 HRESULT hr;
3199 if (desc)
3201 FIXME( "description not supported\n" );
3202 return E_NOTIMPL;
3205 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3206 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3207 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3209 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3210 text_uint64.value = *ptr;
3211 return write_type_text( writer, mapping, &text_uint64.text );
3214 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3215 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3216 const void *value, ULONG size )
3218 WS_XML_DOUBLE_TEXT text_double;
3219 const double *ptr;
3220 HRESULT hr;
3222 if (desc)
3224 FIXME( "description not supported\n" );
3225 return E_NOTIMPL;
3228 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3229 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3230 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3232 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3233 text_double.value = *ptr;
3234 return write_type_text( writer, mapping, &text_double.text );
3237 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3238 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3239 const void *value, ULONG size )
3241 WS_XML_DATETIME_TEXT text_datetime;
3242 const WS_DATETIME *ptr;
3243 HRESULT hr;
3245 if (desc)
3247 FIXME( "description not supported\n" );
3248 return E_NOTIMPL;
3251 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3252 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3253 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3254 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3256 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3257 text_datetime.value = *ptr;
3258 return write_type_text( writer, mapping, &text_datetime.text );
3261 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3262 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3263 const void *value, ULONG size )
3265 WS_XML_GUID_TEXT text_guid;
3266 const GUID *ptr;
3267 HRESULT hr;
3269 if (desc)
3271 FIXME( "description not supported\n" );
3272 return E_NOTIMPL;
3275 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3276 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3277 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3279 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3280 text_guid.value = *ptr;
3281 return write_type_text( writer, mapping, &text_guid.text );
3284 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3285 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3286 const void *value, ULONG size )
3288 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3289 WS_XML_UTF16_TEXT text_utf16;
3290 const WS_UNIQUE_ID *ptr;
3291 HRESULT hr;
3293 if (desc)
3295 FIXME( "description not supported\n" );
3296 return E_NOTIMPL;
3299 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3300 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3301 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3303 if (ptr->uri.length)
3305 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3306 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3307 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3308 return write_type_text( writer, mapping, &text_utf16.text );
3311 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3312 text_unique_id.value = ptr->guid;
3313 return write_type_text( writer, mapping, &text_unique_id.text );
3316 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3317 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3318 const void *value, ULONG size )
3320 WS_XML_UTF16_TEXT utf16;
3321 const WS_STRING *ptr;
3322 HRESULT hr;
3324 if (desc)
3326 FIXME( "description not supported\n" );
3327 return E_NOTIMPL;
3330 if (!option) return E_INVALIDARG;
3331 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3332 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3333 if (!ptr->length) return S_OK;
3335 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3336 utf16.bytes = (BYTE *)ptr->chars;
3337 utf16.byteCount = ptr->length * sizeof(WCHAR);
3338 return write_type_text( writer, mapping, &utf16.text );
3341 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3342 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3343 const void *value, ULONG size )
3345 WS_XML_UTF16_TEXT utf16;
3346 const WCHAR *ptr;
3347 HRESULT hr;
3348 int len;
3350 if (desc)
3352 FIXME( "description not supported\n" );
3353 return E_NOTIMPL;
3356 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3357 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3358 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3359 if (!(len = strlenW( ptr ))) return S_OK;
3361 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3362 utf16.bytes = (BYTE *)ptr;
3363 utf16.byteCount = len * sizeof(WCHAR);
3364 return write_type_text( writer, mapping, &utf16.text );
3367 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3368 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3369 const void *value, ULONG size )
3371 WS_XML_BASE64_TEXT base64;
3372 const WS_BYTES *ptr;
3373 HRESULT hr;
3375 if (desc)
3377 FIXME( "description not supported\n" );
3378 return E_NOTIMPL;
3381 if (!option) return E_INVALIDARG;
3382 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3383 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3384 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3385 if (!ptr->length) return S_OK;
3387 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3388 base64.bytes = ptr->bytes;
3389 base64.length = ptr->length;
3390 return write_type_text( writer, mapping, &base64.text );
3393 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3394 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3395 const void *value, ULONG size )
3397 WS_XML_UTF8_TEXT utf8;
3398 const WS_XML_STRING *ptr;
3399 HRESULT hr;
3401 if (desc)
3403 FIXME( "description not supported\n" );
3404 return E_NOTIMPL;
3407 if (!option) return E_INVALIDARG;
3408 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3409 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3410 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3411 if (!ptr->length) return S_OK;
3413 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3414 utf8.value.bytes = ptr->bytes;
3415 utf8.value.length = ptr->length;
3416 return write_type_text( writer, mapping, &utf8.text );
3419 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3421 const struct node *node;
3422 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3424 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3425 ULONG i;
3426 for (i = 0; i < elem->attributeCount; i++)
3428 if (!elem->attributes[i]->isXmlNs) continue;
3429 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3430 *prefix = elem->attributes[i]->prefix;
3431 return S_OK;
3434 return WS_E_INVALID_FORMAT;
3437 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3438 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3439 const void *value, ULONG size )
3441 WS_XML_QNAME_TEXT qname;
3442 const WS_XML_QNAME *ptr;
3443 const WS_XML_STRING *prefix;
3444 HRESULT hr;
3446 if (desc)
3448 FIXME( "description not supported\n" );
3449 return E_NOTIMPL;
3452 if (!option) return E_INVALIDARG;
3453 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3454 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3455 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3457 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3459 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3460 qname.prefix = (WS_XML_STRING *)prefix;
3461 qname.localName = (WS_XML_STRING *)&ptr->localName;
3462 qname.ns = (WS_XML_STRING *)&ptr->ns;
3463 return write_type_text( writer, mapping, &qname.text );
3466 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3468 if (options & WS_FIELD_POINTER)
3470 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3471 return WS_WRITE_REQUIRED_POINTER;
3474 switch (type)
3476 case WS_BOOL_TYPE:
3477 case WS_INT8_TYPE:
3478 case WS_INT16_TYPE:
3479 case WS_INT32_TYPE:
3480 case WS_INT64_TYPE:
3481 case WS_UINT8_TYPE:
3482 case WS_UINT16_TYPE:
3483 case WS_UINT32_TYPE:
3484 case WS_UINT64_TYPE:
3485 case WS_DOUBLE_TYPE:
3486 case WS_DATETIME_TYPE:
3487 case WS_GUID_TYPE:
3488 case WS_UNIQUE_ID_TYPE:
3489 case WS_STRING_TYPE:
3490 case WS_BYTES_TYPE:
3491 case WS_XML_STRING_TYPE:
3492 case WS_XML_QNAME_TYPE:
3493 case WS_STRUCT_TYPE:
3494 case WS_ENUM_TYPE:
3495 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3496 return WS_WRITE_REQUIRED_VALUE;
3498 case WS_WSZ_TYPE:
3499 case WS_DESCRIPTION_TYPE:
3500 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3501 return WS_WRITE_REQUIRED_POINTER;
3503 default:
3504 FIXME( "unhandled type %u\n", type );
3505 return 0;
3509 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3510 const void *, ULONG );
3512 static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
3513 const char *buf, ULONG count )
3515 HRESULT hr = S_OK;
3516 ULONG i, size, offset = 0;
3517 WS_WRITE_OPTION option;
3519 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3521 /* wrapper element */
3522 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3523 return hr;
3525 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3526 size = get_type_size( desc->type, desc->typeDescription );
3527 else
3528 size = sizeof(const void *);
3530 for (i = 0; i < count; i++)
3532 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3533 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3534 buf + offset, size )) != S_OK) return hr;
3535 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3536 offset += size;
3539 if (desc->localName) hr = write_endelement_node( writer );
3540 return hr;
3543 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3545 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3546 const void *value, ULONG size )
3548 ULONG i, offset;
3549 const void *ptr;
3550 int enum_value;
3551 HRESULT hr;
3553 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3555 if (size < sizeof(enum_value)) return E_INVALIDARG;
3556 if ((enum_value = *(int *)(char *)ptr + desc->enumOffset) == desc->noneEnumValue)
3558 switch (option)
3560 case WS_WRITE_REQUIRED_VALUE:
3561 return WS_E_INVALID_FORMAT;
3563 case WS_WRITE_NILLABLE_VALUE:
3564 return S_OK;
3566 default:
3567 ERR( "unhandled write option %u\n", option );
3568 return E_INVALIDARG;
3572 for (i = 0; i < desc->fieldCount; i++)
3574 if (desc->fields[i]->value == enum_value)
3576 offset = desc->fields[i]->field.offset;
3577 return write_type_field( writer, &desc->fields[i]->field, ptr, offset );
3581 return E_INVALIDARG;
3584 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3585 ULONG offset )
3587 HRESULT hr;
3588 WS_TYPE_MAPPING mapping;
3589 WS_WRITE_OPTION option;
3590 ULONG count, size, field_options = desc->options;
3591 const char *ptr = buf + offset;
3593 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
3595 FIXME( "options 0x%x not supported\n", desc->options );
3596 return E_NOTIMPL;
3599 /* zero-terminated strings are always pointers */
3600 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
3602 if (field_options & WS_FIELD_POINTER)
3603 size = sizeof(const void *);
3604 else
3605 size = get_type_size( desc->type, desc->typeDescription );
3607 if (is_nil_value( ptr, size ))
3609 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3610 if (field_options & WS_FIELD_NILLABLE)
3612 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3613 else option = WS_WRITE_NILLABLE_VALUE;
3615 else
3617 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3618 else option = WS_WRITE_REQUIRED_VALUE;
3621 else
3623 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3624 else option = WS_WRITE_REQUIRED_VALUE;
3627 switch (desc->mapping)
3629 case WS_ATTRIBUTE_FIELD_MAPPING:
3630 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3631 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3632 return hr;
3633 writer->state = WRITER_STATE_STARTATTRIBUTE;
3635 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3636 break;
3638 case WS_ELEMENT_FIELD_MAPPING:
3639 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3640 mapping = WS_ELEMENT_TYPE_MAPPING;
3641 break;
3643 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3644 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3645 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3646 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3648 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3649 count = *(const ULONG *)(buf + desc->countOffset);
3650 return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
3652 case WS_TEXT_FIELD_MAPPING:
3653 switch (writer->state)
3655 case WRITER_STATE_STARTELEMENT:
3656 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3657 break;
3659 case WRITER_STATE_STARTATTRIBUTE:
3660 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3661 break;
3663 default:
3664 FIXME( "unhandled writer state %u\n", writer->state );
3665 return E_NOTIMPL;
3667 break;
3669 default:
3670 FIXME( "field mapping %u not supported\n", desc->mapping );
3671 return E_NOTIMPL;
3674 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3675 return hr;
3677 switch (mapping)
3679 case WS_ATTRIBUTE_TYPE_MAPPING:
3680 writer->state = WRITER_STATE_STARTELEMENT;
3681 break;
3683 case WS_ELEMENT_TYPE_MAPPING:
3684 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3685 break;
3687 default: break;
3690 return S_OK;
3693 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3694 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3695 const void *value, ULONG size )
3697 ULONG i, offset;
3698 const void *ptr;
3699 HRESULT hr;
3701 if (!desc) return E_INVALIDARG;
3702 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3704 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3706 for (i = 0; i < desc->fieldCount; i++)
3708 offset = desc->fields[i]->offset;
3709 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3712 return S_OK;
3715 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3716 const void *desc, WS_WRITE_OPTION option, const void *value,
3717 ULONG size )
3719 switch (type)
3721 case WS_BOOL_TYPE:
3722 return write_type_bool( writer, mapping, desc, option, value, size );
3724 case WS_INT8_TYPE:
3725 return write_type_int8( writer, mapping, desc, option, value, size );
3727 case WS_INT16_TYPE:
3728 return write_type_int16( writer, mapping, desc, option, value, size );
3730 case WS_INT32_TYPE:
3731 return write_type_int32( writer, mapping, desc, option, value, size );
3733 case WS_INT64_TYPE:
3734 return write_type_int64( writer, mapping, desc, option, value, size );
3736 case WS_UINT8_TYPE:
3737 return write_type_uint8( writer, mapping, desc, option, value, size );
3739 case WS_UINT16_TYPE:
3740 return write_type_uint16( writer, mapping, desc, option, value, size );
3742 case WS_UINT32_TYPE:
3743 return write_type_uint32( writer, mapping, desc, option, value, size );
3745 case WS_UINT64_TYPE:
3746 return write_type_uint64( writer, mapping, desc, option, value, size );
3748 case WS_DOUBLE_TYPE:
3749 return write_type_double( writer, mapping, desc, option, value, size );
3751 case WS_DATETIME_TYPE:
3752 return write_type_datetime( writer, mapping, desc, option, value, size );
3754 case WS_GUID_TYPE:
3755 return write_type_guid( writer, mapping, desc, option, value, size );
3757 case WS_UNIQUE_ID_TYPE:
3758 return write_type_unique_id( writer, mapping, desc, option, value, size );
3760 case WS_STRING_TYPE:
3761 return write_type_string( writer, mapping, desc, option, value, size );
3763 case WS_WSZ_TYPE:
3764 return write_type_wsz( writer, mapping, desc, option, value, size );
3766 case WS_BYTES_TYPE:
3767 return write_type_bytes( writer, mapping, desc, option, value, size );
3769 case WS_XML_STRING_TYPE:
3770 return write_type_xml_string( writer, mapping, desc, option, value, size );
3772 case WS_XML_QNAME_TYPE:
3773 return write_type_qname( writer, mapping, desc, option, value, size );
3775 case WS_STRUCT_TYPE:
3776 return write_type_struct( writer, mapping, desc, option, value, size );
3778 default:
3779 FIXME( "type %u not supported\n", type );
3780 return E_NOTIMPL;
3784 /**************************************************************************
3785 * WsWriteAttribute [webservices.@]
3787 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
3788 WS_WRITE_OPTION option, const void *value, ULONG size,
3789 WS_ERROR *error )
3791 struct writer *writer = (struct writer *)handle;
3792 HRESULT hr;
3794 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3795 if (error) FIXME( "ignoring error parameter\n" );
3797 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
3798 return E_INVALIDARG;
3800 EnterCriticalSection( &writer->cs );
3802 if (writer->magic != WRITER_MAGIC)
3804 LeaveCriticalSection( &writer->cs );
3805 return E_INVALIDARG;
3808 if (writer->state != WRITER_STATE_STARTELEMENT)
3810 LeaveCriticalSection( &writer->cs );
3811 return WS_E_INVALID_OPERATION;
3814 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK)
3816 LeaveCriticalSection( &writer->cs );
3817 return hr;
3819 writer->state = WRITER_STATE_STARTATTRIBUTE;
3821 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
3823 LeaveCriticalSection( &writer->cs );
3824 return hr;
3827 /**************************************************************************
3828 * WsWriteElement [webservices.@]
3830 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3831 WS_WRITE_OPTION option, const void *value, ULONG size,
3832 WS_ERROR *error )
3834 struct writer *writer = (struct writer *)handle;
3835 HRESULT hr;
3837 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3838 if (error) FIXME( "ignoring error parameter\n" );
3840 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
3841 return E_INVALIDARG;
3843 EnterCriticalSection( &writer->cs );
3845 if (writer->magic != WRITER_MAGIC)
3847 LeaveCriticalSection( &writer->cs );
3848 return E_INVALIDARG;
3851 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
3853 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
3854 option, value, size )) != S_OK) goto done;
3856 hr = write_endelement_node( writer );
3858 done:
3859 LeaveCriticalSection( &writer->cs );
3860 return hr;
3863 /**************************************************************************
3864 * WsWriteType [webservices.@]
3866 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
3867 const void *desc, WS_WRITE_OPTION option, const void *value,
3868 ULONG size, WS_ERROR *error )
3870 struct writer *writer = (struct writer *)handle;
3871 HRESULT hr;
3873 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
3874 size, error );
3875 if (error) FIXME( "ignoring error parameter\n" );
3877 if (!writer || !value) return E_INVALIDARG;
3879 EnterCriticalSection( &writer->cs );
3881 if (writer->magic != WRITER_MAGIC)
3883 LeaveCriticalSection( &writer->cs );
3884 return E_INVALIDARG;
3887 switch (mapping)
3889 case WS_ATTRIBUTE_TYPE_MAPPING:
3890 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
3891 else hr = write_type( writer, mapping, type, desc, option, value, size );
3892 break;
3894 case WS_ELEMENT_TYPE_MAPPING:
3895 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3896 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
3897 else hr = write_type( writer, mapping, type, desc, option, value, size );
3898 break;
3900 case WS_ANY_ELEMENT_TYPE_MAPPING:
3901 hr = write_type( writer, mapping, type, desc, option, value, size );
3902 break;
3904 default:
3905 FIXME( "mapping %u not implemented\n", mapping );
3906 hr = E_NOTIMPL;
3909 LeaveCriticalSection( &writer->cs );
3910 return hr;
3913 WS_TYPE map_value_type( WS_VALUE_TYPE type )
3915 switch (type)
3917 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
3918 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
3919 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
3920 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
3921 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
3922 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
3923 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
3924 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
3925 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
3926 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
3927 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
3928 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
3929 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
3930 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
3931 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
3932 default:
3933 FIXME( "unhandled type %u\n", type );
3934 return ~0u;
3938 /**************************************************************************
3939 * WsWriteValue [webservices.@]
3941 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
3942 ULONG size, WS_ERROR *error )
3944 struct writer *writer = (struct writer *)handle;
3945 WS_TYPE_MAPPING mapping;
3946 HRESULT hr = S_OK;
3947 WS_TYPE type;
3949 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
3950 if (error) FIXME( "ignoring error parameter\n" );
3952 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
3954 EnterCriticalSection( &writer->cs );
3956 if (writer->magic != WRITER_MAGIC)
3958 LeaveCriticalSection( &writer->cs );
3959 return E_INVALIDARG;
3962 switch (writer->state)
3964 case WRITER_STATE_STARTATTRIBUTE:
3965 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3966 break;
3968 case WRITER_STATE_STARTELEMENT:
3969 mapping = WS_ELEMENT_TYPE_MAPPING;
3970 break;
3972 default:
3973 hr = WS_E_INVALID_FORMAT;
3976 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
3978 LeaveCriticalSection( &writer->cs );
3979 return hr;
3982 /**************************************************************************
3983 * WsWriteArray [webservices.@]
3985 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3986 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
3987 ULONG count, WS_ERROR *error )
3989 struct writer *writer = (struct writer *)handle;
3990 WS_TYPE type;
3991 ULONG type_size, i;
3992 HRESULT hr = S_OK;
3994 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3995 value_type, array, size, offset, count, error );
3996 if (error) FIXME( "ignoring error parameter\n" );
3998 if (!writer) return E_INVALIDARG;
4000 EnterCriticalSection( &writer->cs );
4002 if (writer->magic != WRITER_MAGIC)
4004 LeaveCriticalSection( &writer->cs );
4005 return E_INVALIDARG;
4008 if (!writer->output_type)
4010 LeaveCriticalSection( &writer->cs );
4011 return WS_E_INVALID_OPERATION;
4014 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
4016 LeaveCriticalSection( &writer->cs );
4017 return E_INVALIDARG;
4020 type_size = get_type_size( type, NULL );
4021 if (size % type_size || (offset + count) * type_size > size || (count && !array))
4023 LeaveCriticalSection( &writer->cs );
4024 return E_INVALIDARG;
4027 for (i = offset; i < count; i++)
4029 const char *ptr = (const char *)array + (offset + i) * type_size;
4030 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4031 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4032 &ptr, sizeof(ptr) )) != S_OK) goto done;
4033 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4036 done:
4037 LeaveCriticalSection( &writer->cs );
4038 return hr;
4041 /**************************************************************************
4042 * WsWriteXmlBuffer [webservices.@]
4044 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4046 struct writer *writer = (struct writer *)handle;
4047 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4048 HRESULT hr;
4050 TRACE( "%p %p %p\n", handle, buffer, error );
4051 if (error) FIXME( "ignoring error parameter\n" );
4053 if (!writer || !xmlbuf) return E_INVALIDARG;
4055 EnterCriticalSection( &writer->cs );
4057 if (writer->magic != WRITER_MAGIC)
4059 LeaveCriticalSection( &writer->cs );
4060 return E_INVALIDARG;
4063 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4065 FIXME( "no support for different encoding and/or charset\n" );
4066 hr = E_NOTIMPL;
4067 goto done;
4070 if ((hr = write_flush( writer )) != S_OK) goto done;
4071 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4072 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4074 done:
4075 LeaveCriticalSection( &writer->cs );
4076 return hr;
4079 /**************************************************************************
4080 * WsWriteXmlBufferToBytes [webservices.@]
4082 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4083 const WS_XML_WRITER_ENCODING *encoding,
4084 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4085 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4087 struct writer *writer = (struct writer *)handle;
4088 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4089 HRESULT hr = S_OK;
4090 char *buf;
4091 ULONG i;
4093 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4094 bytes, size, error );
4095 if (error) FIXME( "ignoring error parameter\n" );
4097 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4099 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4101 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4102 return E_NOTIMPL;
4105 EnterCriticalSection( &writer->cs );
4107 if (writer->magic != WRITER_MAGIC)
4109 LeaveCriticalSection( &writer->cs );
4110 return E_INVALIDARG;
4113 for (i = 0; i < count; i++)
4115 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4116 properties[i].valueSize );
4117 if (hr != S_OK) goto done;
4120 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4121 else
4123 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4124 *bytes = buf;
4125 *size = xmlbuf->bytes.length;
4128 done:
4129 LeaveCriticalSection( &writer->cs );
4130 return hr;
4133 /**************************************************************************
4134 * WsWriteXmlnsAttribute [webservices.@]
4136 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4137 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4139 struct writer *writer = (struct writer *)handle;
4140 HRESULT hr = S_OK;
4142 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4143 single, error );
4144 if (error) FIXME( "ignoring error parameter\n" );
4146 if (!writer || !ns) return E_INVALIDARG;
4148 EnterCriticalSection( &writer->cs );
4150 if (writer->magic != WRITER_MAGIC)
4152 LeaveCriticalSection( &writer->cs );
4153 return E_INVALIDARG;
4156 if (writer->state != WRITER_STATE_STARTELEMENT)
4158 LeaveCriticalSection( &writer->cs );
4159 return WS_E_INVALID_OPERATION;
4162 if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4163 hr = add_namespace_attribute( writer, prefix, ns, single );
4165 LeaveCriticalSection( &writer->cs );
4166 return hr;
4169 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4170 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4172 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4173 HRESULT hr;
4175 if ((hr = write_flush( writer )) != S_OK) return hr;
4176 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4178 qname.prefix = (WS_XML_STRING *)prefix;
4179 qname.localName = (WS_XML_STRING *)localname;
4180 qname.ns = (WS_XML_STRING *)ns;
4182 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4183 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4186 /**************************************************************************
4187 * WsWriteQualifiedName [webservices.@]
4189 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4190 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4191 WS_ERROR *error )
4193 struct writer *writer = (struct writer *)handle;
4194 HRESULT hr;
4196 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4197 debugstr_xmlstr(ns), error );
4198 if (error) FIXME( "ignoring error parameter\n" );
4200 if (!writer) return E_INVALIDARG;
4202 EnterCriticalSection( &writer->cs );
4204 if (writer->magic != WRITER_MAGIC)
4206 LeaveCriticalSection( &writer->cs );
4207 return E_INVALIDARG;
4210 if (!writer->output_type)
4212 LeaveCriticalSection( &writer->cs );
4213 return WS_E_INVALID_OPERATION;
4216 if (writer->state != WRITER_STATE_STARTELEMENT)
4218 LeaveCriticalSection( &writer->cs );
4219 return WS_E_INVALID_FORMAT;
4222 if (!localname || (!prefix && !ns))
4224 LeaveCriticalSection( &writer->cs );
4225 return E_INVALIDARG;
4228 hr = write_qualified_name( writer, prefix, localname, ns );
4230 LeaveCriticalSection( &writer->cs );
4231 return hr;
4234 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4236 BOOL success = FALSE;
4237 struct node *node = writer->current;
4239 switch (move)
4241 case WS_MOVE_TO_ROOT_ELEMENT:
4242 success = move_to_root_element( writer->root, &node );
4243 break;
4245 case WS_MOVE_TO_NEXT_ELEMENT:
4246 success = move_to_next_element( &node );
4247 break;
4249 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4250 success = move_to_prev_element( &node );
4251 break;
4253 case WS_MOVE_TO_CHILD_ELEMENT:
4254 success = move_to_child_element( &node );
4255 break;
4257 case WS_MOVE_TO_END_ELEMENT:
4258 success = move_to_end_element( &node );
4259 break;
4261 case WS_MOVE_TO_PARENT_ELEMENT:
4262 success = move_to_parent_element( &node );
4263 break;
4265 case WS_MOVE_TO_FIRST_NODE:
4266 success = move_to_first_node( &node );
4267 break;
4269 case WS_MOVE_TO_NEXT_NODE:
4270 success = move_to_next_node( &node );
4271 break;
4273 case WS_MOVE_TO_PREVIOUS_NODE:
4274 success = move_to_prev_node( &node );
4275 break;
4277 case WS_MOVE_TO_CHILD_NODE:
4278 success = move_to_child_node( &node );
4279 break;
4281 case WS_MOVE_TO_BOF:
4282 success = move_to_bof( writer->root, &node );
4283 break;
4285 case WS_MOVE_TO_EOF:
4286 success = move_to_eof( writer->root, &node );
4287 break;
4289 default:
4290 FIXME( "unhandled move %u\n", move );
4291 return E_NOTIMPL;
4294 if (success && node == writer->root) return E_INVALIDARG;
4295 writer->current = node;
4297 if (found)
4299 *found = success;
4300 return S_OK;
4302 return success ? S_OK : WS_E_INVALID_FORMAT;
4305 /**************************************************************************
4306 * WsMoveWriter [webservices.@]
4308 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4310 struct writer *writer = (struct writer *)handle;
4311 HRESULT hr;
4313 TRACE( "%p %u %p %p\n", handle, move, found, error );
4314 if (error) FIXME( "ignoring error parameter\n" );
4316 if (!writer) return E_INVALIDARG;
4318 EnterCriticalSection( &writer->cs );
4320 if (writer->magic != WRITER_MAGIC)
4322 LeaveCriticalSection( &writer->cs );
4323 return E_INVALIDARG;
4326 if (!writer->output_type)
4328 LeaveCriticalSection( &writer->cs );
4329 return WS_E_INVALID_OPERATION;
4332 hr = write_move_to( writer, move, found );
4334 LeaveCriticalSection( &writer->cs );
4335 return hr;
4338 /**************************************************************************
4339 * WsGetWriterPosition [webservices.@]
4341 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4343 struct writer *writer = (struct writer *)handle;
4345 TRACE( "%p %p %p\n", handle, pos, error );
4346 if (error) FIXME( "ignoring error parameter\n" );
4348 if (!writer || !pos) return E_INVALIDARG;
4350 EnterCriticalSection( &writer->cs );
4352 if (writer->magic != WRITER_MAGIC)
4354 LeaveCriticalSection( &writer->cs );
4355 return E_INVALIDARG;
4358 if (!writer->output_type)
4360 LeaveCriticalSection( &writer->cs );
4361 return WS_E_INVALID_OPERATION;
4364 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4365 pos->node = writer->current;
4367 LeaveCriticalSection( &writer->cs );
4368 return S_OK;
4371 /**************************************************************************
4372 * WsSetWriterPosition [webservices.@]
4374 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4376 struct writer *writer = (struct writer *)handle;
4378 TRACE( "%p %p %p\n", handle, pos, error );
4379 if (error) FIXME( "ignoring error parameter\n" );
4381 if (!writer || !pos) return E_INVALIDARG;
4383 EnterCriticalSection( &writer->cs );
4385 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4387 LeaveCriticalSection( &writer->cs );
4388 return E_INVALIDARG;
4391 if (!writer->output_type)
4393 LeaveCriticalSection( &writer->cs );
4394 return WS_E_INVALID_OPERATION;
4397 writer->current = pos->node;
4399 LeaveCriticalSection( &writer->cs );
4400 return S_OK;
4403 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4405 struct node *node, *parent;
4406 WS_XML_COMMENT_NODE *comment;
4408 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4409 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4410 comment = (WS_XML_COMMENT_NODE *)node;
4412 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4414 free_node( node );
4415 return E_OUTOFMEMORY;
4417 memcpy( comment->value.bytes, value->bytes, value->length );
4418 comment->value.length = value->length;
4420 write_insert_node( writer, parent, node );
4421 return S_OK;
4424 static HRESULT write_comment_text( struct writer *writer )
4426 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4427 HRESULT hr;
4429 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4430 write_bytes( writer, (const BYTE *)"<!--", 4 );
4431 write_bytes( writer, comment->value.bytes, comment->value.length );
4432 write_bytes( writer, (const BYTE *)"-->", 3 );
4433 return S_OK;
4436 static HRESULT write_comment_bin( struct writer *writer )
4438 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4439 HRESULT hr;
4441 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4442 write_char( writer, RECORD_COMMENT );
4443 return write_string( writer, comment->value.bytes, comment->value.length );
4446 static HRESULT write_comment( struct writer *writer )
4448 switch (writer->output_enc)
4450 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4451 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4452 default:
4453 ERR( "unhandled encoding %u\n", writer->output_enc );
4454 return WS_E_NOT_SUPPORTED;
4458 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4460 HRESULT hr;
4461 if ((hr = write_flush( writer )) != S_OK) return hr;
4462 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4463 if ((hr = write_comment( writer )) != S_OK) return hr;
4464 writer->state = WRITER_STATE_COMMENT;
4465 return S_OK;
4468 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4470 ULONG i;
4471 HRESULT hr;
4473 for (i = 0; i < count; i++)
4475 const WS_XML_STRING *prefix = attrs[i]->prefix;
4476 const WS_XML_STRING *localname = attrs[i]->localName;
4477 const WS_XML_STRING *ns = attrs[i]->ns;
4478 BOOL single = attrs[i]->singleQuote;
4480 if (attrs[i]->isXmlNs)
4482 if ((hr = add_namespace_attribute( writer, prefix, ns, single )) != S_OK) return hr;
4484 else
4486 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) != S_OK) return hr;
4487 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4490 return S_OK;
4493 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4495 HRESULT hr;
4497 switch (node->nodeType)
4499 case WS_XML_NODE_TYPE_ELEMENT:
4501 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4502 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4503 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4505 case WS_XML_NODE_TYPE_TEXT:
4507 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4508 return write_text_node( writer, text->text );
4510 case WS_XML_NODE_TYPE_END_ELEMENT:
4511 return write_endelement_node( writer );
4513 case WS_XML_NODE_TYPE_COMMENT:
4515 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4516 return write_comment_node( writer, &comment->value );
4518 case WS_XML_NODE_TYPE_CDATA:
4519 return write_cdata_node( writer );
4521 case WS_XML_NODE_TYPE_END_CDATA:
4522 return write_endcdata_node( writer );
4524 case WS_XML_NODE_TYPE_EOF:
4525 case WS_XML_NODE_TYPE_BOF:
4526 return S_OK;
4528 default:
4529 WARN( "unknown node type %u\n", node->nodeType );
4530 return E_INVALIDARG;
4534 /**************************************************************************
4535 * WsWriteNode [webservices.@]
4537 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4539 struct writer *writer = (struct writer *)handle;
4540 HRESULT hr;
4542 TRACE( "%p %p %p\n", handle, node, error );
4543 if (error) FIXME( "ignoring error parameter\n" );
4545 if (!writer || !node) return E_INVALIDARG;
4547 EnterCriticalSection( &writer->cs );
4549 if (writer->magic != WRITER_MAGIC)
4551 LeaveCriticalSection( &writer->cs );
4552 return E_INVALIDARG;
4555 if (!writer->output_type)
4557 LeaveCriticalSection( &writer->cs );
4558 return WS_E_INVALID_OPERATION;
4561 hr = write_node( writer, node );
4563 LeaveCriticalSection( &writer->cs );
4564 return hr;
4567 static HRESULT write_tree_node( struct writer *writer )
4569 HRESULT hr;
4571 switch (node_type( writer->current ))
4573 case WS_XML_NODE_TYPE_ELEMENT:
4574 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4575 return hr;
4576 if ((hr = write_startelement( writer )) != S_OK) return hr;
4577 writer->state = WRITER_STATE_STARTELEMENT;
4578 return S_OK;
4580 case WS_XML_NODE_TYPE_TEXT:
4581 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4582 return hr;
4583 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4584 writer->state = WRITER_STATE_TEXT;
4585 return S_OK;
4587 case WS_XML_NODE_TYPE_END_ELEMENT:
4588 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4589 writer->state = WRITER_STATE_ENDELEMENT;
4590 return S_OK;
4592 case WS_XML_NODE_TYPE_COMMENT:
4593 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4594 return hr;
4595 if ((hr = write_comment( writer )) != S_OK) return hr;
4596 writer->state = WRITER_STATE_COMMENT;
4597 return S_OK;
4599 case WS_XML_NODE_TYPE_CDATA:
4600 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4601 return hr;
4602 if ((hr = write_cdata( writer )) != S_OK) return hr;
4603 writer->state = WRITER_STATE_STARTCDATA;
4604 return S_OK;
4606 case WS_XML_NODE_TYPE_END_CDATA:
4607 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4608 writer->state = WRITER_STATE_ENDCDATA;
4609 return S_OK;
4611 case WS_XML_NODE_TYPE_EOF:
4612 case WS_XML_NODE_TYPE_BOF:
4613 return S_OK;
4615 default:
4616 ERR( "unknown node type %u\n", node_type(writer->current) );
4617 return E_INVALIDARG;
4621 static HRESULT write_tree( struct writer *writer )
4623 HRESULT hr;
4625 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4626 for (;;)
4628 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4629 if (move_to_child_node( &writer->current ))
4631 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4632 continue;
4634 if (move_to_next_node( &writer->current ))
4636 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4637 continue;
4639 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4641 ERR( "invalid tree\n" );
4642 return WS_E_INVALID_FORMAT;
4644 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4646 return S_OK;
4649 static void write_rewind( struct writer *writer )
4651 writer->write_pos = 0;
4652 writer->current = writer->root;
4653 writer->state = WRITER_STATE_INITIAL;
4656 /**************************************************************************
4657 * WsCopyNode [webservices.@]
4659 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4661 struct writer *writer = (struct writer *)handle;
4662 struct node *parent, *current, *node = NULL;
4663 HRESULT hr;
4665 TRACE( "%p %p %p\n", handle, reader, error );
4666 if (error) FIXME( "ignoring error parameter\n" );
4668 if (!writer) return E_INVALIDARG;
4670 EnterCriticalSection( &writer->cs );
4672 if (writer->magic != WRITER_MAGIC)
4674 LeaveCriticalSection( &writer->cs );
4675 return E_INVALIDARG;
4678 if (!(parent = find_parent( writer )))
4680 LeaveCriticalSection( &writer->cs );
4681 return WS_E_INVALID_FORMAT;
4684 if ((hr = copy_node( reader, &node )) != S_OK) goto done;
4685 current = writer->current;
4686 write_insert_node( writer, parent, node );
4688 write_rewind( writer );
4689 if ((hr = write_tree( writer )) != S_OK) goto done;
4690 writer->current = current;
4692 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4694 done:
4695 LeaveCriticalSection( &writer->cs );
4696 return hr;
4699 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4701 return write_type_field( writer, desc, value, 0 );
4704 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4706 ULONG i, ret = 0;
4707 for (i = 0; i < count; i++)
4709 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4710 continue;
4711 if (args[i]) ret = *(const ULONG *)args[i];
4712 break;
4714 return ret;
4717 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4718 ULONG len )
4720 return write_type_repeating_element( writer, desc, value, len );
4723 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4724 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4726 struct writer *writer = (struct writer *)handle;
4727 const WS_STRUCT_DESCRIPTION *desc_struct;
4728 const WS_FIELD_DESCRIPTION *desc_field;
4729 HRESULT hr;
4730 ULONG i;
4732 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4734 EnterCriticalSection( &writer->cs );
4736 if (writer->magic != WRITER_MAGIC)
4738 LeaveCriticalSection( &writer->cs );
4739 return E_INVALIDARG;
4742 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4744 for (i = 0; i < count; i++)
4746 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4747 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4749 FIXME( "messages type not supported\n" );
4750 hr = E_NOTIMPL;
4751 goto done;
4753 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4754 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4756 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4758 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4760 const void *ptr = *(const void **)args[i];
4761 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4762 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4766 hr = write_endelement_node( writer );
4768 done:
4769 LeaveCriticalSection( &writer->cs );
4770 return hr;
4773 HRESULT writer_enable_lookup( WS_XML_WRITER *handle )
4775 struct writer *writer = (struct writer *)handle;
4777 EnterCriticalSection( &writer->cs );
4779 if (writer->magic != WRITER_MAGIC)
4781 LeaveCriticalSection( &writer->cs );
4782 return E_INVALIDARG;
4785 writer->dict_do_lookup = TRUE;
4787 LeaveCriticalSection( &writer->cs );
4788 return S_OK;