webservices: Implement the Message Framing Protocol.
[wine.git] / dlls / webservices / writer.c
blob2071a955d9ec9db4d8e3e9445802540fd9dd1628
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 case WS_XML_TEXT_TYPE_DATETIME:
726 return RECORD_DATETIME_TEXT;
728 default:
729 FIXME( "unhandled text type %u\n", text->textType );
730 return 0;
734 static INT64 get_text_value_int( const WS_XML_TEXT *text )
736 switch (text->textType)
738 case WS_XML_TEXT_TYPE_INT32:
740 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
741 return text_int32->value;
743 case WS_XML_TEXT_TYPE_INT64:
745 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
746 return text_int64->value;
748 case WS_XML_TEXT_TYPE_UINT64:
750 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
751 return text_uint64->value;
753 case WS_XML_TEXT_TYPE_DOUBLE:
755 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
756 return text_double->value;
758 default:
759 ERR( "unhandled text type %u\n", text->textType );
760 assert(0);
761 return 0;
765 static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
767 enum record_type type = get_attr_text_record_type( text );
768 HRESULT hr;
770 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
771 write_char( writer, type );
773 switch (type)
775 case RECORD_CHARS8_TEXT:
777 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
778 if (!text_utf8)
780 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
781 write_char( writer, 0 );
782 return S_OK;
784 if ((hr = write_grow_buffer( writer, 1 + text_utf8->value.length )) != S_OK) return hr;
785 write_char( writer, text_utf8->value.length );
786 write_bytes( writer, text_utf8->value.bytes, text_utf8->value.length );
787 return S_OK;
789 case RECORD_CHARS16_TEXT:
791 WS_XML_UTF8_TEXT *text_utf8 = (WS_XML_UTF8_TEXT *)text;
792 UINT16 len = text_utf8->value.length;
793 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
794 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
795 write_bytes( writer, text_utf8->value.bytes, len );
796 return S_OK;
798 case RECORD_BYTES8_TEXT:
800 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
801 if ((hr = write_grow_buffer( writer, 1 + text_base64->length )) != S_OK) return hr;
802 write_char( writer, text_base64->length );
803 write_bytes( writer, text_base64->bytes, text_base64->length );
804 return S_OK;
806 case RECORD_BYTES16_TEXT:
808 WS_XML_BASE64_TEXT *text_base64 = (WS_XML_BASE64_TEXT *)text;
809 UINT16 len = text_base64->length;
810 if ((hr = write_grow_buffer( writer, sizeof(len) + len )) != S_OK) return hr;
811 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
812 write_bytes( writer, text_base64->bytes, len );
813 return S_OK;
815 case RECORD_ZERO_TEXT:
816 case RECORD_ONE_TEXT:
817 case RECORD_FALSE_TEXT:
818 case RECORD_TRUE_TEXT:
819 return S_OK;
821 case RECORD_INT8_TEXT:
823 INT8 val = get_text_value_int( text );
824 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
825 write_char( writer, val );
826 return S_OK;
828 case RECORD_INT16_TEXT:
830 INT16 val = get_text_value_int( text );
831 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
832 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
833 return S_OK;
835 case RECORD_INT32_TEXT:
837 INT32 val = get_text_value_int( text );
838 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
839 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
840 return S_OK;
842 case RECORD_INT64_TEXT:
844 INT64 val = get_text_value_int( text );
845 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
846 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
847 return S_OK;
849 case RECORD_UINT64_TEXT:
851 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
852 if ((hr = write_grow_buffer( writer, sizeof(text_uint64->value) )) != S_OK) return hr;
853 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
854 return S_OK;
856 case RECORD_DOUBLE_TEXT:
858 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
859 if ((hr = write_grow_buffer( writer, sizeof(text_double->value) )) != S_OK) return hr;
860 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
861 return S_OK;
863 case RECORD_GUID_TEXT:
865 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
866 if ((hr = write_grow_buffer( writer, sizeof(text_guid->value) )) != S_OK) return hr;
867 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
868 return S_OK;
870 case RECORD_UNIQUE_ID_TEXT:
872 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
873 if ((hr = write_grow_buffer( writer, sizeof(text_unique_id->value) )) != S_OK) return hr;
874 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
875 return S_OK;
877 case RECORD_DATETIME_TEXT:
879 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
880 UINT64 val = text_datetime->value.ticks;
882 assert( val <= TICKS_MAX );
883 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
884 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
886 if ((hr = write_grow_buffer( writer, sizeof(val) )) != S_OK) return hr;
887 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
888 return S_OK;
890 default:
891 FIXME( "unhandled record type %02x\n", type );
892 return E_NOTIMPL;
896 static BOOL lookup_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
898 if (writer->dict && str->dictionary == writer->dict)
900 *id = str->id << 1;
901 return TRUE;
903 if (writer->dict_cb)
905 BOOL found = FALSE;
906 writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
907 if (found) *id = (*id << 1) | 1;
908 return found;
910 return FALSE;
913 static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
915 if (!attr->prefix || !attr->prefix->length)
917 if (use_dict) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
918 return RECORD_SHORT_ATTRIBUTE;
920 if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
922 if (use_dict) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
923 return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
925 if (use_dict) return RECORD_DICTIONARY_ATTRIBUTE;
926 return RECORD_ATTRIBUTE;
929 static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
931 ULONG id;
932 enum record_type type = get_attr_record_type( attr, lookup_string_id(writer, attr->localName, &id) );
933 HRESULT hr;
935 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
936 write_char( writer, type );
938 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
940 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
941 return write_attribute_value_bin( writer, attr->value );
943 if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
945 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
946 return write_attribute_value_bin( writer, attr->value );
949 switch (type)
951 case RECORD_SHORT_ATTRIBUTE:
952 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
953 break;
955 case RECORD_ATTRIBUTE:
956 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
957 if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
958 break;
960 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
961 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
962 break;
964 case RECORD_DICTIONARY_ATTRIBUTE:
965 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
966 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
967 break;
969 default:
970 ERR( "unhandled record type %02x\n", type );
971 return WS_E_NOT_SUPPORTED;
974 return write_attribute_value_bin( writer, attr->value );
977 static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
979 switch (writer->output_enc)
981 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
982 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
983 default:
984 ERR( "unhandled encoding %u\n", writer->output_enc );
985 return WS_E_NOT_SUPPORTED;
989 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
991 return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
994 /**************************************************************************
995 * WsGetPrefixFromNamespace [webservices.@]
997 HRESULT WINAPI WsGetPrefixFromNamespace( WS_XML_WRITER *handle, const WS_XML_STRING *ns,
998 BOOL required, const WS_XML_STRING **prefix,
999 WS_ERROR *error )
1001 struct writer *writer = (struct writer *)handle;
1002 WS_XML_ELEMENT_NODE *elem;
1003 BOOL found = FALSE;
1004 HRESULT hr = S_OK;
1006 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(ns), required, prefix, error );
1007 if (error) FIXME( "ignoring error parameter\n" );
1009 if (!writer || !ns || !prefix) return E_INVALIDARG;
1011 EnterCriticalSection( &writer->cs );
1013 if (writer->magic != WRITER_MAGIC)
1015 LeaveCriticalSection( &writer->cs );
1016 return E_INVALIDARG;
1019 elem = &writer->current->hdr;
1020 if (elem->prefix && is_current_namespace( writer, ns ))
1022 *prefix = elem->prefix;
1023 found = TRUE;
1026 if (!found)
1028 if (required) hr = WS_E_INVALID_FORMAT;
1029 else
1031 *prefix = NULL;
1032 hr = S_FALSE;
1036 LeaveCriticalSection( &writer->cs );
1037 return hr;
1040 static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1042 unsigned char quote = attr->singleQuote ? '\'' : '"';
1043 ULONG size;
1044 HRESULT hr;
1046 /* ' xmlns:prefix="namespace"' */
1048 size = attr->ns->length + 9 /* ' xmlns=""' */;
1049 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
1050 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1052 write_bytes( writer, (const BYTE *)" xmlns", 6 );
1053 if (attr->prefix)
1055 write_char( writer, ':' );
1056 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
1058 write_char( writer, '=' );
1059 write_char( writer, quote );
1060 write_bytes( writer, attr->ns->bytes, attr->ns->length );
1061 write_char( writer, quote );
1063 return S_OK;
1066 static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
1068 if (!attr->prefix || !attr->prefix->length)
1070 if (use_dict) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
1071 return RECORD_SHORT_XMLNS_ATTRIBUTE;
1073 if (use_dict) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
1074 return RECORD_XMLNS_ATTRIBUTE;
1077 static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1079 ULONG id;
1080 enum record_type type = get_xmlns_record_type( attr, lookup_string_id(writer, attr->ns, &id) );
1081 HRESULT hr;
1083 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1084 write_char( writer, type );
1086 switch (type)
1088 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1089 break;
1091 case RECORD_XMLNS_ATTRIBUTE:
1092 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1093 break;
1095 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1096 return write_dict_string( writer, id );
1098 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1099 if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
1100 return write_dict_string( writer, id );
1102 default:
1103 ERR( "unhandled record type %02x\n", type );
1104 return WS_E_NOT_SUPPORTED;
1107 return write_string( writer, attr->ns->bytes, attr->ns->length );
1110 static HRESULT write_namespace_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
1112 switch (writer->output_enc)
1114 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_namespace_attribute_text( writer, attr );
1115 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_namespace_attribute_bin( writer, attr );
1116 default:
1117 ERR( "unhandled encoding %u\n", writer->output_enc );
1118 return WS_E_NOT_SUPPORTED;
1122 static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1123 const WS_XML_STRING *ns, BOOL single )
1125 WS_XML_ATTRIBUTE *attr;
1126 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1127 HRESULT hr;
1129 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1131 attr->singleQuote = !!single;
1132 attr->isXmlNs = 1;
1133 if (prefix && !(attr->prefix = dup_xml_string( prefix )))
1135 free_attribute( attr );
1136 return E_OUTOFMEMORY;
1138 if (!(attr->ns = dup_xml_string( ns )))
1140 free_attribute( attr );
1141 return E_OUTOFMEMORY;
1143 if ((hr = append_attribute( elem, attr )) != S_OK)
1145 free_attribute( attr );
1146 return hr;
1148 return S_OK;
1151 static inline BOOL str_equal( const WS_XML_STRING *str1, const WS_XML_STRING *str2 )
1153 if (!str1 && !str2) return TRUE;
1154 return WsXmlStringEquals( str1, str2, NULL ) == S_OK;
1157 static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_STRING *prefix,
1158 const WS_XML_STRING *ns )
1160 ULONG i;
1161 const struct node *node;
1163 for (node = (const struct node *)elem; node; node = node->parent)
1165 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) break;
1167 elem = &node->hdr;
1168 for (i = 0; i < elem->attributeCount; i++)
1170 if (!elem->attributes[i]->isXmlNs) continue;
1171 if (str_equal( elem->attributes[i]->prefix, prefix ) &&
1172 str_equal( elem->attributes[i]->ns, ns )) return TRUE;
1175 return FALSE;
1178 static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
1180 WS_XML_STRING *str;
1181 if (!(str = dup_xml_string( ns ))) return E_OUTOFMEMORY;
1182 free_xml_string( writer->current_ns );
1183 writer->current_ns = str;
1184 return S_OK;
1187 static HRESULT set_namespaces( struct writer *writer )
1189 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1190 HRESULT hr;
1191 ULONG i;
1193 if (elem->ns->length && !namespace_in_scope( elem, elem->prefix, elem->ns ))
1195 if ((hr = add_namespace_attribute( writer, elem->prefix, elem->ns, FALSE )) != S_OK) return hr;
1196 if ((hr = set_current_namespace( writer, elem->ns )) != S_OK) return hr;
1199 for (i = 0; i < elem->attributeCount; i++)
1201 const WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1202 if (!attr->ns->length || namespace_in_scope( elem, attr->prefix, attr->ns )) continue;
1203 if ((hr = add_namespace_attribute( writer, attr->prefix, attr->ns, FALSE )) != S_OK) return hr;
1206 return S_OK;
1209 /**************************************************************************
1210 * WsWriteEndAttribute [webservices.@]
1212 HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error )
1214 struct writer *writer = (struct writer *)handle;
1216 TRACE( "%p %p\n", handle, error );
1217 if (error) FIXME( "ignoring error parameter\n" );
1219 if (!writer) return E_INVALIDARG;
1221 EnterCriticalSection( &writer->cs );
1223 if (writer->magic != WRITER_MAGIC)
1225 LeaveCriticalSection( &writer->cs );
1226 return E_INVALIDARG;
1229 writer->state = WRITER_STATE_STARTELEMENT;
1231 LeaveCriticalSection( &writer->cs );
1232 return S_OK;
1235 static HRESULT write_attributes( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1237 ULONG i;
1238 HRESULT hr;
1239 for (i = 0; i < elem->attributeCount; i++)
1241 if (elem->attributes[i]->isXmlNs) continue;
1242 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1244 for (i = 0; i < elem->attributeCount; i++)
1246 if (!elem->attributes[i]->isXmlNs || !elem->attributes[i]->prefix) continue;
1247 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1249 for (i = 0; i < elem->attributeCount; i++)
1251 if (!elem->attributes[i]->isXmlNs || elem->attributes[i]->prefix) continue;
1252 if ((hr = write_namespace_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
1254 return S_OK;
1257 static HRESULT write_startelement_text( struct writer *writer )
1259 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1260 ULONG size;
1261 HRESULT hr;
1263 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1265 size = elem->localName->length + 1 /* '<' */;
1266 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1267 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1269 write_char( writer, '<' );
1270 if (elem->prefix && elem->prefix->length)
1272 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1273 write_char( writer, ':' );
1275 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1276 return write_attributes( writer, elem );
1279 static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, BOOL use_dict )
1281 if (!elem->prefix || !elem->prefix->length)
1283 if (use_dict) return RECORD_SHORT_DICTIONARY_ELEMENT;
1284 return RECORD_SHORT_ELEMENT;
1286 if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
1288 if (use_dict) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1289 return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
1291 if (use_dict) return RECORD_DICTIONARY_ELEMENT;
1292 return RECORD_ELEMENT;
1295 static HRESULT write_startelement_bin( struct writer *writer )
1297 const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1298 ULONG id;
1299 enum record_type type = get_elem_record_type( elem, lookup_string_id(writer, elem->localName, &id) );
1300 HRESULT hr;
1302 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1303 write_char( writer, type );
1305 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1307 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1308 return write_attributes( writer, elem );
1310 if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1312 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1313 return write_attributes( writer, elem );
1316 switch (type)
1318 case RECORD_SHORT_ELEMENT:
1319 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1320 break;
1322 case RECORD_ELEMENT:
1323 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1324 if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
1325 break;
1327 case RECORD_SHORT_DICTIONARY_ELEMENT:
1328 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1329 break;
1331 case RECORD_DICTIONARY_ELEMENT:
1332 if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
1333 if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
1334 break;
1336 default:
1337 ERR( "unhandled record type %02x\n", type );
1338 return WS_E_NOT_SUPPORTED;
1341 return write_attributes( writer, elem );
1344 static HRESULT write_startelement( struct writer *writer )
1346 switch (writer->output_enc)
1348 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_startelement_text( writer );
1349 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_startelement_bin( writer );
1350 default:
1351 ERR( "unhandled encoding %u\n", writer->output_enc );
1352 return WS_E_NOT_SUPPORTED;
1356 static struct node *write_find_startelement( struct writer *writer )
1358 struct node *node;
1359 for (node = writer->current; node; node = node->parent)
1361 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT) return node;
1363 return NULL;
1366 static inline BOOL is_empty_element( const struct node *node )
1368 const struct node *head = LIST_ENTRY( list_head( &node->children ), struct node, entry );
1369 return node_type( head ) == WS_XML_NODE_TYPE_END_ELEMENT;
1372 static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1374 ULONG size;
1375 HRESULT hr;
1377 /* '/>' */
1379 if (elem->isEmpty && writer->state != WRITER_STATE_ENDSTARTELEMENT)
1381 if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
1382 write_char( writer, '/' );
1383 write_char( writer, '>' );
1384 return S_OK;
1387 /* '</prefix:localname>' */
1389 size = elem->localName->length + 3 /* '</>' */;
1390 if (elem->prefix && elem->prefix->length) size += elem->prefix->length + 1 /* ':' */;
1391 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
1393 write_char( writer, '<' );
1394 write_char( writer, '/' );
1395 if (elem->prefix && elem->prefix->length)
1397 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
1398 write_char( writer, ':' );
1400 write_bytes( writer, elem->localName->bytes, elem->localName->length );
1401 write_char( writer, '>' );
1402 return S_OK;
1405 static HRESULT write_endelement_bin( struct writer *writer )
1407 HRESULT hr;
1408 if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
1409 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1410 write_char( writer, RECORD_ENDELEMENT );
1411 return S_OK;
1414 static HRESULT write_endelement( struct writer *writer, const WS_XML_ELEMENT_NODE *elem )
1416 switch (writer->output_enc)
1418 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endelement_text( writer, elem );
1419 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_endelement_bin( writer );
1420 default:
1421 ERR( "unhandled encoding %u\n", writer->output_enc );
1422 return WS_E_NOT_SUPPORTED;
1426 static HRESULT write_close_element( struct writer *writer, struct node *node )
1428 WS_XML_ELEMENT_NODE *elem = &node->hdr;
1429 elem->isEmpty = is_empty_element( node );
1430 return write_endelement( writer, elem );
1433 static HRESULT write_endelement_node( struct writer *writer )
1435 struct node *node;
1436 HRESULT hr;
1438 if (!(node = write_find_startelement( writer ))) return WS_E_INVALID_FORMAT;
1439 if (writer->state == WRITER_STATE_STARTELEMENT)
1441 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1442 if ((hr = write_startelement( writer )) != S_OK) return hr;
1444 if ((hr = write_close_element( writer, node )) != S_OK) return hr;
1445 writer->current = node->parent;
1446 writer->state = WRITER_STATE_ENDELEMENT;
1447 return S_OK;
1450 /**************************************************************************
1451 * WsWriteEndElement [webservices.@]
1453 HRESULT WINAPI WsWriteEndElement( WS_XML_WRITER *handle, WS_ERROR *error )
1455 struct writer *writer = (struct writer *)handle;
1456 HRESULT hr;
1458 TRACE( "%p %p\n", handle, error );
1459 if (error) FIXME( "ignoring error parameter\n" );
1461 if (!writer) return E_INVALIDARG;
1463 EnterCriticalSection( &writer->cs );
1465 if (writer->magic != WRITER_MAGIC)
1467 LeaveCriticalSection( &writer->cs );
1468 return E_INVALIDARG;
1471 hr = write_endelement_node( writer );
1473 LeaveCriticalSection( &writer->cs );
1474 return hr;
1477 static HRESULT write_endstartelement_text( struct writer *writer )
1479 HRESULT hr;
1480 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
1481 write_char( writer, '>' );
1482 return S_OK;
1485 static HRESULT write_endstartelement( struct writer *writer )
1487 switch (writer->output_enc)
1489 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_endstartelement_text( writer );
1490 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return S_OK;
1491 default:
1492 ERR( "unhandled encoding %u\n", writer->output_enc );
1493 return WS_E_NOT_SUPPORTED;
1497 /**************************************************************************
1498 * WsWriteEndStartElement [webservices.@]
1500 HRESULT WINAPI WsWriteEndStartElement( WS_XML_WRITER *handle, WS_ERROR *error )
1502 struct writer *writer = (struct writer *)handle;
1503 HRESULT hr;
1505 TRACE( "%p %p\n", handle, error );
1506 if (error) FIXME( "ignoring error parameter\n" );
1508 if (!writer) return E_INVALIDARG;
1510 EnterCriticalSection( &writer->cs );
1512 if (writer->magic != WRITER_MAGIC)
1514 LeaveCriticalSection( &writer->cs );
1515 return E_INVALIDARG;
1518 if (writer->state != WRITER_STATE_STARTELEMENT)
1520 LeaveCriticalSection( &writer->cs );
1521 return WS_E_INVALID_OPERATION;
1524 if ((hr = set_namespaces( writer )) != S_OK) goto done;
1525 if ((hr = write_startelement( writer )) != S_OK) goto done;
1526 if ((hr = write_endstartelement( writer )) != S_OK) goto done;
1527 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1529 done:
1530 LeaveCriticalSection( &writer->cs );
1531 return hr;
1534 static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *prefix,
1535 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1536 BOOL single )
1538 WS_XML_ATTRIBUTE *attr;
1539 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
1540 HRESULT hr;
1542 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1544 if (!prefix && ns->length) prefix = elem->prefix;
1546 attr->singleQuote = !!single;
1547 if (prefix && !(attr->prefix = dup_xml_string( prefix )))
1549 free_attribute( attr );
1550 return E_OUTOFMEMORY;
1552 if (!(attr->localName = dup_xml_string( localname )))
1554 free_attribute( attr );
1555 return E_OUTOFMEMORY;
1557 if (!(attr->ns = dup_xml_string( ns )))
1559 free_attribute( attr );
1560 return E_OUTOFMEMORY;
1562 if ((hr = append_attribute( elem, attr )) != S_OK)
1564 free_attribute( attr );
1565 return hr;
1567 return S_OK;
1570 /**************************************************************************
1571 * WsWriteStartAttribute [webservices.@]
1573 HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1574 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1575 BOOL single, WS_ERROR *error )
1577 struct writer *writer = (struct writer *)handle;
1578 HRESULT hr;
1580 TRACE( "%p %s %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1581 debugstr_xmlstr(ns), single, error );
1582 if (error) FIXME( "ignoring error parameter\n" );
1584 if (!writer || !localname || !ns) return E_INVALIDARG;
1586 EnterCriticalSection( &writer->cs );
1588 if (writer->magic != WRITER_MAGIC)
1590 LeaveCriticalSection( &writer->cs );
1591 return E_INVALIDARG;
1594 if (writer->state != WRITER_STATE_STARTELEMENT)
1596 LeaveCriticalSection( &writer->cs );
1597 return WS_E_INVALID_OPERATION;
1600 if ((hr = write_add_attribute( writer, prefix, localname, ns, single )) == S_OK)
1601 writer->state = WRITER_STATE_STARTATTRIBUTE;
1603 LeaveCriticalSection( &writer->cs );
1604 return hr;
1607 /* flush current start element if necessary */
1608 static HRESULT write_flush( struct writer *writer )
1610 if (writer->state == WRITER_STATE_STARTELEMENT)
1612 HRESULT hr;
1613 if ((hr = set_namespaces( writer )) != S_OK) return hr;
1614 if ((hr = write_startelement( writer )) != S_OK) return hr;
1615 if ((hr = write_endstartelement( writer )) != S_OK) return hr;
1616 writer->state = WRITER_STATE_ENDSTARTELEMENT;
1618 return S_OK;
1621 static HRESULT write_add_cdata_node( struct writer *writer )
1623 struct node *node, *parent;
1624 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1625 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1626 write_insert_node( writer, parent, node );
1627 return S_OK;
1630 static HRESULT write_add_endcdata_node( struct writer *writer )
1632 struct node *node;
1633 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_CDATA ))) return E_OUTOFMEMORY;
1634 node->parent = writer->current;
1635 list_add_tail( &node->parent->children, &node->entry );
1636 return S_OK;
1639 static HRESULT write_cdata( struct writer *writer )
1641 HRESULT hr;
1642 if ((hr = write_grow_buffer( writer, 9 )) != S_OK) return hr;
1643 write_bytes( writer, (const BYTE *)"<![CDATA[", 9 );
1644 return S_OK;
1647 static HRESULT write_cdata_node( struct writer *writer )
1649 HRESULT hr;
1650 if ((hr = write_flush( writer )) != S_OK) return hr;
1651 if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
1652 if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
1653 if ((hr = write_cdata( writer )) != S_OK) return hr;
1654 writer->state = WRITER_STATE_STARTCDATA;
1655 return S_OK;
1658 /**************************************************************************
1659 * WsWriteStartCData [webservices.@]
1661 HRESULT WINAPI WsWriteStartCData( WS_XML_WRITER *handle, WS_ERROR *error )
1663 struct writer *writer = (struct writer *)handle;
1664 HRESULT hr;
1666 TRACE( "%p %p\n", handle, error );
1667 if (error) FIXME( "ignoring error parameter\n" );
1669 if (!writer) return E_INVALIDARG;
1671 EnterCriticalSection( &writer->cs );
1673 if (writer->magic != WRITER_MAGIC)
1675 LeaveCriticalSection( &writer->cs );
1676 return E_INVALIDARG;
1679 hr = write_cdata_node( writer );
1681 LeaveCriticalSection( &writer->cs );
1682 return hr;
1685 static HRESULT write_endcdata( struct writer *writer )
1687 HRESULT hr;
1688 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
1689 write_bytes( writer, (const BYTE *)"]]>", 3 );
1690 return S_OK;
1693 static HRESULT write_endcdata_node( struct writer *writer )
1695 HRESULT hr;
1696 if ((hr = write_endcdata( writer )) != S_OK) return hr;
1697 writer->current = writer->current->parent;
1698 writer->state = WRITER_STATE_ENDCDATA;
1699 return S_OK;
1702 /**************************************************************************
1703 * WsWriteEndCData [webservices.@]
1705 HRESULT WINAPI WsWriteEndCData( WS_XML_WRITER *handle, WS_ERROR *error )
1707 struct writer *writer = (struct writer *)handle;
1708 HRESULT hr;
1710 TRACE( "%p %p\n", handle, error );
1711 if (error) FIXME( "ignoring error parameter\n" );
1713 if (!writer) return E_INVALIDARG;
1715 EnterCriticalSection( &writer->cs );
1717 if (writer->magic != WRITER_MAGIC)
1719 LeaveCriticalSection( &writer->cs );
1720 return E_INVALIDARG;
1723 if (writer->state != WRITER_STATE_TEXT)
1725 LeaveCriticalSection( &writer->cs );
1726 return WS_E_INVALID_OPERATION;
1729 hr = write_endcdata_node( writer );
1731 LeaveCriticalSection( &writer->cs );
1732 return hr;
1735 static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1736 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1738 struct node *node, *parent;
1739 WS_XML_ELEMENT_NODE *elem;
1741 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
1743 if (!prefix && node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1745 elem = &parent->hdr;
1746 if (WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) prefix = elem->prefix;
1749 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
1750 elem = &node->hdr;
1752 if (prefix && !(elem->prefix = dup_xml_string( prefix )))
1754 free_node( node );
1755 return E_OUTOFMEMORY;
1757 if (!(elem->localName = dup_xml_string( localname )))
1759 free_node( node );
1760 return E_OUTOFMEMORY;
1762 if (!(elem->ns = dup_xml_string( ns )))
1764 free_node( node );
1765 return E_OUTOFMEMORY;
1767 write_insert_node( writer, parent, node );
1768 return S_OK;
1771 static HRESULT write_add_endelement_node( struct writer *writer, struct node *parent )
1773 struct node *node;
1774 if (!(node = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) return E_OUTOFMEMORY;
1775 node->parent = parent;
1776 list_add_tail( &parent->children, &node->entry );
1777 return S_OK;
1780 static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *prefix,
1781 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
1783 HRESULT hr;
1784 if ((hr = write_flush( writer )) != S_OK) return hr;
1785 if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
1786 if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
1787 writer->state = WRITER_STATE_STARTELEMENT;
1788 return S_OK;
1791 /**************************************************************************
1792 * WsWriteStartElement [webservices.@]
1794 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
1795 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
1796 WS_ERROR *error )
1798 struct writer *writer = (struct writer *)handle;
1799 HRESULT hr;
1801 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
1802 debugstr_xmlstr(ns), error );
1803 if (error) FIXME( "ignoring error parameter\n" );
1805 if (!writer || !localname || !ns) return E_INVALIDARG;
1807 EnterCriticalSection( &writer->cs );
1809 if (writer->magic != WRITER_MAGIC)
1811 LeaveCriticalSection( &writer->cs );
1812 return E_INVALIDARG;
1815 hr = write_element_node( writer, prefix, localname, ns );
1817 LeaveCriticalSection( &writer->cs );
1818 return hr;
1821 static ULONG format_bool( const BOOL *ptr, unsigned char *buf )
1823 static const unsigned char bool_true[] = {'t','r','u','e'}, bool_false[] = {'f','a','l','s','e'};
1824 if (*ptr)
1826 memcpy( buf, bool_true, sizeof(bool_true) );
1827 return sizeof(bool_true);
1829 memcpy( buf, bool_false, sizeof(bool_false) );
1830 return sizeof(bool_false);
1833 static ULONG format_int32( const INT32 *ptr, unsigned char *buf )
1835 return wsprintfA( (char *)buf, "%d", *ptr );
1838 static ULONG format_int64( const INT64 *ptr, unsigned char *buf )
1840 return wsprintfA( (char *)buf, "%I64d", *ptr );
1843 static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
1845 return wsprintfA( (char *)buf, "%I64u", *ptr );
1848 static ULONG format_double( const double *ptr, unsigned char *buf )
1850 #ifdef HAVE_POWL
1851 static const long double precision = 0.0000000000000001;
1852 unsigned char *p = buf;
1853 long double val = *ptr;
1854 int neg, mag, mag2, use_exp;
1856 if (isnan( val ))
1858 memcpy( buf, "NaN", 3 );
1859 return 3;
1861 if (isinf( val ))
1863 if (val < 0)
1865 memcpy( buf, "-INF", 4 );
1866 return 4;
1868 memcpy( buf, "INF", 3 );
1869 return 3;
1871 if (val == 0.0)
1873 *p = '0';
1874 return 1;
1877 if ((neg = val < 0))
1879 *p++ = '-';
1880 val = -val;
1883 mag = log10l( val );
1884 use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1);
1885 if (use_exp)
1887 if (mag < 0) mag -= 1;
1888 val = val / powl( 10.0, mag );
1889 mag2 = mag;
1890 mag = 0;
1892 else if (mag < 1) mag = 0;
1894 while (val > precision || mag >= 0)
1896 long double weight = powl( 10.0, mag );
1897 if (weight > 0 && !isinf( weight ))
1899 int digit = floorl( val / weight );
1900 val -= digit * weight;
1901 *(p++) = '0' + digit;
1903 if (!mag && val > precision) *(p++) = '.';
1904 mag--;
1907 if (use_exp)
1909 int i, j;
1910 *(p++) = 'E';
1911 if (mag2 > 0) *(p++) = '+';
1912 else
1914 *(p++) = '-';
1915 mag2 = -mag2;
1917 mag = 0;
1918 while (mag2 > 0)
1920 *(p++) = '0' + mag2 % 10;
1921 mag2 /= 10;
1922 mag++;
1924 for (i = -mag, j = -1; i < j; i++, j--)
1926 p[i] ^= p[j];
1927 p[j] ^= p[i];
1928 p[i] ^= p[j];
1932 return p - buf;
1933 #else
1934 FIXME( "powl not found at build time\n" );
1935 return 0;
1936 #endif
1939 static inline int year_size( int year )
1941 return leap_year( year ) ? 366 : 365;
1944 #define TZ_OFFSET 8
1945 static ULONG format_datetime( const WS_DATETIME *ptr, unsigned char *buf )
1947 static const char fmt[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1948 int day, hour, min, sec, sec_frac, month = 0, year = 1, tz_hour;
1949 unsigned __int64 ticks, day_ticks;
1950 ULONG len;
1952 if (ptr->format == WS_DATETIME_FORMAT_LOCAL &&
1953 ptr->ticks >= TICKS_1601_01_01 + TZ_OFFSET * TICKS_PER_HOUR)
1955 ticks = ptr->ticks - TZ_OFFSET * TICKS_PER_HOUR;
1956 tz_hour = TZ_OFFSET;
1958 else
1960 ticks = ptr->ticks;
1961 tz_hour = 0;
1963 day = ticks / TICKS_PER_DAY;
1964 day_ticks = ticks % TICKS_PER_DAY;
1965 hour = day_ticks / TICKS_PER_HOUR;
1966 min = (day_ticks % TICKS_PER_HOUR) / TICKS_PER_MIN;
1967 sec = (day_ticks % TICKS_PER_MIN) / TICKS_PER_SEC;
1968 sec_frac = day_ticks % TICKS_PER_SEC;
1970 while (day >= year_size( year ))
1972 day -= year_size( year );
1973 year++;
1975 while (day >= month_days[leap_year( year )][month])
1977 day -= month_days[leap_year( year )][month];
1978 month++;
1981 len = sprintf( (char *)buf, fmt, year, month + 1, day + 1, hour, min, sec );
1982 if (sec_frac)
1984 static const char fmt_frac[] = ".%07u";
1985 len += sprintf( (char *)buf + len, fmt_frac, sec_frac );
1986 while (buf[len - 1] == '0') len--;
1988 if (ptr->format == WS_DATETIME_FORMAT_UTC)
1990 buf[len++] = 'Z';
1992 else if (ptr->format == WS_DATETIME_FORMAT_LOCAL)
1994 static const char fmt_tz[] = "%c%02u:00";
1995 len += sprintf( (char *)buf + len, fmt_tz, tz_hour ? '-' : '+', tz_hour );
1998 return len;
2001 static ULONG format_guid( const GUID *ptr, unsigned char *buf )
2003 static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
2004 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
2005 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
2006 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
2009 static ULONG format_urn( const GUID *ptr, unsigned char *buf )
2011 static const char fmt[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
2012 return sprintf( (char *)buf, fmt, ptr->Data1, ptr->Data2, ptr->Data3,
2013 ptr->Data4[0], ptr->Data4[1], ptr->Data4[2], ptr->Data4[3],
2014 ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] );
2017 static ULONG format_qname( const WS_XML_STRING *prefix, const WS_XML_STRING *localname, unsigned char *buf )
2019 ULONG len = 0;
2020 if (prefix && prefix->length)
2022 memcpy( buf, prefix->bytes, prefix->length );
2023 len += prefix->length;
2024 buf[len++] = ':';
2026 memcpy( buf + len, localname->bytes, localname->length );
2027 return len + localname->length;
2030 static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf )
2032 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2033 ULONG i = 0, x;
2035 while (len > 0)
2037 buf[i++] = base64[(bin[0] & 0xfc) >> 2];
2038 x = (bin[0] & 3) << 4;
2039 if (len == 1)
2041 buf[i++] = base64[x];
2042 buf[i++] = '=';
2043 buf[i++] = '=';
2044 break;
2046 buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)];
2047 x = (bin[1] & 0x0f) << 2;
2048 if (len == 2)
2050 buf[i++] = base64[x];
2051 buf[i++] = '=';
2052 break;
2054 buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)];
2055 buf[i++] = base64[bin[2] & 0x3f];
2056 bin += 3;
2057 len -= 3;
2059 return i;
2062 static HRESULT text_to_utf8text( const WS_XML_TEXT *text, const WS_XML_UTF8_TEXT *old, ULONG *offset,
2063 WS_XML_UTF8_TEXT **ret )
2065 ULONG len_old = old ? old->value.length : 0;
2066 if (offset) *offset = len_old;
2068 switch (text->textType)
2070 case WS_XML_TEXT_TYPE_UTF8:
2072 const WS_XML_UTF8_TEXT *src = (const WS_XML_UTF8_TEXT *)text;
2074 if (!(*ret = alloc_utf8_text( NULL, len_old + src->value.length ))) return E_OUTOFMEMORY;
2075 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2076 memcpy( (*ret)->value.bytes + len_old, src->value.bytes, src->value.length );
2077 return S_OK;
2079 case WS_XML_TEXT_TYPE_UTF16:
2081 const WS_XML_UTF16_TEXT *src = (const WS_XML_UTF16_TEXT *)text;
2082 const WCHAR *str = (const WCHAR *)src->bytes;
2083 ULONG len = src->byteCount / sizeof(WCHAR), len_utf8;
2085 if (src->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2086 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2087 if (!(*ret = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2088 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2089 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes + len_old, len_utf8, NULL, NULL );
2090 return S_OK;
2092 case WS_XML_TEXT_TYPE_BASE64:
2094 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2095 ULONG len = ((4 * base64->length / 3) + 3) & ~3;
2097 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2098 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2099 (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes + len_old ) + len_old;
2100 return S_OK;
2102 case WS_XML_TEXT_TYPE_BOOL:
2104 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2106 if (!(*ret = alloc_utf8_text( NULL, len_old + 5 ))) return E_OUTOFMEMORY;
2107 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2108 (*ret)->value.length = format_bool( &bool_text->value, (*ret)->value.bytes + len_old ) + len_old;
2109 return S_OK;
2111 case WS_XML_TEXT_TYPE_INT32:
2113 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2114 unsigned char buf[12]; /* "-2147483648" */
2115 ULONG len = format_int32( &int32_text->value, buf );
2117 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2118 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2119 memcpy( (*ret)->value.bytes + len_old, buf, len );
2120 return S_OK;
2122 case WS_XML_TEXT_TYPE_INT64:
2124 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2125 unsigned char buf[21]; /* "-9223372036854775808" */
2126 ULONG len = format_int64( &int64_text->value, buf );
2128 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2129 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2130 memcpy( (*ret)->value.bytes + len_old, buf, len );
2131 return S_OK;
2133 case WS_XML_TEXT_TYPE_UINT64:
2135 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2136 unsigned char buf[21]; /* "18446744073709551615" */
2137 ULONG len = format_uint64( &uint64_text->value, buf );
2139 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2140 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2141 memcpy( (*ret)->value.bytes + len_old, buf, len );
2142 return S_OK;
2144 case WS_XML_TEXT_TYPE_DOUBLE:
2146 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2147 unsigned char buf[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
2148 unsigned short fpword;
2149 ULONG len;
2151 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
2152 len = format_double( &double_text->value, buf );
2153 restore_fpword( fpword );
2154 if (!len) return E_NOTIMPL;
2156 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2157 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2158 memcpy( (*ret)->value.bytes + len_old, buf, len );
2159 return S_OK;
2161 case WS_XML_TEXT_TYPE_GUID:
2163 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2165 if (!(*ret = alloc_utf8_text( NULL, len_old + 37 ))) return E_OUTOFMEMORY;
2166 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2167 (*ret)->value.length = format_guid( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2168 return S_OK;
2170 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2172 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2174 if (!(*ret = alloc_utf8_text( NULL, len_old + 46 ))) return E_OUTOFMEMORY;
2175 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2176 (*ret)->value.length = format_urn( &id->value, (*ret)->value.bytes + len_old ) + len_old;
2177 return S_OK;
2179 case WS_XML_TEXT_TYPE_DATETIME:
2181 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2183 if (!(*ret = alloc_utf8_text( NULL, len_old + 34 ))) return E_OUTOFMEMORY;
2184 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2185 (*ret)->value.length = format_datetime( &dt->value, (*ret)->value.bytes + len_old ) + len_old;
2186 return S_OK;
2188 case WS_XML_TEXT_TYPE_QNAME:
2190 const WS_XML_QNAME_TEXT *qn = (const WS_XML_QNAME_TEXT *)text;
2191 ULONG len = qn->localName->length;
2193 if (qn->prefix && qn->prefix->length) len += qn->prefix->length + 1;
2194 if (!(*ret = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2195 if (old) memcpy( (*ret)->value.bytes, old->value.bytes, len_old );
2196 (*ret)->value.length = format_qname( qn->prefix, qn->localName, (*ret)->value.bytes + len_old ) + len_old;
2197 return S_OK;
2199 default:
2200 FIXME( "unhandled text type %u\n", text->textType );
2201 return E_NOTIMPL;
2205 static HRESULT text_to_text( const WS_XML_TEXT *text, const WS_XML_TEXT *old, ULONG *offset, WS_XML_TEXT **ret )
2207 if (offset) *offset = 0;
2208 switch (text->textType)
2210 case WS_XML_TEXT_TYPE_UTF8:
2212 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2213 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2214 WS_XML_UTF8_TEXT *new;
2215 ULONG len = utf8->value.length, len_old = utf8_old ? utf8_old->value.length : 0;
2217 if (!(new = alloc_utf8_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2218 if (utf8_old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2219 memcpy( new->value.bytes + len_old, utf8->value.bytes, len );
2220 if (offset) *offset = len_old;
2221 *ret = &new->text;
2222 return S_OK;
2224 case WS_XML_TEXT_TYPE_UTF16:
2226 const WS_XML_UTF16_TEXT *utf16 = (const WS_XML_UTF16_TEXT *)text;
2227 const WS_XML_UTF8_TEXT *utf8_old = (const WS_XML_UTF8_TEXT *)old;
2228 WS_XML_UTF8_TEXT *new;
2229 const WCHAR *str = (const WCHAR *)utf16->bytes;
2230 ULONG len = utf16->byteCount / sizeof(WCHAR), len_utf8, len_old = utf8_old ? utf8_old->value.length : 0;
2232 if (utf16->byteCount % sizeof(WCHAR)) return E_INVALIDARG;
2233 len_utf8 = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
2234 if (!(new = alloc_utf8_text( NULL, len_old + len_utf8 ))) return E_OUTOFMEMORY;
2235 if (old) memcpy( new->value.bytes, utf8_old->value.bytes, len_old );
2236 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)new->value.bytes + len_old, len_utf8, NULL, NULL );
2237 if (offset) *offset = len_old;
2238 *ret = &new->text;
2239 return S_OK;
2241 case WS_XML_TEXT_TYPE_BASE64:
2243 const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text;
2244 const WS_XML_BASE64_TEXT *base64_old = (const WS_XML_BASE64_TEXT *)old;
2245 WS_XML_BASE64_TEXT *new;
2246 ULONG len = base64->length, len_old = base64_old ? base64_old->length : 0;
2248 if (!(new = alloc_base64_text( NULL, len_old + len ))) return E_OUTOFMEMORY;
2249 if (base64_old) memcpy( new->bytes, base64_old->bytes, len_old );
2250 memcpy( new->bytes + len_old, base64->bytes, len );
2251 if (offset) *offset = len_old;
2252 *ret = &new->text;
2253 return S_OK;
2255 case WS_XML_TEXT_TYPE_BOOL:
2257 const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text;
2258 WS_XML_BOOL_TEXT *new;
2260 if (!(new = alloc_bool_text( bool_text->value ))) return E_OUTOFMEMORY;
2261 *ret = &new->text;
2262 return S_OK;
2264 case WS_XML_TEXT_TYPE_INT32:
2266 const WS_XML_INT32_TEXT *int32_text = (const WS_XML_INT32_TEXT *)text;
2267 WS_XML_INT32_TEXT *new;
2269 if (!(new = alloc_int32_text( int32_text->value ))) return E_OUTOFMEMORY;
2270 *ret = &new->text;
2271 return S_OK;
2273 case WS_XML_TEXT_TYPE_INT64:
2275 const WS_XML_INT64_TEXT *int64_text = (const WS_XML_INT64_TEXT *)text;
2276 WS_XML_INT64_TEXT *new;
2278 if (!(new = alloc_int64_text( int64_text->value ))) return E_OUTOFMEMORY;
2279 *ret = &new->text;
2280 return S_OK;
2282 case WS_XML_TEXT_TYPE_UINT64:
2284 const WS_XML_UINT64_TEXT *uint64_text = (const WS_XML_UINT64_TEXT *)text;
2285 WS_XML_UINT64_TEXT *new;
2287 if (!(new = alloc_uint64_text( uint64_text->value ))) return E_OUTOFMEMORY;
2288 *ret = &new->text;
2289 return S_OK;
2291 case WS_XML_TEXT_TYPE_DOUBLE:
2293 const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text;
2294 WS_XML_DOUBLE_TEXT *new;
2296 if (!(new = alloc_double_text( double_text->value ))) return E_OUTOFMEMORY;
2297 *ret = &new->text;
2298 return S_OK;
2300 case WS_XML_TEXT_TYPE_GUID:
2302 const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
2303 WS_XML_GUID_TEXT *new;
2305 if (!(new = alloc_guid_text( &id->value ))) return E_OUTOFMEMORY;
2306 *ret = &new->text;
2307 return S_OK;
2309 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2311 const WS_XML_UNIQUE_ID_TEXT *id = (const WS_XML_UNIQUE_ID_TEXT *)text;
2312 WS_XML_UNIQUE_ID_TEXT *new;
2314 if (!(new = alloc_unique_id_text( &id->value ))) return E_OUTOFMEMORY;
2315 *ret = &new->text;
2316 return S_OK;
2318 case WS_XML_TEXT_TYPE_DATETIME:
2320 const WS_XML_DATETIME_TEXT *dt = (const WS_XML_DATETIME_TEXT *)text;
2321 WS_XML_DATETIME_TEXT *new;
2323 if (!(new = alloc_datetime_text( &dt->value ))) return E_OUTOFMEMORY;
2324 *ret = &new->text;
2325 return S_OK;
2327 default:
2328 FIXME( "unhandled text type %u\n", text->textType );
2329 return E_NOTIMPL;
2333 static HRESULT write_set_attribute_value( struct writer *writer, const WS_XML_TEXT *value )
2335 WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
2336 HRESULT hr;
2338 switch (value->textType)
2340 case WS_XML_TEXT_TYPE_UTF8:
2341 case WS_XML_TEXT_TYPE_UTF16:
2342 case WS_XML_TEXT_TYPE_BASE64:
2343 break;
2345 case WS_XML_TEXT_TYPE_BOOL:
2346 case WS_XML_TEXT_TYPE_INT32:
2347 case WS_XML_TEXT_TYPE_INT64:
2348 case WS_XML_TEXT_TYPE_UINT64:
2349 case WS_XML_TEXT_TYPE_DOUBLE:
2350 case WS_XML_TEXT_TYPE_GUID:
2351 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2352 case WS_XML_TEXT_TYPE_DATETIME:
2353 if (elem->attributes[elem->attributeCount - 1]->value) return WS_E_INVALID_OPERATION;
2354 break;
2356 default:
2357 FIXME( "unhandled text type %u\n", value->textType );
2358 return E_NOTIMPL;
2361 switch (writer->output_enc)
2363 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2365 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)elem->attributes[elem->attributeCount - 1]->value;
2366 if ((hr = text_to_utf8text( value, old, NULL, &new )) != S_OK) return hr;
2367 heap_free( old );
2368 elem->attributes[elem->attributeCount - 1]->value = &new->text;
2369 break;
2371 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2373 WS_XML_TEXT *new, *old = elem->attributes[elem->attributeCount - 1]->value;
2374 if ((hr = text_to_text( value, old, NULL, &new )) != S_OK) return hr;
2375 heap_free( old );
2376 elem->attributes[elem->attributeCount - 1]->value = new;
2377 break;
2379 default:
2380 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2381 return E_NOTIMPL;
2384 return S_OK;
2387 static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *value )
2389 struct node *node;
2390 WS_XML_TEXT_NODE *text;
2391 HRESULT hr;
2393 if (node_type( writer->current ) != WS_XML_NODE_TYPE_ELEMENT &&
2394 node_type( writer->current ) != WS_XML_NODE_TYPE_BOF &&
2395 node_type( writer->current ) != WS_XML_NODE_TYPE_CDATA) return WS_E_INVALID_FORMAT;
2397 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2398 text = (WS_XML_TEXT_NODE *)node;
2400 switch (writer->output_enc)
2402 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2404 WS_XML_UTF8_TEXT *new;
2405 if ((hr = text_to_utf8text( value, NULL, NULL, &new )) != S_OK)
2407 heap_free( node );
2408 return hr;
2410 text->text = &new->text;
2411 break;
2413 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2415 WS_XML_TEXT *new;
2416 if ((hr = text_to_text( value, NULL, NULL, &new )) != S_OK)
2418 heap_free( node );
2419 return hr;
2421 text->text = new;
2422 break;
2424 default:
2425 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2426 heap_free( node );
2427 return E_NOTIMPL;
2430 write_insert_node( writer, writer->current, node );
2431 return S_OK;
2434 static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2436 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2437 HRESULT hr;
2439 if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
2441 const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
2442 return write_bytes_escape( writer, utf8->value.bytes + offset, utf8->value.length - offset, escapes, 3 );
2444 else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
2446 if ((hr = write_grow_buffer( writer, utf8->value.length - offset )) != S_OK) return hr;
2447 write_bytes( writer, utf8->value.bytes + offset, utf8->value.length - offset );
2448 return S_OK;
2451 return WS_E_INVALID_FORMAT;
2454 static enum record_type get_text_record_type( const WS_XML_TEXT *text )
2456 switch (text->textType)
2458 case WS_XML_TEXT_TYPE_UTF8:
2460 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2461 if (text_utf8->value.length <= MAX_UINT8) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
2462 if (text_utf8->value.length <= MAX_UINT16) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT;
2463 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT;
2465 case WS_XML_TEXT_TYPE_BASE64:
2467 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2468 ULONG rem = text_base64->length % 3, len = text_base64->length - rem;
2469 if (len <= MAX_UINT8) return RECORD_BYTES8_TEXT;
2470 if (len <= MAX_UINT16) return RECORD_BYTES16_TEXT;
2471 return RECORD_BYTES32_TEXT;
2473 case WS_XML_TEXT_TYPE_BOOL:
2475 const WS_XML_BOOL_TEXT *text_bool = (const WS_XML_BOOL_TEXT *)text;
2476 return text_bool->value ? RECORD_TRUE_TEXT_WITH_ENDELEMENT : RECORD_FALSE_TEXT_WITH_ENDELEMENT;
2478 case WS_XML_TEXT_TYPE_INT32:
2480 const WS_XML_INT32_TEXT *text_int32 = (const WS_XML_INT32_TEXT *)text;
2481 if (!text_int32->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2482 if (text_int32->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2483 if (text_int32->value >= MIN_INT8 && text_int32->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2484 if (text_int32->value >= MIN_INT16 && text_int32->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2485 return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2487 case WS_XML_TEXT_TYPE_INT64:
2489 const WS_XML_INT64_TEXT *text_int64 = (const WS_XML_INT64_TEXT *)text;
2490 if (!text_int64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2491 if (text_int64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2492 if (text_int64->value >= MIN_INT8 && text_int64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2493 if (text_int64->value >= MIN_INT16 && text_int64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2494 if (text_int64->value >= MIN_INT32 && text_int64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2495 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2497 case WS_XML_TEXT_TYPE_UINT64:
2499 const WS_XML_UINT64_TEXT *text_uint64 = (const WS_XML_UINT64_TEXT *)text;
2500 if (!text_uint64->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2501 if (text_uint64->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2502 if (text_uint64->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2503 if (text_uint64->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2504 if (text_uint64->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2505 if (text_uint64->value <= MAX_INT64) return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2506 return RECORD_UINT64_TEXT_WITH_ENDELEMENT;
2508 case WS_XML_TEXT_TYPE_DOUBLE:
2510 const WS_XML_DOUBLE_TEXT *text_double = (const WS_XML_DOUBLE_TEXT *)text;
2511 if (!text_double->value) return RECORD_ZERO_TEXT_WITH_ENDELEMENT;
2512 if (text_double->value == 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT;
2513 if (isinf( text_double->value ) || (INT64)text_double->value != text_double->value)
2514 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT;
2515 if (text_double->value <= MAX_INT8) return RECORD_INT8_TEXT_WITH_ENDELEMENT;
2516 if (text_double->value <= MAX_INT16) return RECORD_INT16_TEXT_WITH_ENDELEMENT;
2517 if (text_double->value <= MAX_INT32) return RECORD_INT32_TEXT_WITH_ENDELEMENT;
2518 return RECORD_INT64_TEXT_WITH_ENDELEMENT;
2520 case WS_XML_TEXT_TYPE_GUID:
2521 return RECORD_GUID_TEXT_WITH_ENDELEMENT;
2523 case WS_XML_TEXT_TYPE_UNIQUE_ID:
2524 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT;
2526 case WS_XML_TEXT_TYPE_DATETIME:
2527 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT;
2529 default:
2530 FIXME( "unhandled text type %u\n", text->textType );
2531 return 0;
2535 static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2537 enum record_type type = get_text_record_type( text );
2538 HRESULT hr;
2540 if (offset)
2542 FIXME( "no support for appending text in binary mode\n" );
2543 return E_NOTIMPL;
2546 switch (type)
2548 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
2550 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2551 UINT8 len = text_utf8->value.length;
2553 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2554 write_char( writer, type );
2555 write_char( writer, len );
2556 write_bytes( writer, text_utf8->value.bytes, len );
2557 return S_OK;
2559 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT:
2561 const WS_XML_UTF8_TEXT *text_utf8 = (const WS_XML_UTF8_TEXT *)text;
2562 UINT16 len = text_utf8->value.length;
2564 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2565 write_char( writer, type );
2566 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2567 write_bytes( writer, text_utf8->value.bytes, len );
2568 return S_OK;
2570 case RECORD_BYTES8_TEXT:
2572 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2573 UINT8 rem = text_base64->length % 3, len = text_base64->length - rem;
2575 if (len)
2577 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2578 write_char( writer, rem ? RECORD_BYTES8_TEXT : RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2579 write_char( writer, len );
2580 write_bytes( writer, text_base64->bytes, len );
2582 if (rem)
2584 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2585 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2586 write_char( writer, rem );
2587 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2589 return S_OK;
2591 case RECORD_BYTES16_TEXT:
2593 const WS_XML_BASE64_TEXT *text_base64 = (const WS_XML_BASE64_TEXT *)text;
2594 UINT16 rem = text_base64->length % 3, len = text_base64->length - rem;
2596 if (len)
2598 if ((hr = write_grow_buffer( writer, 1 + sizeof(len) + len )) != S_OK) return hr;
2599 write_char( writer, rem ? RECORD_BYTES16_TEXT : RECORD_BYTES16_TEXT_WITH_ENDELEMENT );
2600 write_bytes( writer, (const BYTE *)&len, sizeof(len) );
2601 write_bytes( writer, text_base64->bytes, len );
2603 if (rem)
2605 if ((hr = write_grow_buffer( writer, 3 )) != S_OK) return hr;
2606 write_char( writer, RECORD_BYTES8_TEXT_WITH_ENDELEMENT );
2607 write_char( writer, rem );
2608 write_bytes( writer, (const BYTE *)text_base64->bytes + len, rem );
2610 return S_OK;
2612 case RECORD_ZERO_TEXT_WITH_ENDELEMENT:
2613 case RECORD_ONE_TEXT_WITH_ENDELEMENT:
2614 case RECORD_FALSE_TEXT_WITH_ENDELEMENT:
2615 case RECORD_TRUE_TEXT_WITH_ENDELEMENT:
2617 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
2618 write_char( writer, type );
2619 return S_OK;
2621 case RECORD_INT8_TEXT_WITH_ENDELEMENT:
2623 INT8 val = get_text_value_int( text );
2624 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2625 write_char( writer, type );
2626 write_char( writer, val );
2627 return S_OK;
2629 case RECORD_INT16_TEXT_WITH_ENDELEMENT:
2631 INT16 val = get_text_value_int( text );
2632 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2633 write_char( writer, type );
2634 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2635 return S_OK;
2637 case RECORD_INT32_TEXT_WITH_ENDELEMENT:
2639 INT32 val = get_text_value_int( text );
2640 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2641 write_char( writer, type );
2642 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2643 return S_OK;
2645 case RECORD_INT64_TEXT_WITH_ENDELEMENT:
2647 INT64 val = get_text_value_int( text );
2648 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2649 write_char( writer, type );
2650 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2651 return S_OK;
2653 case RECORD_UINT64_TEXT_WITH_ENDELEMENT:
2655 WS_XML_UINT64_TEXT *text_uint64 = (WS_XML_UINT64_TEXT *)text;
2656 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_uint64->value) )) != S_OK) return hr;
2657 write_char( writer, type );
2658 write_bytes( writer, (const BYTE *)&text_uint64->value, sizeof(text_uint64->value) );
2659 return S_OK;
2661 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT:
2663 WS_XML_DOUBLE_TEXT *text_double = (WS_XML_DOUBLE_TEXT *)text;
2664 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_double->value) )) != S_OK) return hr;
2665 write_char( writer, type );
2666 write_bytes( writer, (const BYTE *)&text_double->value, sizeof(text_double->value) );
2667 return S_OK;
2669 case RECORD_GUID_TEXT_WITH_ENDELEMENT:
2671 WS_XML_GUID_TEXT *text_guid = (WS_XML_GUID_TEXT *)text;
2672 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_guid->value) )) != S_OK) return hr;
2673 write_char( writer, type );
2674 write_bytes( writer, (const BYTE *)&text_guid->value, sizeof(text_guid->value) );
2675 return S_OK;
2677 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT:
2679 WS_XML_UNIQUE_ID_TEXT *text_unique_id = (WS_XML_UNIQUE_ID_TEXT *)text;
2680 if ((hr = write_grow_buffer( writer, 1 + sizeof(text_unique_id->value) )) != S_OK) return hr;
2681 write_char( writer, type );
2682 write_bytes( writer, (const BYTE *)&text_unique_id->value, sizeof(text_unique_id->value) );
2683 return S_OK;
2685 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT:
2687 WS_XML_DATETIME_TEXT *text_datetime = (WS_XML_DATETIME_TEXT *)text;
2688 UINT64 val = text_datetime->value.ticks;
2690 assert( val <= TICKS_MAX );
2691 if (text_datetime->value.format == WS_DATETIME_FORMAT_UTC) val |= (UINT64)1 << 62;
2692 else if (text_datetime->value.format == WS_DATETIME_FORMAT_LOCAL) val |= (UINT64)1 << 63;
2694 if ((hr = write_grow_buffer( writer, 1 + sizeof(val) )) != S_OK) return hr;
2695 write_char( writer, type );
2696 write_bytes( writer, (const BYTE *)&val, sizeof(val) );
2697 return S_OK;
2699 default:
2700 FIXME( "unhandled record type %02x\n", type );
2701 return E_NOTIMPL;
2705 static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
2707 if (!writer->current->parent) return WS_E_INVALID_FORMAT;
2709 switch (writer->output_enc)
2711 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
2712 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
2713 default:
2714 ERR( "unhandled encoding %u\n", writer->output_enc );
2715 return WS_E_NOT_SUPPORTED;
2719 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
2721 WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
2722 ULONG offset = 0;
2723 HRESULT hr;
2725 if ((hr = write_flush( writer )) != S_OK) return hr;
2726 if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
2728 if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
2729 node = (WS_XML_TEXT_NODE *)writer->current;
2731 else
2733 switch (writer->output_enc)
2735 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
2737 WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
2738 offset = old->value.length;
2739 if ((hr = text_to_utf8text( text, old, &offset, &new )) != S_OK) return hr;
2740 heap_free( old );
2741 node->text = &new->text;
2742 break;
2744 case WS_XML_WRITER_ENCODING_TYPE_BINARY:
2746 WS_XML_TEXT *new, *old = node->text;
2747 if ((hr = text_to_text( text, old, &offset, &new )) != S_OK) return hr;
2748 heap_free( old );
2749 node->text = new;
2750 break;
2752 default:
2753 FIXME( "unhandled output encoding %u\n", writer->output_enc );
2754 return E_NOTIMPL;
2758 if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
2760 writer->state = WRITER_STATE_TEXT;
2761 return S_OK;
2764 /**************************************************************************
2765 * WsWriteText [webservices.@]
2767 HRESULT WINAPI WsWriteText( WS_XML_WRITER *handle, const WS_XML_TEXT *text, WS_ERROR *error )
2769 struct writer *writer = (struct writer *)handle;
2770 HRESULT hr;
2772 TRACE( "%p %p %p\n", handle, text, error );
2773 if (error) FIXME( "ignoring error parameter\n" );
2775 if (!writer || !text) return E_INVALIDARG;
2777 EnterCriticalSection( &writer->cs );
2779 if (writer->magic != WRITER_MAGIC)
2781 LeaveCriticalSection( &writer->cs );
2782 return E_INVALIDARG;
2785 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, text );
2786 else hr = write_text_node( writer, text );
2788 LeaveCriticalSection( &writer->cs );
2789 return hr;
2792 /**************************************************************************
2793 * WsWriteBytes [webservices.@]
2795 HRESULT WINAPI WsWriteBytes( WS_XML_WRITER *handle, const void *bytes, ULONG count, WS_ERROR *error )
2797 struct writer *writer = (struct writer *)handle;
2798 WS_XML_BASE64_TEXT base64;
2799 HRESULT hr;
2801 TRACE( "%p %p %u %p\n", handle, bytes, count, error );
2802 if (error) FIXME( "ignoring error parameter\n" );
2804 if (!writer) return E_INVALIDARG;
2806 EnterCriticalSection( &writer->cs );
2808 if (writer->magic != WRITER_MAGIC)
2810 LeaveCriticalSection( &writer->cs );
2811 return E_INVALIDARG;
2814 if (!writer->output_type)
2816 LeaveCriticalSection( &writer->cs );
2817 return WS_E_INVALID_OPERATION;
2820 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
2821 base64.bytes = (BYTE *)bytes;
2822 base64.length = count;
2824 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &base64.text );
2825 else hr = write_text_node( writer, &base64.text );
2827 LeaveCriticalSection( &writer->cs );
2828 return hr;
2831 /**************************************************************************
2832 * WsWriteChars [webservices.@]
2834 HRESULT WINAPI WsWriteChars( WS_XML_WRITER *handle, const WCHAR *chars, ULONG count, WS_ERROR *error )
2836 struct writer *writer = (struct writer *)handle;
2837 WS_XML_UTF16_TEXT utf16;
2838 HRESULT hr;
2840 TRACE( "%p %s %u %p\n", handle, debugstr_wn(chars, count), count, error );
2841 if (error) FIXME( "ignoring error parameter\n" );
2843 if (!writer) return E_INVALIDARG;
2845 EnterCriticalSection( &writer->cs );
2847 if (writer->magic != WRITER_MAGIC)
2849 LeaveCriticalSection( &writer->cs );
2850 return E_INVALIDARG;
2853 if (!writer->output_type)
2855 LeaveCriticalSection( &writer->cs );
2856 return WS_E_INVALID_OPERATION;
2859 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
2860 utf16.bytes = (BYTE *)chars;
2861 utf16.byteCount = count * sizeof(WCHAR);
2863 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf16.text );
2864 else hr = write_text_node( writer, &utf16.text );
2866 LeaveCriticalSection( &writer->cs );
2867 return hr;
2870 /**************************************************************************
2871 * WsWriteCharsUtf8 [webservices.@]
2873 HRESULT WINAPI WsWriteCharsUtf8( WS_XML_WRITER *handle, const BYTE *bytes, ULONG count, WS_ERROR *error )
2875 struct writer *writer = (struct writer *)handle;
2876 WS_XML_UTF8_TEXT utf8;
2877 HRESULT hr;
2879 TRACE( "%p %s %u %p\n", handle, debugstr_an((const char *)bytes, count), count, error );
2880 if (error) FIXME( "ignoring error parameter\n" );
2882 if (!writer) return E_INVALIDARG;
2884 EnterCriticalSection( &writer->cs );
2886 if (writer->magic != WRITER_MAGIC)
2888 LeaveCriticalSection( &writer->cs );
2889 return E_INVALIDARG;
2892 if (!writer->output_type)
2894 LeaveCriticalSection( &writer->cs );
2895 return WS_E_INVALID_OPERATION;
2898 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
2899 utf8.value.bytes = (BYTE *)bytes;
2900 utf8.value.length = count;
2902 if (writer->state == WRITER_STATE_STARTATTRIBUTE) hr = write_set_attribute_value( writer, &utf8.text );
2903 else hr = write_text_node( writer, &utf8.text );
2905 LeaveCriticalSection( &writer->cs );
2906 return hr;
2909 static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_TEXT *text )
2911 switch (mapping)
2913 case WS_ELEMENT_TYPE_MAPPING:
2914 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2915 return write_text_node( writer, text );
2917 case WS_ATTRIBUTE_TYPE_MAPPING:
2918 return write_set_attribute_value( writer, text );
2920 case WS_ANY_ELEMENT_TYPE_MAPPING:
2921 switch (writer->state)
2923 case WRITER_STATE_STARTATTRIBUTE:
2924 return write_set_attribute_value( writer, text );
2926 case WRITER_STATE_STARTELEMENT:
2927 return write_text_node( writer, text );
2929 default:
2930 FIXME( "writer state %u not handled\n", writer->state );
2931 return E_NOTIMPL;
2934 default:
2935 FIXME( "mapping %u not implemented\n", mapping );
2936 return E_NOTIMPL;
2940 static HRESULT write_add_nil_attribute( struct writer *writer )
2942 static const WS_XML_STRING prefix = {1, (BYTE *)"a"};
2943 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
2944 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
2945 static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}};
2946 HRESULT hr;
2948 if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr;
2949 if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr;
2950 return add_namespace_attribute( writer, &prefix, &ns, FALSE );
2953 static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size,
2954 const void **ptr )
2956 switch (option)
2958 case WS_WRITE_REQUIRED_VALUE:
2959 case WS_WRITE_NILLABLE_VALUE:
2960 if (!value || size != expected_size) return E_INVALIDARG;
2961 *ptr = value;
2962 return S_OK;
2964 case WS_WRITE_REQUIRED_POINTER:
2965 if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG;
2966 return S_OK;
2968 case WS_WRITE_NILLABLE_POINTER:
2969 if (size != sizeof(const void *)) return E_INVALIDARG;
2970 *ptr = *(const void **)value;
2971 return S_OK;
2973 default:
2974 return E_INVALIDARG;
2978 static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping,
2979 const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option,
2980 const BOOL *value, ULONG size )
2982 WS_XML_BOOL_TEXT text_bool;
2983 const BOOL *ptr;
2984 HRESULT hr;
2986 if (desc)
2988 FIXME( "description not supported\n" );
2989 return E_NOTIMPL;
2992 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
2993 if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr;
2994 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
2996 text_bool.text.textType = WS_XML_TEXT_TYPE_BOOL;
2997 text_bool.value = *ptr;
2998 return write_type_text( writer, mapping, &text_bool.text );
3001 static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping,
3002 const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3003 const BOOL *value, ULONG size )
3005 WS_XML_INT32_TEXT text_int32;
3006 const INT8 *ptr;
3007 HRESULT hr;
3009 if (desc)
3011 FIXME( "description not supported\n" );
3012 return E_NOTIMPL;
3015 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3016 if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr;
3017 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3019 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3020 text_int32.value = *ptr;
3021 return write_type_text( writer, mapping, &text_int32.text );
3024 static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping,
3025 const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3026 const BOOL *value, ULONG size )
3028 WS_XML_INT32_TEXT text_int32;
3029 const INT16 *ptr;
3030 HRESULT hr;
3032 if (desc)
3034 FIXME( "description not supported\n" );
3035 return E_NOTIMPL;
3038 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3039 if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr;
3040 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3042 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3043 text_int32.value = *ptr;
3044 return write_type_text( writer, mapping, &text_int32.text );
3047 static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping,
3048 const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3049 const void *value, ULONG size )
3051 WS_XML_INT32_TEXT text_int32;
3052 const INT32 *ptr;
3053 HRESULT hr;
3055 if (desc)
3057 FIXME( "description not supported\n" );
3058 return E_NOTIMPL;
3061 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3062 if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr;
3063 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3065 text_int32.text.textType = WS_XML_TEXT_TYPE_INT32;
3066 text_int32.value = *ptr;
3067 return write_type_text( writer, mapping, &text_int32.text );
3070 static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping,
3071 const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3072 const void *value, ULONG size )
3074 WS_XML_INT64_TEXT text_int64;
3075 const INT64 *ptr;
3076 HRESULT hr;
3078 if (desc)
3080 FIXME( "description not supported\n" );
3081 return E_NOTIMPL;
3084 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3085 if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr;
3086 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3088 text_int64.text.textType = WS_XML_TEXT_TYPE_INT64;
3089 text_int64.value = *ptr;
3090 return write_type_text( writer, mapping, &text_int64.text );
3093 static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping,
3094 const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option,
3095 const void *value, ULONG size )
3097 WS_XML_UINT64_TEXT text_uint64;
3098 const UINT8 *ptr;
3099 HRESULT hr;
3101 if (desc)
3103 FIXME( "description not supported\n" );
3104 return E_NOTIMPL;
3107 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3108 if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr;
3109 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3111 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3112 text_uint64.value = *ptr;
3113 return write_type_text( writer, mapping, &text_uint64.text );
3116 static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping,
3117 const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option,
3118 const void *value, ULONG size )
3120 WS_XML_UINT64_TEXT text_uint64;
3121 const UINT16 *ptr;
3122 HRESULT hr;
3124 if (desc)
3126 FIXME( "description not supported\n" );
3127 return E_NOTIMPL;
3130 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3131 if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr;
3132 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3134 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3135 text_uint64.value = *ptr;
3136 return write_type_text( writer, mapping, &text_uint64.text );
3139 static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping,
3140 const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option,
3141 const void *value, ULONG size )
3143 WS_XML_UINT64_TEXT text_uint64;
3144 const UINT32 *ptr;
3145 HRESULT hr;
3147 if (desc)
3149 FIXME( "description not supported\n" );
3150 return E_NOTIMPL;
3153 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3154 if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr;
3155 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3157 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3158 text_uint64.value = *ptr;
3159 return write_type_text( writer, mapping, &text_uint64.text );
3162 static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping,
3163 const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option,
3164 const void *value, ULONG size )
3166 WS_XML_UINT64_TEXT text_uint64;
3167 const UINT64 *ptr;
3168 HRESULT hr;
3170 if (desc)
3172 FIXME( "description not supported\n" );
3173 return E_NOTIMPL;
3176 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3177 if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr;
3178 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3180 text_uint64.text.textType = WS_XML_TEXT_TYPE_UINT64;
3181 text_uint64.value = *ptr;
3182 return write_type_text( writer, mapping, &text_uint64.text );
3185 static HRESULT write_type_double( struct writer *writer, WS_TYPE_MAPPING mapping,
3186 const WS_DOUBLE_DESCRIPTION *desc, WS_WRITE_OPTION option,
3187 const void *value, ULONG size )
3189 WS_XML_DOUBLE_TEXT text_double;
3190 const double *ptr;
3191 HRESULT hr;
3193 if (desc)
3195 FIXME( "description not supported\n" );
3196 return E_NOTIMPL;
3199 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3200 if ((hr = get_value_ptr( option, value, size, sizeof(double), (const void **)&ptr )) != S_OK) return hr;
3201 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3203 text_double.text.textType = WS_XML_TEXT_TYPE_DOUBLE;
3204 text_double.value = *ptr;
3205 return write_type_text( writer, mapping, &text_double.text );
3208 static HRESULT write_type_datetime( struct writer *writer, WS_TYPE_MAPPING mapping,
3209 const WS_DATETIME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3210 const void *value, ULONG size )
3212 WS_XML_DATETIME_TEXT text_datetime;
3213 const WS_DATETIME *ptr;
3214 HRESULT hr;
3216 if (desc)
3218 FIXME( "description not supported\n" );
3219 return E_NOTIMPL;
3222 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3223 if ((hr = get_value_ptr( option, value, size, sizeof(WS_DATETIME), (const void **)&ptr )) != S_OK) return hr;
3224 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3225 if (ptr->ticks > TICKS_MAX || ptr->format > WS_DATETIME_FORMAT_NONE) return WS_E_INVALID_FORMAT;
3227 text_datetime.text.textType = WS_XML_TEXT_TYPE_DATETIME;
3228 text_datetime.value = *ptr;
3229 return write_type_text( writer, mapping, &text_datetime.text );
3232 static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping,
3233 const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3234 const void *value, ULONG size )
3236 WS_XML_GUID_TEXT text_guid;
3237 const GUID *ptr;
3238 HRESULT hr;
3240 if (desc)
3242 FIXME( "description not supported\n" );
3243 return E_NOTIMPL;
3246 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3247 if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr;
3248 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3250 text_guid.text.textType = WS_XML_TEXT_TYPE_GUID;
3251 text_guid.value = *ptr;
3252 return write_type_text( writer, mapping, &text_guid.text );
3255 static HRESULT write_type_unique_id( struct writer *writer, WS_TYPE_MAPPING mapping,
3256 const WS_UNIQUE_ID_DESCRIPTION *desc, WS_WRITE_OPTION option,
3257 const void *value, ULONG size )
3259 WS_XML_UNIQUE_ID_TEXT text_unique_id;
3260 WS_XML_UTF16_TEXT text_utf16;
3261 const WS_UNIQUE_ID *ptr;
3262 HRESULT hr;
3264 if (desc)
3266 FIXME( "description not supported\n" );
3267 return E_NOTIMPL;
3270 if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3271 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3272 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3274 if (ptr->uri.length)
3276 text_utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3277 text_utf16.bytes = (BYTE *)ptr->uri.chars;
3278 text_utf16.byteCount = ptr->uri.length * sizeof(WCHAR);
3279 return write_type_text( writer, mapping, &text_utf16.text );
3282 text_unique_id.text.textType = WS_XML_TEXT_TYPE_UNIQUE_ID;
3283 text_unique_id.value = ptr->guid;
3284 return write_type_text( writer, mapping, &text_unique_id.text );
3287 static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3288 const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3289 const void *value, ULONG size )
3291 WS_XML_UTF16_TEXT utf16;
3292 const WS_STRING *ptr;
3293 HRESULT hr;
3295 if (desc)
3297 FIXME( "description not supported\n" );
3298 return E_NOTIMPL;
3301 if (!option) return E_INVALIDARG;
3302 if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr;
3303 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3304 if (!ptr->length) return S_OK;
3306 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3307 utf16.bytes = (BYTE *)ptr->chars;
3308 utf16.byteCount = ptr->length * sizeof(WCHAR);
3309 return write_type_text( writer, mapping, &utf16.text );
3312 static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping,
3313 const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option,
3314 const void *value, ULONG size )
3316 WS_XML_UTF16_TEXT utf16;
3317 const WCHAR *ptr;
3318 HRESULT hr;
3319 int len;
3321 if (desc)
3323 FIXME( "description not supported\n" );
3324 return E_NOTIMPL;
3327 if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG;
3328 if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr;
3329 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3330 if (!(len = strlenW( ptr ))) return S_OK;
3332 utf16.text.textType = WS_XML_TEXT_TYPE_UTF16;
3333 utf16.bytes = (BYTE *)ptr;
3334 utf16.byteCount = len * sizeof(WCHAR);
3335 return write_type_text( writer, mapping, &utf16.text );
3338 static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping,
3339 const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option,
3340 const void *value, ULONG size )
3342 WS_XML_BASE64_TEXT base64;
3343 const WS_BYTES *ptr;
3344 HRESULT hr;
3346 if (desc)
3348 FIXME( "description not supported\n" );
3349 return E_NOTIMPL;
3352 if (!option) return E_INVALIDARG;
3353 if ((hr = get_value_ptr( option, value, size, sizeof(WS_BYTES), (const void **)&ptr )) != S_OK) return hr;
3354 if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) ||
3355 (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer );
3356 if (!ptr->length) return S_OK;
3358 base64.text.textType = WS_XML_TEXT_TYPE_BASE64;
3359 base64.bytes = ptr->bytes;
3360 base64.length = ptr->length;
3361 return write_type_text( writer, mapping, &base64.text );
3364 static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping,
3365 const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option,
3366 const void *value, ULONG size )
3368 WS_XML_UTF8_TEXT utf8;
3369 const WS_XML_STRING *ptr;
3370 HRESULT hr;
3372 if (desc)
3374 FIXME( "description not supported\n" );
3375 return E_NOTIMPL;
3378 if (!option) return E_INVALIDARG;
3379 if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr;
3380 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3381 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3382 if (!ptr->length) return S_OK;
3384 utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
3385 utf8.value.bytes = ptr->bytes;
3386 utf8.value.length = ptr->length;
3387 return write_type_text( writer, mapping, &utf8.text );
3390 static HRESULT find_prefix( struct writer *writer, const WS_XML_STRING *ns, const WS_XML_STRING **prefix )
3392 const struct node *node;
3393 for (node = writer->current; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3395 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3396 ULONG i;
3397 for (i = 0; i < elem->attributeCount; i++)
3399 if (!elem->attributes[i]->isXmlNs) continue;
3400 if (WsXmlStringEquals( elem->attributes[i]->ns, ns, NULL ) != S_OK) continue;
3401 *prefix = elem->attributes[i]->prefix;
3402 return S_OK;
3405 return WS_E_INVALID_FORMAT;
3408 static HRESULT write_type_qname( struct writer *writer, WS_TYPE_MAPPING mapping,
3409 const WS_XML_QNAME_DESCRIPTION *desc, WS_WRITE_OPTION option,
3410 const void *value, ULONG size )
3412 WS_XML_QNAME_TEXT qname;
3413 const WS_XML_QNAME *ptr;
3414 const WS_XML_STRING *prefix;
3415 HRESULT hr;
3417 if (desc)
3419 FIXME( "description not supported\n" );
3420 return E_NOTIMPL;
3423 if (!option) return E_INVALIDARG;
3424 if ((hr = get_value_ptr( option, value, size, sizeof(*ptr), (const void **)&ptr )) != S_OK) return hr;
3425 if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer );
3426 if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer );
3428 if (((hr = find_prefix( writer, &ptr->ns, &prefix )) != S_OK)) return hr;
3430 qname.text.textType = WS_XML_TEXT_TYPE_QNAME;
3431 qname.prefix = (WS_XML_STRING *)prefix;
3432 qname.localName = (WS_XML_STRING *)&ptr->localName;
3433 qname.ns = (WS_XML_STRING *)&ptr->ns;
3434 return write_type_text( writer, mapping, &qname.text );
3437 static WS_WRITE_OPTION get_field_write_option( WS_TYPE type, ULONG options )
3439 if (options & WS_FIELD_POINTER)
3441 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3442 return WS_WRITE_REQUIRED_POINTER;
3445 switch (type)
3447 case WS_BOOL_TYPE:
3448 case WS_INT8_TYPE:
3449 case WS_INT16_TYPE:
3450 case WS_INT32_TYPE:
3451 case WS_INT64_TYPE:
3452 case WS_UINT8_TYPE:
3453 case WS_UINT16_TYPE:
3454 case WS_UINT32_TYPE:
3455 case WS_UINT64_TYPE:
3456 case WS_DOUBLE_TYPE:
3457 case WS_DATETIME_TYPE:
3458 case WS_GUID_TYPE:
3459 case WS_UNIQUE_ID_TYPE:
3460 case WS_STRING_TYPE:
3461 case WS_BYTES_TYPE:
3462 case WS_XML_STRING_TYPE:
3463 case WS_XML_QNAME_TYPE:
3464 case WS_STRUCT_TYPE:
3465 case WS_ENUM_TYPE:
3466 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_VALUE;
3467 return WS_WRITE_REQUIRED_VALUE;
3469 case WS_WSZ_TYPE:
3470 case WS_DESCRIPTION_TYPE:
3471 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_WRITE_NILLABLE_POINTER;
3472 return WS_WRITE_REQUIRED_POINTER;
3474 default:
3475 FIXME( "unhandled type %u\n", type );
3476 return 0;
3480 static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION,
3481 const void *, ULONG );
3483 static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
3484 const char *buf, ULONG count )
3486 HRESULT hr = S_OK;
3487 ULONG i, size, offset = 0;
3488 WS_WRITE_OPTION option;
3490 if (!(option = get_field_write_option( desc->type, desc->options ))) return E_INVALIDARG;
3492 /* wrapper element */
3493 if (desc->localName && ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK))
3494 return hr;
3496 if (option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE)
3497 size = get_type_size( desc->type, desc->typeDescription );
3498 else
3499 size = sizeof(const void *);
3501 for (i = 0; i < count; i++)
3503 if ((hr = write_element_node( writer, NULL, desc->itemLocalName, desc->itemNs )) != S_OK) return hr;
3504 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription, option,
3505 buf + offset, size )) != S_OK) return hr;
3506 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3507 offset += size;
3510 if (desc->localName) hr = write_endelement_node( writer );
3511 return hr;
3514 static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
3516 static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
3517 const void *value, ULONG size )
3519 ULONG i, offset;
3520 const void *ptr;
3521 int enum_value;
3522 HRESULT hr;
3524 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3526 if (size < sizeof(enum_value)) return E_INVALIDARG;
3527 if ((enum_value = *(int *)(char *)ptr + desc->enumOffset) == desc->noneEnumValue)
3529 switch (option)
3531 case WS_WRITE_REQUIRED_VALUE:
3532 return WS_E_INVALID_FORMAT;
3534 case WS_WRITE_NILLABLE_VALUE:
3535 return S_OK;
3537 default:
3538 ERR( "unhandled write option %u\n", option );
3539 return E_INVALIDARG;
3543 for (i = 0; i < desc->fieldCount; i++)
3545 if (desc->fields[i]->value == enum_value)
3547 offset = desc->fields[i]->field.offset;
3548 return write_type_field( writer, &desc->fields[i]->field, ptr, offset );
3552 return E_INVALIDARG;
3555 static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
3556 ULONG offset )
3558 HRESULT hr;
3559 WS_TYPE_MAPPING mapping;
3560 WS_WRITE_OPTION option;
3561 ULONG count, size, field_options = desc->options;
3562 const char *ptr = buf + offset;
3564 if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE))
3566 FIXME( "options 0x%x not supported\n", desc->options );
3567 return E_NOTIMPL;
3570 /* zero-terminated strings are always pointers */
3571 if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER;
3573 if (field_options & WS_FIELD_POINTER)
3574 size = sizeof(const void *);
3575 else
3576 size = get_type_size( desc->type, desc->typeDescription );
3578 if (is_nil_value( ptr, size ))
3580 if (field_options & WS_FIELD_OPTIONAL) return S_OK;
3581 if (field_options & WS_FIELD_NILLABLE)
3583 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER;
3584 else option = WS_WRITE_NILLABLE_VALUE;
3586 else
3588 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3589 else option = WS_WRITE_REQUIRED_VALUE;
3592 else
3594 if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER;
3595 else option = WS_WRITE_REQUIRED_VALUE;
3598 switch (desc->mapping)
3600 case WS_ATTRIBUTE_FIELD_MAPPING:
3601 if (!desc->localName || !desc->ns) return E_INVALIDARG;
3602 if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK)
3603 return hr;
3604 writer->state = WRITER_STATE_STARTATTRIBUTE;
3606 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3607 break;
3609 case WS_ELEMENT_FIELD_MAPPING:
3610 if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr;
3611 mapping = WS_ELEMENT_TYPE_MAPPING;
3612 break;
3614 case WS_ELEMENT_CHOICE_FIELD_MAPPING:
3615 if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
3616 option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
3617 return write_type_union( writer, desc->typeDescription, option, ptr, size );
3619 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3620 count = *(const ULONG *)(buf + desc->countOffset);
3621 return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
3623 case WS_TEXT_FIELD_MAPPING:
3624 switch (writer->state)
3626 case WRITER_STATE_STARTELEMENT:
3627 mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING;
3628 break;
3630 case WRITER_STATE_STARTATTRIBUTE:
3631 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3632 break;
3634 default:
3635 FIXME( "unhandled writer state %u\n", writer->state );
3636 return E_NOTIMPL;
3638 break;
3640 default:
3641 FIXME( "field mapping %u not supported\n", desc->mapping );
3642 return E_NOTIMPL;
3645 if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, ptr, size )) != S_OK)
3646 return hr;
3648 switch (mapping)
3650 case WS_ATTRIBUTE_TYPE_MAPPING:
3651 writer->state = WRITER_STATE_STARTELEMENT;
3652 break;
3654 case WS_ELEMENT_TYPE_MAPPING:
3655 if ((hr = write_endelement_node( writer )) != S_OK) return hr;
3656 break;
3658 default: break;
3661 return S_OK;
3664 static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping,
3665 const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option,
3666 const void *value, ULONG size )
3668 ULONG i, offset;
3669 const void *ptr;
3670 HRESULT hr;
3672 if (!desc) return E_INVALIDARG;
3673 if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions );
3675 if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
3677 for (i = 0; i < desc->fieldCount; i++)
3679 offset = desc->fields[i]->offset;
3680 if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
3683 return S_OK;
3686 static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type,
3687 const void *desc, WS_WRITE_OPTION option, const void *value,
3688 ULONG size )
3690 switch (type)
3692 case WS_BOOL_TYPE:
3693 return write_type_bool( writer, mapping, desc, option, value, size );
3695 case WS_INT8_TYPE:
3696 return write_type_int8( writer, mapping, desc, option, value, size );
3698 case WS_INT16_TYPE:
3699 return write_type_int16( writer, mapping, desc, option, value, size );
3701 case WS_INT32_TYPE:
3702 return write_type_int32( writer, mapping, desc, option, value, size );
3704 case WS_INT64_TYPE:
3705 return write_type_int64( writer, mapping, desc, option, value, size );
3707 case WS_UINT8_TYPE:
3708 return write_type_uint8( writer, mapping, desc, option, value, size );
3710 case WS_UINT16_TYPE:
3711 return write_type_uint16( writer, mapping, desc, option, value, size );
3713 case WS_UINT32_TYPE:
3714 return write_type_uint32( writer, mapping, desc, option, value, size );
3716 case WS_UINT64_TYPE:
3717 return write_type_uint64( writer, mapping, desc, option, value, size );
3719 case WS_DOUBLE_TYPE:
3720 return write_type_double( writer, mapping, desc, option, value, size );
3722 case WS_DATETIME_TYPE:
3723 return write_type_datetime( writer, mapping, desc, option, value, size );
3725 case WS_GUID_TYPE:
3726 return write_type_guid( writer, mapping, desc, option, value, size );
3728 case WS_UNIQUE_ID_TYPE:
3729 return write_type_unique_id( writer, mapping, desc, option, value, size );
3731 case WS_STRING_TYPE:
3732 return write_type_string( writer, mapping, desc, option, value, size );
3734 case WS_WSZ_TYPE:
3735 return write_type_wsz( writer, mapping, desc, option, value, size );
3737 case WS_BYTES_TYPE:
3738 return write_type_bytes( writer, mapping, desc, option, value, size );
3740 case WS_XML_STRING_TYPE:
3741 return write_type_xml_string( writer, mapping, desc, option, value, size );
3743 case WS_XML_QNAME_TYPE:
3744 return write_type_qname( writer, mapping, desc, option, value, size );
3746 case WS_STRUCT_TYPE:
3747 return write_type_struct( writer, mapping, desc, option, value, size );
3749 default:
3750 FIXME( "type %u not supported\n", type );
3751 return E_NOTIMPL;
3755 /**************************************************************************
3756 * WsWriteAttribute [webservices.@]
3758 HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
3759 WS_WRITE_OPTION option, const void *value, ULONG size,
3760 WS_ERROR *error )
3762 struct writer *writer = (struct writer *)handle;
3763 HRESULT hr;
3765 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3766 if (error) FIXME( "ignoring error parameter\n" );
3768 if (!writer || !desc || !desc->attributeLocalName || !desc->attributeNs || !value)
3769 return E_INVALIDARG;
3771 EnterCriticalSection( &writer->cs );
3773 if (writer->magic != WRITER_MAGIC)
3775 LeaveCriticalSection( &writer->cs );
3776 return E_INVALIDARG;
3779 if (writer->state != WRITER_STATE_STARTELEMENT)
3781 LeaveCriticalSection( &writer->cs );
3782 return WS_E_INVALID_OPERATION;
3785 if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK)
3787 LeaveCriticalSection( &writer->cs );
3788 return hr;
3790 writer->state = WRITER_STATE_STARTATTRIBUTE;
3792 hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, option, value, size );
3794 LeaveCriticalSection( &writer->cs );
3795 return hr;
3798 /**************************************************************************
3799 * WsWriteElement [webservices.@]
3801 HRESULT WINAPI WsWriteElement( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
3802 WS_WRITE_OPTION option, const void *value, ULONG size,
3803 WS_ERROR *error )
3805 struct writer *writer = (struct writer *)handle;
3806 HRESULT hr;
3808 TRACE( "%p %p %u %p %u %p\n", handle, desc, option, value, size, error );
3809 if (error) FIXME( "ignoring error parameter\n" );
3811 if (!writer || !desc || !desc->elementLocalName || !desc->elementNs || !value)
3812 return E_INVALIDARG;
3814 EnterCriticalSection( &writer->cs );
3816 if (writer->magic != WRITER_MAGIC)
3818 LeaveCriticalSection( &writer->cs );
3819 return E_INVALIDARG;
3822 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
3824 if ((hr = write_type( writer, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, desc->typeDescription,
3825 option, value, size )) != S_OK) goto done;
3827 hr = write_endelement_node( writer );
3829 done:
3830 LeaveCriticalSection( &writer->cs );
3831 return hr;
3834 /**************************************************************************
3835 * WsWriteType [webservices.@]
3837 HRESULT WINAPI WsWriteType( WS_XML_WRITER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
3838 const void *desc, WS_WRITE_OPTION option, const void *value,
3839 ULONG size, WS_ERROR *error )
3841 struct writer *writer = (struct writer *)handle;
3842 HRESULT hr;
3844 TRACE( "%p %u %u %p %u %p %u %p\n", handle, mapping, type, desc, option, value,
3845 size, error );
3846 if (error) FIXME( "ignoring error parameter\n" );
3848 if (!writer || !value) return E_INVALIDARG;
3850 EnterCriticalSection( &writer->cs );
3852 if (writer->magic != WRITER_MAGIC)
3854 LeaveCriticalSection( &writer->cs );
3855 return E_INVALIDARG;
3858 switch (mapping)
3860 case WS_ATTRIBUTE_TYPE_MAPPING:
3861 if (writer->state != WRITER_STATE_STARTATTRIBUTE) hr = WS_E_INVALID_FORMAT;
3862 else hr = write_type( writer, mapping, type, desc, option, value, size );
3863 break;
3865 case WS_ELEMENT_TYPE_MAPPING:
3866 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3867 if (writer->state != WRITER_STATE_STARTELEMENT) hr = WS_E_INVALID_FORMAT;
3868 else hr = write_type( writer, mapping, type, desc, option, value, size );
3869 break;
3871 case WS_ANY_ELEMENT_TYPE_MAPPING:
3872 hr = write_type( writer, mapping, type, desc, option, value, size );
3873 break;
3875 default:
3876 FIXME( "mapping %u not implemented\n", mapping );
3877 hr = E_NOTIMPL;
3880 LeaveCriticalSection( &writer->cs );
3881 return hr;
3884 WS_TYPE map_value_type( WS_VALUE_TYPE type )
3886 switch (type)
3888 case WS_BOOL_VALUE_TYPE: return WS_BOOL_TYPE;
3889 case WS_INT8_VALUE_TYPE: return WS_INT8_TYPE;
3890 case WS_INT16_VALUE_TYPE: return WS_INT16_TYPE;
3891 case WS_INT32_VALUE_TYPE: return WS_INT32_TYPE;
3892 case WS_INT64_VALUE_TYPE: return WS_INT64_TYPE;
3893 case WS_UINT8_VALUE_TYPE: return WS_UINT8_TYPE;
3894 case WS_UINT16_VALUE_TYPE: return WS_UINT16_TYPE;
3895 case WS_UINT32_VALUE_TYPE: return WS_UINT32_TYPE;
3896 case WS_UINT64_VALUE_TYPE: return WS_UINT64_TYPE;
3897 case WS_FLOAT_VALUE_TYPE: return WS_FLOAT_TYPE;
3898 case WS_DOUBLE_VALUE_TYPE: return WS_DOUBLE_TYPE;
3899 case WS_DECIMAL_VALUE_TYPE: return WS_DECIMAL_TYPE;
3900 case WS_DATETIME_VALUE_TYPE: return WS_DATETIME_TYPE;
3901 case WS_TIMESPAN_VALUE_TYPE: return WS_TIMESPAN_TYPE;
3902 case WS_GUID_VALUE_TYPE: return WS_GUID_TYPE;
3903 default:
3904 FIXME( "unhandled type %u\n", type );
3905 return ~0u;
3909 /**************************************************************************
3910 * WsWriteValue [webservices.@]
3912 HRESULT WINAPI WsWriteValue( WS_XML_WRITER *handle, WS_VALUE_TYPE value_type, const void *value,
3913 ULONG size, WS_ERROR *error )
3915 struct writer *writer = (struct writer *)handle;
3916 WS_TYPE_MAPPING mapping;
3917 HRESULT hr = S_OK;
3918 WS_TYPE type;
3920 TRACE( "%p %u %p %u %p\n", handle, value_type, value, size, error );
3921 if (error) FIXME( "ignoring error parameter\n" );
3923 if (!writer || !value || (type = map_value_type( value_type )) == ~0u) return E_INVALIDARG;
3925 EnterCriticalSection( &writer->cs );
3927 if (writer->magic != WRITER_MAGIC)
3929 LeaveCriticalSection( &writer->cs );
3930 return E_INVALIDARG;
3933 switch (writer->state)
3935 case WRITER_STATE_STARTATTRIBUTE:
3936 mapping = WS_ATTRIBUTE_TYPE_MAPPING;
3937 break;
3939 case WRITER_STATE_STARTELEMENT:
3940 mapping = WS_ELEMENT_TYPE_MAPPING;
3941 break;
3943 default:
3944 hr = WS_E_INVALID_FORMAT;
3947 if (hr == S_OK) hr = write_type( writer, mapping, type, NULL, WS_WRITE_REQUIRED_VALUE, value, size );
3949 LeaveCriticalSection( &writer->cs );
3950 return hr;
3953 /**************************************************************************
3954 * WsWriteArray [webservices.@]
3956 HRESULT WINAPI WsWriteArray( WS_XML_WRITER *handle, const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3957 WS_VALUE_TYPE value_type, const void *array, ULONG size, ULONG offset,
3958 ULONG count, WS_ERROR *error )
3960 struct writer *writer = (struct writer *)handle;
3961 WS_TYPE type;
3962 ULONG type_size, i;
3963 HRESULT hr = S_OK;
3965 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3966 value_type, array, size, offset, count, error );
3967 if (error) FIXME( "ignoring error parameter\n" );
3969 if (!writer) return E_INVALIDARG;
3971 EnterCriticalSection( &writer->cs );
3973 if (writer->magic != WRITER_MAGIC)
3975 LeaveCriticalSection( &writer->cs );
3976 return E_INVALIDARG;
3979 if (!writer->output_type)
3981 LeaveCriticalSection( &writer->cs );
3982 return WS_E_INVALID_OPERATION;
3985 if (!localname || !ns || (type = map_value_type( value_type )) == ~0u)
3987 LeaveCriticalSection( &writer->cs );
3988 return E_INVALIDARG;
3991 type_size = get_type_size( type, NULL );
3992 if (size % type_size || (offset + count) * type_size > size || (count && !array))
3994 LeaveCriticalSection( &writer->cs );
3995 return E_INVALIDARG;
3998 for (i = offset; i < count; i++)
4000 const char *ptr = (const char *)array + (offset + i) * type_size;
4001 if ((hr = write_element_node( writer, NULL, localname, ns )) != S_OK) goto done;
4002 if ((hr = write_type( writer, WS_ELEMENT_TYPE_MAPPING, type, NULL, WS_WRITE_REQUIRED_POINTER,
4003 &ptr, sizeof(ptr) )) != S_OK) goto done;
4004 if ((hr = write_endelement_node( writer )) != S_OK) goto done;
4007 done:
4008 LeaveCriticalSection( &writer->cs );
4009 return hr;
4012 /**************************************************************************
4013 * WsWriteXmlBuffer [webservices.@]
4015 HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, WS_ERROR *error )
4017 struct writer *writer = (struct writer *)handle;
4018 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4019 HRESULT hr;
4021 TRACE( "%p %p %p\n", handle, buffer, error );
4022 if (error) FIXME( "ignoring error parameter\n" );
4024 if (!writer || !xmlbuf) return E_INVALIDARG;
4026 EnterCriticalSection( &writer->cs );
4028 if (writer->magic != WRITER_MAGIC)
4030 LeaveCriticalSection( &writer->cs );
4031 return E_INVALIDARG;
4034 if (xmlbuf->encoding != writer->output_enc || xmlbuf->charset != writer->output_charset)
4036 FIXME( "no support for different encoding and/or charset\n" );
4037 hr = E_NOTIMPL;
4038 goto done;
4041 if ((hr = write_flush( writer )) != S_OK) goto done;
4042 if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
4043 write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4045 done:
4046 LeaveCriticalSection( &writer->cs );
4047 return hr;
4050 /**************************************************************************
4051 * WsWriteXmlBufferToBytes [webservices.@]
4053 HRESULT WINAPI WsWriteXmlBufferToBytes( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
4054 const WS_XML_WRITER_ENCODING *encoding,
4055 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
4056 WS_HEAP *heap, void **bytes, ULONG *size, WS_ERROR *error )
4058 struct writer *writer = (struct writer *)handle;
4059 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4060 HRESULT hr = S_OK;
4061 char *buf;
4062 ULONG i;
4064 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle, buffer, encoding, properties, count, heap,
4065 bytes, size, error );
4066 if (error) FIXME( "ignoring error parameter\n" );
4068 if (!writer || !xmlbuf || !heap || !bytes) return E_INVALIDARG;
4070 if (encoding && encoding->encodingType != WS_XML_WRITER_ENCODING_TYPE_TEXT)
4072 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4073 return E_NOTIMPL;
4076 EnterCriticalSection( &writer->cs );
4078 if (writer->magic != WRITER_MAGIC)
4080 LeaveCriticalSection( &writer->cs );
4081 return E_INVALIDARG;
4084 for (i = 0; i < count; i++)
4086 hr = prop_set( writer->prop, writer->prop_count, properties[i].id, properties[i].value,
4087 properties[i].valueSize );
4088 if (hr != S_OK) goto done;
4091 if (!(buf = ws_alloc( heap, xmlbuf->bytes.length ))) hr = WS_E_QUOTA_EXCEEDED;
4092 else
4094 memcpy( buf, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
4095 *bytes = buf;
4096 *size = xmlbuf->bytes.length;
4099 done:
4100 LeaveCriticalSection( &writer->cs );
4101 return hr;
4104 /**************************************************************************
4105 * WsWriteXmlnsAttribute [webservices.@]
4107 HRESULT WINAPI WsWriteXmlnsAttribute( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4108 const WS_XML_STRING *ns, BOOL single, WS_ERROR *error )
4110 struct writer *writer = (struct writer *)handle;
4111 HRESULT hr = S_OK;
4113 TRACE( "%p %s %s %d %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(ns),
4114 single, error );
4115 if (error) FIXME( "ignoring error parameter\n" );
4117 if (!writer || !ns) return E_INVALIDARG;
4119 EnterCriticalSection( &writer->cs );
4121 if (writer->magic != WRITER_MAGIC)
4123 LeaveCriticalSection( &writer->cs );
4124 return E_INVALIDARG;
4127 if (writer->state != WRITER_STATE_STARTELEMENT)
4129 LeaveCriticalSection( &writer->cs );
4130 return WS_E_INVALID_OPERATION;
4133 if (!namespace_in_scope( &writer->current->hdr, prefix, ns ))
4134 hr = add_namespace_attribute( writer, prefix, ns, single );
4136 LeaveCriticalSection( &writer->cs );
4137 return hr;
4140 static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING *prefix,
4141 const WS_XML_STRING *localname, const WS_XML_STRING *ns )
4143 WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
4144 HRESULT hr;
4146 if ((hr = write_flush( writer )) != S_OK) return hr;
4147 if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
4149 qname.prefix = (WS_XML_STRING *)prefix;
4150 qname.localName = (WS_XML_STRING *)localname;
4151 qname.ns = (WS_XML_STRING *)ns;
4153 if ((hr = write_add_text_node( writer, &qname.text )) != S_OK) return hr;
4154 return write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 );
4157 /**************************************************************************
4158 * WsWriteQualifiedName [webservices.@]
4160 HRESULT WINAPI WsWriteQualifiedName( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
4161 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4162 WS_ERROR *error )
4164 struct writer *writer = (struct writer *)handle;
4165 HRESULT hr;
4167 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
4168 debugstr_xmlstr(ns), error );
4169 if (error) FIXME( "ignoring error parameter\n" );
4171 if (!writer) return E_INVALIDARG;
4173 EnterCriticalSection( &writer->cs );
4175 if (writer->magic != WRITER_MAGIC)
4177 LeaveCriticalSection( &writer->cs );
4178 return E_INVALIDARG;
4181 if (!writer->output_type)
4183 LeaveCriticalSection( &writer->cs );
4184 return WS_E_INVALID_OPERATION;
4187 if (writer->state != WRITER_STATE_STARTELEMENT)
4189 LeaveCriticalSection( &writer->cs );
4190 return WS_E_INVALID_FORMAT;
4193 if (!localname || (!prefix && !ns))
4195 LeaveCriticalSection( &writer->cs );
4196 return E_INVALIDARG;
4199 hr = write_qualified_name( writer, prefix, localname, ns );
4201 LeaveCriticalSection( &writer->cs );
4202 return hr;
4205 static HRESULT write_move_to( struct writer *writer, WS_MOVE_TO move, BOOL *found )
4207 BOOL success = FALSE;
4208 struct node *node = writer->current;
4210 switch (move)
4212 case WS_MOVE_TO_ROOT_ELEMENT:
4213 success = move_to_root_element( writer->root, &node );
4214 break;
4216 case WS_MOVE_TO_NEXT_ELEMENT:
4217 success = move_to_next_element( &node );
4218 break;
4220 case WS_MOVE_TO_PREVIOUS_ELEMENT:
4221 success = move_to_prev_element( &node );
4222 break;
4224 case WS_MOVE_TO_CHILD_ELEMENT:
4225 success = move_to_child_element( &node );
4226 break;
4228 case WS_MOVE_TO_END_ELEMENT:
4229 success = move_to_end_element( &node );
4230 break;
4232 case WS_MOVE_TO_PARENT_ELEMENT:
4233 success = move_to_parent_element( &node );
4234 break;
4236 case WS_MOVE_TO_FIRST_NODE:
4237 success = move_to_first_node( &node );
4238 break;
4240 case WS_MOVE_TO_NEXT_NODE:
4241 success = move_to_next_node( &node );
4242 break;
4244 case WS_MOVE_TO_PREVIOUS_NODE:
4245 success = move_to_prev_node( &node );
4246 break;
4248 case WS_MOVE_TO_CHILD_NODE:
4249 success = move_to_child_node( &node );
4250 break;
4252 case WS_MOVE_TO_BOF:
4253 success = move_to_bof( writer->root, &node );
4254 break;
4256 case WS_MOVE_TO_EOF:
4257 success = move_to_eof( writer->root, &node );
4258 break;
4260 default:
4261 FIXME( "unhandled move %u\n", move );
4262 return E_NOTIMPL;
4265 if (success && node == writer->root) return E_INVALIDARG;
4266 writer->current = node;
4268 if (found)
4270 *found = success;
4271 return S_OK;
4273 return success ? S_OK : WS_E_INVALID_FORMAT;
4276 /**************************************************************************
4277 * WsMoveWriter [webservices.@]
4279 HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
4281 struct writer *writer = (struct writer *)handle;
4282 HRESULT hr;
4284 TRACE( "%p %u %p %p\n", handle, move, found, error );
4285 if (error) FIXME( "ignoring error parameter\n" );
4287 if (!writer) return E_INVALIDARG;
4289 EnterCriticalSection( &writer->cs );
4291 if (writer->magic != WRITER_MAGIC)
4293 LeaveCriticalSection( &writer->cs );
4294 return E_INVALIDARG;
4297 if (!writer->output_type)
4299 LeaveCriticalSection( &writer->cs );
4300 return WS_E_INVALID_OPERATION;
4303 hr = write_move_to( writer, move, found );
4305 LeaveCriticalSection( &writer->cs );
4306 return hr;
4309 /**************************************************************************
4310 * WsGetWriterPosition [webservices.@]
4312 HRESULT WINAPI WsGetWriterPosition( WS_XML_WRITER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4314 struct writer *writer = (struct writer *)handle;
4316 TRACE( "%p %p %p\n", handle, pos, error );
4317 if (error) FIXME( "ignoring error parameter\n" );
4319 if (!writer || !pos) return E_INVALIDARG;
4321 EnterCriticalSection( &writer->cs );
4323 if (writer->magic != WRITER_MAGIC)
4325 LeaveCriticalSection( &writer->cs );
4326 return E_INVALIDARG;
4329 if (!writer->output_type)
4331 LeaveCriticalSection( &writer->cs );
4332 return WS_E_INVALID_OPERATION;
4335 pos->buffer = (WS_XML_BUFFER *)writer->output_buf;
4336 pos->node = writer->current;
4338 LeaveCriticalSection( &writer->cs );
4339 return S_OK;
4342 /**************************************************************************
4343 * WsSetWriterPosition [webservices.@]
4345 HRESULT WINAPI WsSetWriterPosition( WS_XML_WRITER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4347 struct writer *writer = (struct writer *)handle;
4349 TRACE( "%p %p %p\n", handle, pos, error );
4350 if (error) FIXME( "ignoring error parameter\n" );
4352 if (!writer || !pos) return E_INVALIDARG;
4354 EnterCriticalSection( &writer->cs );
4356 if (writer->magic != WRITER_MAGIC || (struct xmlbuf *)pos->buffer != writer->output_buf)
4358 LeaveCriticalSection( &writer->cs );
4359 return E_INVALIDARG;
4362 if (!writer->output_type)
4364 LeaveCriticalSection( &writer->cs );
4365 return WS_E_INVALID_OPERATION;
4368 writer->current = pos->node;
4370 LeaveCriticalSection( &writer->cs );
4371 return S_OK;
4374 static HRESULT write_add_comment_node( struct writer *writer, const WS_XML_STRING *value )
4376 struct node *node, *parent;
4377 WS_XML_COMMENT_NODE *comment;
4379 if (!(parent = find_parent( writer ))) return WS_E_INVALID_FORMAT;
4380 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
4381 comment = (WS_XML_COMMENT_NODE *)node;
4383 if (value->length && !(comment->value.bytes = heap_alloc( value->length )))
4385 free_node( node );
4386 return E_OUTOFMEMORY;
4388 memcpy( comment->value.bytes, value->bytes, value->length );
4389 comment->value.length = value->length;
4391 write_insert_node( writer, parent, node );
4392 return S_OK;
4395 static HRESULT write_comment_text( struct writer *writer )
4397 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4398 HRESULT hr;
4400 if ((hr = write_grow_buffer( writer, comment->value.length + 7 )) != S_OK) return hr;
4401 write_bytes( writer, (const BYTE *)"<!--", 4 );
4402 write_bytes( writer, comment->value.bytes, comment->value.length );
4403 write_bytes( writer, (const BYTE *)"-->", 3 );
4404 return S_OK;
4407 static HRESULT write_comment_bin( struct writer *writer )
4409 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)writer->current;
4410 HRESULT hr;
4412 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
4413 write_char( writer, RECORD_COMMENT );
4414 return write_string( writer, comment->value.bytes, comment->value.length );
4417 static HRESULT write_comment( struct writer *writer )
4419 switch (writer->output_enc)
4421 case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_comment_text( writer );
4422 case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_comment_bin( writer );
4423 default:
4424 ERR( "unhandled encoding %u\n", writer->output_enc );
4425 return WS_E_NOT_SUPPORTED;
4429 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
4431 HRESULT hr;
4432 if ((hr = write_flush( writer )) != S_OK) return hr;
4433 if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
4434 if ((hr = write_comment( writer )) != S_OK) return hr;
4435 writer->state = WRITER_STATE_COMMENT;
4436 return S_OK;
4439 static HRESULT write_set_attributes( struct writer *writer, WS_XML_ATTRIBUTE **attrs, ULONG count )
4441 ULONG i;
4442 HRESULT hr;
4444 for (i = 0; i < count; i++)
4446 if ((hr = write_add_attribute( writer, attrs[i]->prefix, attrs[i]->localName, attrs[i]->ns,
4447 attrs[i]->singleQuote )) != S_OK) return hr;
4448 if ((hr = write_set_attribute_value( writer, attrs[i]->value )) != S_OK) return hr;
4450 return S_OK;
4453 static HRESULT write_node( struct writer *writer, const WS_XML_NODE *node )
4455 HRESULT hr;
4457 switch (node->nodeType)
4459 case WS_XML_NODE_TYPE_ELEMENT:
4461 const WS_XML_ELEMENT_NODE *elem = (const WS_XML_ELEMENT_NODE *)node;
4462 if ((hr = write_element_node( writer, elem->prefix, elem->localName, elem->ns )) != S_OK) return hr;
4463 return write_set_attributes( writer, elem->attributes, elem->attributeCount );
4465 case WS_XML_NODE_TYPE_TEXT:
4467 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4468 return write_text_node( writer, text->text );
4470 case WS_XML_NODE_TYPE_END_ELEMENT:
4471 return write_endelement_node( writer );
4473 case WS_XML_NODE_TYPE_COMMENT:
4475 const WS_XML_COMMENT_NODE *comment = (const WS_XML_COMMENT_NODE *)node;
4476 return write_comment_node( writer, &comment->value );
4478 case WS_XML_NODE_TYPE_CDATA:
4479 return write_cdata_node( writer );
4481 case WS_XML_NODE_TYPE_END_CDATA:
4482 return write_endcdata_node( writer );
4484 case WS_XML_NODE_TYPE_EOF:
4485 case WS_XML_NODE_TYPE_BOF:
4486 return S_OK;
4488 default:
4489 WARN( "unknown node type %u\n", node->nodeType );
4490 return E_INVALIDARG;
4494 /**************************************************************************
4495 * WsWriteNode [webservices.@]
4497 HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_ERROR *error )
4499 struct writer *writer = (struct writer *)handle;
4500 HRESULT hr;
4502 TRACE( "%p %p %p\n", handle, node, error );
4503 if (error) FIXME( "ignoring error parameter\n" );
4505 if (!writer || !node) return E_INVALIDARG;
4507 EnterCriticalSection( &writer->cs );
4509 if (writer->magic != WRITER_MAGIC)
4511 LeaveCriticalSection( &writer->cs );
4512 return E_INVALIDARG;
4515 if (!writer->output_type)
4517 LeaveCriticalSection( &writer->cs );
4518 return WS_E_INVALID_OPERATION;
4521 hr = write_node( writer, node );
4523 LeaveCriticalSection( &writer->cs );
4524 return hr;
4527 static HRESULT write_tree_node( struct writer *writer )
4529 HRESULT hr;
4531 switch (node_type( writer->current ))
4533 case WS_XML_NODE_TYPE_ELEMENT:
4534 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4535 return hr;
4536 if ((hr = write_startelement( writer )) != S_OK) return hr;
4537 writer->state = WRITER_STATE_STARTELEMENT;
4538 return S_OK;
4540 case WS_XML_NODE_TYPE_TEXT:
4541 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4542 return hr;
4543 if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
4544 writer->state = WRITER_STATE_TEXT;
4545 return S_OK;
4547 case WS_XML_NODE_TYPE_END_ELEMENT:
4548 if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
4549 writer->state = WRITER_STATE_ENDELEMENT;
4550 return S_OK;
4552 case WS_XML_NODE_TYPE_COMMENT:
4553 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4554 return hr;
4555 if ((hr = write_comment( writer )) != S_OK) return hr;
4556 writer->state = WRITER_STATE_COMMENT;
4557 return S_OK;
4559 case WS_XML_NODE_TYPE_CDATA:
4560 if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
4561 return hr;
4562 if ((hr = write_cdata( writer )) != S_OK) return hr;
4563 writer->state = WRITER_STATE_STARTCDATA;
4564 return S_OK;
4566 case WS_XML_NODE_TYPE_END_CDATA:
4567 if ((hr = write_endcdata( writer )) != S_OK) return hr;
4568 writer->state = WRITER_STATE_ENDCDATA;
4569 return S_OK;
4571 case WS_XML_NODE_TYPE_EOF:
4572 case WS_XML_NODE_TYPE_BOF:
4573 return S_OK;
4575 default:
4576 ERR( "unknown node type %u\n", node_type(writer->current) );
4577 return E_INVALIDARG;
4581 static HRESULT write_tree( struct writer *writer )
4583 HRESULT hr;
4585 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4586 for (;;)
4588 if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
4589 if (move_to_child_node( &writer->current ))
4591 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4592 continue;
4594 if (move_to_next_node( &writer->current ))
4596 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4597 continue;
4599 if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
4601 ERR( "invalid tree\n" );
4602 return WS_E_INVALID_FORMAT;
4604 if ((hr = write_tree_node( writer )) != S_OK) return hr;
4606 return S_OK;
4609 static void write_rewind( struct writer *writer )
4611 writer->write_pos = 0;
4612 writer->current = writer->root;
4613 writer->state = WRITER_STATE_INITIAL;
4616 /**************************************************************************
4617 * WsCopyNode [webservices.@]
4619 HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
4621 struct writer *writer = (struct writer *)handle;
4622 struct node *parent, *current, *node = NULL;
4623 HRESULT hr;
4625 TRACE( "%p %p %p\n", handle, reader, error );
4626 if (error) FIXME( "ignoring error parameter\n" );
4628 if (!writer) return E_INVALIDARG;
4630 EnterCriticalSection( &writer->cs );
4632 if (writer->magic != WRITER_MAGIC)
4634 LeaveCriticalSection( &writer->cs );
4635 return E_INVALIDARG;
4638 if (!(parent = find_parent( writer )))
4640 LeaveCriticalSection( &writer->cs );
4641 return WS_E_INVALID_FORMAT;
4644 if ((hr = copy_node( reader, &node )) != S_OK) goto done;
4645 current = writer->current;
4646 write_insert_node( writer, parent, node );
4648 write_rewind( writer );
4649 if ((hr = write_tree( writer )) != S_OK) goto done;
4650 writer->current = current;
4652 WsMoveReader( reader, WS_MOVE_TO_NEXT_NODE, NULL, NULL );
4654 done:
4655 LeaveCriticalSection( &writer->cs );
4656 return hr;
4659 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
4661 return write_type_field( writer, desc, value, 0 );
4664 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
4666 ULONG i, ret = 0;
4667 for (i = 0; i < count; i++)
4669 if (params[i].inputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4670 continue;
4671 if (args[i]) ret = *(const ULONG *)args[i];
4672 break;
4674 return ret;
4677 static HRESULT write_param_array( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value,
4678 ULONG len )
4680 return write_type_repeating_element( writer, desc, value, len );
4683 HRESULT write_input_params( WS_XML_WRITER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4684 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4686 struct writer *writer = (struct writer *)handle;
4687 const WS_STRUCT_DESCRIPTION *desc_struct;
4688 const WS_FIELD_DESCRIPTION *desc_field;
4689 HRESULT hr;
4690 ULONG i;
4692 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4694 EnterCriticalSection( &writer->cs );
4696 if (writer->magic != WRITER_MAGIC)
4698 LeaveCriticalSection( &writer->cs );
4699 return E_INVALIDARG;
4702 if ((hr = write_element_node( writer, NULL, desc->elementLocalName, desc->elementNs )) != S_OK) goto done;
4704 for (i = 0; i < count; i++)
4706 if (params[i].inputMessageIndex == INVALID_PARAMETER_INDEX) continue;
4707 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
4709 FIXME( "messages type not supported\n" );
4710 hr = E_NOTIMPL;
4711 goto done;
4713 if ((hr = get_param_desc( desc_struct, params[i].inputMessageIndex, &desc_field )) != S_OK) goto done;
4714 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
4716 if ((hr = write_param( writer, desc_field, args[i] )) != S_OK) goto done;
4718 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
4720 const void *ptr = *(const void **)args[i];
4721 ULONG len = get_array_len( params, count, params[i].inputMessageIndex, args );
4722 if ((hr = write_param_array( writer, desc_field, ptr, len )) != S_OK) goto done;
4726 hr = write_endelement_node( writer );
4728 done:
4729 LeaveCriticalSection( &writer->cs );
4730 return hr;