webservices: Add support for UNIQUE_ID records in the writer.
[wine.git] / dlls / webservices / writer.c
blobe262254d6f749ff3056b219947cd814f2c476b85
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 WS_XML_DICTIONARY *dict;
89 WS_DYNAMIC_STRING_CALLBACK dict_cb;
90 void *dict_cb_state;
91 ULONG prop_count;
92 struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
95 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
97 static struct writer *alloc_writer(void)
99 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
100 struct writer *ret;
101 ULONG size = sizeof(*ret) + prop_size( writer_props, count );
103 if (!(ret = heap_alloc_zero( size ))) return NULL;
105 ret->magic = WRITER_MAGIC;
106 InitializeCriticalSection( &ret->cs );
107 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": writer.cs");
109 prop_init( writer_props, count, ret->prop, &ret[1] );
110 ret->prop_count = count;
111 return ret;
114 static void free_writer( struct writer *writer )
116 destroy_nodes( writer->root );
117 free_xml_string( writer->current_ns );
118 WsFreeHeap( writer->output_heap );
120 writer->cs.DebugInfo->Spare[0] = 0;
121 DeleteCriticalSection( &writer->cs );
122 heap_free( writer );
125 static void write_insert_eof( struct writer *writer, struct node *eof )
127 if (!writer->root) writer->root = eof;
128 else
130 eof->parent = writer->root;
131 list_add_tail( &writer->root->children, &eof->entry );
133 writer->current = eof;
136 static void write_insert_bof( struct writer *writer, struct node *bof )
138 writer->root->parent = bof;
139 list_add_tail( &bof->children, &writer->root->entry );
140 writer->current = writer->root = bof;
143 static void write_insert_node( struct writer *writer, struct node *parent, struct node *node )
145 node->parent = parent;
146 list_add_before( list_tail( &parent->children ), &node->entry );
147 writer->current = node;
150 static struct node *find_parent( struct writer *writer )
152 if (is_valid_parent( writer->current )) return writer->current;
153 if (is_valid_parent( writer->current->parent )) return writer->current->parent;
154 return NULL;
157 static HRESULT init_writer( struct writer *writer )
159 struct node *node;
161 writer->write_pos = 0;
162 writer->write_bufptr = NULL;
163 destroy_nodes( writer->root );
164 writer->root = writer->current = NULL;
165 free_xml_string( writer->current_ns );
166 writer->current_ns = NULL;
168 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
169 write_insert_eof( writer, node );
170 writer->state = WRITER_STATE_INITIAL;
171 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
172 writer->output_charset = WS_CHARSET_UTF8;
173 writer->dict = NULL;
174 writer->dict_cb = NULL;
175 writer->dict_cb_state = NULL;
176 return S_OK;
179 /**************************************************************************
180 * WsCreateWriter [webservices.@]
182 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
183 WS_XML_WRITER **handle, WS_ERROR *error )
185 struct writer *writer;
186 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
187 WS_CHARSET charset = WS_CHARSET_UTF8;
188 HRESULT hr;
190 TRACE( "%p %u %p %p\n", properties, count, handle, error );
191 if (error) FIXME( "ignoring error parameter\n" );
193 if (!handle) return E_INVALIDARG;
194 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
196 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
197 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
198 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
199 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
200 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
201 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
202 prop_set( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
204 for (i = 0; i < count; i++)
206 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
207 properties[i].valueSize );
208 if (hr != S_OK)
210 free_writer( writer );
211 return hr;
215 hr = prop_get( writer->prop, writer->prop_count, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE,
216 &max_size, sizeof(max_size) );
217 if (hr != S_OK)
219 free_writer( writer );
220 return hr;
223 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
224 if (hr != S_OK)
226 free_writer( writer );
227 return hr;
230 hr = init_writer( writer );
231 if (hr != S_OK)
233 free_writer( writer );
234 return hr;
237 *handle = (WS_XML_WRITER *)writer;
238 return S_OK;
241 /**************************************************************************
242 * WsFreeWriter [webservices.@]
244 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
246 struct writer *writer = (struct writer *)handle;
248 TRACE( "%p\n", handle );
250 if (!writer) return;
252 EnterCriticalSection( &writer->cs );
254 if (writer->magic != WRITER_MAGIC)
256 LeaveCriticalSection( &writer->cs );
257 return;
260 writer->magic = 0;
262 LeaveCriticalSection( &writer->cs );
263 free_writer( writer );
266 /**************************************************************************
267 * WsGetWriterProperty [webservices.@]
269 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
270 void *buf, ULONG size, WS_ERROR *error )
272 struct writer *writer = (struct writer *)handle;
273 HRESULT hr = S_OK;
275 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
276 if (error) FIXME( "ignoring error parameter\n" );
278 if (!writer) return E_INVALIDARG;
280 EnterCriticalSection( &writer->cs );
282 if (writer->magic != WRITER_MAGIC)
284 LeaveCriticalSection( &writer->cs );
285 return E_INVALIDARG;
288 if (!writer->output_type)
290 LeaveCriticalSection( &writer->cs );
291 return WS_E_INVALID_OPERATION;
294 switch (id)
296 case WS_XML_WRITER_PROPERTY_BYTES:
298 WS_BYTES *bytes = buf;
299 if (size != sizeof(*bytes)) hr = E_INVALIDARG;
300 else
302 bytes->bytes = writer->output_buf->bytes.bytes;
303 bytes->length = writer->output_buf->bytes.length;
305 break;
307 case WS_XML_WRITER_PROPERTY_BUFFERS:
308 if (writer->output_buf->bytes.length)
310 WS_BUFFERS *buffers = buf;
311 if (size != sizeof(*buffers)) hr = E_INVALIDARG;
312 else
314 buffers->bufferCount = 1;
315 buffers->buffers = &writer->output_buf->bytes;
317 break;
319 /* fall through */
320 default:
321 hr = prop_get( writer->prop, writer->prop_count, id, buf, size );
324 LeaveCriticalSection( &writer->cs );
325 return hr;
328 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
330 /* free current buffer if it's ours */
331 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
333 free_xmlbuf( writer->output_buf );
335 writer->output_buf = xmlbuf;
336 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
337 writer->write_bufptr = xmlbuf->bytes.bytes;
338 writer->write_pos = 0;
341 /**************************************************************************
342 * WsSetOutput [webservices.@]
344 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
345 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
346 ULONG count, WS_ERROR *error )
348 struct writer *writer = (struct writer *)handle;
349 struct node *node;
350 HRESULT hr;
351 ULONG i;
353 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
354 if (error) FIXME( "ignoring error parameter\n" );
356 if (!writer) return E_INVALIDARG;
358 EnterCriticalSection( &writer->cs );
360 if (writer->magic != WRITER_MAGIC)
362 LeaveCriticalSection( &writer->cs );
363 return E_INVALIDARG;
366 for (i = 0; i < count; i++)
368 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
369 properties[i].valueSize );
370 if (hr != S_OK) goto done;
373 if ((hr = init_writer( writer )) != S_OK) goto done;
375 switch (encoding->encodingType)
377 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
379 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
380 if (text->charSet != WS_CHARSET_UTF8)
382 FIXME( "charset %u not supported\n", text->charSet );
383 hr = E_NOTIMPL;
384 goto done;
386 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
387 writer->output_charset = WS_CHARSET_UTF8;
388 break;
390 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
392 WS_XML_WRITER_BINARY_ENCODING *bin = (WS_XML_WRITER_BINARY_ENCODING *)encoding;
393 writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
394 writer->output_charset = 0;
395 writer->dict = bin->staticDictionary;
396 writer->dict_cb = bin->dynamicStringCallback;
397 writer->dict_cb_state = bin->dynamicStringCallbackState;
398 break;
400 default:
401 FIXME( "encoding type %u not supported\n", encoding->encodingType );
402 hr = E_NOTIMPL;
403 goto done;
406 switch (output->outputType)
408 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
410 struct xmlbuf *xmlbuf;
411 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap, writer->output_enc, writer->output_charset )))
413 hr = WS_E_QUOTA_EXCEEDED;
414 goto done;
416 set_output_buffer( writer, xmlbuf );
417 break;
419 default:
420 FIXME( "output type %u not supported\n", output->outputType );
421 hr = E_NOTIMPL;
422 goto done;
425 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
426 else write_insert_bof( writer, node );
428 done:
429 LeaveCriticalSection( &writer->cs );
430 return hr;
433 /**************************************************************************
434 * WsSetOutputToBuffer [webservices.@]
436 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
437 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
438 WS_ERROR *error )
440 struct writer *writer = (struct writer *)handle;
441 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
442 struct node *node;
443 HRESULT hr;
444 ULONG i;
446 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
447 if (error) FIXME( "ignoring error parameter\n" );
449 if (!writer || !xmlbuf) return E_INVALIDARG;
451 EnterCriticalSection( &writer->cs );
453 if (writer->magic != WRITER_MAGIC)
455 LeaveCriticalSection( &writer->cs );
456 return E_INVALIDARG;
459 for (i = 0; i < count; i++)
461 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
462 properties[i].valueSize );
463 if (hr != S_OK) goto done;
466 if ((hr = init_writer( writer )) != S_OK) goto done;
467 writer->output_enc = xmlbuf->encoding;
468 writer->output_charset = xmlbuf->charset;
469 set_output_buffer( writer, xmlbuf );
471 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
472 else write_insert_bof( writer, node );
474 done:
475 LeaveCriticalSection( &writer->cs );
476 return hr;
479 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
481 struct xmlbuf *buf = writer->output_buf;
482 SIZE_T new_size;
483 void *tmp;
485 if (buf->size >= writer->write_pos + size)
487 buf->bytes.length = writer->write_pos + size;
488 return S_OK;
490 new_size = max( buf->size * 2, writer->write_pos + size );
491 if (!(tmp = ws_realloc( buf->heap, buf->bytes.bytes, buf->size, new_size ))) return WS_E_QUOTA_EXCEEDED;
492 writer->write_bufptr = buf->bytes.bytes = tmp;
493 buf->size = new_size;
494 buf->bytes.length = writer->write_pos + size;
495 return S_OK;
498 static inline void write_char( struct writer *writer, unsigned char ch )
500 writer->write_bufptr[writer->write_pos++] = ch;
503 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
505 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
506 writer->write_pos += len;
509 struct escape
511 char ch;
512 const char *entity;
513 ULONG len;
515 static const struct escape escape_lt = { '<', "&lt;", 4 };
516 static const struct escape escape_gt = { '>', "&gt;", 4 };
517 static const struct escape escape_amp = { '&', "&amp;", 5 };
518 static const struct escape escape_apos = { '\'', "&apos;", 6 };
519 static const struct escape escape_quot = { '"', "&quot;", 6 };
521 static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
522 const struct escape **escapes, ULONG nb_escapes )
524 ULONG i, j, size;
525 const BYTE *ptr;
526 HRESULT hr;
528 for (i = 0; i < len; i++)
530 ptr = &bytes[i];
531 size = 1;
532 for (j = 0; j < nb_escapes; j++)
534 if (bytes[i] == escapes[j]->ch)
536 ptr = (const BYTE *)escapes[j]->entity;
537 size = escapes[j]->len;
538 break;
541 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
542 write_bytes( writer, ptr, size );
545 return S_OK;
548 static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
550 WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
551 const struct escape *escapes[3];
553 escapes[0] = single ? &escape_apos : &escape_quot;
554 escapes[1] = &escape_lt;
555 escapes[2] = &escape_amp;
556 return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
559 static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
561 unsigned char quote = attr->singleQuote ? '\'' : '"';
562 const WS_XML_STRING *prefix = NULL;
563 ULONG size;
564 HRESULT hr;
566 if (attr->prefix) prefix = attr->prefix;
568 /* ' prefix:attr="value"' */
570 size = attr->localName->length + 4 /* ' =""' */;
571 if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
572 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
574 write_char( writer, ' ' );
575 if (prefix && prefix->length)
577 write_bytes( writer, prefix->bytes, prefix->length );
578 write_char( writer, ':' );
580 write_bytes( writer, attr->localName->bytes, attr->localName->length );
581 write_char( writer, '=' );
582 write_char( writer, quote );
583 if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
584 write_char( writer, quote );
586 return hr;
589 static HRESULT write_int31( struct writer *writer, ULONG len )
591 HRESULT hr;
593 if (len > 0x7fffffff) return E_INVALIDARG;
595 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
596 if (len < 0x80)
598 write_char( writer, len );
599 return S_OK;
601 write_char( writer, (len & 0x7f) | 0x80 );
603 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
604 if ((len >>= 7) < 0x80)
606 write_char( writer, len );
607 return S_OK;
609 write_char( writer, (len & 0x7f) | 0x80 );
611 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
612 if ((len >>= 7) < 0x80)
614 write_char( writer, len );
615 return S_OK;
617 write_char( writer, (len & 0x7f) | 0x80 );
619 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
620 if ((len >>= 7) < 0x80)
622 write_char( writer, len );
623 return S_OK;
625 write_char( writer, (len & 0x7f) | 0x80 );
627 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
628 if ((len >>= 7) < 0x08)
630 write_char( writer, len );
631 return S_OK;
633 return WS_E_INVALID_FORMAT;
636 static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
638 HRESULT hr;
639 if ((hr = write_int31( writer, len )) != S_OK) return hr;
640 if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
641 write_bytes( writer, bytes, len );
642 return S_OK;
645 static HRESULT write_dict_string( struct writer *writer, ULONG id )
647 HRESULT hr;
648 if (id > 0x7fffffff) return E_INVALIDARG;
649 if ((hr = write_int31( writer, id )) != S_OK) return hr;
650 return S_OK;
653 static enum record_type get_attr_text_record_type( const WS_XML_TEXT *text )
655 if (!text) return RECORD_CHARS8_TEXT;
656 switch (text->textType)
658 case WS_XML_TEXT_TYPE_UTF8:
660 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
661 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT;
662 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT;
663 return RECORD_CHARS32_TEXT;
665 case WS_XML_TEXT_TYPE_BASE64:
667 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
668 if (text_base64->length <= MAX_UINT8) return RECORD_BYTES8_TEXT;
669 if (text_base64->length <= MAX_UINT16) return RECORD_BYTES16_TEXT;
670 return RECORD_BYTES32_TEXT;
672 case WS_XML_TEXT_TYPE_BOOL:
674 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
675 return text_bool->value ? RECORD_TRUE_TEXT : RECORD_FALSE_TEXT;
677 case WS_XML_TEXT_TYPE_INT32:
679 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
680 if (!text_int32->value) return RECORD_ZERO_TEXT;
681 if (text_int32->value == 1) return RECORD_ONE_TEXT;
682 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT;
683 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT;
684 return RECORD_INT32_TEXT;
686 case WS_XML_TEXT_TYPE_INT64:
688 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
689 if (!text_int64->value) return RECORD_ZERO_TEXT;
690 if (text_int64->value == 1) return RECORD_ONE_TEXT;
691 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT;
692 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT;
693 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT;
694 return RECORD_INT64_TEXT;
696 case WS_XML_TEXT_TYPE_UINT64:
698 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
699 if (!text_uint64->value) return RECORD_ZERO_TEXT;
700 if (text_uint64->value == 1) return RECORD_ONE_TEXT;
701 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT;
702 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT;
703 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT;
704 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT;
705 return RECORD_UINT64_TEXT;
707 case WS_XML_TEXT_TYPE_DOUBLE:
709 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
710 if (!text_double->value) return RECORD_ZERO_TEXT;
711 if (text_double->value == 1) return RECORD_ONE_TEXT;
712 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
713 return RECORD_DOUBLE_TEXT;
714 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT;
715 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT;
716 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT;
717 return RECORD_INT64_TEXT;
719 case WS_XML_TEXT_TYPE_GUID:
720 return RECORD_GUID_TEXT;
722 case WS_XML_TEXT_TYPE_UNIQUE_ID:
723 return RECORD_UNIQUE_ID_TEXT;
725 default:
726 FIXME( "unhandled text type %u\n", text->textType );
727 return 0;
731 static INT64 get_text_value_int( const WS_XML_TEXT *text )
733 switch (text->textType)
735 case WS_XML_TEXT_TYPE_INT32:
737 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
738 return text_int32->value;
740 case WS_XML_TEXT_TYPE_INT64:
742 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
743 return text_int64->value;
745 case WS_XML_TEXT_TYPE_UINT64:
747 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
748 return text_uint64->value;
750 case WS_XML_TEXT_TYPE_DOUBLE:
752 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
753 return text_double->value;
755 default:
756 ERR( "unhandled text type %u\n", text->textType );
757 assert(0);
758 return 0;
762 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
764 enum record_type type = get_attr_text_record_type( text );
765 HRESULT hr;
767 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
768 write_char( writer, type );
770 switch (type)
772 case RECORD_CHARS8_TEXT:
774 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
775 if (!text_utf8)
777 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
778 write_char( writer, 0 );
779 return S_OK;
781 if ((hr = write_grow_buffer( writer, 1 + text_utf8->value.length )) != S_OK) return hr;
782 write_char( writer, text_utf8->value.length );
783 write_bytes( writer, text_utf8->value.bytes, text_utf8->value.length );
784 return S_OK;
786 case RECORD_CHARS16_TEXT:
788 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
789 UINT16 len = text_utf8->value.length;
790 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
791 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
792 write_bytes( writer, text_utf8->value.bytes, len );
793 return S_OK;
795 case RECORD_BYTES8_TEXT:
797 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
798 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
799 write_char( writer, text_base64->length );
800 write_bytes( writer, text_base64->bytes, text_base64->length );
801 return S_OK;
803 case RECORD_BYTES16_TEXT:
805 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
806 UINT16 len = text_base64->length;
807 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
808 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
809 write_bytes( writer, text_base64->bytes, len );
810 return S_OK;
812 case RECORD_ZERO_TEXT:
813 case RECORD_ONE_TEXT:
814 case RECORD_FALSE_TEXT:
815 case RECORD_TRUE_TEXT:
816 return S_OK;
818 case RECORD_INT8_TEXT:
820 INT8 val = get_text_value_int( text );
821 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
822 write_char( writer, val );
823 return S_OK;
825 case RECORD_INT16_TEXT:
827 INT16 val = get_text_value_int( text );
828 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
829 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
830 return S_OK;
832 case RECORD_INT32_TEXT:
834 INT32 val = get_text_value_int( text );
835 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
836 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
837 return S_OK;
839 case RECORD_INT64_TEXT:
841 INT64 val = get_text_value_int( text );
842 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
843 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
844 return S_OK;
846 case RECORD_UINT64_TEXT:
848 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
849 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
850 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
851 return S_OK;
853 case RECORD_DOUBLE_TEXT:
855 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
856 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
857 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
858 return S_OK;
860 case RECORD_GUID_TEXT:
862 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
863 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
864 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
865 return S_OK;
867 case RECORD_UNIQUE_ID_TEXT:
869 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
870 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
871 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
872 return S_OK;
874 default:
875 FIXME( "unhandled record type %02x\n", type );
876 return E_NOTIMPL;
880 static BOOL lookup_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
882 if (writer->dict && str->dictionary == writer->dict)
884 *id = str->id << 1;
885 return TRUE;
887 if (writer->dict_cb)
889 BOOL found = FALSE;
890 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
891 if (found) *id = (*id << 1) | 1;
892 return found;
894 return FALSE;
897 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
899 if (!attr->prefix || !attr->prefix->length)
901 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
902 return RECORD_SHORT_ATTRIBUTE;
904 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
906 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
907 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
909 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
910 return RECORD_ATTRIBUTE;
913 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
915 ULONG id;
916 enum record_type type = get_attr_record_type( attr, lookup_string_id(writer, attr->localName, &id) );
917 HRESULT hr;
919 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
920 write_char( writer, type );
922 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
924 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
925 return write_attribute_value_bin( writer, attr->value );
927 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
929 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
930 return write_attribute_value_bin( writer, attr->value );
933 switch (type)
935 case RECORD_SHORT_ATTRIBUTE:
936 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
937 break;
939 case RECORD_ATTRIBUTE:
940 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
941 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
942 break;
944 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
945 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
946 break;
948 case RECORD_DICTIONARY_ATTRIBUTE:
949 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
950 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
951 break;
953 default:
954 ERR( "unhandled record type %02x\n", type );
955 return WS_E_NOT_SUPPORTED;
958 return write_attribute_value_bin( writer, attr->value );
961 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
963 switch (writer->output_enc)
965 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
966 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
967 default:
968 ERR( "unhandled encoding %u\n", writer->output_enc );
969 return WS_E_NOT_SUPPORTED;
973 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
975 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
978 /**************************************************************************
979 * WsGetPrefixFromNamespace [webservices.@]
981 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
982 BOOL required, const WS_XML_STRING **prefix,
983 WS_ERROR *error )
985 struct writer *writer = (struct writer *)handle;
986 WS_XML_ELEMENT_NODE *elem;
987 BOOL found = FALSE;
988 HRESULT hr = S_OK;
990 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
991 if (error) FIXME( "ignoring error parameter\n" );
993 if (!writer || !ns || !prefix) return E_INVALIDARG;
995 EnterCriticalSection( &writer->cs );
997 if (writer->magic != WRITER_MAGIC)
999 LeaveCriticalSection( &writer->cs );
1000 return E_INVALIDARG;
1003 elem = &writer->current->hdr;
1004 if (elem->prefix && is_current_namespace( writer, ns ))
1006 *prefix = elem->prefix;
1007 found = TRUE;
1010 if (!found)
1012 if (required) hr = WS_E_INVALID_FORMAT;
1013 else
1015 *prefix = NULL;
1016 hr = S_FALSE;
1020 LeaveCriticalSection( &writer->cs );
1021 return hr;
1024 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1026 unsigned char quote = attr->singleQuote ? '\'' : '"';
1027 ULONG size;
1028 HRESULT hr;
1030 /* ' xmlns:prefix="namespace"' */
1032 size = attr->ns->length + 9 /* ' xmlns=""' */;
1033 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
1034 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1036 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1037 if (attr->prefix)
1039 write_char( writer, ':' );
1040 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1042 write_char( writer, '=' );
1043 write_char( writer, quote );
1044 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1045 write_char( writer, quote );
1047 return S_OK;
1050 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1052 if (!attr->prefix || !attr->prefix->length)
1054 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1055 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1057 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1058 return RECORD_XMLNS_ATTRIBUTE;
1061 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1063 ULONG id;
1064 enum record_type type = get_xmlns_record_type( attr, lookup_string_id(writer, attr->ns, &id) );
1065 HRESULT hr;
1067 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1068 write_char( writer, type );
1070 switch (type)
1072 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1073 break;
1075 case RECORD_XMLNS_ATTRIBUTE:
1076 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1077 break;
1079 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1080 return write_dict_string( writer, id );
1082 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1083 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1084 return write_dict_string( writer, id );
1086 default:
1087 ERR( "unhandled record type %02x\n", type );
1088 return WS_E_NOT_SUPPORTED;
1091 return write_string( writer, attr->ns->bytes, attr->ns->length );
1094 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1096 switch (writer->output_enc)
1098 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1099 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1100 default:
1101 ERR( "unhandled encoding %u\n", writer->output_enc );
1102 return WS_E_NOT_SUPPORTED;
1106 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1107 const WS_XML_STRING *ns, BOOL single )
1109 WS_XML_ATTRIBUTE *attr;
1110 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1111 HRESULT hr;
1113 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1115 attr->singleQuote = !!single;
1116 attr->isXmlNs = 1;
1117 if (prefix && !(attr->prefix = dup_xml_string( prefix )))
1119 free_attribute( attr );
1120 return E_OUTOFMEMORY;
1122 if (!(attr->ns = dup_xml_string( ns )))
1124 free_attribute( attr );
1125 return E_OUTOFMEMORY;
1127 if ((hr = append_attribute( elem, attr )) != S_OK)
1129 free_attribute( attr );
1130 return hr;
1132 return S_OK;
1135 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1137 if (!str1 && !str2) return TRUE;
1138 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1141 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1142 const WS_XML_STRING *ns )
1144 ULONG i;
1145 const struct node *node;
1147 for (node = (const struct node *)elem; node; node = node->parent)
1149 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1151 elem = &node->hdr;
1152 for (i = 0; i < elem->attributeCount; i++)
1154 if (!elem->attributes[i]->isXmlNs) continue;
1155 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1156 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1159 return FALSE;
1162 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1164 WS_XML_STRING *str;
1165 if (!(str = dup_xml_string( ns ))) return E_OUTOFMEMORY;
1166 free_xml_string( writer->current_ns );
1167 writer->current_ns = str;
1168 return S_OK;
1171 static HRESULT set_namespaces( struct writer *writer )
1173 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1174 HRESULT hr;
1175 ULONG i;
1177 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1179 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1180 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1183 for (i = 0; i < elem->attributeCount; i++)
1185 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1186 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1187 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1190 return S_OK;
1193 /**************************************************************************
1194 * WsWriteEndAttribute [webservices.@]
1196 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1198 struct writer *writer = (struct writer *)handle;
1200 TRACE( "%p %p\n", handle, error );
1201 if (error) FIXME( "ignoring error parameter\n" );
1203 if (!writer) return E_INVALIDARG;
1205 EnterCriticalSection( &writer->cs );
1207 if (writer->magic != WRITER_MAGIC)
1209 LeaveCriticalSection( &writer->cs );
1210 return E_INVALIDARG;
1213 writer->state = WRITER_STATE_STARTELEMENT;
1215 LeaveCriticalSection( &writer->cs );
1216 return S_OK;
1219 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1221 ULONG i;
1222 HRESULT hr;
1223 for (i = 0; i < elem->attributeCount; i++)
1225 if (elem->attributes[i]->isXmlNs) continue;
1226 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1228 for (i = 0; i < elem->attributeCount; i++)
1230 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1231 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1233 for (i = 0; i < elem->attributeCount; i++)
1235 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1236 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1238 return S_OK;
1241 static HRESULT write_startelement_text( struct writer *writer )
1243 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1244 ULONG size;
1245 HRESULT hr;
1247 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1249 size = elem->localName->length + 1 /* '<' */;
1250 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1251 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1253 write_char( writer, '<' );
1254 if (elem->prefix && elem->prefix->length)
1256 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1257 write_char( writer, ':' );
1259 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1260 return write_attributes( writer, elem );
1263 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1265 if (!elem->prefix || !elem->prefix->length)
1267 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1268 return RECORD_SHORT_ELEMENT;
1270 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1272 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1273 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1275 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1276 return RECORD_ELEMENT;
1279 static HRESULT write_startelement_bin( struct writer *writer )
1281 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1282 ULONG id;
1283 enum record_type type = get_elem_record_type( elem, lookup_string_id(writer, elem->localName, &id) );
1284 HRESULT hr;
1286 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1287 write_char( writer, type );
1289 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1291 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1292 return write_attributes( writer, elem );
1294 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1296 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1297 return write_attributes( writer, elem );
1300 switch (type)
1302 case RECORD_SHORT_ELEMENT:
1303 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1304 break;
1306 case RECORD_ELEMENT:
1307 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1308 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1309 break;
1311 case RECORD_SHORT_DICTIONARY_ELEMENT:
1312 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1313 break;
1315 case RECORD_DICTIONARY_ELEMENT:
1316 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1317 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1318 break;
1320 default:
1321 ERR( "unhandled record type %02x\n", type );
1322 return WS_E_NOT_SUPPORTED;
1325 return write_attributes( writer, elem );
1328 static HRESULT write_startelement( struct writer *writer )
1330 switch (writer->output_enc)
1332 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1333 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1334 default:
1335 ERR( "unhandled encoding %u\n", writer->output_enc );
1336 return WS_E_NOT_SUPPORTED;
1340 static struct node *write_find_startelement( struct writer *writer )
1342 struct node *node;
1343 for (node = writer->current; node; node = node->parent)
1345 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1347 return NULL;
1350 static inline BOOL is_empty_element( const struct node *node )
1352 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1353 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1356 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1358 ULONG size;
1359 HRESULT hr;
1361 /* '/>' */
1363 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1365 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1366 write_char( writer, '/' );
1367 write_char( writer, '>' );
1368 return S_OK;
1371 /* '</prefix:localname>' */
1373 size = elem->localName->length + 3 /* '</>' */;
1374 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1375 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1377 write_char( writer, '<' );
1378 write_char( writer, '/' );
1379 if (elem->prefix && elem->prefix->length)
1381 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1382 write_char( writer, ':' );
1384 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1385 write_char( writer, '>' );
1386 return S_OK;
1389 static HRESULT write_endelement_bin( struct writer *writer )
1391 HRESULT hr;
1392 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1393 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1394 write_char( writer, RECORD_ENDELEMENT );
1395 return S_OK;
1398 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1400 switch (writer->output_enc)
1402 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1403 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1404 default:
1405 ERR( "unhandled encoding %u\n", writer->output_enc );
1406 return WS_E_NOT_SUPPORTED;
1410 static HRESULT write_close_element( struct writer *writer, struct node *node )
1412 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1413 elem->isEmpty = is_empty_element( node );
1414 return write_endelement( writer, elem );
1417 static HRESULT write_endelement_node( struct writer *writer )
1419 struct node *node;
1420 HRESULT hr;
1422 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1423 if (writer->state == WRITER_STATE_STARTELEMENT)
1425 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1426 if ((hr = write_startelement( writer )) != S_OK) return hr;
1428 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1429 writer->current = node->parent;
1430 writer->state = WRITER_STATE_ENDELEMENT;
1431 return S_OK;
1434 /**************************************************************************
1435 * WsWriteEndElement [webservices.@]
1437 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1439 struct writer *writer = (struct writer *)handle;
1440 HRESULT hr;
1442 TRACE( "%p %p\n", handle, error );
1443 if (error) FIXME( "ignoring error parameter\n" );
1445 if (!writer) return E_INVALIDARG;
1447 EnterCriticalSection( &writer->cs );
1449 if (writer->magic != WRITER_MAGIC)
1451 LeaveCriticalSection( &writer->cs );
1452 return E_INVALIDARG;
1455 hr = write_endelement_node( writer );
1457 LeaveCriticalSection( &writer->cs );
1458 return hr;
1461 static HRESULT write_endstartelement_text( struct writer *writer )
1463 HRESULT hr;
1464 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1465 write_char( writer, '>' );
1466 return S_OK;
1469 static HRESULT write_endstartelement( struct writer *writer )
1471 switch (writer->output_enc)
1473 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1474 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1475 default:
1476 ERR( "unhandled encoding %u\n", writer->output_enc );
1477 return WS_E_NOT_SUPPORTED;
1481 /**************************************************************************
1482 * WsWriteEndStartElement [webservices.@]
1484 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
1486 struct writer *writer = (struct writer *)handle;
1487 HRESULT hr;
1489 TRACE( "%p %p\n", handle, error );
1490 if (error) FIXME( "ignoring error parameter\n" );
1492 if (!writer) return E_INVALIDARG;
1494 EnterCriticalSection( &writer->cs );
1496 if (writer->magic != WRITER_MAGIC)
1498 LeaveCriticalSection( &writer->cs );
1499 return E_INVALIDARG;
1502 if (writer->state != WRITER_STATE_STARTELEMENT)
1504 LeaveCriticalSection( &writer->cs );
1505 return WS_E_INVALID_OPERATION;
1508 if ((hr = set_namespaces( writer )) != S_OK) goto done;
1509 if ((hr = write_startelement( writer )) != S_OK) goto done;
1510 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
1511 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1513 done:
1514 LeaveCriticalSection( &writer->cs );
1515 return hr;
1518 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1519 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1520 BOOL single )
1522 WS_XML_ATTRIBUTE *attr;
1523 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1524 HRESULT hr;
1526 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1528 if (!prefix && ns->length) prefix = elem->prefix;
1530 attr->singleQuote = !!single;
1531 if (prefix && !(attr->prefix = dup_xml_string( prefix )))
1533 free_attribute( attr );
1534 return E_OUTOFMEMORY;
1536 if (!(attr->localName = dup_xml_string( localname )))
1538 free_attribute( attr );
1539 return E_OUTOFMEMORY;
1541 if (!(attr->ns = dup_xml_string( ns )))
1543 free_attribute( attr );
1544 return E_OUTOFMEMORY;
1546 if ((hr = append_attribute( elem, attr )) != S_OK)
1548 free_attribute( attr );
1549 return hr;
1551 return S_OK;
1554 /**************************************************************************
1555 * WsWriteStartAttribute [webservices.@]
1557 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1558 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1559 BOOL single, WS_ERROR *error )
1561 struct writer *writer = (struct writer *)handle;
1562 HRESULT hr;
1564 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1565 debugstr_xmlstr(ns), single, error );
1566 if (error) FIXME( "ignoring error parameter\n" );
1568 if (!writer || !localname || !ns) return E_INVALIDARG;
1570 EnterCriticalSection( &writer->cs );
1572 if (writer->magic != WRITER_MAGIC)
1574 LeaveCriticalSection( &writer->cs );
1575 return E_INVALIDARG;
1578 if (writer->state != WRITER_STATE_STARTELEMENT)
1580 LeaveCriticalSection( &writer->cs );
1581 return WS_E_INVALID_OPERATION;
1584 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
1585 writer->state = WRITER_STATE_STARTATTRIBUTE;
1587 LeaveCriticalSection( &writer->cs );
1588 return hr;
1591 /* flush current start element if necessary */
1592 static HRESULT write_flush( struct writer *writer )
1594 if (writer->state == WRITER_STATE_STARTELEMENT)
1596 HRESULT hr;
1597 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1598 if ((hr = write_startelement( writer )) != S_OK) return hr;
1599 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
1600 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1602 return S_OK;
1605 static HRESULT write_add_cdata_node( struct writer *writer )
1607 struct node *node, *parent;
1608 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1609 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1610 write_insert_node( writer, parent, node );
1611 return S_OK;
1614 static HRESULT write_add_endcdata_node( struct writer *writer )
1616 struct node *node;
1617 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
1618 node->parent = writer->current;
1619 list_add_tail( &node->parent->children, &node->entry );
1620 return S_OK;
1623 static HRESULT write_cdata( struct writer *writer )
1625 HRESULT hr;
1626 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
1627 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
1628 return S_OK;
1631 static HRESULT write_cdata_node( struct writer *writer )
1633 HRESULT hr;
1634 if ((hr = write_flush( writer )) != S_OK) return hr;
1635 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
1636 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
1637 if ((hr = write_cdata( writer )) != S_OK) return hr;
1638 writer->state = WRITER_STATE_STARTCDATA;
1639 return S_OK;
1642 /**************************************************************************
1643 * WsWriteStartCData [webservices.@]
1645 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
1647 struct writer *writer = (struct writer *)handle;
1648 HRESULT hr;
1650 TRACE( "%p %p\n", handle, error );
1651 if (error) FIXME( "ignoring error parameter\n" );
1653 if (!writer) return E_INVALIDARG;
1655 EnterCriticalSection( &writer->cs );
1657 if (writer->magic != WRITER_MAGIC)
1659 LeaveCriticalSection( &writer->cs );
1660 return E_INVALIDARG;
1663 hr = write_cdata_node( writer );
1665 LeaveCriticalSection( &writer->cs );
1666 return hr;
1669 static HRESULT write_endcdata( struct writer *writer )
1671 HRESULT hr;
1672 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
1673 write_bytes( writer, (const BYTE *)"]]>", 3 );
1674 return S_OK;
1677 static HRESULT write_endcdata_node( struct writer *writer )
1679 HRESULT hr;
1680 if ((hr = write_endcdata( writer )) != S_OK) return hr;
1681 writer->current = writer->current->parent;
1682 writer->state = WRITER_STATE_ENDCDATA;
1683 return S_OK;
1686 /**************************************************************************
1687 * WsWriteEndCData [webservices.@]
1689 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
1691 struct writer *writer = (struct writer *)handle;
1692 HRESULT hr;
1694 TRACE( "%p %p\n", handle, error );
1695 if (error) FIXME( "ignoring error parameter\n" );
1697 if (!writer) return E_INVALIDARG;
1699 EnterCriticalSection( &writer->cs );
1701 if (writer->magic != WRITER_MAGIC)
1703 LeaveCriticalSection( &writer->cs );
1704 return E_INVALIDARG;
1707 if (writer->state != WRITER_STATE_TEXT)
1709 LeaveCriticalSection( &writer->cs );
1710 return WS_E_INVALID_OPERATION;
1713 hr = write_endcdata_node( writer );
1715 LeaveCriticalSection( &writer->cs );
1716 return hr;
1719 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1720 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1722 struct node *node, *parent;
1723 WS_XML_ELEMENT_NODE *elem;
1725 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1727 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1729 elem = &parent->hdr;
1730 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
1733 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
1734 elem = &node->hdr;
1736 if (prefix && !(elem->prefix = dup_xml_string( prefix )))
1738 free_node( node );
1739 return E_OUTOFMEMORY;
1741 if (!(elem->localName = dup_xml_string( localname )))
1743 free_node( node );
1744 return E_OUTOFMEMORY;
1746 if (!(elem->ns = dup_xml_string( ns )))
1748 free_node( node );
1749 return E_OUTOFMEMORY;
1751 write_insert_node( writer, parent, node );
1752 return S_OK;
1755 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1757 struct node *node;
1758 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1759 node->parent = parent;
1760 list_add_tail( &parent->children, &node->entry );
1761 return S_OK;
1764 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1765 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1767 HRESULT hr;
1768 if ((hr = write_flush( writer )) != S_OK) return hr;
1769 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1770 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1771 writer->state = WRITER_STATE_STARTELEMENT;
1772 return S_OK;
1775 /**************************************************************************
1776 * WsWriteStartElement [webservices.@]
1778 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1779 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1780 WS_ERROR *error )
1782 struct writer *writer = (struct writer *)handle;
1783 HRESULT hr;
1785 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1786 debugstr_xmlstr(ns), error );
1787 if (error) FIXME( "ignoring error parameter\n" );
1789 if (!writer || !localname || !ns) return E_INVALIDARG;
1791 EnterCriticalSection( &writer->cs );
1793 if (writer->magic != WRITER_MAGIC)
1795 LeaveCriticalSection( &writer->cs );
1796 return E_INVALIDARG;
1799 hr = write_element_node( writer, prefix, localname, ns );
1801 LeaveCriticalSection( &writer->cs );
1802 return hr;
1805 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1807 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1808 if (*ptr)
1810 memcpy( buf, bool_true, sizeof(bool_true) );
1811 return sizeof(bool_true);
1813 memcpy( buf, bool_false, sizeof(bool_false) );
1814 return sizeof(bool_false);
1817 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1819 return wsprintfA( (char *)buf, "%d", *ptr );
1822 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1824 return wsprintfA( (char *)buf, "%I64d", *ptr );
1827 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1829 return wsprintfA( (char *)buf, "%I64u", *ptr );
1832 static ULONG format_double( const double *ptr, unsigned char *buf )
1834 #ifdef HAVE_POWL
1835 static const long double precision = 0.0000000000000001;
1836 unsigned char *p = buf;
1837 long double val = *ptr;
1838 int neg, mag, mag2, use_exp;
1840 if (isnan( val ))
1842 memcpy( buf, "NaN", 3 );
1843 return 3;
1845 if (isinf( val ))
1847 if (val < 0)
1849 memcpy( buf, "-INF", 4 );
1850 return 4;
1852 memcpy( buf, "INF", 3 );
1853 return 3;
1855 if (val == 0.0)
1857 *p = '0';
1858 return 1;
1861 if ((neg = val < 0))
1863 *p++ = '-';
1864 val = -val;
1867 mag = log10l( val );
1868 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1869 if (use_exp)
1871 if (mag < 0) mag -= 1;
1872 val = val / powl( 10.0, mag );
1873 mag2 = mag;
1874 mag = 0;
1876 else if (mag < 1) mag = 0;
1878 while (val > precision || mag >= 0)
1880 long double weight = powl( 10.0, mag );
1881 if (weight > 0 && !isinf( weight ))
1883 int digit = floorl( val / weight );
1884 val -= digit * weight;
1885 *(p++) = '0' + digit;
1887 if (!mag && val > precision) *(p++) = '.';
1888 mag--;
1891 if (use_exp)
1893 int i, j;
1894 *(p++) = 'E';
1895 if (mag2 > 0) *(p++) = '+';
1896 else
1898 *(p++) = '-';
1899 mag2 = -mag2;
1901 mag = 0;
1902 while (mag2 > 0)
1904 *(p++) = '0' + mag2 % 10;
1905 mag2 /= 10;
1906 mag++;
1908 for (i = -mag, j = -1; i < j; i++, j--)
1910 p[i] ^= p[j];
1911 p[j] ^= p[i];
1912 p[i] ^= p[j];
1916 return p - buf;
1917 #else
1918 FIXME( "powl not found at build time\n" );
1919 return 0;
1920 #endif
1923 static inline int year_size( int year )
1925 return leap_year( year ) ? 366 : 365;
1928 #define TZ_OFFSET 8
1929 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1931 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1932 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
1933 unsigned __int64 ticks, day_ticks;
1934 ULONG len;
1936 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1937 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1939 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1940 tz_hour = TZ_OFFSET;
1942 else
1944 ticks = ptr->ticks;
1945 tz_hour = 0;
1947 day = ticks / TICKS_PER_DAY;
1948 day_ticks = ticks % TICKS_PER_DAY;
1949 hour = day_ticks / TICKS_PER_HOUR;
1950 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1951 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1952 sec_frac = day_ticks % TICKS_PER_SEC;
1954 while (day >= year_size( year ))
1956 day -= year_size( year );
1957 year++;
1959 while (day >= month_days[leap_year( year )][month])
1961 day -= month_days[leap_year( year )][month];
1962 month++;
1965 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1966 if (sec_frac)
1968 static const char fmt_frac[] = ".%07u";
1969 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1970 while (buf[len - 1] == '0') len--;
1972 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1974 buf[len++] = 'Z';
1976 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1978 static const char fmt_tz[] = "%c%02u:00";
1979 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1982 return len;
1985 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
1987 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1988 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1989 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1990 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
1993 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
1995 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1996 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
1997 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
1998 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
2001 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
2003 ULONG len = 0;
2004 if (prefix && prefix->length)
2006 memcpy( buf, prefix->bytes, prefix->length );
2007 len += prefix->length;
2008 buf[len++] = ':';
2010 memcpy( buf + len, localname->bytes, localname->length );
2011 return len + localname->length;
2014 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
2016 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2017 ULONG i = 0, x;
2019 while (len > 0)
2021 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
2022 x = (bin[0] & 3) << 4;
2023 if (len == 1)
2025 buf[i++] = base64[x];
2026 buf[i++] = '=';
2027 buf[i++] = '=';
2028 break;
2030 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
2031 x = (bin[1] & 0x0f) << 2;
2032 if (len == 2)
2034 buf[i++] = base64[x];
2035 buf[i++] = '=';
2036 break;
2038 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
2039 buf[i++] = base64[bin[2] & 0x3f];
2040 bin += 3;
2041 len -= 3;
2043 return i;
2046 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
2047 WS_XML_UTF8_TEXT **ret )
2049 ULONG len_old = old ? old->value.length : 0;
2050 if (offset) *offset = len_old;
2052 switch (text->textType)
2054 case WS_XML_TEXT_TYPE_UTF8:
2056 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
2058 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
2059 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2060 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
2061 return S_OK;
2063 case WS_XML_TEXT_TYPE_UTF16:
2065 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
2066 const WCHAR *str = (const WCHAR *)src->bytes;
2067 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
2069 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2070 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2071 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2072 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2073 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
2074 return S_OK;
2076 case WS_XML_TEXT_TYPE_BASE64:
2078 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2079 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
2081 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2082 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2083 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
2084 return S_OK;
2086 case WS_XML_TEXT_TYPE_BOOL:
2088 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2090 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
2091 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2092 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
2093 return S_OK;
2095 case WS_XML_TEXT_TYPE_INT32:
2097 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2098 unsigned char buf[12]; /* "-2147483648" */
2099 ULONG len = format_int32( &int32_text->value, buf );
2101 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2102 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2103 memcpy( (*ret)->value.bytes + len_old, buf, len );
2104 return S_OK;
2106 case WS_XML_TEXT_TYPE_INT64:
2108 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2109 unsigned char buf[21]; /* "-9223372036854775808" */
2110 ULONG len = format_int64( &int64_text->value, buf );
2112 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2113 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2114 memcpy( (*ret)->value.bytes + len_old, buf, len );
2115 return S_OK;
2117 case WS_XML_TEXT_TYPE_UINT64:
2119 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2120 unsigned char buf[21]; /* "18446744073709551615" */
2121 ULONG len = format_uint64( &uint64_text->value, buf );
2123 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2124 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2125 memcpy( (*ret)->value.bytes + len_old, buf, len );
2126 return S_OK;
2128 case WS_XML_TEXT_TYPE_DOUBLE:
2130 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2131 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
2132 unsigned short fpword;
2133 ULONG len;
2135 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
2136 len = format_double( &double_text->value, buf );
2137 restore_fpword( fpword );
2138 if (!len) return E_NOTIMPL;
2140 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2141 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2142 memcpy( (*ret)->value.bytes + len_old, buf, len );
2143 return S_OK;
2145 case WS_XML_TEXT_TYPE_GUID:
2147 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2149 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
2150 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2151 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2152 return S_OK;
2154 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2156 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2158 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
2159 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2160 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2161 return S_OK;
2163 case WS_XML_TEXT_TYPE_DATETIME:
2165 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2167 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
2168 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2169 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
2170 return S_OK;
2172 case WS_XML_TEXT_TYPE_QNAME:
2174 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
2175 ULONG len = qn->localName->length;
2177 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
2178 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2179 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2180 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
2181 return S_OK;
2183 default:
2184 FIXME( "unhandled text type %u\n", text->textType );
2185 return E_NOTIMPL;
2189 static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2191 if (offset) *offset = 0;
2192 switch (text->textType)
2194 case WS_XML_TEXT_TYPE_UTF8:
2196 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2197 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2198 WS_XML_UTF8_TEXT *new;
2199 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2201 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2202 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2203 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2204 if (offset) *offset = len_old;
2205 *ret = &new->text;
2206 return S_OK;
2208 case WS_XML_TEXT_TYPE_UTF16:
2210 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2211 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2212 WS_XML_UTF8_TEXT *new;
2213 const WCHAR *str = (const WCHAR *)utf16->bytes;
2214 ULONG len = utf16->byteCount / sizeof(WCHAR), len_utf8, len_old = utf8_old ? utf8_old->value.length : 0;
2216 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2217 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2218 if (!(new = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2219 if (old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2220 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)new->value.bytes + len_old, len_utf8, NULL, NULL );
2221 if (offset) *offset = len_old;
2222 *ret = &new->text;
2223 return S_OK;
2225 case WS_XML_TEXT_TYPE_BASE64:
2227 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2228 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2229 WS_XML_BASE64_TEXT *new;
2230 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2232 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2233 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2234 memcpy( new->bytes + len_old, base64->bytes, len );
2235 if (offset) *offset = len_old;
2236 *ret = &new->text;
2237 return S_OK;
2239 case WS_XML_TEXT_TYPE_BOOL:
2241 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2242 WS_XML_BOOL_TEXT *new;
2244 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2245 *ret = &new->text;
2246 return S_OK;
2248 case WS_XML_TEXT_TYPE_INT32:
2250 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2251 WS_XML_INT32_TEXT *new;
2253 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2254 *ret = &new->text;
2255 return S_OK;
2257 case WS_XML_TEXT_TYPE_INT64:
2259 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2260 WS_XML_INT64_TEXT *new;
2262 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2263 *ret = &new->text;
2264 return S_OK;
2266 case WS_XML_TEXT_TYPE_UINT64:
2268 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2269 WS_XML_UINT64_TEXT *new;
2271 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2272 *ret = &new->text;
2273 return S_OK;
2275 case WS_XML_TEXT_TYPE_DOUBLE:
2277 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2278 WS_XML_DOUBLE_TEXT *new;
2280 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2281 *ret = &new->text;
2282 return S_OK;
2284 case WS_XML_TEXT_TYPE_GUID:
2286 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2287 WS_XML_GUID_TEXT *new;
2289 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2290 *ret = &new->text;
2291 return S_OK;
2293 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2295 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2296 WS_XML_UNIQUE_ID_TEXT *new;
2298 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2299 *ret = &new->text;
2300 return S_OK;
2302 case WS_XML_TEXT_TYPE_DATETIME:
2304 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2305 WS_XML_DATETIME_TEXT *new;
2307 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2308 *ret = &new->text;
2309 return S_OK;
2311 default:
2312 FIXME( "unhandled text type %u\n", text->textType );
2313 return E_NOTIMPL;
2317 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2319 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2320 HRESULT hr;
2322 switch (value->textType)
2324 case WS_XML_TEXT_TYPE_UTF8:
2325 case WS_XML_TEXT_TYPE_UTF16:
2326 case WS_XML_TEXT_TYPE_BASE64:
2327 break;
2329 case WS_XML_TEXT_TYPE_BOOL:
2330 case WS_XML_TEXT_TYPE_INT32:
2331 case WS_XML_TEXT_TYPE_INT64:
2332 case WS_XML_TEXT_TYPE_UINT64:
2333 case WS_XML_TEXT_TYPE_DOUBLE:
2334 case WS_XML_TEXT_TYPE_GUID:
2335 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2336 case WS_XML_TEXT_TYPE_DATETIME:
2337 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2338 break;
2340 default:
2341 FIXME( "unhandled text type %u\n", value->textType );
2342 return E_NOTIMPL;
2345 switch (writer->output_enc)
2347 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2349 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2350 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2351 heap_free( old );
2352 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2353 break;
2355 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2357 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2358 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2359 heap_free( old );
2360 elem->attributes[elem->attributeCount - 1]->value = new;
2361 break;
2363 default:
2364 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2365 return E_NOTIMPL;
2368 return S_OK;
2371 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2373 struct node *node;
2374 WS_XML_TEXT_NODE *text;
2375 HRESULT hr;
2377 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2378 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2379 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2381 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2382 text = (WS_XML_TEXT_NODE *)node;
2384 switch (writer->output_enc)
2386 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2388 WS_XML_UTF8_TEXT *new;
2389 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2391 heap_free( node );
2392 return hr;
2394 text->text = &new->text;
2395 break;
2397 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2399 WS_XML_TEXT *new;
2400 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2402 heap_free( node );
2403 return hr;
2405 text->text = new;
2406 break;
2408 default:
2409 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2410 heap_free( node );
2411 return E_NOTIMPL;
2414 write_insert_node( writer, writer->current, node );
2415 return S_OK;
2418 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2420 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2421 HRESULT hr;
2423 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2425 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2426 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2428 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2430 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2431 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2432 return S_OK;
2435 return WS_E_INVALID_FORMAT;
2438 static enum record_type get_text_record_type( const WS_XML_TEXT *text )
2440 switch (text->textType)
2442 case WS_XML_TEXT_TYPE_UTF8:
2444 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2445 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2446 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2447 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2449 case WS_XML_TEXT_TYPE_BASE64:
2451 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2452 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2453 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2454 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2455 return RECORD_BYTES32_TEXT;
2457 case WS_XML_TEXT_TYPE_BOOL:
2459 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2460 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2462 case WS_XML_TEXT_TYPE_INT32:
2464 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2465 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2466 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2467 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2468 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2469 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2471 case WS_XML_TEXT_TYPE_INT64:
2473 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2474 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2475 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2476 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2477 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2478 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2479 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2481 case WS_XML_TEXT_TYPE_UINT64:
2483 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2484 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2485 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2486 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2487 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2488 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2489 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2490 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2492 case WS_XML_TEXT_TYPE_DOUBLE:
2494 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2495 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2496 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2497 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2498 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2499 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2500 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2501 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2502 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2504 case WS_XML_TEXT_TYPE_GUID:
2505 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2507 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2508 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2510 default:
2511 FIXME( "unhandled text type %u\n", text->textType );
2512 return 0;
2516 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2518 enum record_type type = get_text_record_type( text );
2519 HRESULT hr;
2521 if (offset)
2523 FIXME( "no support for appending text in binary mode\n" );
2524 return E_NOTIMPL;
2527 switch (type)
2529 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2531 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2532 UINT8 len = text_utf8->value.length;
2534 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2535 write_char( writer, type );
2536 write_char( writer, len );
2537 write_bytes( writer, text_utf8->value.bytes, len );
2538 return S_OK;
2540 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2542 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2543 UINT16 len = text_utf8->value.length;
2545 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2546 write_char( writer, type );
2547 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2548 write_bytes( writer, text_utf8->value.bytes, len );
2549 return S_OK;
2551 case RECORD_BYTES8_TEXT:
2553 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2554 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2556 if (len)
2558 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2559 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2560 write_char( writer, len );
2561 write_bytes( writer, text_base64->bytes, len );
2563 if (rem)
2565 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2566 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2567 write_char( writer, rem );
2568 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2570 return S_OK;
2572 case RECORD_BYTES16_TEXT:
2574 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2575 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2577 if (len)
2579 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2580 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2581 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2582 write_bytes( writer, text_base64->bytes, len );
2584 if (rem)
2586 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2587 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2588 write_char( writer, rem );
2589 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2591 return S_OK;
2593 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2594 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2595 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2596 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2598 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2599 write_char( writer, type );
2600 return S_OK;
2602 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2604 INT8 val = get_text_value_int( text );
2605 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2606 write_char( writer, type );
2607 write_char( writer, val );
2608 return S_OK;
2610 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2612 INT16 val = get_text_value_int( text );
2613 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2614 write_char( writer, type );
2615 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2616 return S_OK;
2618 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2620 INT32 val = get_text_value_int( text );
2621 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2622 write_char( writer, type );
2623 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2624 return S_OK;
2626 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2628 INT64 val = get_text_value_int( text );
2629 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2630 write_char( writer, type );
2631 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2632 return S_OK;
2634 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2636 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2637 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2638 write_char( writer, type );
2639 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2640 return S_OK;
2642 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2644 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2645 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2646 write_char( writer, type );
2647 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2648 return S_OK;
2650 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2652 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2653 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2654 write_char( writer, type );
2655 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2656 return S_OK;
2658 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2660 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2661 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2662 write_char( writer, type );
2663 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2664 return S_OK;
2666 default:
2667 FIXME( "unhandled record type %02x\n", type );
2668 return E_NOTIMPL;
2672 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2674 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2676 switch (writer->output_enc)
2678 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2679 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2680 default:
2681 ERR( "unhandled encoding %u\n", writer->output_enc );
2682 return WS_E_NOT_SUPPORTED;
2686 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2688 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2689 ULONG offset = 0;
2690 HRESULT hr;
2692 if ((hr = write_flush( writer )) != S_OK) return hr;
2693 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2695 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2696 node = (WS_XML_TEXT_NODE *)writer->current;
2698 else
2700 switch (writer->output_enc)
2702 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2704 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2705 offset = old->value.length;
2706 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2707 heap_free( old );
2708 node->text = &new->text;
2709 break;
2711 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2713 WS_XML_TEXT *new, *old = node->text;
2714 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2715 heap_free( old );
2716 node->text = new;
2717 break;
2719 default:
2720 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2721 return E_NOTIMPL;
2725 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2727 writer->state = WRITER_STATE_TEXT;
2728 return S_OK;
2731 /**************************************************************************
2732 * WsWriteText [webservices.@]
2734 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2736 struct writer *writer = (struct writer *)handle;
2737 HRESULT hr;
2739 TRACE( "%p %p %p\n", handle, text, error );
2740 if (error) FIXME( "ignoring error parameter\n" );
2742 if (!writer || !text) return E_INVALIDARG;
2744 EnterCriticalSection( &writer->cs );
2746 if (writer->magic != WRITER_MAGIC)
2748 LeaveCriticalSection( &writer->cs );
2749 return E_INVALIDARG;
2752 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2753 else hr = write_text_node( writer, text );
2755 LeaveCriticalSection( &writer->cs );
2756 return hr;
2759 /**************************************************************************
2760 * WsWriteBytes [webservices.@]
2762 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2764 struct writer *writer = (struct writer *)handle;
2765 WS_XML_BASE64_TEXT base64;
2766 HRESULT hr;
2768 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2769 if (error) FIXME( "ignoring error parameter\n" );
2771 if (!writer) return E_INVALIDARG;
2773 EnterCriticalSection( &writer->cs );
2775 if (writer->magic != WRITER_MAGIC)
2777 LeaveCriticalSection( &writer->cs );
2778 return E_INVALIDARG;
2781 if (!writer->output_type)
2783 LeaveCriticalSection( &writer->cs );
2784 return WS_E_INVALID_OPERATION;
2787 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2788 base64.bytes = (BYTE *)bytes;
2789 base64.length = count;
2791 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2792 else hr = write_text_node( writer, &base64.text );
2794 LeaveCriticalSection( &writer->cs );
2795 return hr;
2798 /**************************************************************************
2799 * WsWriteChars [webservices.@]
2801 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
2803 struct writer *writer = (struct writer *)handle;
2804 WS_XML_UTF16_TEXT utf16;
2805 HRESULT hr;
2807 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
2808 if (error) FIXME( "ignoring error parameter\n" );
2810 if (!writer) return E_INVALIDARG;
2812 EnterCriticalSection( &writer->cs );
2814 if (writer->magic != WRITER_MAGIC)
2816 LeaveCriticalSection( &writer->cs );
2817 return E_INVALIDARG;
2820 if (!writer->output_type)
2822 LeaveCriticalSection( &writer->cs );
2823 return WS_E_INVALID_OPERATION;
2826 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2827 utf16.bytes = (BYTE *)chars;
2828 utf16.byteCount = count * sizeof(WCHAR);
2830 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
2831 else hr = write_text_node( writer, &utf16.text );
2833 LeaveCriticalSection( &writer->cs );
2834 return hr;
2837 /**************************************************************************
2838 * WsWriteCharsUtf8 [webservices.@]
2840 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
2842 struct writer *writer = (struct writer *)handle;
2843 WS_XML_UTF8_TEXT utf8;
2844 HRESULT hr;
2846 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
2847 if (error) FIXME( "ignoring error parameter\n" );
2849 if (!writer) return E_INVALIDARG;
2851 EnterCriticalSection( &writer->cs );
2853 if (writer->magic != WRITER_MAGIC)
2855 LeaveCriticalSection( &writer->cs );
2856 return E_INVALIDARG;
2859 if (!writer->output_type)
2861 LeaveCriticalSection( &writer->cs );
2862 return WS_E_INVALID_OPERATION;
2865 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2866 utf8.value.bytes = (BYTE *)bytes;
2867 utf8.value.length = count;
2869 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
2870 else hr = write_text_node( writer, &utf8.text );
2872 LeaveCriticalSection( &writer->cs );
2873 return hr;
2876 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
2878 switch (mapping)
2880 case WS_ELEMENT_TYPE_MAPPING:
2881 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2882 return write_text_node( writer, text );
2884 case WS_ATTRIBUTE_TYPE_MAPPING:
2885 return write_set_attribute_value( writer, text );
2887 case WS_ANY_ELEMENT_TYPE_MAPPING:
2888 switch (writer->state)
2890 case WRITER_STATE_STARTATTRIBUTE:
2891 return write_set_attribute_value( writer, text );
2893 case WRITER_STATE_STARTELEMENT:
2894 return write_text_node( writer, text );
2896 default:
2897 FIXME( "writer state %u not handled\n", writer->state );
2898 return E_NOTIMPL;
2901 default:
2902 FIXME( "mapping %u not implemented\n", mapping );
2903 return E_NOTIMPL;
2907 static HRESULT write_add_nil_attribute( struct writer *writer )
2909 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
2910 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
2911 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
2912 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
2913 HRESULT hr;
2915 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
2916 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
2917 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
2920 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
2921 const void **ptr )
2923 switch (option)
2925 case WS_WRITE_REQUIRED_VALUE:
2926 case WS_WRITE_NILLABLE_VALUE:
2927 if (!value || size != expected_size) return E_INVALIDARG;
2928 *ptr = value;
2929 return S_OK;
2931 case WS_WRITE_REQUIRED_POINTER:
2932 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
2933 return S_OK;
2935 case WS_WRITE_NILLABLE_POINTER:
2936 if (size != sizeof(const void *)) return E_INVALIDARG;
2937 *ptr = *(const void **)value;
2938 return S_OK;
2940 default:
2941 return E_INVALIDARG;
2945 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
2946 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
2947 const BOOL *value, ULONG size )
2949 WS_XML_BOOL_TEXT text_bool;
2950 const BOOL *ptr;
2951 HRESULT hr;
2953 if (desc)
2955 FIXME( "description not supported\n" );
2956 return E_NOTIMPL;
2959 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2960 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
2961 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2963 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
2964 text_bool.value = *ptr;
2965 return write_type_text( writer, mapping, &text_bool.text );
2968 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
2969 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
2970 const BOOL *value, ULONG size )
2972 WS_XML_INT32_TEXT text_int32;
2973 const INT8 *ptr;
2974 HRESULT hr;
2976 if (desc)
2978 FIXME( "description not supported\n" );
2979 return E_NOTIMPL;
2982 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2983 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
2984 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2986 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
2987 text_int32.value = *ptr;
2988 return write_type_text( writer, mapping, &text_int32.text );
2991 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
2992 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
2993 const BOOL *value, ULONG size )
2995 WS_XML_INT32_TEXT text_int32;
2996 const INT16 *ptr;
2997 HRESULT hr;
2999 if (desc)
3001 FIXME( "description not supported\n" );
3002 return E_NOTIMPL;
3005 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3006 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3007 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3009 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3010 text_int32.value = *ptr;
3011 return write_type_text( writer, mapping, &text_int32.text );
3014 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3015 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3016 const void *value, ULONG size )
3018 WS_XML_INT32_TEXT text_int32;
3019 const INT32 *ptr;
3020 HRESULT hr;
3022 if (desc)
3024 FIXME( "description not supported\n" );
3025 return E_NOTIMPL;
3028 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3029 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3030 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3032 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3033 text_int32.value = *ptr;
3034 return write_type_text( writer, mapping, &text_int32.text );
3037 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3038 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3039 const void *value, ULONG size )
3041 WS_XML_INT64_TEXT text_int64;
3042 const INT64 *ptr;
3043 HRESULT hr;
3045 if (desc)
3047 FIXME( "description not supported\n" );
3048 return E_NOTIMPL;
3051 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3052 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3053 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3055 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3056 text_int64.value = *ptr;
3057 return write_type_text( writer, mapping, &text_int64.text );
3060 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3061 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3062 const void *value, ULONG size )
3064 WS_XML_UINT64_TEXT text_uint64;
3065 const UINT8 *ptr;
3066 HRESULT hr;
3068 if (desc)
3070 FIXME( "description not supported\n" );
3071 return E_NOTIMPL;
3074 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3075 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3076 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3078 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3079 text_uint64.value = *ptr;
3080 return write_type_text( writer, mapping, &text_uint64.text );
3083 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3084 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3085 const void *value, ULONG size )
3087 WS_XML_UINT64_TEXT text_uint64;
3088 const UINT16 *ptr;
3089 HRESULT hr;
3091 if (desc)
3093 FIXME( "description not supported\n" );
3094 return E_NOTIMPL;
3097 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3098 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3099 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3101 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3102 text_uint64.value = *ptr;
3103 return write_type_text( writer, mapping, &text_uint64.text );
3106 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3107 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3108 const void *value, ULONG size )
3110 WS_XML_UINT64_TEXT text_uint64;
3111 const UINT32 *ptr;
3112 HRESULT hr;
3114 if (desc)
3116 FIXME( "description not supported\n" );
3117 return E_NOTIMPL;
3120 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3121 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3122 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3124 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3125 text_uint64.value = *ptr;
3126 return write_type_text( writer, mapping, &text_uint64.text );
3129 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3130 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3131 const void *value, ULONG size )
3133 WS_XML_UINT64_TEXT text_uint64;
3134 const UINT64 *ptr;
3135 HRESULT hr;
3137 if (desc)
3139 FIXME( "description not supported\n" );
3140 return E_NOTIMPL;
3143 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3144 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3145 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3147 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3148 text_uint64.value = *ptr;
3149 return write_type_text( writer, mapping, &text_uint64.text );
3152 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3153 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3154 const void *value, ULONG size )
3156 WS_XML_DOUBLE_TEXT text_double;
3157 const double *ptr;
3158 HRESULT hr;
3160 if (desc)
3162 FIXME( "description not supported\n" );
3163 return E_NOTIMPL;
3166 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3167 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3168 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3170 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3171 text_double.value = *ptr;
3172 return write_type_text( writer, mapping, &text_double.text );
3175 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3176 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3177 const void *value, ULONG size )
3179 WS_XML_UTF8_TEXT utf8;
3180 unsigned char buf[34]; /* "0000-00-00T00:00:00.0000000-00:00" */
3181 const WS_DATETIME *ptr;
3182 HRESULT hr;
3184 if (desc)
3186 FIXME( "description not supported\n" );
3187 return E_NOTIMPL;
3190 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3191 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3192 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3193 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3195 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3196 utf8.value.bytes = buf;
3197 utf8.value.length = format_datetime( ptr, buf );
3198 return write_type_text( writer, mapping, &utf8.text );
3201 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3202 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3203 const void *value, ULONG size )
3205 WS_XML_GUID_TEXT text_guid;
3206 const GUID *ptr;
3207 HRESULT hr;
3209 if (desc)
3211 FIXME( "description not supported\n" );
3212 return E_NOTIMPL;
3215 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3216 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3217 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3219 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3220 text_guid.value = *ptr;
3221 return write_type_text( writer, mapping, &text_guid.text );
3224 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3225 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3226 const void *value, ULONG size )
3228 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3229 WS_XML_UTF16_TEXT text_utf16;
3230 const WS_UNIQUE_ID *ptr;
3231 HRESULT hr;
3233 if (desc)
3235 FIXME( "description not supported\n" );
3236 return E_NOTIMPL;
3239 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3240 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3241 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3243 if (ptr->uri.length)
3245 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3246 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3247 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3248 return write_type_text( writer, mapping, &text_utf16.text );
3251 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3252 text_unique_id.value = ptr->guid;
3253 return write_type_text( writer, mapping, &text_unique_id.text );
3256 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3257 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3258 const void *value, ULONG size )
3260 WS_XML_UTF16_TEXT utf16;
3261 const WS_STRING *ptr;
3262 HRESULT hr;
3264 if (desc)
3266 FIXME( "description not supported\n" );
3267 return E_NOTIMPL;
3270 if (!option) return E_INVALIDARG;
3271 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3272 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3273 if (!ptr->length) return S_OK;
3275 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3276 utf16.bytes = (BYTE *)ptr->chars;
3277 utf16.byteCount = ptr->length * sizeof(WCHAR);
3278 return write_type_text( writer, mapping, &utf16.text );
3281 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3282 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3283 const void *value, ULONG size )
3285 WS_XML_UTF16_TEXT utf16;
3286 const WCHAR *ptr;
3287 HRESULT hr;
3288 int len;
3290 if (desc)
3292 FIXME( "description not supported\n" );
3293 return E_NOTIMPL;
3296 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3297 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3298 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3299 if (!(len = strlenW( ptr ))) return S_OK;
3301 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3302 utf16.bytes = (BYTE *)ptr;
3303 utf16.byteCount = len * sizeof(WCHAR);
3304 return write_type_text( writer, mapping, &utf16.text );
3307 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3308 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3309 const void *value, ULONG size )
3311 WS_XML_BASE64_TEXT base64;
3312 const WS_BYTES *ptr;
3313 HRESULT hr;
3315 if (desc)
3317 FIXME( "description not supported\n" );
3318 return E_NOTIMPL;
3321 if (!option) return E_INVALIDARG;
3322 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3323 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3324 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3325 if (!ptr->length) return S_OK;
3327 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3328 base64.bytes = ptr->bytes;
3329 base64.length = ptr->length;
3330 return write_type_text( writer, mapping, &base64.text );
3333 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3334 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3335 const void *value, ULONG size )
3337 WS_XML_UTF8_TEXT utf8;
3338 const WS_XML_STRING *ptr;
3339 HRESULT hr;
3341 if (desc)
3343 FIXME( "description not supported\n" );
3344 return E_NOTIMPL;
3347 if (!option) return E_INVALIDARG;
3348 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3349 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3350 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3351 if (!ptr->length) return S_OK;
3353 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3354 utf8.value.bytes = ptr->bytes;
3355 utf8.value.length = ptr->length;
3356 return write_type_text( writer, mapping, &utf8.text );
3359 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3361 const struct node *node;
3362 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3364 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3365 ULONG i;
3366 for (i = 0; i < elem->attributeCount; i++)
3368 if (!elem->attributes[i]->isXmlNs) continue;
3369 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3370 *prefix = elem->attributes[i]->prefix;
3371 return S_OK;
3374 return WS_E_INVALID_FORMAT;
3377 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3378 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3379 const void *value, ULONG size )
3381 WS_XML_QNAME_TEXT qname;
3382 const WS_XML_QNAME *ptr;
3383 const WS_XML_STRING *prefix;
3384 HRESULT hr;
3386 if (desc)
3388 FIXME( "description not supported\n" );
3389 return E_NOTIMPL;
3392 if (!option) return E_INVALIDARG;
3393 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3394 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3395 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3397 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3399 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3400 qname.prefix = (WS_XML_STRING *)prefix;
3401 qname.localName = (WS_XML_STRING *)&ptr->localName;
3402 qname.ns = (WS_XML_STRING *)&ptr->ns;
3403 return write_type_text( writer, mapping, &qname.text );
3406 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3408 if (options & WS_FIELD_POINTER)
3410 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3411 return WS_WRITE_REQUIRED_POINTER;
3414 switch (type)
3416 case WS_BOOL_TYPE:
3417 case WS_INT8_TYPE:
3418 case WS_INT16_TYPE:
3419 case WS_INT32_TYPE:
3420 case WS_INT64_TYPE:
3421 case WS_UINT8_TYPE:
3422 case WS_UINT16_TYPE:
3423 case WS_UINT32_TYPE:
3424 case WS_UINT64_TYPE:
3425 case WS_DOUBLE_TYPE:
3426 case WS_DATETIME_TYPE:
3427 case WS_GUID_TYPE:
3428 case WS_UNIQUE_ID_TYPE:
3429 case WS_STRING_TYPE:
3430 case WS_BYTES_TYPE:
3431 case WS_XML_STRING_TYPE:
3432 case WS_XML_QNAME_TYPE:
3433 case WS_STRUCT_TYPE:
3434 case WS_ENUM_TYPE:
3435 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3436 return WS_WRITE_REQUIRED_VALUE;
3438 case WS_WSZ_TYPE:
3439 case WS_DESCRIPTION_TYPE:
3440 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3441 return WS_WRITE_REQUIRED_POINTER;
3443 default:
3444 FIXME( "unhandled type %u\n", type );
3445 return 0;
3449 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3450 const void *, ULONG );
3452 static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
3453 const char *buf, ULONG count )
3455 HRESULT hr = S_OK;
3456 ULONG i, size, offset = 0;
3457 WS_WRITE_OPTION option;
3459 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3461 /* wrapper element */
3462 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3463 return hr;
3465 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3466 size = get_type_size( desc->type, desc->typeDescription );
3467 else
3468 size = sizeof(const void *);
3470 for (i = 0; i < count; i++)
3472 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3473 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3474 buf + offset, size )) != S_OK) return hr;
3475 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3476 offset += size;
3479 if (desc->localName) hr = write_endelement_node( writer );
3480 return hr;
3483 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3485 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3486 const void *value, ULONG size )
3488 ULONG i, offset;
3489 const void *ptr;
3490 int enum_value;
3491 HRESULT hr;
3493 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3495 if (size < sizeof(enum_value)) return E_INVALIDARG;
3496 if ((enum_value = *(int *)(char *)ptr + desc->enumOffset) == desc->noneEnumValue)
3498 switch (option)
3500 case WS_WRITE_REQUIRED_VALUE:
3501 return WS_E_INVALID_FORMAT;
3503 case WS_WRITE_NILLABLE_VALUE:
3504 return S_OK;
3506 default:
3507 ERR( "unhandled write option %u\n", option );
3508 return E_INVALIDARG;
3512 for (i = 0; i < desc->fieldCount; i++)
3514 if (desc->fields[i]->value == enum_value)
3516 offset = desc->fields[i]->field.offset;
3517 return write_type_field( writer, &desc->fields[i]->field, ptr, offset );
3521 return E_INVALIDARG;
3524 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3525 ULONG offset )
3527 HRESULT hr;
3528 WS_TYPE_MAPPING mapping;
3529 WS_WRITE_OPTION option;
3530 ULONG count, size, field_options = desc->options;
3531 const char *ptr = buf + offset;
3533 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
3535 FIXME( "options 0x%x not supported\n", desc->options );
3536 return E_NOTIMPL;
3539 /* zero-terminated strings are always pointers */
3540 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
3542 if (field_options & WS_FIELD_POINTER)
3543 size = sizeof(const void *);
3544 else
3545 size = get_type_size( desc->type, desc->typeDescription );
3547 if (is_nil_value( ptr, size ))
3549 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3550 if (field_options & WS_FIELD_NILLABLE)
3552 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3553 else option = WS_WRITE_NILLABLE_VALUE;
3555 else
3557 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3558 else option = WS_WRITE_REQUIRED_VALUE;
3561 else
3563 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3564 else option = WS_WRITE_REQUIRED_VALUE;
3567 switch (desc->mapping)
3569 case WS_ATTRIBUTE_FIELD_MAPPING:
3570 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3571 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3572 return hr;
3573 writer->state = WRITER_STATE_STARTATTRIBUTE;
3575 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3576 break;
3578 case WS_ELEMENT_FIELD_MAPPING:
3579 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3580 mapping = WS_ELEMENT_TYPE_MAPPING;
3581 break;
3583 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3584 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3585 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3586 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3588 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3589 count = *(const ULONG *)(buf + desc->countOffset);
3590 return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
3592 case WS_TEXT_FIELD_MAPPING:
3593 switch (writer->state)
3595 case WRITER_STATE_STARTELEMENT:
3596 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3597 break;
3599 case WRITER_STATE_STARTATTRIBUTE:
3600 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3601 break;
3603 default:
3604 FIXME( "unhandled writer state %u\n", writer->state );
3605 return E_NOTIMPL;
3607 break;
3609 default:
3610 FIXME( "field mapping %u not supported\n", desc->mapping );
3611 return E_NOTIMPL;
3614 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3615 return hr;
3617 switch (mapping)
3619 case WS_ATTRIBUTE_TYPE_MAPPING:
3620 writer->state = WRITER_STATE_STARTELEMENT;
3621 break;
3623 case WS_ELEMENT_TYPE_MAPPING:
3624 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3625 break;
3627 default: break;
3630 return S_OK;
3633 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3634 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3635 const void *value, ULONG size )
3637 ULONG i, offset;
3638 const void *ptr;
3639 HRESULT hr;
3641 if (!desc) return E_INVALIDARG;
3642 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3644 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3646 for (i = 0; i < desc->fieldCount; i++)
3648 offset = desc->fields[i]->offset;
3649 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3652 return S_OK;
3655 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3656 const void *desc, WS_WRITE_OPTION option, const void *value,
3657 ULONG size )
3659 switch (type)
3661 case WS_BOOL_TYPE:
3662 return write_type_bool( writer, mapping, desc, option, value, size );
3664 case WS_INT8_TYPE:
3665 return write_type_int8( writer, mapping, desc, option, value, size );
3667 case WS_INT16_TYPE:
3668 return write_type_int16( writer, mapping, desc, option, value, size );
3670 case WS_INT32_TYPE:
3671 return write_type_int32( writer, mapping, desc, option, value, size );
3673 case WS_INT64_TYPE:
3674 return write_type_int64( writer, mapping, desc, option, value, size );
3676 case WS_UINT8_TYPE:
3677 return write_type_uint8( writer, mapping, desc, option, value, size );
3679 case WS_UINT16_TYPE:
3680 return write_type_uint16( writer, mapping, desc, option, value, size );
3682 case WS_UINT32_TYPE:
3683 return write_type_uint32( writer, mapping, desc, option, value, size );
3685 case WS_UINT64_TYPE:
3686 return write_type_uint64( writer, mapping, desc, option, value, size );
3688 case WS_DOUBLE_TYPE:
3689 return write_type_double( writer, mapping, desc, option, value, size );
3691 case WS_DATETIME_TYPE:
3692 return write_type_datetime( writer, mapping, desc, option, value, size );
3694 case WS_GUID_TYPE:
3695 return write_type_guid( writer, mapping, desc, option, value, size );
3697 case WS_UNIQUE_ID_TYPE:
3698 return write_type_unique_id( writer, mapping, desc, option, value, size );
3700 case WS_STRING_TYPE:
3701 return write_type_string( writer, mapping, desc, option, value, size );
3703 case WS_WSZ_TYPE:
3704 return write_type_wsz( writer, mapping, desc, option, value, size );
3706 case WS_BYTES_TYPE:
3707 return write_type_bytes( writer, mapping, desc, option, value, size );
3709 case WS_XML_STRING_TYPE:
3710 return write_type_xml_string( writer, mapping, desc, option, value, size );
3712 case WS_XML_QNAME_TYPE:
3713 return write_type_qname( writer, mapping, desc, option, value, size );
3715 case WS_STRUCT_TYPE:
3716 return write_type_struct( writer, mapping, desc, option, value, size );
3718 default:
3719 FIXME( "type %u not supported\n", type );
3720 return E_NOTIMPL;
3724 /**************************************************************************
3725 * WsWriteAttribute [webservices.@]
3727 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
3728 WS_WRITE_OPTION option, const void *value, ULONG size,
3729 WS_ERROR *error )
3731 struct writer *writer = (struct writer *)handle;
3732 HRESULT hr;
3734 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3735 if (error) FIXME( "ignoring error parameter\n" );
3737 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
3738 return E_INVALIDARG;
3740 EnterCriticalSection( &writer->cs );
3742 if (writer->magic != WRITER_MAGIC)
3744 LeaveCriticalSection( &writer->cs );
3745 return E_INVALIDARG;
3748 if (writer->state != WRITER_STATE_STARTELEMENT)
3750 LeaveCriticalSection( &writer->cs );
3751 return WS_E_INVALID_OPERATION;
3754 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK)
3756 LeaveCriticalSection( &writer->cs );
3757 return hr;
3759 writer->state = WRITER_STATE_STARTATTRIBUTE;
3761 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
3763 LeaveCriticalSection( &writer->cs );
3764 return hr;
3767 /**************************************************************************
3768 * WsWriteElement [webservices.@]
3770 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3771 WS_WRITE_OPTION option, const void *value, ULONG size,
3772 WS_ERROR *error )
3774 struct writer *writer = (struct writer *)handle;
3775 HRESULT hr;
3777 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3778 if (error) FIXME( "ignoring error parameter\n" );
3780 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
3781 return E_INVALIDARG;
3783 EnterCriticalSection( &writer->cs );
3785 if (writer->magic != WRITER_MAGIC)
3787 LeaveCriticalSection( &writer->cs );
3788 return E_INVALIDARG;
3791 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
3793 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
3794 option, value, size )) != S_OK) goto done;
3796 hr = write_endelement_node( writer );
3798 done:
3799 LeaveCriticalSection( &writer->cs );
3800 return hr;
3803 /**************************************************************************
3804 * WsWriteType [webservices.@]
3806 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
3807 const void *desc, WS_WRITE_OPTION option, const void *value,
3808 ULONG size, WS_ERROR *error )
3810 struct writer *writer = (struct writer *)handle;
3811 HRESULT hr;
3813 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
3814 size, error );
3815 if (error) FIXME( "ignoring error parameter\n" );
3817 if (!writer || !value) return E_INVALIDARG;
3819 EnterCriticalSection( &writer->cs );
3821 if (writer->magic != WRITER_MAGIC)
3823 LeaveCriticalSection( &writer->cs );
3824 return E_INVALIDARG;
3827 switch (mapping)
3829 case WS_ATTRIBUTE_TYPE_MAPPING:
3830 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
3831 else hr = write_type( writer, mapping, type, desc, option, value, size );
3832 break;
3834 case WS_ELEMENT_TYPE_MAPPING:
3835 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3836 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
3837 else hr = write_type( writer, mapping, type, desc, option, value, size );
3838 break;
3840 case WS_ANY_ELEMENT_TYPE_MAPPING:
3841 hr = write_type( writer, mapping, type, desc, option, value, size );
3842 break;
3844 default:
3845 FIXME( "mapping %u not implemented\n", mapping );
3846 hr = E_NOTIMPL;
3849 LeaveCriticalSection( &writer->cs );
3850 return hr;
3853 WS_TYPE map_value_type( WS_VALUE_TYPE type )
3855 switch (type)
3857 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
3858 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
3859 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
3860 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
3861 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
3862 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
3863 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
3864 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
3865 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
3866 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
3867 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
3868 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
3869 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
3870 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
3871 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
3872 default:
3873 FIXME( "unhandled type %u\n", type );
3874 return ~0u;
3878 /**************************************************************************
3879 * WsWriteValue [webservices.@]
3881 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
3882 ULONG size, WS_ERROR *error )
3884 struct writer *writer = (struct writer *)handle;
3885 WS_TYPE_MAPPING mapping;
3886 HRESULT hr = S_OK;
3887 WS_TYPE type;
3889 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
3890 if (error) FIXME( "ignoring error parameter\n" );
3892 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
3894 EnterCriticalSection( &writer->cs );
3896 if (writer->magic != WRITER_MAGIC)
3898 LeaveCriticalSection( &writer->cs );
3899 return E_INVALIDARG;
3902 switch (writer->state)
3904 case WRITER_STATE_STARTATTRIBUTE:
3905 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3906 break;
3908 case WRITER_STATE_STARTELEMENT:
3909 mapping = WS_ELEMENT_TYPE_MAPPING;
3910 break;
3912 default:
3913 hr = WS_E_INVALID_FORMAT;
3916 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
3918 LeaveCriticalSection( &writer->cs );
3919 return hr;
3922 /**************************************************************************
3923 * WsWriteArray [webservices.@]
3925 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3926 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
3927 ULONG count, WS_ERROR *error )
3929 struct writer *writer = (struct writer *)handle;
3930 WS_TYPE type;
3931 ULONG type_size, i;
3932 HRESULT hr = S_OK;
3934 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3935 value_type, array, size, offset, count, error );
3936 if (error) FIXME( "ignoring error parameter\n" );
3938 if (!writer) return E_INVALIDARG;
3940 EnterCriticalSection( &writer->cs );
3942 if (writer->magic != WRITER_MAGIC)
3944 LeaveCriticalSection( &writer->cs );
3945 return E_INVALIDARG;
3948 if (!writer->output_type)
3950 LeaveCriticalSection( &writer->cs );
3951 return WS_E_INVALID_OPERATION;
3954 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
3956 LeaveCriticalSection( &writer->cs );
3957 return E_INVALIDARG;
3960 type_size = get_type_size( type, NULL );
3961 if (size % type_size || (offset + count) * type_size > size || (count && !array))
3963 LeaveCriticalSection( &writer->cs );
3964 return E_INVALIDARG;
3967 for (i = offset; i < count; i++)
3969 const char *ptr = (const char *)array + (offset + i) * type_size;
3970 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
3971 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
3972 &ptr, sizeof(ptr) )) != S_OK) goto done;
3973 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
3976 done:
3977 LeaveCriticalSection( &writer->cs );
3978 return hr;
3981 /**************************************************************************
3982 * WsWriteXmlBuffer [webservices.@]
3984 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
3986 struct writer *writer = (struct writer *)handle;
3987 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
3988 HRESULT hr;
3990 TRACE( "%p %p %p\n", handle, buffer, error );
3991 if (error) FIXME( "ignoring error parameter\n" );
3993 if (!writer || !xmlbuf) return E_INVALIDARG;
3995 EnterCriticalSection( &writer->cs );
3997 if (writer->magic != WRITER_MAGIC)
3999 LeaveCriticalSection( &writer->cs );
4000 return E_INVALIDARG;
4003 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4005 FIXME( "no support for different encoding and/or charset\n" );
4006 hr = E_NOTIMPL;
4007 goto done;
4010 if ((hr = write_flush( writer )) != S_OK) goto done;
4011 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4012 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4014 done:
4015 LeaveCriticalSection( &writer->cs );
4016 return hr;
4019 /**************************************************************************
4020 * WsWriteXmlBufferToBytes [webservices.@]
4022 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4023 const WS_XML_WRITER_ENCODING *encoding,
4024 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4025 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4027 struct writer *writer = (struct writer *)handle;
4028 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4029 HRESULT hr = S_OK;
4030 char *buf;
4031 ULONG i;
4033 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4034 bytes, size, error );
4035 if (error) FIXME( "ignoring error parameter\n" );
4037 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4039 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4041 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4042 return E_NOTIMPL;
4045 EnterCriticalSection( &writer->cs );
4047 if (writer->magic != WRITER_MAGIC)
4049 LeaveCriticalSection( &writer->cs );
4050 return E_INVALIDARG;
4053 for (i = 0; i < count; i++)
4055 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4056 properties[i].valueSize );
4057 if (hr != S_OK) goto done;
4060 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4061 else
4063 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4064 *bytes = buf;
4065 *size = xmlbuf->bytes.length;
4068 done:
4069 LeaveCriticalSection( &writer->cs );
4070 return hr;
4073 /**************************************************************************
4074 * WsWriteXmlnsAttribute [webservices.@]
4076 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4077 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4079 struct writer *writer = (struct writer *)handle;
4080 HRESULT hr = S_OK;
4082 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4083 single, error );
4084 if (error) FIXME( "ignoring error parameter\n" );
4086 if (!writer || !ns) return E_INVALIDARG;
4088 EnterCriticalSection( &writer->cs );
4090 if (writer->magic != WRITER_MAGIC)
4092 LeaveCriticalSection( &writer->cs );
4093 return E_INVALIDARG;
4096 if (writer->state != WRITER_STATE_STARTELEMENT)
4098 LeaveCriticalSection( &writer->cs );
4099 return WS_E_INVALID_OPERATION;
4102 if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4103 hr = add_namespace_attribute( writer, prefix, ns, single );
4105 LeaveCriticalSection( &writer->cs );
4106 return hr;
4109 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4110 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4112 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4113 HRESULT hr;
4115 if ((hr = write_flush( writer )) != S_OK) return hr;
4116 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4118 qname.prefix = (WS_XML_STRING *)prefix;
4119 qname.localName = (WS_XML_STRING *)localname;
4120 qname.ns = (WS_XML_STRING *)ns;
4122 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4123 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4126 /**************************************************************************
4127 * WsWriteQualifiedName [webservices.@]
4129 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4130 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4131 WS_ERROR *error )
4133 struct writer *writer = (struct writer *)handle;
4134 HRESULT hr;
4136 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4137 debugstr_xmlstr(ns), error );
4138 if (error) FIXME( "ignoring error parameter\n" );
4140 if (!writer) return E_INVALIDARG;
4142 EnterCriticalSection( &writer->cs );
4144 if (writer->magic != WRITER_MAGIC)
4146 LeaveCriticalSection( &writer->cs );
4147 return E_INVALIDARG;
4150 if (!writer->output_type)
4152 LeaveCriticalSection( &writer->cs );
4153 return WS_E_INVALID_OPERATION;
4156 if (writer->state != WRITER_STATE_STARTELEMENT)
4158 LeaveCriticalSection( &writer->cs );
4159 return WS_E_INVALID_FORMAT;
4162 if (!localname || (!prefix && !ns))
4164 LeaveCriticalSection( &writer->cs );
4165 return E_INVALIDARG;
4168 hr = write_qualified_name( writer, prefix, localname, ns );
4170 LeaveCriticalSection( &writer->cs );
4171 return hr;
4174 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4176 BOOL success = FALSE;
4177 struct node *node = writer->current;
4179 switch (move)
4181 case WS_MOVE_TO_ROOT_ELEMENT:
4182 success = move_to_root_element( writer->root, &node );
4183 break;
4185 case WS_MOVE_TO_NEXT_ELEMENT:
4186 success = move_to_next_element( &node );
4187 break;
4189 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4190 success = move_to_prev_element( &node );
4191 break;
4193 case WS_MOVE_TO_CHILD_ELEMENT:
4194 success = move_to_child_element( &node );
4195 break;
4197 case WS_MOVE_TO_END_ELEMENT:
4198 success = move_to_end_element( &node );
4199 break;
4201 case WS_MOVE_TO_PARENT_ELEMENT:
4202 success = move_to_parent_element( &node );
4203 break;
4205 case WS_MOVE_TO_FIRST_NODE:
4206 success = move_to_first_node( &node );
4207 break;
4209 case WS_MOVE_TO_NEXT_NODE:
4210 success = move_to_next_node( &node );
4211 break;
4213 case WS_MOVE_TO_PREVIOUS_NODE:
4214 success = move_to_prev_node( &node );
4215 break;
4217 case WS_MOVE_TO_CHILD_NODE:
4218 success = move_to_child_node( &node );
4219 break;
4221 case WS_MOVE_TO_BOF:
4222 success = move_to_bof( writer->root, &node );
4223 break;
4225 case WS_MOVE_TO_EOF:
4226 success = move_to_eof( writer->root, &node );
4227 break;
4229 default:
4230 FIXME( "unhandled move %u\n", move );
4231 return E_NOTIMPL;
4234 if (success && node == writer->root) return E_INVALIDARG;
4235 writer->current = node;
4237 if (found)
4239 *found = success;
4240 return S_OK;
4242 return success ? S_OK : WS_E_INVALID_FORMAT;
4245 /**************************************************************************
4246 * WsMoveWriter [webservices.@]
4248 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4250 struct writer *writer = (struct writer *)handle;
4251 HRESULT hr;
4253 TRACE( "%p %u %p %p\n", handle, move, found, error );
4254 if (error) FIXME( "ignoring error parameter\n" );
4256 if (!writer) return E_INVALIDARG;
4258 EnterCriticalSection( &writer->cs );
4260 if (writer->magic != WRITER_MAGIC)
4262 LeaveCriticalSection( &writer->cs );
4263 return E_INVALIDARG;
4266 if (!writer->output_type)
4268 LeaveCriticalSection( &writer->cs );
4269 return WS_E_INVALID_OPERATION;
4272 hr = write_move_to( writer, move, found );
4274 LeaveCriticalSection( &writer->cs );
4275 return hr;
4278 /**************************************************************************
4279 * WsGetWriterPosition [webservices.@]
4281 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4283 struct writer *writer = (struct writer *)handle;
4285 TRACE( "%p %p %p\n", handle, pos, error );
4286 if (error) FIXME( "ignoring error parameter\n" );
4288 if (!writer || !pos) return E_INVALIDARG;
4290 EnterCriticalSection( &writer->cs );
4292 if (writer->magic != WRITER_MAGIC)
4294 LeaveCriticalSection( &writer->cs );
4295 return E_INVALIDARG;
4298 if (!writer->output_type)
4300 LeaveCriticalSection( &writer->cs );
4301 return WS_E_INVALID_OPERATION;
4304 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4305 pos->node = writer->current;
4307 LeaveCriticalSection( &writer->cs );
4308 return S_OK;
4311 /**************************************************************************
4312 * WsSetWriterPosition [webservices.@]
4314 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4316 struct writer *writer = (struct writer *)handle;
4318 TRACE( "%p %p %p\n", handle, pos, error );
4319 if (error) FIXME( "ignoring error parameter\n" );
4321 if (!writer || !pos) return E_INVALIDARG;
4323 EnterCriticalSection( &writer->cs );
4325 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4327 LeaveCriticalSection( &writer->cs );
4328 return E_INVALIDARG;
4331 if (!writer->output_type)
4333 LeaveCriticalSection( &writer->cs );
4334 return WS_E_INVALID_OPERATION;
4337 writer->current = pos->node;
4339 LeaveCriticalSection( &writer->cs );
4340 return S_OK;
4343 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4345 struct node *node, *parent;
4346 WS_XML_COMMENT_NODE *comment;
4348 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4349 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4350 comment = (WS_XML_COMMENT_NODE *)node;
4352 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4354 free_node( node );
4355 return E_OUTOFMEMORY;
4357 memcpy( comment->value.bytes, value->bytes, value->length );
4358 comment->value.length = value->length;
4360 write_insert_node( writer, parent, node );
4361 return S_OK;
4364 static HRESULT write_comment_text( struct writer *writer )
4366 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4367 HRESULT hr;
4369 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4370 write_bytes( writer, (const BYTE *)"<!--", 4 );
4371 write_bytes( writer, comment->value.bytes, comment->value.length );
4372 write_bytes( writer, (const BYTE *)"-->", 3 );
4373 return S_OK;
4376 static HRESULT write_comment_bin( struct writer *writer )
4378 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4379 HRESULT hr;
4381 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4382 write_char( writer, RECORD_COMMENT );
4383 return write_string( writer, comment->value.bytes, comment->value.length );
4386 static HRESULT write_comment( struct writer *writer )
4388 switch (writer->output_enc)
4390 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4391 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4392 default:
4393 ERR( "unhandled encoding %u\n", writer->output_enc );
4394 return WS_E_NOT_SUPPORTED;
4398 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4400 HRESULT hr;
4401 if ((hr = write_flush( writer )) != S_OK) return hr;
4402 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4403 if ((hr = write_comment( writer )) != S_OK) return hr;
4404 writer->state = WRITER_STATE_COMMENT;
4405 return S_OK;
4408 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4410 ULONG i;
4411 HRESULT hr;
4413 for (i = 0; i < count; i++)
4415 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
4416 attrs[i]->singleQuote )) != S_OK) return hr;
4417 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4419 return S_OK;
4422 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4424 HRESULT hr;
4426 switch (node->nodeType)
4428 case WS_XML_NODE_TYPE_ELEMENT:
4430 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4431 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4432 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4434 case WS_XML_NODE_TYPE_TEXT:
4436 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4437 return write_text_node( writer, text->text );
4439 case WS_XML_NODE_TYPE_END_ELEMENT:
4440 return write_endelement_node( writer );
4442 case WS_XML_NODE_TYPE_COMMENT:
4444 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4445 return write_comment_node( writer, &comment->value );
4447 case WS_XML_NODE_TYPE_CDATA:
4448 return write_cdata_node( writer );
4450 case WS_XML_NODE_TYPE_END_CDATA:
4451 return write_endcdata_node( writer );
4453 case WS_XML_NODE_TYPE_EOF:
4454 case WS_XML_NODE_TYPE_BOF:
4455 return S_OK;
4457 default:
4458 WARN( "unknown node type %u\n", node->nodeType );
4459 return E_INVALIDARG;
4463 /**************************************************************************
4464 * WsWriteNode [webservices.@]
4466 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4468 struct writer *writer = (struct writer *)handle;
4469 HRESULT hr;
4471 TRACE( "%p %p %p\n", handle, node, error );
4472 if (error) FIXME( "ignoring error parameter\n" );
4474 if (!writer || !node) return E_INVALIDARG;
4476 EnterCriticalSection( &writer->cs );
4478 if (writer->magic != WRITER_MAGIC)
4480 LeaveCriticalSection( &writer->cs );
4481 return E_INVALIDARG;
4484 if (!writer->output_type)
4486 LeaveCriticalSection( &writer->cs );
4487 return WS_E_INVALID_OPERATION;
4490 hr = write_node( writer, node );
4492 LeaveCriticalSection( &writer->cs );
4493 return hr;
4496 static HRESULT write_tree_node( struct writer *writer )
4498 HRESULT hr;
4500 switch (node_type( writer->current ))
4502 case WS_XML_NODE_TYPE_ELEMENT:
4503 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4504 return hr;
4505 if ((hr = write_startelement( writer )) != S_OK) return hr;
4506 writer->state = WRITER_STATE_STARTELEMENT;
4507 return S_OK;
4509 case WS_XML_NODE_TYPE_TEXT:
4510 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4511 return hr;
4512 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4513 writer->state = WRITER_STATE_TEXT;
4514 return S_OK;
4516 case WS_XML_NODE_TYPE_END_ELEMENT:
4517 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4518 writer->state = WRITER_STATE_ENDELEMENT;
4519 return S_OK;
4521 case WS_XML_NODE_TYPE_COMMENT:
4522 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4523 return hr;
4524 if ((hr = write_comment( writer )) != S_OK) return hr;
4525 writer->state = WRITER_STATE_COMMENT;
4526 return S_OK;
4528 case WS_XML_NODE_TYPE_CDATA:
4529 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4530 return hr;
4531 if ((hr = write_cdata( writer )) != S_OK) return hr;
4532 writer->state = WRITER_STATE_STARTCDATA;
4533 return S_OK;
4535 case WS_XML_NODE_TYPE_END_CDATA:
4536 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4537 writer->state = WRITER_STATE_ENDCDATA;
4538 return S_OK;
4540 case WS_XML_NODE_TYPE_EOF:
4541 case WS_XML_NODE_TYPE_BOF:
4542 return S_OK;
4544 default:
4545 ERR( "unknown node type %u\n", node_type(writer->current) );
4546 return E_INVALIDARG;
4550 static HRESULT write_tree( struct writer *writer )
4552 HRESULT hr;
4554 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4555 for (;;)
4557 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4558 if (move_to_child_node( &writer->current ))
4560 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4561 continue;
4563 if (move_to_next_node( &writer->current ))
4565 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4566 continue;
4568 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4570 ERR( "invalid tree\n" );
4571 return WS_E_INVALID_FORMAT;
4573 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4575 return S_OK;
4578 static void write_rewind( struct writer *writer )
4580 writer->write_pos = 0;
4581 writer->current = writer->root;
4582 writer->state = WRITER_STATE_INITIAL;
4585 /**************************************************************************
4586 * WsCopyNode [webservices.@]
4588 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4590 struct writer *writer = (struct writer *)handle;
4591 struct node *parent, *current, *node = NULL;
4592 HRESULT hr;
4594 TRACE( "%p %p %p\n", handle, reader, error );
4595 if (error) FIXME( "ignoring error parameter\n" );
4597 if (!writer) return E_INVALIDARG;
4599 EnterCriticalSection( &writer->cs );
4601 if (writer->magic != WRITER_MAGIC)
4603 LeaveCriticalSection( &writer->cs );
4604 return E_INVALIDARG;
4607 if (!(parent = find_parent( writer )))
4609 LeaveCriticalSection( &writer->cs );
4610 return WS_E_INVALID_FORMAT;
4613 if ((hr = copy_node( reader, &node )) != S_OK) goto done;
4614 current = writer->current;
4615 write_insert_node( writer, parent, node );
4617 write_rewind( writer );
4618 if ((hr = write_tree( writer )) != S_OK) goto done;
4619 writer->current = current;
4621 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4623 done:
4624 LeaveCriticalSection( &writer->cs );
4625 return hr;
4628 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4630 return write_type_field( writer, desc, value, 0 );
4633 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4635 ULONG i, ret = 0;
4636 for (i = 0; i < count; i++)
4638 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4639 continue;
4640 if (args[i]) ret = *(const ULONG *)args[i];
4641 break;
4643 return ret;
4646 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4647 ULONG len )
4649 return write_type_repeating_element( writer, desc, value, len );
4652 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4653 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4655 struct writer *writer = (struct writer *)handle;
4656 const WS_STRUCT_DESCRIPTION *desc_struct;
4657 const WS_FIELD_DESCRIPTION *desc_field;
4658 HRESULT hr;
4659 ULONG i;
4661 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4663 EnterCriticalSection( &writer->cs );
4665 if (writer->magic != WRITER_MAGIC)
4667 LeaveCriticalSection( &writer->cs );
4668 return E_INVALIDARG;
4671 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4673 for (i = 0; i < count; i++)
4675 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4676 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4678 FIXME( "messages type not supported\n" );
4679 hr = E_NOTIMPL;
4680 goto done;
4682 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4683 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4685 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4687 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4689 const void *ptr = *(const void **)args[i];
4690 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4691 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4695 hr = write_endelement_node( writer );
4697 done:
4698 LeaveCriticalSection( &writer->cs );
4699 return hr;