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
28 #include "webservices.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
32 #include "wine/list.h"
33 #include "wine/unicode.h"
34 #include "webservices_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
38 static const struct prop_desc writer_props
[] =
40 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
41 { sizeof(BOOL
), FALSE
}, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
42 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES */
43 { sizeof(BOOL
), FALSE
}, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
44 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_INDENT */
45 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
46 { sizeof(WS_CHARSET
), FALSE
}, /* WS_XML_WRITER_PROPERTY_CHARSET */
47 { sizeof(WS_BUFFERS
), FALSE
}, /* WS_XML_WRITER_PROPERTY_BUFFERS */
48 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
49 { sizeof(WS_BYTES
), FALSE
}, /* WS_XML_WRITER_PROPERTY_BYTES */
50 { sizeof(BOOL
), TRUE
}, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
51 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
52 { sizeof(WS_BYTES
), FALSE
}, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
53 { sizeof(BOOL
), FALSE
}, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
54 { sizeof(ULONG
), FALSE
}, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
55 { sizeof(ULONG
), TRUE
}, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
56 { sizeof(ULONG
), TRUE
}, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
57 { sizeof(BOOL
), FALSE
}, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
58 { sizeof(BOOL
), FALSE
} /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
64 WRITER_STATE_STARTELEMENT
,
65 WRITER_STATE_STARTATTRIBUTE
,
66 WRITER_STATE_STARTCDATA
,
67 WRITER_STATE_ENDSTARTELEMENT
,
70 WRITER_STATE_ENDELEMENT
,
79 unsigned char *write_bufptr
;
80 enum writer_state state
;
83 WS_XML_STRING
*current_ns
;
84 WS_XML_WRITER_ENCODING_TYPE output_enc
;
85 WS_CHARSET output_charset
;
86 WS_XML_WRITER_OUTPUT_TYPE output_type
;
87 WS_WRITE_CALLBACK output_cb
;
88 void *output_cb_state
;
89 struct xmlbuf
*output_buf
;
92 unsigned char *stream_buf
;
93 const WS_XML_DICTIONARY
*dict
;
95 WS_DYNAMIC_STRING_CALLBACK dict_cb
;
98 struct prop prop
[ARRAY_SIZE( writer_props
)];
101 #define WRITER_MAGIC (('W' << 24) | ('R' << 16) | ('I' << 8) | 'T')
103 static struct writer
*alloc_writer(void)
105 static const ULONG count
= ARRAY_SIZE( writer_props
);
107 ULONG size
= sizeof(*ret
) + prop_size( writer_props
, count
);
109 if (!(ret
= heap_alloc_zero( size
))) return NULL
;
111 ret
->magic
= WRITER_MAGIC
;
112 InitializeCriticalSection( &ret
->cs
);
114 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": writer.cs");
117 prop_init( writer_props
, count
, ret
->prop
, &ret
[1] );
118 ret
->prop_count
= count
;
122 static void free_writer( struct writer
*writer
)
124 destroy_nodes( writer
->root
);
125 free_xml_string( writer
->current_ns
);
126 WsFreeHeap( writer
->output_heap
);
127 heap_free( writer
->stream_buf
);
130 writer
->cs
.DebugInfo
->Spare
[0] = 0;
132 DeleteCriticalSection( &writer
->cs
);
136 static void write_insert_eof( struct writer
*writer
, struct node
*eof
)
138 if (!writer
->root
) writer
->root
= eof
;
141 eof
->parent
= writer
->root
;
142 list_add_tail( &writer
->root
->children
, &eof
->entry
);
144 writer
->current
= eof
;
147 static void write_insert_bof( struct writer
*writer
, struct node
*bof
)
149 writer
->root
->parent
= bof
;
150 list_add_tail( &bof
->children
, &writer
->root
->entry
);
151 writer
->current
= writer
->root
= bof
;
154 static void write_insert_node( struct writer
*writer
, struct node
*parent
, struct node
*node
)
156 node
->parent
= parent
;
157 list_add_before( list_tail( &parent
->children
), &node
->entry
);
158 writer
->current
= node
;
161 static struct node
*find_parent( struct writer
*writer
)
163 if (is_valid_parent( writer
->current
)) return writer
->current
;
164 if (is_valid_parent( writer
->current
->parent
)) return writer
->current
->parent
;
168 static HRESULT
init_writer( struct writer
*writer
)
172 writer
->write_pos
= 0;
173 writer
->write_bufptr
= NULL
;
174 destroy_nodes( writer
->root
);
175 writer
->root
= writer
->current
= NULL
;
176 free_xml_string( writer
->current_ns
);
177 writer
->current_ns
= NULL
;
179 if (!(node
= alloc_node( WS_XML_NODE_TYPE_EOF
))) return E_OUTOFMEMORY
;
180 write_insert_eof( writer
, node
);
181 writer
->state
= WRITER_STATE_INITIAL
;
182 writer
->output_enc
= WS_XML_WRITER_ENCODING_TYPE_TEXT
;
183 writer
->output_charset
= WS_CHARSET_UTF8
;
185 writer
->dict_do_lookup
= FALSE
;
186 writer
->dict_cb
= NULL
;
187 writer
->dict_cb_state
= NULL
;
191 /**************************************************************************
192 * WsCreateWriter [webservices.@]
194 HRESULT WINAPI
WsCreateWriter( const WS_XML_WRITER_PROPERTY
*properties
, ULONG count
,
195 WS_XML_WRITER
**handle
, WS_ERROR
*error
)
197 struct writer
*writer
;
198 ULONG i
, max_depth
= 32, max_attrs
= 128, trim_size
= 4096, max_size
= 65536, max_ns
= 32;
199 WS_CHARSET charset
= WS_CHARSET_UTF8
;
202 TRACE( "%p %u %p %p\n", properties
, count
, handle
, error
);
203 if (error
) FIXME( "ignoring error parameter\n" );
205 if (!handle
) return E_INVALIDARG
;
206 if (!(writer
= alloc_writer())) return E_OUTOFMEMORY
;
208 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_MAX_DEPTH
, &max_depth
, sizeof(max_depth
) );
209 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES
, &max_attrs
, sizeof(max_attrs
) );
210 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE
, &trim_size
, sizeof(trim_size
) );
211 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_CHARSET
, &charset
, sizeof(charset
) );
212 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE
, &max_size
, sizeof(max_size
) );
213 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE
, &max_size
, sizeof(max_size
) );
214 prop_set( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES
, &max_ns
, sizeof(max_ns
) );
216 for (i
= 0; i
< count
; i
++)
218 hr
= prop_set( writer
->prop
, writer
->prop_count
, properties
[i
].id
, properties
[i
].value
,
219 properties
[i
].valueSize
);
222 free_writer( writer
);
227 hr
= prop_get( writer
->prop
, writer
->prop_count
, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE
,
228 &max_size
, sizeof(max_size
) );
231 free_writer( writer
);
235 hr
= WsCreateHeap( max_size
, 0, NULL
, 0, &writer
->output_heap
, NULL
);
238 free_writer( writer
);
242 hr
= init_writer( writer
);
245 free_writer( writer
);
249 TRACE( "created %p\n", writer
);
250 *handle
= (WS_XML_WRITER
*)writer
;
254 /**************************************************************************
255 * WsFreeWriter [webservices.@]
257 void WINAPI
WsFreeWriter( WS_XML_WRITER
*handle
)
259 struct writer
*writer
= (struct writer
*)handle
;
261 TRACE( "%p\n", handle
);
265 EnterCriticalSection( &writer
->cs
);
267 if (writer
->magic
!= WRITER_MAGIC
)
269 LeaveCriticalSection( &writer
->cs
);
275 LeaveCriticalSection( &writer
->cs
);
276 free_writer( writer
);
279 /**************************************************************************
280 * WsGetWriterProperty [webservices.@]
282 HRESULT WINAPI
WsGetWriterProperty( WS_XML_WRITER
*handle
, WS_XML_WRITER_PROPERTY_ID id
,
283 void *buf
, ULONG size
, WS_ERROR
*error
)
285 struct writer
*writer
= (struct writer
*)handle
;
288 TRACE( "%p %u %p %u %p\n", handle
, id
, buf
, size
, error
);
289 if (error
) FIXME( "ignoring error parameter\n" );
291 if (!writer
) return E_INVALIDARG
;
293 EnterCriticalSection( &writer
->cs
);
295 if (writer
->magic
!= WRITER_MAGIC
)
297 LeaveCriticalSection( &writer
->cs
);
301 if (writer
->output_type
!= WS_XML_WRITER_OUTPUT_TYPE_BUFFER
) hr
= WS_E_INVALID_OPERATION
;
306 case WS_XML_WRITER_PROPERTY_BYTES
:
308 WS_BYTES
*bytes
= buf
;
309 if (size
!= sizeof(*bytes
)) hr
= E_INVALIDARG
;
312 bytes
->bytes
= writer
->output_buf
->bytes
.bytes
;
313 bytes
->length
= writer
->output_buf
->bytes
.length
;
317 case WS_XML_WRITER_PROPERTY_BUFFERS
:
318 if (writer
->output_buf
->bytes
.length
)
320 WS_BUFFERS
*buffers
= buf
;
321 if (size
!= sizeof(*buffers
)) hr
= E_INVALIDARG
;
324 buffers
->bufferCount
= 1;
325 buffers
->buffers
= &writer
->output_buf
->bytes
;
331 hr
= prop_get( writer
->prop
, writer
->prop_count
, id
, buf
, size
);
335 LeaveCriticalSection( &writer
->cs
);
336 TRACE( "returning %08x\n", hr
);
340 static void set_output_buffer( struct writer
*writer
, struct xmlbuf
*xmlbuf
)
342 /* free current buffer if it's ours */
343 if (writer
->output_buf
&& !writer
->output_buf_user
)
345 free_xmlbuf( writer
->output_buf
);
347 writer
->output_buf
= xmlbuf
;
348 writer
->output_type
= WS_XML_WRITER_OUTPUT_TYPE_BUFFER
;
349 writer
->write_bufptr
= xmlbuf
->bytes
.bytes
;
350 writer
->write_pos
= 0;
353 static void set_output_stream( struct writer
*writer
, WS_WRITE_CALLBACK callback
, void *state
)
355 writer
->output_type
= WS_XML_WRITER_OUTPUT_TYPE_STREAM
;
356 writer
->output_cb
= callback
;
357 writer
->output_cb_state
= state
;
358 writer
->write_bufptr
= writer
->stream_buf
;
359 writer
->write_pos
= 0;
362 /**************************************************************************
363 * WsSetOutput [webservices.@]
365 HRESULT WINAPI
WsSetOutput( WS_XML_WRITER
*handle
, const WS_XML_WRITER_ENCODING
*encoding
,
366 const WS_XML_WRITER_OUTPUT
*output
, const WS_XML_WRITER_PROPERTY
*properties
,
367 ULONG count
, WS_ERROR
*error
)
369 struct writer
*writer
= (struct writer
*)handle
;
374 TRACE( "%p %p %p %p %u %p\n", handle
, encoding
, output
, properties
, count
, error
);
375 if (error
) FIXME( "ignoring error parameter\n" );
377 if (!writer
) return E_INVALIDARG
;
379 EnterCriticalSection( &writer
->cs
);
381 if (writer
->magic
!= WRITER_MAGIC
)
383 LeaveCriticalSection( &writer
->cs
);
387 for (i
= 0; i
< count
; i
++)
389 hr
= prop_set( writer
->prop
, writer
->prop_count
, properties
[i
].id
, properties
[i
].value
,
390 properties
[i
].valueSize
);
391 if (hr
!= S_OK
) goto done
;
394 if ((hr
= init_writer( writer
)) != S_OK
) goto done
;
396 switch (encoding
->encodingType
)
398 case WS_XML_WRITER_ENCODING_TYPE_TEXT
:
400 const WS_XML_WRITER_TEXT_ENCODING
*text
= (const WS_XML_WRITER_TEXT_ENCODING
*)encoding
;
401 if (text
->charSet
!= WS_CHARSET_UTF8
)
403 FIXME( "charset %u not supported\n", text
->charSet
);
407 writer
->output_enc
= WS_XML_WRITER_ENCODING_TYPE_TEXT
;
408 writer
->output_charset
= WS_CHARSET_UTF8
;
411 case WS_XML_WRITER_ENCODING_TYPE_BINARY
:
413 const WS_XML_WRITER_BINARY_ENCODING
*bin
= (const WS_XML_WRITER_BINARY_ENCODING
*)encoding
;
414 writer
->output_enc
= WS_XML_WRITER_ENCODING_TYPE_BINARY
;
415 writer
->output_charset
= 0;
416 writer
->dict
= bin
->staticDictionary
;
417 writer
->dict_cb
= bin
->dynamicStringCallback
;
418 writer
->dict_cb_state
= bin
->dynamicStringCallbackState
;
422 FIXME( "encoding type %u not supported\n", encoding
->encodingType
);
427 switch (output
->outputType
)
429 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER
:
431 struct xmlbuf
*xmlbuf
;
432 if (!(xmlbuf
= alloc_xmlbuf( writer
->output_heap
, 0, writer
->output_enc
, writer
->output_charset
,
433 writer
->dict
, NULL
)))
435 hr
= WS_E_QUOTA_EXCEEDED
;
438 set_output_buffer( writer
, xmlbuf
);
439 writer
->output_buf_user
= FALSE
;
442 case WS_XML_WRITER_OUTPUT_TYPE_STREAM
:
444 const WS_XML_WRITER_STREAM_OUTPUT
*stream
= (const WS_XML_WRITER_STREAM_OUTPUT
*)output
;
445 if (!writer
->stream_buf
&& !(writer
->stream_buf
= heap_alloc( STREAM_BUFSIZE
)))
450 set_output_stream( writer
, stream
->writeCallback
, stream
->writeCallbackState
);
455 FIXME( "output type %u not supported\n", output
->outputType
);
460 if (!(node
= alloc_node( WS_XML_NODE_TYPE_BOF
))) hr
= E_OUTOFMEMORY
;
461 else write_insert_bof( writer
, node
);
464 LeaveCriticalSection( &writer
->cs
);
465 TRACE( "returning %08x\n", hr
);
469 /**************************************************************************
470 * WsSetOutputToBuffer [webservices.@]
472 HRESULT WINAPI
WsSetOutputToBuffer( WS_XML_WRITER
*handle
, WS_XML_BUFFER
*buffer
,
473 const WS_XML_WRITER_PROPERTY
*properties
, ULONG count
,
476 struct writer
*writer
= (struct writer
*)handle
;
477 struct xmlbuf
*xmlbuf
= (struct xmlbuf
*)buffer
;
482 TRACE( "%p %p %p %u %p\n", handle
, buffer
, properties
, count
, error
);
483 if (error
) FIXME( "ignoring error parameter\n" );
485 if (!writer
|| !xmlbuf
) return E_INVALIDARG
;
487 EnterCriticalSection( &writer
->cs
);
489 if (writer
->magic
!= WRITER_MAGIC
)
491 LeaveCriticalSection( &writer
->cs
);
495 for (i
= 0; i
< count
; i
++)
497 hr
= prop_set( writer
->prop
, writer
->prop_count
, properties
[i
].id
, properties
[i
].value
,
498 properties
[i
].valueSize
);
499 if (hr
!= S_OK
) goto done
;
502 if ((hr
= init_writer( writer
)) != S_OK
) goto done
;
503 writer
->output_enc
= xmlbuf
->encoding
;
504 writer
->output_charset
= xmlbuf
->charset
;
505 set_output_buffer( writer
, xmlbuf
);
506 writer
->output_buf_user
= TRUE
;
508 if (!(node
= alloc_node( WS_XML_NODE_TYPE_BOF
))) hr
= E_OUTOFMEMORY
;
509 else write_insert_bof( writer
, node
);
512 LeaveCriticalSection( &writer
->cs
);
513 TRACE( "returning %08x\n", hr
);
517 static HRESULT
flush_writer( struct writer
*writer
, ULONG min_size
, const WS_ASYNC_CONTEXT
*ctx
,
522 if (writer
->write_pos
< min_size
) return S_OK
;
524 buf
.bytes
= writer
->write_bufptr
;
525 buf
.length
= writer
->write_pos
;
526 writer
->output_cb( writer
->output_cb_state
, &buf
, 1, ctx
, error
);
527 writer
->write_pos
= 0;
531 /**************************************************************************
532 * WsFlushWriter [webservices.@]
534 HRESULT WINAPI
WsFlushWriter( WS_XML_WRITER
*handle
, ULONG min_size
, const WS_ASYNC_CONTEXT
*ctx
,
537 struct writer
*writer
= (struct writer
*)handle
;
540 TRACE( "%p %u %p %p\n", handle
, min_size
, ctx
, error
);
541 if (error
) FIXME( "ignoring error parameter\n" );
542 if (ctx
) FIXME( "ignoring ctx parameter\n" );
544 if (!writer
) return E_INVALIDARG
;
546 EnterCriticalSection( &writer
->cs
);
548 if (writer
->magic
!= WRITER_MAGIC
)
550 LeaveCriticalSection( &writer
->cs
);
554 if (writer
->output_type
!= WS_XML_WRITER_OUTPUT_TYPE_STREAM
) hr
= WS_E_INVALID_OPERATION
;
555 else hr
= flush_writer( writer
, min_size
, ctx
, error
);
557 LeaveCriticalSection( &writer
->cs
);
558 TRACE( "returning %08x\n", hr
);
562 static HRESULT
write_grow_buffer( struct writer
*writer
, ULONG size
)
564 struct xmlbuf
*buf
= writer
->output_buf
;
568 if (writer
->output_type
== WS_XML_WRITER_OUTPUT_TYPE_STREAM
)
570 if (size
> STREAM_BUFSIZE
) return WS_E_QUOTA_EXCEEDED
;
571 return flush_writer( writer
, STREAM_BUFSIZE
- size
, NULL
, NULL
);
574 if (buf
->size
>= writer
->write_pos
+ size
)
576 buf
->bytes
.length
= writer
->write_pos
+ size
;
579 new_size
= max( buf
->size
* 2, writer
->write_pos
+ size
);
580 if (!(tmp
= ws_realloc( buf
->heap
, buf
->bytes
.bytes
, buf
->size
, new_size
))) return WS_E_QUOTA_EXCEEDED
;
581 writer
->write_bufptr
= buf
->bytes
.bytes
= tmp
;
582 buf
->size
= new_size
;
583 buf
->bytes
.length
= writer
->write_pos
+ size
;
587 static inline void write_char( struct writer
*writer
, unsigned char ch
)
589 writer
->write_bufptr
[writer
->write_pos
++] = ch
;
592 static inline void write_bytes( struct writer
*writer
, const BYTE
*bytes
, ULONG len
)
594 memcpy( writer
->write_bufptr
+ writer
->write_pos
, bytes
, len
);
595 writer
->write_pos
+= len
;
604 static const struct escape escape_lt
= { '<', "<", 4 };
605 static const struct escape escape_gt
= { '>', ">", 4 };
606 static const struct escape escape_amp
= { '&', "&", 5 };
607 static const struct escape escape_apos
= { '\'', "'", 6 };
608 static const struct escape escape_quot
= { '"', """, 6 };
610 static HRESULT
write_bytes_escape( struct writer
*writer
, const BYTE
*bytes
, ULONG len
,
611 const struct escape
**escapes
, ULONG nb_escapes
)
617 for (i
= 0; i
< len
; i
++)
621 for (j
= 0; j
< nb_escapes
; j
++)
623 if (bytes
[i
] == escapes
[j
]->ch
)
625 ptr
= (const BYTE
*)escapes
[j
]->entity
;
626 size
= escapes
[j
]->len
;
630 if ((hr
= write_grow_buffer( writer
, size
)) != S_OK
) return hr
;
631 write_bytes( writer
, ptr
, size
);
637 static HRESULT
write_attribute_value_text( struct writer
*writer
, const WS_XML_TEXT
*text
, BOOL single
)
639 WS_XML_UTF8_TEXT
*utf8
= (WS_XML_UTF8_TEXT
*)text
;
640 const struct escape
*escapes
[3];
642 escapes
[0] = single
? &escape_apos
: &escape_quot
;
643 escapes
[1] = &escape_lt
;
644 escapes
[2] = &escape_amp
;
645 return write_bytes_escape( writer
, utf8
->value
.bytes
, utf8
->value
.length
, escapes
, 3 );
648 static HRESULT
write_attribute_text( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
650 unsigned char quote
= attr
->singleQuote
? '\'' : '"';
651 const WS_XML_STRING
*prefix
= NULL
;
655 if (attr
->prefix
) prefix
= attr
->prefix
;
657 /* ' prefix:attr="value"' */
659 size
= attr
->localName
->length
+ 4 /* ' =""' */;
660 if (prefix
&& prefix
->length
) size
+= prefix
->length
+ 1 /* ':' */;
661 if ((hr
= write_grow_buffer( writer
, size
)) != S_OK
) return hr
;
663 write_char( writer
, ' ' );
664 if (prefix
&& prefix
->length
)
666 write_bytes( writer
, prefix
->bytes
, prefix
->length
);
667 write_char( writer
, ':' );
669 write_bytes( writer
, attr
->localName
->bytes
, attr
->localName
->length
);
670 write_char( writer
, '=' );
671 write_char( writer
, quote
);
672 if (attr
->value
) hr
= write_attribute_value_text( writer
, attr
->value
, attr
->singleQuote
);
673 write_char( writer
, quote
);
678 static HRESULT
write_int31( struct writer
*writer
, ULONG len
)
682 if (len
> 0x7fffffff) return E_INVALIDARG
;
684 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
687 write_char( writer
, len
);
690 write_char( writer
, (len
& 0x7f) | 0x80 );
692 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
693 if ((len
>>= 7) < 0x80)
695 write_char( writer
, len
);
698 write_char( writer
, (len
& 0x7f) | 0x80 );
700 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
701 if ((len
>>= 7) < 0x80)
703 write_char( writer
, len
);
706 write_char( writer
, (len
& 0x7f) | 0x80 );
708 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
709 if ((len
>>= 7) < 0x80)
711 write_char( writer
, len
);
714 write_char( writer
, (len
& 0x7f) | 0x80 );
716 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
717 if ((len
>>= 7) < 0x08)
719 write_char( writer
, len
);
722 return WS_E_INVALID_FORMAT
;
725 static HRESULT
write_string( struct writer
*writer
, const BYTE
*bytes
, ULONG len
)
728 if ((hr
= write_int31( writer
, len
)) != S_OK
) return hr
;
729 if ((hr
= write_grow_buffer( writer
, len
)) != S_OK
) return hr
;
730 write_bytes( writer
, bytes
, len
);
734 static HRESULT
write_dict_string( struct writer
*writer
, ULONG id
)
736 if (id
> 0x7fffffff) return E_INVALIDARG
;
737 return write_int31( writer
, id
);
740 static enum record_type
get_attr_text_record_type( const WS_XML_TEXT
*text
, BOOL use_dict
)
742 if (!text
) return RECORD_CHARS8_TEXT
;
743 switch (text
->textType
)
745 case WS_XML_TEXT_TYPE_UTF8
:
747 const WS_XML_UTF8_TEXT
*text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
748 if (use_dict
) return RECORD_DICTIONARY_TEXT
;
749 if (text_utf8
->value
.length
<= MAX_UINT8
) return RECORD_CHARS8_TEXT
;
750 if (text_utf8
->value
.length
<= MAX_UINT16
) return RECORD_CHARS16_TEXT
;
751 return RECORD_CHARS32_TEXT
;
753 case WS_XML_TEXT_TYPE_UTF16
:
755 const WS_XML_UTF16_TEXT
*text_utf16
= (const WS_XML_UTF16_TEXT
*)text
;
756 int len
= text_utf16
->byteCount
/ sizeof(WCHAR
);
757 int len_utf8
= WideCharToMultiByte( CP_UTF8
, 0, (const WCHAR
*)text_utf16
->bytes
, len
, NULL
, 0, NULL
, NULL
);
758 if (len_utf8
<= MAX_UINT8
) return RECORD_CHARS8_TEXT
;
759 if (len_utf8
<= MAX_UINT16
) return RECORD_CHARS16_TEXT
;
760 return RECORD_CHARS32_TEXT
;
762 case WS_XML_TEXT_TYPE_BASE64
:
764 const WS_XML_BASE64_TEXT
*text_base64
= (const WS_XML_BASE64_TEXT
*)text
;
765 if (text_base64
->length
<= MAX_UINT8
) return RECORD_BYTES8_TEXT
;
766 if (text_base64
->length
<= MAX_UINT16
) return RECORD_BYTES16_TEXT
;
767 return RECORD_BYTES32_TEXT
;
769 case WS_XML_TEXT_TYPE_BOOL
:
771 const WS_XML_BOOL_TEXT
*text_bool
= (const WS_XML_BOOL_TEXT
*)text
;
772 return text_bool
->value
? RECORD_TRUE_TEXT
: RECORD_FALSE_TEXT
;
774 case WS_XML_TEXT_TYPE_INT32
:
776 const WS_XML_INT32_TEXT
*text_int32
= (const WS_XML_INT32_TEXT
*)text
;
777 if (!text_int32
->value
) return RECORD_ZERO_TEXT
;
778 if (text_int32
->value
== 1) return RECORD_ONE_TEXT
;
779 if (text_int32
->value
>= MIN_INT8
&& text_int32
->value
<= MAX_INT8
) return RECORD_INT8_TEXT
;
780 if (text_int32
->value
>= MIN_INT16
&& text_int32
->value
<= MAX_INT16
) return RECORD_INT16_TEXT
;
781 return RECORD_INT32_TEXT
;
783 case WS_XML_TEXT_TYPE_INT64
:
785 const WS_XML_INT64_TEXT
*text_int64
= (const WS_XML_INT64_TEXT
*)text
;
786 if (!text_int64
->value
) return RECORD_ZERO_TEXT
;
787 if (text_int64
->value
== 1) return RECORD_ONE_TEXT
;
788 if (text_int64
->value
>= MIN_INT8
&& text_int64
->value
<= MAX_INT8
) return RECORD_INT8_TEXT
;
789 if (text_int64
->value
>= MIN_INT16
&& text_int64
->value
<= MAX_INT16
) return RECORD_INT16_TEXT
;
790 if (text_int64
->value
>= MIN_INT32
&& text_int64
->value
<= MAX_INT32
) return RECORD_INT32_TEXT
;
791 return RECORD_INT64_TEXT
;
793 case WS_XML_TEXT_TYPE_UINT64
:
795 const WS_XML_UINT64_TEXT
*text_uint64
= (const WS_XML_UINT64_TEXT
*)text
;
796 if (!text_uint64
->value
) return RECORD_ZERO_TEXT
;
797 if (text_uint64
->value
== 1) return RECORD_ONE_TEXT
;
798 if (text_uint64
->value
<= MAX_INT8
) return RECORD_INT8_TEXT
;
799 if (text_uint64
->value
<= MAX_INT16
) return RECORD_INT16_TEXT
;
800 if (text_uint64
->value
<= MAX_INT32
) return RECORD_INT32_TEXT
;
801 if (text_uint64
->value
<= MAX_INT64
) return RECORD_INT64_TEXT
;
802 return RECORD_UINT64_TEXT
;
804 case WS_XML_TEXT_TYPE_DOUBLE
:
806 const WS_XML_DOUBLE_TEXT
*text_double
= (const WS_XML_DOUBLE_TEXT
*)text
;
807 if (!text_double
->value
) return RECORD_ZERO_TEXT
;
808 if (text_double
->value
== 1) return RECORD_ONE_TEXT
;
809 if (isinf( text_double
->value
) || (INT64
)text_double
->value
!= text_double
->value
)
810 return RECORD_DOUBLE_TEXT
;
811 if (text_double
->value
<= MAX_INT8
) return RECORD_INT8_TEXT
;
812 if (text_double
->value
<= MAX_INT16
) return RECORD_INT16_TEXT
;
813 if (text_double
->value
<= MAX_INT32
) return RECORD_INT32_TEXT
;
814 return RECORD_INT64_TEXT
;
816 case WS_XML_TEXT_TYPE_GUID
:
817 return RECORD_GUID_TEXT
;
819 case WS_XML_TEXT_TYPE_UNIQUE_ID
:
820 return RECORD_UNIQUE_ID_TEXT
;
822 case WS_XML_TEXT_TYPE_DATETIME
:
823 return RECORD_DATETIME_TEXT
;
826 FIXME( "unhandled text type %u\n", text
->textType
);
831 static INT64
get_text_value_int( const WS_XML_TEXT
*text
)
833 switch (text
->textType
)
835 case WS_XML_TEXT_TYPE_INT32
:
837 const WS_XML_INT32_TEXT
*text_int32
= (const WS_XML_INT32_TEXT
*)text
;
838 return text_int32
->value
;
840 case WS_XML_TEXT_TYPE_INT64
:
842 const WS_XML_INT64_TEXT
*text_int64
= (const WS_XML_INT64_TEXT
*)text
;
843 return text_int64
->value
;
845 case WS_XML_TEXT_TYPE_UINT64
:
847 const WS_XML_UINT64_TEXT
*text_uint64
= (const WS_XML_UINT64_TEXT
*)text
;
848 return text_uint64
->value
;
850 case WS_XML_TEXT_TYPE_DOUBLE
:
852 const WS_XML_DOUBLE_TEXT
*text_double
= (const WS_XML_DOUBLE_TEXT
*)text
;
853 return text_double
->value
;
856 ERR( "unhandled text type %u\n", text
->textType
);
862 static BOOL
get_string_id( struct writer
*writer
, const WS_XML_STRING
*str
, ULONG
*id
)
864 if (writer
->dict
&& str
->dictionary
== writer
->dict
)
872 writer
->dict_cb( writer
->dict_cb_state
, str
, &found
, id
, NULL
);
873 if (found
) *id
= (*id
<< 1) | 1;
879 static ULONG
format_bool( const BOOL
*ptr
, unsigned char *buf
)
881 static const unsigned char bool_true
[] = {'t','r','u','e'}, bool_false
[] = {'f','a','l','s','e'};
884 memcpy( buf
, bool_true
, sizeof(bool_true
) );
885 return sizeof(bool_true
);
887 memcpy( buf
, bool_false
, sizeof(bool_false
) );
888 return sizeof(bool_false
);
891 static ULONG
format_int32( const INT32
*ptr
, unsigned char *buf
)
893 return wsprintfA( (char *)buf
, "%d", *ptr
);
896 static ULONG
format_int64( const INT64
*ptr
, unsigned char *buf
)
898 return wsprintfA( (char *)buf
, "%I64d", *ptr
);
901 static ULONG
format_uint64( const UINT64
*ptr
, unsigned char *buf
)
903 return wsprintfA( (char *)buf
, "%I64u", *ptr
);
906 static ULONG
format_double( const double *ptr
, unsigned char *buf
)
909 static const long double precision
= 0.0000000000000001;
910 unsigned char *p
= buf
;
911 long double val
= *ptr
;
912 int neg
, mag
, mag2
, use_exp
;
916 memcpy( buf
, "NaN", 3 );
923 memcpy( buf
, "-INF", 4 );
926 memcpy( buf
, "INF", 3 );
942 use_exp
= (mag
>= 15 || (neg
&& mag
>= 1) || mag
<= -1);
945 if (mag
< 0) mag
-= 1;
946 val
= val
/ powl( 10.0, mag
);
950 else if (mag
< 1) mag
= 0;
952 while (val
> precision
|| mag
>= 0)
954 long double weight
= powl( 10.0, mag
);
955 if (weight
> 0 && !isinf( weight
))
957 int digit
= floorl( val
/ weight
);
958 val
-= digit
* weight
;
959 *(p
++) = '0' + digit
;
961 if (!mag
&& val
> precision
) *(p
++) = '.';
969 if (mag2
> 0) *(p
++) = '+';
978 *(p
++) = '0' + mag2
% 10;
982 for (i
= -mag
, j
= -1; i
< j
; i
++, j
--)
992 FIXME( "powl not found at build time\n" );
997 static inline int year_size( int year
)
999 return leap_year( year
) ? 366 : 365;
1003 static ULONG
format_datetime( const WS_DATETIME
*ptr
, unsigned char *buf
)
1005 static const char fmt
[] = "%04u-%02u-%02uT%02u:%02u:%02u";
1006 int day
, hour
, min
, sec
, sec_frac
, month
= 0, year
= 1, tz_hour
;
1007 unsigned __int64 ticks
, day_ticks
;
1010 if (ptr
->format
== WS_DATETIME_FORMAT_LOCAL
&&
1011 ptr
->ticks
>= TICKS_1601_01_01
+ TZ_OFFSET
* TICKS_PER_HOUR
)
1013 ticks
= ptr
->ticks
- TZ_OFFSET
* TICKS_PER_HOUR
;
1014 tz_hour
= TZ_OFFSET
;
1021 day
= ticks
/ TICKS_PER_DAY
;
1022 day_ticks
= ticks
% TICKS_PER_DAY
;
1023 hour
= day_ticks
/ TICKS_PER_HOUR
;
1024 min
= (day_ticks
% TICKS_PER_HOUR
) / TICKS_PER_MIN
;
1025 sec
= (day_ticks
% TICKS_PER_MIN
) / TICKS_PER_SEC
;
1026 sec_frac
= day_ticks
% TICKS_PER_SEC
;
1028 while (day
>= year_size( year
))
1030 day
-= year_size( year
);
1033 while (day
>= month_days
[leap_year( year
)][month
])
1035 day
-= month_days
[leap_year( year
)][month
];
1039 len
= sprintf( (char *)buf
, fmt
, year
, month
+ 1, day
+ 1, hour
, min
, sec
);
1042 static const char fmt_frac
[] = ".%07u";
1043 len
+= sprintf( (char *)buf
+ len
, fmt_frac
, sec_frac
);
1044 while (buf
[len
- 1] == '0') len
--;
1046 if (ptr
->format
== WS_DATETIME_FORMAT_UTC
)
1050 else if (ptr
->format
== WS_DATETIME_FORMAT_LOCAL
)
1052 static const char fmt_tz
[] = "%c%02u:00";
1053 len
+= sprintf( (char *)buf
+ len
, fmt_tz
, tz_hour
? '-' : '+', tz_hour
);
1059 static ULONG
format_guid( const GUID
*ptr
, unsigned char *buf
)
1061 static const char fmt
[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1062 return sprintf( (char *)buf
, fmt
, ptr
->Data1
, ptr
->Data2
, ptr
->Data3
,
1063 ptr
->Data4
[0], ptr
->Data4
[1], ptr
->Data4
[2], ptr
->Data4
[3],
1064 ptr
->Data4
[4], ptr
->Data4
[5], ptr
->Data4
[6], ptr
->Data4
[7] );
1067 static ULONG
format_urn( const GUID
*ptr
, unsigned char *buf
)
1069 static const char fmt
[] = "urn:uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
1070 return sprintf( (char *)buf
, fmt
, ptr
->Data1
, ptr
->Data2
, ptr
->Data3
,
1071 ptr
->Data4
[0], ptr
->Data4
[1], ptr
->Data4
[2], ptr
->Data4
[3],
1072 ptr
->Data4
[4], ptr
->Data4
[5], ptr
->Data4
[6], ptr
->Data4
[7] );
1075 static ULONG
format_qname( const WS_XML_STRING
*prefix
, const WS_XML_STRING
*localname
, unsigned char *buf
)
1078 if (prefix
&& prefix
->length
)
1080 memcpy( buf
, prefix
->bytes
, prefix
->length
);
1081 len
+= prefix
->length
;
1084 memcpy( buf
+ len
, localname
->bytes
, localname
->length
);
1085 return len
+ localname
->length
;
1088 static ULONG
encode_base64( const unsigned char *bin
, ULONG len
, unsigned char *buf
)
1090 static const char base64
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1095 buf
[i
++] = base64
[(bin
[0] & 0xfc) >> 2];
1096 x
= (bin
[0] & 3) << 4;
1099 buf
[i
++] = base64
[x
];
1104 buf
[i
++] = base64
[x
| ((bin
[1] & 0xf0) >> 4)];
1105 x
= (bin
[1] & 0x0f) << 2;
1108 buf
[i
++] = base64
[x
];
1112 buf
[i
++] = base64
[x
| ((bin
[2] & 0xc0) >> 6)];
1113 buf
[i
++] = base64
[bin
[2] & 0x3f];
1120 HRESULT
text_to_utf8text( const WS_XML_TEXT
*text
, const WS_XML_UTF8_TEXT
*old
, ULONG
*offset
,
1121 WS_XML_UTF8_TEXT
**ret
)
1123 ULONG len_old
= old
? old
->value
.length
: 0;
1124 if (offset
) *offset
= len_old
;
1126 switch (text
->textType
)
1128 case WS_XML_TEXT_TYPE_UTF8
:
1130 const WS_XML_UTF8_TEXT
*src
= (const WS_XML_UTF8_TEXT
*)text
;
1132 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ src
->value
.length
))) return E_OUTOFMEMORY
;
1133 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1134 memcpy( (*ret
)->value
.bytes
+ len_old
, src
->value
.bytes
, src
->value
.length
);
1137 case WS_XML_TEXT_TYPE_UTF16
:
1139 const WS_XML_UTF16_TEXT
*src
= (const WS_XML_UTF16_TEXT
*)text
;
1140 const WCHAR
*str
= (const WCHAR
*)src
->bytes
;
1141 ULONG len
= src
->byteCount
/ sizeof(WCHAR
), len_utf8
;
1143 if (src
->byteCount
% sizeof(WCHAR
)) return E_INVALIDARG
;
1144 len_utf8
= WideCharToMultiByte( CP_UTF8
, 0, str
, len
, NULL
, 0, NULL
, NULL
);
1145 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len_utf8
))) return E_OUTOFMEMORY
;
1146 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1147 WideCharToMultiByte( CP_UTF8
, 0, str
, len
, (char *)(*ret
)->value
.bytes
+ len_old
, len_utf8
, NULL
, NULL
);
1150 case WS_XML_TEXT_TYPE_BASE64
:
1152 const WS_XML_BASE64_TEXT
*base64
= (const WS_XML_BASE64_TEXT
*)text
;
1153 ULONG len
= ((4 * base64
->length
/ 3) + 3) & ~3;
1155 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1156 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1157 (*ret
)->value
.length
= encode_base64( base64
->bytes
, base64
->length
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1160 case WS_XML_TEXT_TYPE_BOOL
:
1162 const WS_XML_BOOL_TEXT
*bool_text
= (const WS_XML_BOOL_TEXT
*)text
;
1164 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ 5 ))) return E_OUTOFMEMORY
;
1165 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1166 (*ret
)->value
.length
= format_bool( &bool_text
->value
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1169 case WS_XML_TEXT_TYPE_INT32
:
1171 const WS_XML_INT32_TEXT
*int32_text
= (const WS_XML_INT32_TEXT
*)text
;
1172 unsigned char buf
[12]; /* "-2147483648" */
1173 ULONG len
= format_int32( &int32_text
->value
, buf
);
1175 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1176 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1177 memcpy( (*ret
)->value
.bytes
+ len_old
, buf
, len
);
1180 case WS_XML_TEXT_TYPE_INT64
:
1182 const WS_XML_INT64_TEXT
*int64_text
= (const WS_XML_INT64_TEXT
*)text
;
1183 unsigned char buf
[21]; /* "-9223372036854775808" */
1184 ULONG len
= format_int64( &int64_text
->value
, buf
);
1186 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1187 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1188 memcpy( (*ret
)->value
.bytes
+ len_old
, buf
, len
);
1191 case WS_XML_TEXT_TYPE_UINT64
:
1193 const WS_XML_UINT64_TEXT
*uint64_text
= (const WS_XML_UINT64_TEXT
*)text
;
1194 unsigned char buf
[21]; /* "18446744073709551615" */
1195 ULONG len
= format_uint64( &uint64_text
->value
, buf
);
1197 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1198 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1199 memcpy( (*ret
)->value
.bytes
+ len_old
, buf
, len
);
1202 case WS_XML_TEXT_TYPE_DOUBLE
:
1204 const WS_XML_DOUBLE_TEXT
*double_text
= (const WS_XML_DOUBLE_TEXT
*)text
;
1205 unsigned char buf
[32]; /* "-1.1111111111111111E-308", oversized to address Valgrind limitations */
1206 unsigned short fpword
;
1209 if (!set_fpword( 0x37f, &fpword
)) return E_NOTIMPL
;
1210 len
= format_double( &double_text
->value
, buf
);
1211 restore_fpword( fpword
);
1212 if (!len
) return E_NOTIMPL
;
1214 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1215 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1216 memcpy( (*ret
)->value
.bytes
+ len_old
, buf
, len
);
1219 case WS_XML_TEXT_TYPE_GUID
:
1221 const WS_XML_GUID_TEXT
*id
= (const WS_XML_GUID_TEXT
*)text
;
1223 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ 37 ))) return E_OUTOFMEMORY
;
1224 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1225 (*ret
)->value
.length
= format_guid( &id
->value
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1228 case WS_XML_TEXT_TYPE_UNIQUE_ID
:
1230 const WS_XML_UNIQUE_ID_TEXT
*id
= (const WS_XML_UNIQUE_ID_TEXT
*)text
;
1232 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ 46 ))) return E_OUTOFMEMORY
;
1233 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1234 (*ret
)->value
.length
= format_urn( &id
->value
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1237 case WS_XML_TEXT_TYPE_DATETIME
:
1239 const WS_XML_DATETIME_TEXT
*dt
= (const WS_XML_DATETIME_TEXT
*)text
;
1241 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ 34 ))) return E_OUTOFMEMORY
;
1242 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1243 (*ret
)->value
.length
= format_datetime( &dt
->value
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1246 case WS_XML_TEXT_TYPE_QNAME
:
1248 const WS_XML_QNAME_TEXT
*qn
= (const WS_XML_QNAME_TEXT
*)text
;
1249 ULONG len
= qn
->localName
->length
;
1251 if (qn
->prefix
&& qn
->prefix
->length
) len
+= qn
->prefix
->length
+ 1;
1252 if (!(*ret
= alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
1253 if (old
) memcpy( (*ret
)->value
.bytes
, old
->value
.bytes
, len_old
);
1254 (*ret
)->value
.length
= format_qname( qn
->prefix
, qn
->localName
, (*ret
)->value
.bytes
+ len_old
) + len_old
;
1258 FIXME( "unhandled text type %u\n", text
->textType
);
1263 static HRESULT
write_attribute_value_bin( struct writer
*writer
, const WS_XML_TEXT
*text
)
1265 enum record_type type
;
1266 BOOL use_dict
= FALSE
;
1270 if (text
&& text
->textType
== WS_XML_TEXT_TYPE_UTF8
)
1272 const WS_XML_UTF8_TEXT
*utf8
= (const WS_XML_UTF8_TEXT
*)text
;
1273 use_dict
= get_string_id( writer
, &utf8
->value
, &id
);
1275 type
= get_attr_text_record_type( text
, use_dict
);
1277 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1278 write_char( writer
, type
);
1282 case RECORD_CHARS8_TEXT
:
1284 const WS_XML_UTF8_TEXT
*text_utf8
;
1285 WS_XML_UTF8_TEXT
*new = NULL
;
1290 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1291 write_char( writer
, 0 );
1294 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
) text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
1297 if ((hr
= text_to_utf8text( text
, NULL
, NULL
, &new )) != S_OK
) return hr
;
1300 len
= text_utf8
->value
.length
;
1301 if ((hr
= write_grow_buffer( writer
, sizeof(len
) + len
)) != S_OK
)
1306 write_char( writer
, len
);
1307 write_bytes( writer
, text_utf8
->value
.bytes
, len
);
1311 case RECORD_CHARS16_TEXT
:
1313 const WS_XML_UTF8_TEXT
*text_utf8
;
1314 WS_XML_UTF8_TEXT
*new = NULL
;
1317 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
) text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
1320 if ((hr
= text_to_utf8text( text
, NULL
, NULL
, &new )) != S_OK
) return hr
;
1323 len
= text_utf8
->value
.length
;
1324 if ((hr
= write_grow_buffer( writer
, sizeof(len
) + len
)) != S_OK
)
1329 write_bytes( writer
, (const BYTE
*)&len
, sizeof(len
) );
1330 write_bytes( writer
, text_utf8
->value
.bytes
, len
);
1334 case RECORD_BYTES8_TEXT
:
1336 WS_XML_BASE64_TEXT
*text_base64
= (WS_XML_BASE64_TEXT
*)text
;
1337 if ((hr
= write_grow_buffer( writer
, 1 + text_base64
->length
)) != S_OK
) return hr
;
1338 write_char( writer
, text_base64
->length
);
1339 write_bytes( writer
, text_base64
->bytes
, text_base64
->length
);
1342 case RECORD_BYTES16_TEXT
:
1344 WS_XML_BASE64_TEXT
*text_base64
= (WS_XML_BASE64_TEXT
*)text
;
1345 UINT16 len
= text_base64
->length
;
1346 if ((hr
= write_grow_buffer( writer
, sizeof(len
) + len
)) != S_OK
) return hr
;
1347 write_bytes( writer
, (const BYTE
*)&len
, sizeof(len
) );
1348 write_bytes( writer
, text_base64
->bytes
, len
);
1351 case RECORD_ZERO_TEXT
:
1352 case RECORD_ONE_TEXT
:
1353 case RECORD_FALSE_TEXT
:
1354 case RECORD_TRUE_TEXT
:
1357 case RECORD_INT8_TEXT
:
1359 INT8 val
= get_text_value_int( text
);
1360 if ((hr
= write_grow_buffer( writer
, sizeof(val
) )) != S_OK
) return hr
;
1361 write_char( writer
, val
);
1364 case RECORD_INT16_TEXT
:
1366 INT16 val
= get_text_value_int( text
);
1367 if ((hr
= write_grow_buffer( writer
, sizeof(val
) )) != S_OK
) return hr
;
1368 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
1371 case RECORD_INT32_TEXT
:
1373 INT32 val
= get_text_value_int( text
);
1374 if ((hr
= write_grow_buffer( writer
, sizeof(val
) )) != S_OK
) return hr
;
1375 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
1378 case RECORD_INT64_TEXT
:
1380 INT64 val
= get_text_value_int( text
);
1381 if ((hr
= write_grow_buffer( writer
, sizeof(val
) )) != S_OK
) return hr
;
1382 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
1385 case RECORD_UINT64_TEXT
:
1387 WS_XML_UINT64_TEXT
*text_uint64
= (WS_XML_UINT64_TEXT
*)text
;
1388 if ((hr
= write_grow_buffer( writer
, sizeof(text_uint64
->value
) )) != S_OK
) return hr
;
1389 write_bytes( writer
, (const BYTE
*)&text_uint64
->value
, sizeof(text_uint64
->value
) );
1392 case RECORD_DOUBLE_TEXT
:
1394 WS_XML_DOUBLE_TEXT
*text_double
= (WS_XML_DOUBLE_TEXT
*)text
;
1395 if ((hr
= write_grow_buffer( writer
, sizeof(text_double
->value
) )) != S_OK
) return hr
;
1396 write_bytes( writer
, (const BYTE
*)&text_double
->value
, sizeof(text_double
->value
) );
1399 case RECORD_GUID_TEXT
:
1401 WS_XML_GUID_TEXT
*text_guid
= (WS_XML_GUID_TEXT
*)text
;
1402 if ((hr
= write_grow_buffer( writer
, sizeof(text_guid
->value
) )) != S_OK
) return hr
;
1403 write_bytes( writer
, (const BYTE
*)&text_guid
->value
, sizeof(text_guid
->value
) );
1406 case RECORD_UNIQUE_ID_TEXT
:
1408 WS_XML_UNIQUE_ID_TEXT
*text_unique_id
= (WS_XML_UNIQUE_ID_TEXT
*)text
;
1409 if ((hr
= write_grow_buffer( writer
, sizeof(text_unique_id
->value
) )) != S_OK
) return hr
;
1410 write_bytes( writer
, (const BYTE
*)&text_unique_id
->value
, sizeof(text_unique_id
->value
) );
1413 case RECORD_DATETIME_TEXT
:
1415 WS_XML_DATETIME_TEXT
*text_datetime
= (WS_XML_DATETIME_TEXT
*)text
;
1416 UINT64 val
= text_datetime
->value
.ticks
;
1418 assert( val
<= TICKS_MAX
);
1419 if (text_datetime
->value
.format
== WS_DATETIME_FORMAT_UTC
) val
|= (UINT64
)1 << 62;
1420 else if (text_datetime
->value
.format
== WS_DATETIME_FORMAT_LOCAL
) val
|= (UINT64
)1 << 63;
1422 if ((hr
= write_grow_buffer( writer
, sizeof(val
) )) != S_OK
) return hr
;
1423 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
1427 FIXME( "unhandled record type %02x\n", type
);
1432 static enum record_type
get_attr_record_type( const WS_XML_ATTRIBUTE
*attr
, BOOL use_dict
)
1434 if (!attr
->prefix
|| !attr
->prefix
->length
)
1436 if (use_dict
) return RECORD_SHORT_DICTIONARY_ATTRIBUTE
;
1437 return RECORD_SHORT_ATTRIBUTE
;
1439 if (attr
->prefix
->length
== 1 && attr
->prefix
->bytes
[0] >= 'a' && attr
->prefix
->bytes
[0] <= 'z')
1441 if (use_dict
) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A
+ attr
->prefix
->bytes
[0] - 'a';
1442 return RECORD_PREFIX_ATTRIBUTE_A
+ attr
->prefix
->bytes
[0] - 'a';
1444 if (use_dict
) return RECORD_DICTIONARY_ATTRIBUTE
;
1445 return RECORD_ATTRIBUTE
;
1448 static HRESULT
write_attribute_bin( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
1451 enum record_type type
= get_attr_record_type( attr
, get_string_id(writer
, attr
->localName
, &id
) );
1454 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1455 write_char( writer
, type
);
1457 if (type
>= RECORD_PREFIX_ATTRIBUTE_A
&& type
<= RECORD_PREFIX_ATTRIBUTE_Z
)
1459 if ((hr
= write_string( writer
, attr
->localName
->bytes
, attr
->localName
->length
)) != S_OK
) return hr
;
1460 return write_attribute_value_bin( writer
, attr
->value
);
1462 if (type
>= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A
&& type
<= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z
)
1464 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1465 return write_attribute_value_bin( writer
, attr
->value
);
1470 case RECORD_SHORT_ATTRIBUTE
:
1471 if ((hr
= write_string( writer
, attr
->localName
->bytes
, attr
->localName
->length
)) != S_OK
) return hr
;
1474 case RECORD_ATTRIBUTE
:
1475 if ((hr
= write_string( writer
, attr
->prefix
->bytes
, attr
->prefix
->length
)) != S_OK
) return hr
;
1476 if ((hr
= write_string( writer
, attr
->localName
->bytes
, attr
->localName
->length
)) != S_OK
) return hr
;
1479 case RECORD_SHORT_DICTIONARY_ATTRIBUTE
:
1480 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1483 case RECORD_DICTIONARY_ATTRIBUTE
:
1484 if ((hr
= write_string( writer
, attr
->prefix
->bytes
, attr
->prefix
->length
)) != S_OK
) return hr
;
1485 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1489 ERR( "unhandled record type %02x\n", type
);
1490 return WS_E_NOT_SUPPORTED
;
1493 return write_attribute_value_bin( writer
, attr
->value
);
1496 static HRESULT
write_attribute( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
1498 switch (writer
->output_enc
)
1500 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_attribute_text( writer
, attr
);
1501 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_attribute_bin( writer
, attr
);
1503 ERR( "unhandled encoding %u\n", writer
->output_enc
);
1504 return WS_E_NOT_SUPPORTED
;
1508 static inline BOOL
is_current_namespace( struct writer
*writer
, const WS_XML_STRING
*ns
)
1510 return (WsXmlStringEquals( writer
->current_ns
, ns
, NULL
) == S_OK
);
1513 /**************************************************************************
1514 * WsGetPrefixFromNamespace [webservices.@]
1516 HRESULT WINAPI
WsGetPrefixFromNamespace( WS_XML_WRITER
*handle
, const WS_XML_STRING
*ns
,
1517 BOOL required
, const WS_XML_STRING
**prefix
,
1520 struct writer
*writer
= (struct writer
*)handle
;
1521 WS_XML_ELEMENT_NODE
*elem
;
1525 TRACE( "%p %s %d %p %p\n", handle
, debugstr_xmlstr(ns
), required
, prefix
, error
);
1526 if (error
) FIXME( "ignoring error parameter\n" );
1528 if (!writer
|| !ns
|| !prefix
) return E_INVALIDARG
;
1530 EnterCriticalSection( &writer
->cs
);
1532 if (writer
->magic
!= WRITER_MAGIC
)
1534 LeaveCriticalSection( &writer
->cs
);
1535 return E_INVALIDARG
;
1538 elem
= &writer
->current
->hdr
;
1539 if (elem
->prefix
&& is_current_namespace( writer
, ns
))
1541 *prefix
= elem
->prefix
;
1547 if (required
) hr
= WS_E_INVALID_FORMAT
;
1555 LeaveCriticalSection( &writer
->cs
);
1556 TRACE( "returning %08x\n", hr
);
1560 static HRESULT
write_namespace_attribute_text( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
1562 unsigned char quote
= attr
->singleQuote
? '\'' : '"';
1566 /* ' xmlns:prefix="namespace"' */
1568 size
= attr
->ns
->length
+ 9 /* ' xmlns=""' */;
1569 if (attr
->prefix
&& attr
->prefix
->length
) size
+= attr
->prefix
->length
+ 1 /* ':' */;
1570 if ((hr
= write_grow_buffer( writer
, size
)) != S_OK
) return hr
;
1572 write_bytes( writer
, (const BYTE
*)" xmlns", 6 );
1573 if (attr
->prefix
&& attr
->prefix
->length
)
1575 write_char( writer
, ':' );
1576 write_bytes( writer
, attr
->prefix
->bytes
, attr
->prefix
->length
);
1578 write_char( writer
, '=' );
1579 write_char( writer
, quote
);
1580 write_bytes( writer
, attr
->ns
->bytes
, attr
->ns
->length
);
1581 write_char( writer
, quote
);
1586 static enum record_type
get_xmlns_record_type( const WS_XML_ATTRIBUTE
*attr
, BOOL use_dict
)
1588 if (!attr
->prefix
|| !attr
->prefix
->length
)
1590 if (use_dict
) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE
;
1591 return RECORD_SHORT_XMLNS_ATTRIBUTE
;
1593 if (use_dict
) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE
;
1594 return RECORD_XMLNS_ATTRIBUTE
;
1597 static HRESULT
write_namespace_attribute_bin( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
1600 enum record_type type
= get_xmlns_record_type( attr
, get_string_id(writer
, attr
->ns
, &id
) );
1603 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1604 write_char( writer
, type
);
1608 case RECORD_SHORT_XMLNS_ATTRIBUTE
:
1611 case RECORD_XMLNS_ATTRIBUTE
:
1612 if ((hr
= write_string( writer
, attr
->prefix
->bytes
, attr
->prefix
->length
)) != S_OK
) return hr
;
1615 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE
:
1616 return write_dict_string( writer
, id
);
1618 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE
:
1619 if ((hr
= write_string( writer
, attr
->prefix
->bytes
, attr
->prefix
->length
)) != S_OK
) return hr
;
1620 return write_dict_string( writer
, id
);
1623 ERR( "unhandled record type %02x\n", type
);
1624 return WS_E_NOT_SUPPORTED
;
1627 return write_string( writer
, attr
->ns
->bytes
, attr
->ns
->length
);
1630 static HRESULT
write_namespace_attribute( struct writer
*writer
, const WS_XML_ATTRIBUTE
*attr
)
1632 switch (writer
->output_enc
)
1634 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_namespace_attribute_text( writer
, attr
);
1635 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_namespace_attribute_bin( writer
, attr
);
1637 ERR( "unhandled encoding %u\n", writer
->output_enc
);
1638 return WS_E_NOT_SUPPORTED
;
1642 static HRESULT
add_namespace_attribute( struct writer
*writer
, const WS_XML_STRING
*prefix
,
1643 const WS_XML_STRING
*ns
, BOOL single
)
1645 WS_XML_ATTRIBUTE
*attr
;
1646 WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
1649 if (!(attr
= heap_alloc_zero( sizeof(*attr
) ))) return E_OUTOFMEMORY
;
1651 attr
->singleQuote
= !!single
;
1653 if (prefix
&& !(attr
->prefix
= dup_xml_string( prefix
, writer
->dict_do_lookup
)))
1655 free_attribute( attr
);
1656 return E_OUTOFMEMORY
;
1658 if (!(attr
->ns
= dup_xml_string( ns
, writer
->dict_do_lookup
)))
1660 free_attribute( attr
);
1661 return E_OUTOFMEMORY
;
1663 if ((hr
= append_attribute( elem
, attr
)) != S_OK
)
1665 free_attribute( attr
);
1671 static inline BOOL
str_equal( const WS_XML_STRING
*str1
, const WS_XML_STRING
*str2
)
1673 if (!str1
&& !str2
) return TRUE
;
1674 return WsXmlStringEquals( str1
, str2
, NULL
) == S_OK
;
1677 static BOOL
namespace_in_scope( const WS_XML_ELEMENT_NODE
*elem
, const WS_XML_STRING
*prefix
,
1678 const WS_XML_STRING
*ns
)
1681 const struct node
*node
;
1683 for (node
= (const struct node
*)elem
; node
; node
= node
->parent
)
1685 if (node_type( node
) != WS_XML_NODE_TYPE_ELEMENT
) break;
1688 for (i
= 0; i
< elem
->attributeCount
; i
++)
1690 if (!elem
->attributes
[i
]->isXmlNs
) continue;
1691 if (str_equal( elem
->attributes
[i
]->prefix
, prefix
) &&
1692 str_equal( elem
->attributes
[i
]->ns
, ns
)) return TRUE
;
1698 static HRESULT
set_current_namespace( struct writer
*writer
, const WS_XML_STRING
*ns
)
1701 if (!(str
= dup_xml_string( ns
, writer
->dict_do_lookup
))) return E_OUTOFMEMORY
;
1702 free_xml_string( writer
->current_ns
);
1703 writer
->current_ns
= str
;
1707 static HRESULT
set_namespaces( struct writer
*writer
)
1709 WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
1713 if (elem
->ns
->length
&& !namespace_in_scope( elem
, elem
->prefix
, elem
->ns
))
1715 if ((hr
= add_namespace_attribute( writer
, elem
->prefix
, elem
->ns
, FALSE
)) != S_OK
) return hr
;
1716 if ((hr
= set_current_namespace( writer
, elem
->ns
)) != S_OK
) return hr
;
1719 for (i
= 0; i
< elem
->attributeCount
; i
++)
1721 const WS_XML_ATTRIBUTE
*attr
= elem
->attributes
[i
];
1722 if (!attr
->ns
->length
|| namespace_in_scope( elem
, attr
->prefix
, attr
->ns
)) continue;
1723 if ((hr
= add_namespace_attribute( writer
, attr
->prefix
, attr
->ns
, FALSE
)) != S_OK
) return hr
;
1729 /**************************************************************************
1730 * WsWriteEndAttribute [webservices.@]
1732 HRESULT WINAPI
WsWriteEndAttribute( WS_XML_WRITER
*handle
, WS_ERROR
*error
)
1734 struct writer
*writer
= (struct writer
*)handle
;
1737 TRACE( "%p %p\n", handle
, error
);
1738 if (error
) FIXME( "ignoring error parameter\n" );
1740 if (!writer
) return E_INVALIDARG
;
1742 EnterCriticalSection( &writer
->cs
);
1744 if (writer
->magic
!= WRITER_MAGIC
)
1746 LeaveCriticalSection( &writer
->cs
);
1747 return E_INVALIDARG
;
1750 writer
->state
= WRITER_STATE_STARTELEMENT
;
1752 LeaveCriticalSection( &writer
->cs
);
1753 TRACE( "returning %08x\n", hr
);
1757 static HRESULT
write_attributes( struct writer
*writer
, const WS_XML_ELEMENT_NODE
*elem
)
1761 for (i
= 0; i
< elem
->attributeCount
; i
++)
1763 if (elem
->attributes
[i
]->isXmlNs
) continue;
1764 if ((hr
= write_attribute( writer
, elem
->attributes
[i
] )) != S_OK
) return hr
;
1766 for (i
= 0; i
< elem
->attributeCount
; i
++)
1768 if (!elem
->attributes
[i
]->isXmlNs
|| !elem
->attributes
[i
]->prefix
) continue;
1769 if ((hr
= write_namespace_attribute( writer
, elem
->attributes
[i
] )) != S_OK
) return hr
;
1771 for (i
= 0; i
< elem
->attributeCount
; i
++)
1773 if (!elem
->attributes
[i
]->isXmlNs
|| elem
->attributes
[i
]->prefix
) continue;
1774 if ((hr
= write_namespace_attribute( writer
, elem
->attributes
[i
] )) != S_OK
) return hr
;
1779 static HRESULT
write_startelement_text( struct writer
*writer
)
1781 const WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
1785 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"'... */
1787 size
= elem
->localName
->length
+ 1 /* '<' */;
1788 if (elem
->prefix
&& elem
->prefix
->length
) size
+= elem
->prefix
->length
+ 1 /* ':' */;
1789 if ((hr
= write_grow_buffer( writer
, size
)) != S_OK
) return hr
;
1791 write_char( writer
, '<' );
1792 if (elem
->prefix
&& elem
->prefix
->length
)
1794 write_bytes( writer
, elem
->prefix
->bytes
, elem
->prefix
->length
);
1795 write_char( writer
, ':' );
1797 write_bytes( writer
, elem
->localName
->bytes
, elem
->localName
->length
);
1798 return write_attributes( writer
, elem
);
1801 static enum record_type
get_elem_record_type( const WS_XML_ELEMENT_NODE
*elem
, BOOL use_dict
)
1803 if (!elem
->prefix
|| !elem
->prefix
->length
)
1805 if (use_dict
) return RECORD_SHORT_DICTIONARY_ELEMENT
;
1806 return RECORD_SHORT_ELEMENT
;
1808 if (elem
->prefix
->length
== 1 && elem
->prefix
->bytes
[0] >= 'a' && elem
->prefix
->bytes
[0] <= 'z')
1810 if (use_dict
) return RECORD_PREFIX_DICTIONARY_ELEMENT_A
+ elem
->prefix
->bytes
[0] - 'a';
1811 return RECORD_PREFIX_ELEMENT_A
+ elem
->prefix
->bytes
[0] - 'a';
1813 if (use_dict
) return RECORD_DICTIONARY_ELEMENT
;
1814 return RECORD_ELEMENT
;
1817 static HRESULT
write_startelement_bin( struct writer
*writer
)
1819 const WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
1821 enum record_type type
= get_elem_record_type( elem
, get_string_id(writer
, elem
->localName
, &id
) );
1824 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1825 write_char( writer
, type
);
1827 if (type
>= RECORD_PREFIX_ELEMENT_A
&& type
<= RECORD_PREFIX_ELEMENT_Z
)
1829 if ((hr
= write_string( writer
, elem
->localName
->bytes
, elem
->localName
->length
)) != S_OK
) return hr
;
1830 return write_attributes( writer
, elem
);
1832 if (type
>= RECORD_PREFIX_DICTIONARY_ELEMENT_A
&& type
<= RECORD_PREFIX_DICTIONARY_ELEMENT_Z
)
1834 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1835 return write_attributes( writer
, elem
);
1840 case RECORD_SHORT_ELEMENT
:
1841 if ((hr
= write_string( writer
, elem
->localName
->bytes
, elem
->localName
->length
)) != S_OK
) return hr
;
1844 case RECORD_ELEMENT
:
1845 if ((hr
= write_string( writer
, elem
->prefix
->bytes
, elem
->prefix
->length
)) != S_OK
) return hr
;
1846 if ((hr
= write_string( writer
, elem
->localName
->bytes
, elem
->localName
->length
)) != S_OK
) return hr
;
1849 case RECORD_SHORT_DICTIONARY_ELEMENT
:
1850 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1853 case RECORD_DICTIONARY_ELEMENT
:
1854 if ((hr
= write_string( writer
, elem
->prefix
->bytes
, elem
->prefix
->length
)) != S_OK
) return hr
;
1855 if ((hr
= write_dict_string( writer
, id
)) != S_OK
) return hr
;
1859 ERR( "unhandled record type %02x\n", type
);
1860 return WS_E_NOT_SUPPORTED
;
1863 return write_attributes( writer
, elem
);
1866 static HRESULT
write_startelement( struct writer
*writer
)
1868 switch (writer
->output_enc
)
1870 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_startelement_text( writer
);
1871 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_startelement_bin( writer
);
1873 ERR( "unhandled encoding %u\n", writer
->output_enc
);
1874 return WS_E_NOT_SUPPORTED
;
1878 static struct node
*write_find_startelement( struct writer
*writer
)
1881 for (node
= writer
->current
; node
; node
= node
->parent
)
1883 if (node_type( node
) == WS_XML_NODE_TYPE_ELEMENT
) return node
;
1888 static inline BOOL
is_empty_element( const struct node
*node
)
1890 const struct node
*head
= LIST_ENTRY( list_head( &node
->children
), struct node
, entry
);
1891 return node_type( head
) == WS_XML_NODE_TYPE_END_ELEMENT
;
1894 static HRESULT
write_endelement_text( struct writer
*writer
, const WS_XML_ELEMENT_NODE
*elem
)
1901 if (elem
->isEmpty
&& writer
->state
!= WRITER_STATE_ENDSTARTELEMENT
)
1903 if ((hr
= write_grow_buffer( writer
, 2 )) != S_OK
) return hr
;
1904 write_char( writer
, '/' );
1905 write_char( writer
, '>' );
1909 /* '</prefix:localname>' */
1911 size
= elem
->localName
->length
+ 3 /* '</>' */;
1912 if (elem
->prefix
&& elem
->prefix
->length
) size
+= elem
->prefix
->length
+ 1 /* ':' */;
1913 if ((hr
= write_grow_buffer( writer
, size
)) != S_OK
) return hr
;
1915 write_char( writer
, '<' );
1916 write_char( writer
, '/' );
1917 if (elem
->prefix
&& elem
->prefix
->length
)
1919 write_bytes( writer
, elem
->prefix
->bytes
, elem
->prefix
->length
);
1920 write_char( writer
, ':' );
1922 write_bytes( writer
, elem
->localName
->bytes
, elem
->localName
->length
);
1923 write_char( writer
, '>' );
1927 static HRESULT
write_endelement_bin( struct writer
*writer
)
1930 if (node_type( writer
->current
) == WS_XML_NODE_TYPE_TEXT
) return S_OK
;
1931 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
1932 write_char( writer
, RECORD_ENDELEMENT
);
1936 static HRESULT
write_endelement( struct writer
*writer
, const WS_XML_ELEMENT_NODE
*elem
)
1938 switch (writer
->output_enc
)
1940 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_endelement_text( writer
, elem
);
1941 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_endelement_bin( writer
);
1943 ERR( "unhandled encoding %u\n", writer
->output_enc
);
1944 return WS_E_NOT_SUPPORTED
;
1948 static HRESULT
write_close_element( struct writer
*writer
, struct node
*node
)
1950 WS_XML_ELEMENT_NODE
*elem
= &node
->hdr
;
1951 elem
->isEmpty
= is_empty_element( node
);
1952 return write_endelement( writer
, elem
);
1955 static HRESULT
write_endelement_node( struct writer
*writer
)
1960 if (!(node
= write_find_startelement( writer
))) return WS_E_INVALID_FORMAT
;
1961 if (writer
->state
== WRITER_STATE_STARTELEMENT
)
1963 if ((hr
= set_namespaces( writer
)) != S_OK
) return hr
;
1964 if ((hr
= write_startelement( writer
)) != S_OK
) return hr
;
1966 if ((hr
= write_close_element( writer
, node
)) != S_OK
) return hr
;
1967 writer
->current
= node
->parent
;
1968 writer
->state
= WRITER_STATE_ENDELEMENT
;
1972 /**************************************************************************
1973 * WsWriteEndElement [webservices.@]
1975 HRESULT WINAPI
WsWriteEndElement( WS_XML_WRITER
*handle
, WS_ERROR
*error
)
1977 struct writer
*writer
= (struct writer
*)handle
;
1980 TRACE( "%p %p\n", handle
, error
);
1981 if (error
) FIXME( "ignoring error parameter\n" );
1983 if (!writer
) return E_INVALIDARG
;
1985 EnterCriticalSection( &writer
->cs
);
1987 if (writer
->magic
!= WRITER_MAGIC
)
1989 LeaveCriticalSection( &writer
->cs
);
1990 return E_INVALIDARG
;
1993 hr
= write_endelement_node( writer
);
1995 LeaveCriticalSection( &writer
->cs
);
1996 TRACE( "returning %08x\n", hr
);
2000 static HRESULT
write_endstartelement_text( struct writer
*writer
)
2003 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
2004 write_char( writer
, '>' );
2008 static HRESULT
write_endstartelement( struct writer
*writer
)
2010 switch (writer
->output_enc
)
2012 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_endstartelement_text( writer
);
2013 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return S_OK
;
2015 ERR( "unhandled encoding %u\n", writer
->output_enc
);
2016 return WS_E_NOT_SUPPORTED
;
2020 /**************************************************************************
2021 * WsWriteEndStartElement [webservices.@]
2023 HRESULT WINAPI
WsWriteEndStartElement( WS_XML_WRITER
*handle
, WS_ERROR
*error
)
2025 struct writer
*writer
= (struct writer
*)handle
;
2028 TRACE( "%p %p\n", handle
, error
);
2029 if (error
) FIXME( "ignoring error parameter\n" );
2031 if (!writer
) return E_INVALIDARG
;
2033 EnterCriticalSection( &writer
->cs
);
2035 if (writer
->magic
!= WRITER_MAGIC
)
2037 LeaveCriticalSection( &writer
->cs
);
2038 return E_INVALIDARG
;
2041 if (writer
->state
!= WRITER_STATE_STARTELEMENT
) hr
= WS_E_INVALID_OPERATION
;
2044 if ((hr
= set_namespaces( writer
)) != S_OK
) goto done
;
2045 if ((hr
= write_startelement( writer
)) != S_OK
) goto done
;
2046 if ((hr
= write_endstartelement( writer
)) != S_OK
) goto done
;
2047 writer
->state
= WRITER_STATE_ENDSTARTELEMENT
;
2051 LeaveCriticalSection( &writer
->cs
);
2052 TRACE( "returning %08x\n", hr
);
2056 static HRESULT
write_add_attribute( struct writer
*writer
, const WS_XML_STRING
*prefix
,
2057 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
,
2060 WS_XML_ATTRIBUTE
*attr
;
2061 WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
2064 if (!(attr
= heap_alloc_zero( sizeof(*attr
) ))) return E_OUTOFMEMORY
;
2066 if (!prefix
&& ns
->length
) prefix
= elem
->prefix
;
2068 attr
->singleQuote
= !!single
;
2069 if (prefix
&& !(attr
->prefix
= dup_xml_string( prefix
, writer
->dict_do_lookup
)))
2071 free_attribute( attr
);
2072 return E_OUTOFMEMORY
;
2074 if (!(attr
->localName
= dup_xml_string( localname
, writer
->dict_do_lookup
)))
2076 free_attribute( attr
);
2077 return E_OUTOFMEMORY
;
2079 if (!(attr
->ns
= dup_xml_string( ns
, writer
->dict_do_lookup
)))
2081 free_attribute( attr
);
2082 return E_OUTOFMEMORY
;
2084 if ((hr
= append_attribute( elem
, attr
)) != S_OK
)
2086 free_attribute( attr
);
2092 /**************************************************************************
2093 * WsWriteStartAttribute [webservices.@]
2095 HRESULT WINAPI
WsWriteStartAttribute( WS_XML_WRITER
*handle
, const WS_XML_STRING
*prefix
,
2096 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
,
2097 BOOL single
, WS_ERROR
*error
)
2099 struct writer
*writer
= (struct writer
*)handle
;
2102 TRACE( "%p %s %s %s %d %p\n", handle
, debugstr_xmlstr(prefix
), debugstr_xmlstr(localname
),
2103 debugstr_xmlstr(ns
), single
, error
);
2104 if (error
) FIXME( "ignoring error parameter\n" );
2106 if (!writer
|| !localname
|| !ns
) return E_INVALIDARG
;
2108 EnterCriticalSection( &writer
->cs
);
2110 if (writer
->magic
!= WRITER_MAGIC
)
2112 LeaveCriticalSection( &writer
->cs
);
2113 return E_INVALIDARG
;
2116 if (writer
->state
!= WRITER_STATE_STARTELEMENT
) hr
= WS_E_INVALID_OPERATION
;
2117 else if ((hr
= write_add_attribute( writer
, prefix
, localname
, ns
, single
)) == S_OK
)
2118 writer
->state
= WRITER_STATE_STARTATTRIBUTE
;
2120 LeaveCriticalSection( &writer
->cs
);
2121 TRACE( "returning %08x\n", hr
);
2125 /* flush current start element if necessary */
2126 static HRESULT
write_commit( struct writer
*writer
)
2128 if (writer
->state
== WRITER_STATE_STARTELEMENT
)
2131 if ((hr
= set_namespaces( writer
)) != S_OK
) return hr
;
2132 if ((hr
= write_startelement( writer
)) != S_OK
) return hr
;
2133 if ((hr
= write_endstartelement( writer
)) != S_OK
) return hr
;
2134 writer
->state
= WRITER_STATE_ENDSTARTELEMENT
;
2139 static HRESULT
write_add_cdata_node( struct writer
*writer
)
2141 struct node
*node
, *parent
;
2142 if (!(parent
= find_parent( writer
))) return WS_E_INVALID_FORMAT
;
2143 if (!(node
= alloc_node( WS_XML_NODE_TYPE_CDATA
))) return E_OUTOFMEMORY
;
2144 write_insert_node( writer
, parent
, node
);
2148 static HRESULT
write_add_endcdata_node( struct writer
*writer
)
2151 if (!(node
= alloc_node( WS_XML_NODE_TYPE_END_CDATA
))) return E_OUTOFMEMORY
;
2152 node
->parent
= writer
->current
;
2153 list_add_tail( &node
->parent
->children
, &node
->entry
);
2157 static HRESULT
write_cdata( struct writer
*writer
)
2160 if ((hr
= write_grow_buffer( writer
, 9 )) != S_OK
) return hr
;
2161 write_bytes( writer
, (const BYTE
*)"<![CDATA[", 9 );
2165 static HRESULT
write_cdata_node( struct writer
*writer
)
2168 if ((hr
= write_commit( writer
)) != S_OK
) return hr
;
2169 if ((hr
= write_add_cdata_node( writer
)) != S_OK
) return hr
;
2170 if ((hr
= write_add_endcdata_node( writer
)) != S_OK
) return hr
;
2171 if ((hr
= write_cdata( writer
)) != S_OK
) return hr
;
2172 writer
->state
= WRITER_STATE_STARTCDATA
;
2176 /**************************************************************************
2177 * WsWriteStartCData [webservices.@]
2179 HRESULT WINAPI
WsWriteStartCData( WS_XML_WRITER
*handle
, WS_ERROR
*error
)
2181 struct writer
*writer
= (struct writer
*)handle
;
2184 TRACE( "%p %p\n", handle
, error
);
2185 if (error
) FIXME( "ignoring error parameter\n" );
2187 if (!writer
) return E_INVALIDARG
;
2189 EnterCriticalSection( &writer
->cs
);
2191 if (writer
->magic
!= WRITER_MAGIC
)
2193 LeaveCriticalSection( &writer
->cs
);
2194 return E_INVALIDARG
;
2197 hr
= write_cdata_node( writer
);
2199 LeaveCriticalSection( &writer
->cs
);
2200 TRACE( "returning %08x\n", hr
);
2204 static HRESULT
write_endcdata( struct writer
*writer
)
2207 if ((hr
= write_grow_buffer( writer
, 3 )) != S_OK
) return hr
;
2208 write_bytes( writer
, (const BYTE
*)"]]>", 3 );
2212 static HRESULT
write_endcdata_node( struct writer
*writer
)
2215 if ((hr
= write_endcdata( writer
)) != S_OK
) return hr
;
2216 writer
->current
= writer
->current
->parent
;
2217 writer
->state
= WRITER_STATE_ENDCDATA
;
2221 /**************************************************************************
2222 * WsWriteEndCData [webservices.@]
2224 HRESULT WINAPI
WsWriteEndCData( WS_XML_WRITER
*handle
, WS_ERROR
*error
)
2226 struct writer
*writer
= (struct writer
*)handle
;
2229 TRACE( "%p %p\n", handle
, error
);
2230 if (error
) FIXME( "ignoring error parameter\n" );
2232 if (!writer
) return E_INVALIDARG
;
2234 EnterCriticalSection( &writer
->cs
);
2236 if (writer
->magic
!= WRITER_MAGIC
)
2238 LeaveCriticalSection( &writer
->cs
);
2239 return E_INVALIDARG
;
2242 if (writer
->state
!= WRITER_STATE_TEXT
) hr
= WS_E_INVALID_OPERATION
;
2243 else hr
= write_endcdata_node( writer
);
2245 LeaveCriticalSection( &writer
->cs
);
2246 TRACE( "returning %08x\n", hr
);
2250 static HRESULT
write_add_element_node( struct writer
*writer
, const WS_XML_STRING
*prefix
,
2251 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
)
2253 struct node
*node
, *parent
;
2254 WS_XML_ELEMENT_NODE
*elem
;
2256 if (!(parent
= find_parent( writer
))) return WS_E_INVALID_FORMAT
;
2258 if (!prefix
&& node_type( parent
) == WS_XML_NODE_TYPE_ELEMENT
)
2260 elem
= &parent
->hdr
;
2261 if (WsXmlStringEquals( ns
, elem
->ns
, NULL
) == S_OK
) prefix
= elem
->prefix
;
2264 if (!(node
= alloc_node( WS_XML_NODE_TYPE_ELEMENT
))) return E_OUTOFMEMORY
;
2267 if (prefix
&& !(elem
->prefix
= dup_xml_string( prefix
, writer
->dict_do_lookup
)))
2270 return E_OUTOFMEMORY
;
2272 if (!(elem
->localName
= dup_xml_string( localname
, writer
->dict_do_lookup
)))
2275 return E_OUTOFMEMORY
;
2277 if (!(elem
->ns
= dup_xml_string( ns
, writer
->dict_do_lookup
)))
2280 return E_OUTOFMEMORY
;
2282 write_insert_node( writer
, parent
, node
);
2286 static HRESULT
write_add_endelement_node( struct writer
*writer
, struct node
*parent
)
2289 if (!(node
= alloc_node( WS_XML_NODE_TYPE_END_ELEMENT
))) return E_OUTOFMEMORY
;
2290 node
->parent
= parent
;
2291 list_add_tail( &parent
->children
, &node
->entry
);
2295 static HRESULT
write_element_node( struct writer
*writer
, const WS_XML_STRING
*prefix
,
2296 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
)
2299 if ((hr
= write_commit( writer
)) != S_OK
) return hr
;
2300 if ((hr
= write_add_element_node( writer
, prefix
, localname
, ns
)) != S_OK
) return hr
;
2301 if ((hr
= write_add_endelement_node( writer
, writer
->current
)) != S_OK
) return hr
;
2302 writer
->state
= WRITER_STATE_STARTELEMENT
;
2306 /**************************************************************************
2307 * WsWriteStartElement [webservices.@]
2309 HRESULT WINAPI
WsWriteStartElement( WS_XML_WRITER
*handle
, const WS_XML_STRING
*prefix
,
2310 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
,
2313 struct writer
*writer
= (struct writer
*)handle
;
2316 TRACE( "%p %s %s %s %p\n", handle
, debugstr_xmlstr(prefix
), debugstr_xmlstr(localname
),
2317 debugstr_xmlstr(ns
), error
);
2318 if (error
) FIXME( "ignoring error parameter\n" );
2320 if (!writer
|| !localname
|| !ns
) return E_INVALIDARG
;
2322 EnterCriticalSection( &writer
->cs
);
2324 if (writer
->magic
!= WRITER_MAGIC
)
2326 LeaveCriticalSection( &writer
->cs
);
2327 return E_INVALIDARG
;
2330 hr
= write_element_node( writer
, prefix
, localname
, ns
);
2332 LeaveCriticalSection( &writer
->cs
);
2333 TRACE( "returning %08x\n", hr
);
2337 HRESULT
text_to_text( const WS_XML_TEXT
*text
, const WS_XML_TEXT
*old
, ULONG
*offset
, WS_XML_TEXT
**ret
)
2339 if (offset
) *offset
= 0;
2340 switch (text
->textType
)
2342 case WS_XML_TEXT_TYPE_UTF8
:
2344 const WS_XML_UTF8_TEXT
*utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2345 const WS_XML_UTF8_TEXT
*utf8_old
= (const WS_XML_UTF8_TEXT
*)old
;
2346 WS_XML_UTF8_TEXT
*new;
2347 ULONG len
= utf8
->value
.length
, len_old
= utf8_old
? utf8_old
->value
.length
: 0;
2349 if (!(new = alloc_utf8_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
2350 if (utf8_old
) memcpy( new->value
.bytes
, utf8_old
->value
.bytes
, len_old
);
2351 memcpy( new->value
.bytes
+ len_old
, utf8
->value
.bytes
, len
);
2352 if (offset
) *offset
= len_old
;
2356 case WS_XML_TEXT_TYPE_UTF16
:
2358 const WS_XML_UTF16_TEXT
*utf16
= (const WS_XML_UTF16_TEXT
*)text
;
2359 const WS_XML_UTF16_TEXT
*utf16_old
= (const WS_XML_UTF16_TEXT
*)old
;
2360 WS_XML_UTF16_TEXT
*new;
2361 ULONG len
= utf16
->byteCount
, len_old
= utf16_old
? utf16_old
->byteCount
: 0;
2363 if (utf16
->byteCount
% sizeof(WCHAR
)) return E_INVALIDARG
;
2364 if (!(new = alloc_utf16_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
2365 if (utf16_old
) memcpy( new->bytes
, utf16_old
->bytes
, len_old
);
2366 memcpy( new->bytes
+ len_old
, utf16
->bytes
, len
);
2367 if (offset
) *offset
= len_old
;
2371 case WS_XML_TEXT_TYPE_BASE64
:
2373 const WS_XML_BASE64_TEXT
*base64
= (const WS_XML_BASE64_TEXT
*)text
;
2374 const WS_XML_BASE64_TEXT
*base64_old
= (const WS_XML_BASE64_TEXT
*)old
;
2375 WS_XML_BASE64_TEXT
*new;
2376 ULONG len
= base64
->length
, len_old
= base64_old
? base64_old
->length
: 0;
2378 if (!(new = alloc_base64_text( NULL
, len_old
+ len
))) return E_OUTOFMEMORY
;
2379 if (base64_old
) memcpy( new->bytes
, base64_old
->bytes
, len_old
);
2380 memcpy( new->bytes
+ len_old
, base64
->bytes
, len
);
2381 if (offset
) *offset
= len_old
;
2385 case WS_XML_TEXT_TYPE_BOOL
:
2387 const WS_XML_BOOL_TEXT
*bool_text
= (const WS_XML_BOOL_TEXT
*)text
;
2388 WS_XML_BOOL_TEXT
*new;
2390 if (!(new = alloc_bool_text( bool_text
->value
))) return E_OUTOFMEMORY
;
2394 case WS_XML_TEXT_TYPE_INT32
:
2396 const WS_XML_INT32_TEXT
*int32_text
= (const WS_XML_INT32_TEXT
*)text
;
2397 WS_XML_INT32_TEXT
*new;
2399 if (!(new = alloc_int32_text( int32_text
->value
))) return E_OUTOFMEMORY
;
2403 case WS_XML_TEXT_TYPE_INT64
:
2405 const WS_XML_INT64_TEXT
*int64_text
= (const WS_XML_INT64_TEXT
*)text
;
2406 WS_XML_INT64_TEXT
*new;
2408 if (!(new = alloc_int64_text( int64_text
->value
))) return E_OUTOFMEMORY
;
2412 case WS_XML_TEXT_TYPE_UINT64
:
2414 const WS_XML_UINT64_TEXT
*uint64_text
= (const WS_XML_UINT64_TEXT
*)text
;
2415 WS_XML_UINT64_TEXT
*new;
2417 if (!(new = alloc_uint64_text( uint64_text
->value
))) return E_OUTOFMEMORY
;
2421 case WS_XML_TEXT_TYPE_DOUBLE
:
2423 const WS_XML_DOUBLE_TEXT
*double_text
= (const WS_XML_DOUBLE_TEXT
*)text
;
2424 WS_XML_DOUBLE_TEXT
*new;
2426 if (!(new = alloc_double_text( double_text
->value
))) return E_OUTOFMEMORY
;
2430 case WS_XML_TEXT_TYPE_GUID
:
2432 const WS_XML_GUID_TEXT
*id
= (const WS_XML_GUID_TEXT
*)text
;
2433 WS_XML_GUID_TEXT
*new;
2435 if (!(new = alloc_guid_text( &id
->value
))) return E_OUTOFMEMORY
;
2439 case WS_XML_TEXT_TYPE_UNIQUE_ID
:
2441 const WS_XML_UNIQUE_ID_TEXT
*id
= (const WS_XML_UNIQUE_ID_TEXT
*)text
;
2442 WS_XML_UNIQUE_ID_TEXT
*new;
2444 if (!(new = alloc_unique_id_text( &id
->value
))) return E_OUTOFMEMORY
;
2448 case WS_XML_TEXT_TYPE_DATETIME
:
2450 const WS_XML_DATETIME_TEXT
*dt
= (const WS_XML_DATETIME_TEXT
*)text
;
2451 WS_XML_DATETIME_TEXT
*new;
2453 if (!(new = alloc_datetime_text( &dt
->value
))) return E_OUTOFMEMORY
;
2458 FIXME( "unhandled text type %u\n", text
->textType
);
2463 static HRESULT
write_set_attribute_value( struct writer
*writer
, const WS_XML_TEXT
*value
)
2465 WS_XML_ELEMENT_NODE
*elem
= &writer
->current
->hdr
;
2468 switch (value
->textType
)
2470 case WS_XML_TEXT_TYPE_UTF8
:
2471 case WS_XML_TEXT_TYPE_UTF16
:
2472 case WS_XML_TEXT_TYPE_BASE64
:
2475 case WS_XML_TEXT_TYPE_BOOL
:
2476 case WS_XML_TEXT_TYPE_INT32
:
2477 case WS_XML_TEXT_TYPE_INT64
:
2478 case WS_XML_TEXT_TYPE_UINT64
:
2479 case WS_XML_TEXT_TYPE_DOUBLE
:
2480 case WS_XML_TEXT_TYPE_GUID
:
2481 case WS_XML_TEXT_TYPE_UNIQUE_ID
:
2482 case WS_XML_TEXT_TYPE_DATETIME
:
2483 if (elem
->attributes
[elem
->attributeCount
- 1]->value
) return WS_E_INVALID_OPERATION
;
2487 FIXME( "unhandled text type %u\n", value
->textType
);
2491 switch (writer
->output_enc
)
2493 case WS_XML_WRITER_ENCODING_TYPE_TEXT
:
2495 WS_XML_UTF8_TEXT
*new, *old
= (WS_XML_UTF8_TEXT
*)elem
->attributes
[elem
->attributeCount
- 1]->value
;
2496 if ((hr
= text_to_utf8text( value
, old
, NULL
, &new )) != S_OK
) return hr
;
2498 elem
->attributes
[elem
->attributeCount
- 1]->value
= &new->text
;
2501 case WS_XML_WRITER_ENCODING_TYPE_BINARY
:
2503 WS_XML_TEXT
*new, *old
= elem
->attributes
[elem
->attributeCount
- 1]->value
;
2504 if ((hr
= text_to_text( value
, old
, NULL
, &new )) != S_OK
) return hr
;
2506 elem
->attributes
[elem
->attributeCount
- 1]->value
= new;
2510 FIXME( "unhandled output encoding %u\n", writer
->output_enc
);
2517 static HRESULT
write_add_text_node( struct writer
*writer
, const WS_XML_TEXT
*value
)
2520 WS_XML_TEXT_NODE
*text
;
2523 if (node_type( writer
->current
) != WS_XML_NODE_TYPE_ELEMENT
&&
2524 node_type( writer
->current
) != WS_XML_NODE_TYPE_BOF
&&
2525 node_type( writer
->current
) != WS_XML_NODE_TYPE_CDATA
) return WS_E_INVALID_FORMAT
;
2527 if (!(node
= alloc_node( WS_XML_NODE_TYPE_TEXT
))) return E_OUTOFMEMORY
;
2528 text
= (WS_XML_TEXT_NODE
*)node
;
2530 switch (writer
->output_enc
)
2532 case WS_XML_WRITER_ENCODING_TYPE_TEXT
:
2534 WS_XML_UTF8_TEXT
*new;
2535 if ((hr
= text_to_utf8text( value
, NULL
, NULL
, &new )) != S_OK
)
2540 text
->text
= &new->text
;
2543 case WS_XML_WRITER_ENCODING_TYPE_BINARY
:
2546 if ((hr
= text_to_text( value
, NULL
, NULL
, &new )) != S_OK
)
2555 FIXME( "unhandled output encoding %u\n", writer
->output_enc
);
2560 write_insert_node( writer
, writer
->current
, node
);
2564 static HRESULT
write_text_text( struct writer
*writer
, const WS_XML_TEXT
*text
, ULONG offset
)
2566 const WS_XML_UTF8_TEXT
*utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2569 if (node_type( writer
->current
->parent
) == WS_XML_NODE_TYPE_ELEMENT
)
2571 const struct escape
*escapes
[3] = { &escape_lt
, &escape_gt
, &escape_amp
};
2572 return write_bytes_escape( writer
, utf8
->value
.bytes
+ offset
, utf8
->value
.length
- offset
, escapes
, 3 );
2574 else if (node_type( writer
->current
->parent
) == WS_XML_NODE_TYPE_CDATA
)
2576 if ((hr
= write_grow_buffer( writer
, utf8
->value
.length
- offset
)) != S_OK
) return hr
;
2577 write_bytes( writer
, utf8
->value
.bytes
+ offset
, utf8
->value
.length
- offset
);
2581 return WS_E_INVALID_FORMAT
;
2584 static enum record_type
get_text_record_type( const WS_XML_TEXT
*text
, BOOL use_dict
)
2586 switch (text
->textType
)
2588 case WS_XML_TEXT_TYPE_UTF8
:
2590 const WS_XML_UTF8_TEXT
*text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2591 if (use_dict
) return RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT
;
2592 if (text_utf8
->value
.length
<= MAX_UINT8
) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT
;
2593 if (text_utf8
->value
.length
<= MAX_UINT16
) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT
;
2594 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT
;
2596 case WS_XML_TEXT_TYPE_UTF16
:
2598 const WS_XML_UTF16_TEXT
*text_utf16
= (const WS_XML_UTF16_TEXT
*)text
;
2599 int len
= text_utf16
->byteCount
/ sizeof(WCHAR
);
2600 int len_utf8
= WideCharToMultiByte( CP_UTF8
, 0, (const WCHAR
*)text_utf16
->bytes
, len
, NULL
, 0, NULL
, NULL
);
2601 if (len_utf8
<= MAX_UINT8
) return RECORD_CHARS8_TEXT_WITH_ENDELEMENT
;
2602 if (len_utf8
<= MAX_UINT16
) return RECORD_CHARS16_TEXT_WITH_ENDELEMENT
;
2603 return RECORD_CHARS32_TEXT_WITH_ENDELEMENT
;
2605 case WS_XML_TEXT_TYPE_BASE64
:
2607 const WS_XML_BASE64_TEXT
*text_base64
= (const WS_XML_BASE64_TEXT
*)text
;
2608 ULONG rem
= text_base64
->length
% 3, len
= text_base64
->length
- rem
;
2609 if (len
<= MAX_UINT8
) return RECORD_BYTES8_TEXT
;
2610 if (len
<= MAX_UINT16
) return RECORD_BYTES16_TEXT
;
2611 return RECORD_BYTES32_TEXT
;
2613 case WS_XML_TEXT_TYPE_BOOL
:
2615 const WS_XML_BOOL_TEXT
*text_bool
= (const WS_XML_BOOL_TEXT
*)text
;
2616 return text_bool
->value
? RECORD_TRUE_TEXT_WITH_ENDELEMENT
: RECORD_FALSE_TEXT_WITH_ENDELEMENT
;
2618 case WS_XML_TEXT_TYPE_INT32
:
2620 const WS_XML_INT32_TEXT
*text_int32
= (const WS_XML_INT32_TEXT
*)text
;
2621 if (!text_int32
->value
) return RECORD_ZERO_TEXT_WITH_ENDELEMENT
;
2622 if (text_int32
->value
== 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT
;
2623 if (text_int32
->value
>= MIN_INT8
&& text_int32
->value
<= MAX_INT8
) return RECORD_INT8_TEXT_WITH_ENDELEMENT
;
2624 if (text_int32
->value
>= MIN_INT16
&& text_int32
->value
<= MAX_INT16
) return RECORD_INT16_TEXT_WITH_ENDELEMENT
;
2625 return RECORD_INT32_TEXT_WITH_ENDELEMENT
;
2627 case WS_XML_TEXT_TYPE_INT64
:
2629 const WS_XML_INT64_TEXT
*text_int64
= (const WS_XML_INT64_TEXT
*)text
;
2630 if (!text_int64
->value
) return RECORD_ZERO_TEXT_WITH_ENDELEMENT
;
2631 if (text_int64
->value
== 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT
;
2632 if (text_int64
->value
>= MIN_INT8
&& text_int64
->value
<= MAX_INT8
) return RECORD_INT8_TEXT_WITH_ENDELEMENT
;
2633 if (text_int64
->value
>= MIN_INT16
&& text_int64
->value
<= MAX_INT16
) return RECORD_INT16_TEXT_WITH_ENDELEMENT
;
2634 if (text_int64
->value
>= MIN_INT32
&& text_int64
->value
<= MAX_INT32
) return RECORD_INT32_TEXT_WITH_ENDELEMENT
;
2635 return RECORD_INT64_TEXT_WITH_ENDELEMENT
;
2637 case WS_XML_TEXT_TYPE_UINT64
:
2639 const WS_XML_UINT64_TEXT
*text_uint64
= (const WS_XML_UINT64_TEXT
*)text
;
2640 if (!text_uint64
->value
) return RECORD_ZERO_TEXT_WITH_ENDELEMENT
;
2641 if (text_uint64
->value
== 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT
;
2642 if (text_uint64
->value
<= MAX_INT8
) return RECORD_INT8_TEXT_WITH_ENDELEMENT
;
2643 if (text_uint64
->value
<= MAX_INT16
) return RECORD_INT16_TEXT_WITH_ENDELEMENT
;
2644 if (text_uint64
->value
<= MAX_INT32
) return RECORD_INT32_TEXT_WITH_ENDELEMENT
;
2645 if (text_uint64
->value
<= MAX_INT64
) return RECORD_INT64_TEXT_WITH_ENDELEMENT
;
2646 return RECORD_UINT64_TEXT_WITH_ENDELEMENT
;
2648 case WS_XML_TEXT_TYPE_DOUBLE
:
2650 const WS_XML_DOUBLE_TEXT
*text_double
= (const WS_XML_DOUBLE_TEXT
*)text
;
2651 if (!text_double
->value
) return RECORD_ZERO_TEXT_WITH_ENDELEMENT
;
2652 if (text_double
->value
== 1) return RECORD_ONE_TEXT_WITH_ENDELEMENT
;
2653 if (isinf( text_double
->value
) || (INT64
)text_double
->value
!= text_double
->value
)
2654 return RECORD_DOUBLE_TEXT_WITH_ENDELEMENT
;
2655 if (text_double
->value
<= MAX_INT8
) return RECORD_INT8_TEXT_WITH_ENDELEMENT
;
2656 if (text_double
->value
<= MAX_INT16
) return RECORD_INT16_TEXT_WITH_ENDELEMENT
;
2657 if (text_double
->value
<= MAX_INT32
) return RECORD_INT32_TEXT_WITH_ENDELEMENT
;
2658 return RECORD_INT64_TEXT_WITH_ENDELEMENT
;
2660 case WS_XML_TEXT_TYPE_GUID
:
2661 return RECORD_GUID_TEXT_WITH_ENDELEMENT
;
2663 case WS_XML_TEXT_TYPE_UNIQUE_ID
:
2664 return RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT
;
2666 case WS_XML_TEXT_TYPE_DATETIME
:
2667 return RECORD_DATETIME_TEXT_WITH_ENDELEMENT
;
2670 FIXME( "unhandled text type %u\n", text
->textType
);
2675 static HRESULT
write_text_bin( struct writer
*writer
, const WS_XML_TEXT
*text
, ULONG offset
)
2677 enum record_type type
;
2678 BOOL use_dict
= FALSE
;
2684 FIXME( "no support for appending text in binary mode\n" );
2688 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
)
2690 const WS_XML_UTF8_TEXT
*utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2691 use_dict
= get_string_id( writer
, &utf8
->value
, &id
);
2694 switch ((type
= get_text_record_type( text
, use_dict
)))
2696 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT
:
2698 const WS_XML_UTF8_TEXT
*text_utf8
;
2699 WS_XML_UTF8_TEXT
*new = NULL
;
2702 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
) text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2705 if ((hr
= text_to_utf8text( text
, NULL
, NULL
, &new )) != S_OK
) return hr
;
2708 len
= text_utf8
->value
.length
;
2709 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(len
) + len
)) != S_OK
)
2714 write_char( writer
, type
);
2715 write_char( writer
, len
);
2716 write_bytes( writer
, text_utf8
->value
.bytes
, len
);
2720 case RECORD_CHARS16_TEXT_WITH_ENDELEMENT
:
2722 const WS_XML_UTF8_TEXT
*text_utf8
;
2723 WS_XML_UTF8_TEXT
*new = NULL
;
2726 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
) text_utf8
= (const WS_XML_UTF8_TEXT
*)text
;
2729 if ((hr
= text_to_utf8text( text
, NULL
, NULL
, &new )) != S_OK
) return hr
;
2732 len
= text_utf8
->value
.length
;
2733 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(len
) + len
)) != S_OK
)
2738 write_char( writer
, type
);
2739 write_bytes( writer
, (const BYTE
*)&len
, sizeof(len
) );
2740 write_bytes( writer
, text_utf8
->value
.bytes
, len
);
2744 case RECORD_BYTES8_TEXT
:
2746 const WS_XML_BASE64_TEXT
*text_base64
= (const WS_XML_BASE64_TEXT
*)text
;
2747 UINT8 rem
= text_base64
->length
% 3, len
= text_base64
->length
- rem
;
2751 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(len
) + len
)) != S_OK
) return hr
;
2752 write_char( writer
, rem
? RECORD_BYTES8_TEXT
: RECORD_BYTES8_TEXT_WITH_ENDELEMENT
);
2753 write_char( writer
, len
);
2754 write_bytes( writer
, text_base64
->bytes
, len
);
2758 if ((hr
= write_grow_buffer( writer
, 3 )) != S_OK
) return hr
;
2759 write_char( writer
, RECORD_BYTES8_TEXT_WITH_ENDELEMENT
);
2760 write_char( writer
, rem
);
2761 write_bytes( writer
, (const BYTE
*)text_base64
->bytes
+ len
, rem
);
2765 case RECORD_BYTES16_TEXT
:
2767 const WS_XML_BASE64_TEXT
*text_base64
= (const WS_XML_BASE64_TEXT
*)text
;
2768 UINT16 rem
= text_base64
->length
% 3, len
= text_base64
->length
- rem
;
2772 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(len
) + len
)) != S_OK
) return hr
;
2773 write_char( writer
, rem
? RECORD_BYTES16_TEXT
: RECORD_BYTES16_TEXT_WITH_ENDELEMENT
);
2774 write_bytes( writer
, (const BYTE
*)&len
, sizeof(len
) );
2775 write_bytes( writer
, text_base64
->bytes
, len
);
2779 if ((hr
= write_grow_buffer( writer
, 3 )) != S_OK
) return hr
;
2780 write_char( writer
, RECORD_BYTES8_TEXT_WITH_ENDELEMENT
);
2781 write_char( writer
, rem
);
2782 write_bytes( writer
, (const BYTE
*)text_base64
->bytes
+ len
, rem
);
2786 case RECORD_ZERO_TEXT_WITH_ENDELEMENT
:
2787 case RECORD_ONE_TEXT_WITH_ENDELEMENT
:
2788 case RECORD_FALSE_TEXT_WITH_ENDELEMENT
:
2789 case RECORD_TRUE_TEXT_WITH_ENDELEMENT
:
2791 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
2792 write_char( writer
, type
);
2795 case RECORD_INT8_TEXT_WITH_ENDELEMENT
:
2797 INT8 val
= get_text_value_int( text
);
2798 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(val
) )) != S_OK
) return hr
;
2799 write_char( writer
, type
);
2800 write_char( writer
, val
);
2803 case RECORD_INT16_TEXT_WITH_ENDELEMENT
:
2805 INT16 val
= get_text_value_int( text
);
2806 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(val
) )) != S_OK
) return hr
;
2807 write_char( writer
, type
);
2808 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
2811 case RECORD_INT32_TEXT_WITH_ENDELEMENT
:
2813 INT32 val
= get_text_value_int( text
);
2814 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(val
) )) != S_OK
) return hr
;
2815 write_char( writer
, type
);
2816 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
2819 case RECORD_INT64_TEXT_WITH_ENDELEMENT
:
2821 INT64 val
= get_text_value_int( text
);
2822 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(val
) )) != S_OK
) return hr
;
2823 write_char( writer
, type
);
2824 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
2827 case RECORD_UINT64_TEXT_WITH_ENDELEMENT
:
2829 WS_XML_UINT64_TEXT
*text_uint64
= (WS_XML_UINT64_TEXT
*)text
;
2830 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(text_uint64
->value
) )) != S_OK
) return hr
;
2831 write_char( writer
, type
);
2832 write_bytes( writer
, (const BYTE
*)&text_uint64
->value
, sizeof(text_uint64
->value
) );
2835 case RECORD_DOUBLE_TEXT_WITH_ENDELEMENT
:
2837 WS_XML_DOUBLE_TEXT
*text_double
= (WS_XML_DOUBLE_TEXT
*)text
;
2838 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(text_double
->value
) )) != S_OK
) return hr
;
2839 write_char( writer
, type
);
2840 write_bytes( writer
, (const BYTE
*)&text_double
->value
, sizeof(text_double
->value
) );
2843 case RECORD_GUID_TEXT_WITH_ENDELEMENT
:
2845 WS_XML_GUID_TEXT
*text_guid
= (WS_XML_GUID_TEXT
*)text
;
2846 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(text_guid
->value
) )) != S_OK
) return hr
;
2847 write_char( writer
, type
);
2848 write_bytes( writer
, (const BYTE
*)&text_guid
->value
, sizeof(text_guid
->value
) );
2851 case RECORD_UNIQUE_ID_TEXT_WITH_ENDELEMENT
:
2853 WS_XML_UNIQUE_ID_TEXT
*text_unique_id
= (WS_XML_UNIQUE_ID_TEXT
*)text
;
2854 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(text_unique_id
->value
) )) != S_OK
) return hr
;
2855 write_char( writer
, type
);
2856 write_bytes( writer
, (const BYTE
*)&text_unique_id
->value
, sizeof(text_unique_id
->value
) );
2859 case RECORD_DATETIME_TEXT_WITH_ENDELEMENT
:
2861 WS_XML_DATETIME_TEXT
*text_datetime
= (WS_XML_DATETIME_TEXT
*)text
;
2862 UINT64 val
= text_datetime
->value
.ticks
;
2864 assert( val
<= TICKS_MAX
);
2865 if (text_datetime
->value
.format
== WS_DATETIME_FORMAT_UTC
) val
|= (UINT64
)1 << 62;
2866 else if (text_datetime
->value
.format
== WS_DATETIME_FORMAT_LOCAL
) val
|= (UINT64
)1 << 63;
2868 if ((hr
= write_grow_buffer( writer
, 1 + sizeof(val
) )) != S_OK
) return hr
;
2869 write_char( writer
, type
);
2870 write_bytes( writer
, (const BYTE
*)&val
, sizeof(val
) );
2873 case RECORD_DICTIONARY_TEXT_WITH_ENDELEMENT
:
2875 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
2876 write_char( writer
, type
);
2877 return write_dict_string( writer
, id
);
2880 FIXME( "unhandled record type %02x\n", type
);
2885 static HRESULT
write_text( struct writer
*writer
, const WS_XML_TEXT
*text
, ULONG offset
)
2887 if (!writer
->current
->parent
) return WS_E_INVALID_FORMAT
;
2889 switch (writer
->output_enc
)
2891 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_text_text( writer
, text
, offset
);
2892 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_text_bin( writer
, text
, offset
);
2894 ERR( "unhandled encoding %u\n", writer
->output_enc
);
2895 return WS_E_NOT_SUPPORTED
;
2899 static HRESULT
write_text_node( struct writer
*writer
, const WS_XML_TEXT
*text
)
2901 WS_XML_TEXT_NODE
*node
= (WS_XML_TEXT_NODE
*)writer
->current
;
2905 if ((hr
= write_commit( writer
)) != S_OK
) return hr
;
2906 if (node_type( writer
->current
) != WS_XML_NODE_TYPE_TEXT
)
2908 if ((hr
= write_add_text_node( writer
, text
)) != S_OK
) return hr
;
2909 node
= (WS_XML_TEXT_NODE
*)writer
->current
;
2913 switch (writer
->output_enc
)
2915 case WS_XML_WRITER_ENCODING_TYPE_TEXT
:
2917 WS_XML_UTF8_TEXT
*new, *old
= (WS_XML_UTF8_TEXT
*)node
->text
;
2918 offset
= old
->value
.length
;
2919 if ((hr
= text_to_utf8text( text
, old
, &offset
, &new )) != S_OK
) return hr
;
2921 node
->text
= &new->text
;
2924 case WS_XML_WRITER_ENCODING_TYPE_BINARY
:
2926 WS_XML_TEXT
*new, *old
= node
->text
;
2927 if ((hr
= text_to_text( text
, old
, &offset
, &new )) != S_OK
) return hr
;
2933 FIXME( "unhandled output encoding %u\n", writer
->output_enc
);
2938 if ((hr
= write_text( writer
, node
->text
, offset
)) != S_OK
) return hr
;
2940 writer
->state
= WRITER_STATE_TEXT
;
2944 /**************************************************************************
2945 * WsWriteText [webservices.@]
2947 HRESULT WINAPI
WsWriteText( WS_XML_WRITER
*handle
, const WS_XML_TEXT
*text
, WS_ERROR
*error
)
2949 struct writer
*writer
= (struct writer
*)handle
;
2952 TRACE( "%p %p %p\n", handle
, text
, error
);
2953 if (error
) FIXME( "ignoring error parameter\n" );
2955 if (!writer
|| !text
) return E_INVALIDARG
;
2957 EnterCriticalSection( &writer
->cs
);
2959 if (writer
->magic
!= WRITER_MAGIC
)
2961 LeaveCriticalSection( &writer
->cs
);
2962 return E_INVALIDARG
;
2965 if (writer
->state
== WRITER_STATE_STARTATTRIBUTE
) hr
= write_set_attribute_value( writer
, text
);
2966 else hr
= write_text_node( writer
, text
);
2968 LeaveCriticalSection( &writer
->cs
);
2969 TRACE( "returning %08x\n", hr
);
2973 /**************************************************************************
2974 * WsWriteBytes [webservices.@]
2976 HRESULT WINAPI
WsWriteBytes( WS_XML_WRITER
*handle
, const void *bytes
, ULONG count
, WS_ERROR
*error
)
2978 struct writer
*writer
= (struct writer
*)handle
;
2979 WS_XML_BASE64_TEXT base64
;
2982 TRACE( "%p %p %u %p\n", handle
, bytes
, count
, error
);
2983 if (error
) FIXME( "ignoring error parameter\n" );
2985 if (!writer
) return E_INVALIDARG
;
2987 EnterCriticalSection( &writer
->cs
);
2989 if (writer
->magic
!= WRITER_MAGIC
)
2991 LeaveCriticalSection( &writer
->cs
);
2992 return E_INVALIDARG
;
2995 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
2998 base64
.text
.textType
= WS_XML_TEXT_TYPE_BASE64
;
2999 base64
.bytes
= (BYTE
*)bytes
;
3000 base64
.length
= count
;
3002 if (writer
->state
== WRITER_STATE_STARTATTRIBUTE
) hr
= write_set_attribute_value( writer
, &base64
.text
);
3003 else hr
= write_text_node( writer
, &base64
.text
);
3006 LeaveCriticalSection( &writer
->cs
);
3007 TRACE( "returning %08x\n", hr
);
3011 /**************************************************************************
3012 * WsWriteChars [webservices.@]
3014 HRESULT WINAPI
WsWriteChars( WS_XML_WRITER
*handle
, const WCHAR
*chars
, ULONG count
, WS_ERROR
*error
)
3016 struct writer
*writer
= (struct writer
*)handle
;
3017 WS_XML_UTF16_TEXT utf16
;
3020 TRACE( "%p %s %u %p\n", handle
, debugstr_wn(chars
, count
), count
, error
);
3021 if (error
) FIXME( "ignoring error parameter\n" );
3023 if (!writer
) return E_INVALIDARG
;
3025 EnterCriticalSection( &writer
->cs
);
3027 if (writer
->magic
!= WRITER_MAGIC
)
3029 LeaveCriticalSection( &writer
->cs
);
3030 return E_INVALIDARG
;
3033 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
3036 utf16
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
3037 utf16
.bytes
= (BYTE
*)chars
;
3038 utf16
.byteCount
= count
* sizeof(WCHAR
);
3040 if (writer
->state
== WRITER_STATE_STARTATTRIBUTE
) hr
= write_set_attribute_value( writer
, &utf16
.text
);
3041 else hr
= write_text_node( writer
, &utf16
.text
);
3044 LeaveCriticalSection( &writer
->cs
);
3045 TRACE( "returning %08x\n", hr
);
3049 /**************************************************************************
3050 * WsWriteCharsUtf8 [webservices.@]
3052 HRESULT WINAPI
WsWriteCharsUtf8( WS_XML_WRITER
*handle
, const BYTE
*bytes
, ULONG count
, WS_ERROR
*error
)
3054 struct writer
*writer
= (struct writer
*)handle
;
3055 WS_XML_UTF8_TEXT utf8
;
3058 TRACE( "%p %s %u %p\n", handle
, debugstr_an((const char *)bytes
, count
), count
, error
);
3059 if (error
) FIXME( "ignoring error parameter\n" );
3061 if (!writer
) return E_INVALIDARG
;
3063 EnterCriticalSection( &writer
->cs
);
3065 if (writer
->magic
!= WRITER_MAGIC
)
3067 LeaveCriticalSection( &writer
->cs
);
3068 return E_INVALIDARG
;
3071 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
3074 utf8
.text
.textType
= WS_XML_TEXT_TYPE_UTF8
;
3075 utf8
.value
.bytes
= (BYTE
*)bytes
;
3076 utf8
.value
.length
= count
;
3078 if (writer
->state
== WRITER_STATE_STARTATTRIBUTE
) hr
= write_set_attribute_value( writer
, &utf8
.text
);
3079 else hr
= write_text_node( writer
, &utf8
.text
);
3082 LeaveCriticalSection( &writer
->cs
);
3083 TRACE( "returning %08x\n", hr
);
3087 static HRESULT
write_type_text( struct writer
*writer
, WS_TYPE_MAPPING mapping
, const WS_XML_TEXT
*text
)
3091 case WS_ELEMENT_TYPE_MAPPING
:
3092 case WS_ELEMENT_CONTENT_TYPE_MAPPING
:
3093 return write_text_node( writer
, text
);
3095 case WS_ATTRIBUTE_TYPE_MAPPING
:
3096 return write_set_attribute_value( writer
, text
);
3098 case WS_ANY_ELEMENT_TYPE_MAPPING
:
3099 switch (writer
->state
)
3101 case WRITER_STATE_STARTATTRIBUTE
:
3102 return write_set_attribute_value( writer
, text
);
3104 case WRITER_STATE_STARTELEMENT
:
3105 return write_text_node( writer
, text
);
3108 FIXME( "writer state %u not handled\n", writer
->state
);
3113 FIXME( "mapping %u not implemented\n", mapping
);
3118 static HRESULT
write_add_nil_attribute( struct writer
*writer
)
3120 static const WS_XML_STRING prefix
= {1, (BYTE
*)"a"};
3121 static const WS_XML_STRING localname
= {3, (BYTE
*)"nil"};
3122 static const WS_XML_STRING ns
= {41, (BYTE
*)"http://www.w3.org/2001/XMLSchema-instance"};
3123 static const WS_XML_UTF8_TEXT value
= {{WS_XML_TEXT_TYPE_UTF8
}, {4, (BYTE
*)"true"}};
3126 if ((hr
= write_add_attribute( writer
, &prefix
, &localname
, &ns
, FALSE
)) != S_OK
) return hr
;
3127 if ((hr
= write_set_attribute_value( writer
, &value
.text
)) != S_OK
) return hr
;
3128 return add_namespace_attribute( writer
, &prefix
, &ns
, FALSE
);
3131 static HRESULT
get_value_ptr( WS_WRITE_OPTION option
, const void *value
, ULONG size
, ULONG expected_size
,
3136 case WS_WRITE_REQUIRED_VALUE
:
3137 case WS_WRITE_NILLABLE_VALUE
:
3138 if (!value
|| size
!= expected_size
) return E_INVALIDARG
;
3142 case WS_WRITE_REQUIRED_POINTER
:
3143 if (size
!= sizeof(const void *) || !(*ptr
= *(const void **)value
)) return E_INVALIDARG
;
3146 case WS_WRITE_NILLABLE_POINTER
:
3147 if (size
!= sizeof(const void *)) return E_INVALIDARG
;
3148 *ptr
= *(const void **)value
;
3152 return E_INVALIDARG
;
3156 static HRESULT
write_type_bool( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3157 const WS_BOOL_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3158 const BOOL
*value
, ULONG size
)
3160 WS_XML_BOOL_TEXT text_bool
;
3166 FIXME( "description not supported\n" );
3170 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3171 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(BOOL
), (const void **)&ptr
)) != S_OK
) return hr
;
3172 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3174 text_bool
.text
.textType
= WS_XML_TEXT_TYPE_BOOL
;
3175 text_bool
.value
= *ptr
;
3176 return write_type_text( writer
, mapping
, &text_bool
.text
);
3179 static HRESULT
write_type_int8( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3180 const WS_INT8_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3181 const BOOL
*value
, ULONG size
)
3183 WS_XML_INT32_TEXT text_int32
;
3189 FIXME( "description not supported\n" );
3193 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3194 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(INT8
), (const void **)&ptr
)) != S_OK
) return hr
;
3195 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3197 text_int32
.text
.textType
= WS_XML_TEXT_TYPE_INT32
;
3198 text_int32
.value
= *ptr
;
3199 return write_type_text( writer
, mapping
, &text_int32
.text
);
3202 static HRESULT
write_type_int16( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3203 const WS_INT16_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3204 const BOOL
*value
, ULONG size
)
3206 WS_XML_INT32_TEXT text_int32
;
3212 FIXME( "description not supported\n" );
3216 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3217 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(INT16
), (const void **)&ptr
)) != S_OK
) return hr
;
3218 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3220 text_int32
.text
.textType
= WS_XML_TEXT_TYPE_INT32
;
3221 text_int32
.value
= *ptr
;
3222 return write_type_text( writer
, mapping
, &text_int32
.text
);
3225 static HRESULT
write_type_int32( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3226 const WS_INT32_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3227 const void *value
, ULONG size
)
3229 WS_XML_INT32_TEXT text_int32
;
3235 FIXME( "description not supported\n" );
3239 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3240 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(INT32
), (const void **)&ptr
)) != S_OK
) return hr
;
3241 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3243 text_int32
.text
.textType
= WS_XML_TEXT_TYPE_INT32
;
3244 text_int32
.value
= *ptr
;
3245 return write_type_text( writer
, mapping
, &text_int32
.text
);
3248 static HRESULT
write_type_int64( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3249 const WS_INT64_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3250 const void *value
, ULONG size
)
3252 WS_XML_INT64_TEXT text_int64
;
3258 FIXME( "description not supported\n" );
3262 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3263 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(INT64
), (const void **)&ptr
)) != S_OK
) return hr
;
3264 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3266 text_int64
.text
.textType
= WS_XML_TEXT_TYPE_INT64
;
3267 text_int64
.value
= *ptr
;
3268 return write_type_text( writer
, mapping
, &text_int64
.text
);
3271 static HRESULT
write_type_uint8( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3272 const WS_UINT8_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3273 const void *value
, ULONG size
)
3275 WS_XML_UINT64_TEXT text_uint64
;
3281 FIXME( "description not supported\n" );
3285 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3286 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(UINT8
), (const void **)&ptr
)) != S_OK
) return hr
;
3287 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3289 text_uint64
.text
.textType
= WS_XML_TEXT_TYPE_UINT64
;
3290 text_uint64
.value
= *ptr
;
3291 return write_type_text( writer
, mapping
, &text_uint64
.text
);
3294 static HRESULT
write_type_uint16( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3295 const WS_UINT16_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3296 const void *value
, ULONG size
)
3298 WS_XML_UINT64_TEXT text_uint64
;
3304 FIXME( "description not supported\n" );
3308 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3309 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(UINT16
), (const void **)&ptr
)) != S_OK
) return hr
;
3310 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3312 text_uint64
.text
.textType
= WS_XML_TEXT_TYPE_UINT64
;
3313 text_uint64
.value
= *ptr
;
3314 return write_type_text( writer
, mapping
, &text_uint64
.text
);
3317 static HRESULT
write_type_uint32( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3318 const WS_UINT32_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3319 const void *value
, ULONG size
)
3321 WS_XML_UINT64_TEXT text_uint64
;
3327 FIXME( "description not supported\n" );
3331 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3332 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(UINT32
), (const void **)&ptr
)) != S_OK
) return hr
;
3333 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3335 text_uint64
.text
.textType
= WS_XML_TEXT_TYPE_UINT64
;
3336 text_uint64
.value
= *ptr
;
3337 return write_type_text( writer
, mapping
, &text_uint64
.text
);
3340 static HRESULT
write_type_uint64( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3341 const WS_UINT64_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3342 const void *value
, ULONG size
)
3344 WS_XML_UINT64_TEXT text_uint64
;
3350 FIXME( "description not supported\n" );
3354 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3355 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(UINT64
), (const void **)&ptr
)) != S_OK
) return hr
;
3356 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3358 text_uint64
.text
.textType
= WS_XML_TEXT_TYPE_UINT64
;
3359 text_uint64
.value
= *ptr
;
3360 return write_type_text( writer
, mapping
, &text_uint64
.text
);
3363 static HRESULT
write_type_double( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3364 const WS_DOUBLE_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3365 const void *value
, ULONG size
)
3367 WS_XML_DOUBLE_TEXT text_double
;
3373 FIXME( "description not supported\n" );
3377 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3378 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(double), (const void **)&ptr
)) != S_OK
) return hr
;
3379 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3381 text_double
.text
.textType
= WS_XML_TEXT_TYPE_DOUBLE
;
3382 text_double
.value
= *ptr
;
3383 return write_type_text( writer
, mapping
, &text_double
.text
);
3386 static HRESULT
write_type_datetime( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3387 const WS_DATETIME_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3388 const void *value
, ULONG size
)
3390 WS_XML_DATETIME_TEXT text_datetime
;
3391 const WS_DATETIME
*ptr
;
3396 FIXME( "description not supported\n" );
3400 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3401 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(WS_DATETIME
), (const void **)&ptr
)) != S_OK
) return hr
;
3402 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3403 if (ptr
->ticks
> TICKS_MAX
|| ptr
->format
> WS_DATETIME_FORMAT_NONE
) return WS_E_INVALID_FORMAT
;
3405 text_datetime
.text
.textType
= WS_XML_TEXT_TYPE_DATETIME
;
3406 text_datetime
.value
= *ptr
;
3407 return write_type_text( writer
, mapping
, &text_datetime
.text
);
3410 static HRESULT
write_type_guid( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3411 const WS_GUID_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3412 const void *value
, ULONG size
)
3414 WS_XML_GUID_TEXT text_guid
;
3420 FIXME( "description not supported\n" );
3424 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3425 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(GUID
), (const void **)&ptr
)) != S_OK
) return hr
;
3426 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3428 text_guid
.text
.textType
= WS_XML_TEXT_TYPE_GUID
;
3429 text_guid
.value
= *ptr
;
3430 return write_type_text( writer
, mapping
, &text_guid
.text
);
3433 static HRESULT
write_type_unique_id( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3434 const WS_UNIQUE_ID_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3435 const void *value
, ULONG size
)
3437 WS_XML_UNIQUE_ID_TEXT text_unique_id
;
3438 WS_XML_UTF16_TEXT text_utf16
;
3439 const WS_UNIQUE_ID
*ptr
;
3444 FIXME( "description not supported\n" );
3448 if (!option
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3449 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(*ptr
), (const void **)&ptr
)) != S_OK
) return hr
;
3450 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3452 if (ptr
->uri
.length
)
3454 text_utf16
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
3455 text_utf16
.bytes
= (BYTE
*)ptr
->uri
.chars
;
3456 text_utf16
.byteCount
= ptr
->uri
.length
* sizeof(WCHAR
);
3457 return write_type_text( writer
, mapping
, &text_utf16
.text
);
3460 text_unique_id
.text
.textType
= WS_XML_TEXT_TYPE_UNIQUE_ID
;
3461 text_unique_id
.value
= ptr
->guid
;
3462 return write_type_text( writer
, mapping
, &text_unique_id
.text
);
3465 static HRESULT
write_type_string( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3466 const WS_STRING_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3467 const void *value
, ULONG size
)
3469 WS_XML_UTF16_TEXT utf16
;
3470 const WS_STRING
*ptr
;
3475 FIXME( "description not supported\n" );
3479 if (!option
) return E_INVALIDARG
;
3480 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(WS_STRING
), (const void **)&ptr
)) != S_OK
) return hr
;
3481 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3482 if (!ptr
->length
) return S_OK
;
3484 utf16
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
3485 utf16
.bytes
= (BYTE
*)ptr
->chars
;
3486 utf16
.byteCount
= ptr
->length
* sizeof(WCHAR
);
3487 return write_type_text( writer
, mapping
, &utf16
.text
);
3490 static HRESULT
write_type_wsz( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3491 const WS_WSZ_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3492 const void *value
, ULONG size
)
3494 WS_XML_UTF16_TEXT utf16
;
3501 FIXME( "description not supported\n" );
3505 if (!option
|| option
== WS_WRITE_REQUIRED_VALUE
|| option
== WS_WRITE_NILLABLE_VALUE
) return E_INVALIDARG
;
3506 if ((hr
= get_value_ptr( option
, value
, size
, 0, (const void **)&ptr
)) != S_OK
) return hr
;
3507 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3508 if (!(len
= strlenW( ptr
))) return S_OK
;
3510 utf16
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
3511 utf16
.bytes
= (BYTE
*)ptr
;
3512 utf16
.byteCount
= len
* sizeof(WCHAR
);
3513 return write_type_text( writer
, mapping
, &utf16
.text
);
3516 static HRESULT
write_type_bytes( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3517 const WS_BYTES_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3518 const void *value
, ULONG size
)
3520 WS_XML_BASE64_TEXT base64
;
3521 const WS_BYTES
*ptr
;
3526 FIXME( "description not supported\n" );
3530 if (!option
) return E_INVALIDARG
;
3531 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(WS_BYTES
), (const void **)&ptr
)) != S_OK
) return hr
;
3532 if ((option
== WS_WRITE_NILLABLE_VALUE
&& is_nil_value( value
, size
)) ||
3533 (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
)) return write_add_nil_attribute( writer
);
3534 if (!ptr
->length
) return S_OK
;
3536 base64
.text
.textType
= WS_XML_TEXT_TYPE_BASE64
;
3537 base64
.bytes
= ptr
->bytes
;
3538 base64
.length
= ptr
->length
;
3539 return write_type_text( writer
, mapping
, &base64
.text
);
3542 static HRESULT
write_type_xml_string( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3543 const WS_XML_STRING_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3544 const void *value
, ULONG size
)
3546 WS_XML_UTF8_TEXT utf8
;
3547 const WS_XML_STRING
*ptr
;
3552 FIXME( "description not supported\n" );
3556 if (!option
) return E_INVALIDARG
;
3557 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(WS_XML_STRING
), (const void **)&ptr
)) != S_OK
) return hr
;
3558 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3559 if (option
== WS_WRITE_NILLABLE_VALUE
&& is_nil_value( value
, size
)) return write_add_nil_attribute( writer
);
3560 if (!ptr
->length
) return S_OK
;
3562 utf8
.text
.textType
= WS_XML_TEXT_TYPE_UTF8
;
3563 utf8
.value
.bytes
= ptr
->bytes
;
3564 utf8
.value
.length
= ptr
->length
;
3565 return write_type_text( writer
, mapping
, &utf8
.text
);
3568 static HRESULT
find_prefix( struct writer
*writer
, const WS_XML_STRING
*ns
, const WS_XML_STRING
**prefix
)
3570 const struct node
*node
;
3571 for (node
= writer
->current
; node_type( node
) == WS_XML_NODE_TYPE_ELEMENT
; node
= node
->parent
)
3573 const WS_XML_ELEMENT_NODE
*elem
= &node
->hdr
;
3575 for (i
= 0; i
< elem
->attributeCount
; i
++)
3577 if (!elem
->attributes
[i
]->isXmlNs
) continue;
3578 if (WsXmlStringEquals( elem
->attributes
[i
]->ns
, ns
, NULL
) != S_OK
) continue;
3579 *prefix
= elem
->attributes
[i
]->prefix
;
3583 return WS_E_INVALID_FORMAT
;
3586 static HRESULT
write_type_qname( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3587 const WS_XML_QNAME_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3588 const void *value
, ULONG size
)
3590 WS_XML_QNAME_TEXT qname
;
3591 const WS_XML_QNAME
*ptr
;
3592 const WS_XML_STRING
*prefix
;
3597 FIXME( "description not supported\n" );
3601 if (!option
) return E_INVALIDARG
;
3602 if ((hr
= get_value_ptr( option
, value
, size
, sizeof(*ptr
), (const void **)&ptr
)) != S_OK
) return hr
;
3603 if (option
== WS_WRITE_NILLABLE_POINTER
&& !ptr
) return write_add_nil_attribute( writer
);
3604 if (option
== WS_WRITE_NILLABLE_VALUE
&& is_nil_value( value
, size
)) return write_add_nil_attribute( writer
);
3606 if (((hr
= find_prefix( writer
, &ptr
->ns
, &prefix
)) != S_OK
)) return hr
;
3608 qname
.text
.textType
= WS_XML_TEXT_TYPE_QNAME
;
3609 qname
.prefix
= (WS_XML_STRING
*)prefix
;
3610 qname
.localName
= (WS_XML_STRING
*)&ptr
->localName
;
3611 qname
.ns
= (WS_XML_STRING
*)&ptr
->ns
;
3612 return write_type_text( writer
, mapping
, &qname
.text
);
3615 static WS_WRITE_OPTION
get_field_write_option( WS_TYPE type
, ULONG options
)
3617 if (options
& WS_FIELD_POINTER
)
3619 if (options
& (WS_FIELD_OPTIONAL
|WS_FIELD_NILLABLE
)) return WS_WRITE_NILLABLE_POINTER
;
3620 return WS_WRITE_REQUIRED_POINTER
;
3631 case WS_UINT16_TYPE
:
3632 case WS_UINT32_TYPE
:
3633 case WS_UINT64_TYPE
:
3634 case WS_DOUBLE_TYPE
:
3635 case WS_DATETIME_TYPE
:
3637 case WS_UNIQUE_ID_TYPE
:
3638 case WS_STRING_TYPE
:
3640 case WS_XML_STRING_TYPE
:
3641 case WS_XML_QNAME_TYPE
:
3642 case WS_STRUCT_TYPE
:
3645 if (options
& (WS_FIELD_OPTIONAL
|WS_FIELD_NILLABLE
)) return WS_WRITE_NILLABLE_VALUE
;
3646 return WS_WRITE_REQUIRED_VALUE
;
3649 case WS_DESCRIPTION_TYPE
:
3650 if (options
& (WS_FIELD_OPTIONAL
|WS_FIELD_NILLABLE
)) return WS_WRITE_NILLABLE_POINTER
;
3651 return WS_WRITE_REQUIRED_POINTER
;
3654 FIXME( "unhandled type %u\n", type
);
3659 static HRESULT
find_index( const WS_UNION_DESCRIPTION
*desc
, int value
, ULONG
*idx
)
3663 if (desc
->valueIndices
)
3665 int c
, min
= 0, max
= desc
->fieldCount
- 1;
3668 i
= (min
+ max
) / 2;
3669 c
= value
- desc
->fields
[desc
->valueIndices
[i
]]->value
;
3676 *idx
= desc
->valueIndices
[i
];
3680 return WS_E_INVALID_FORMAT
;
3683 /* fall back to linear search */
3684 for (i
= 0; i
< desc
->fieldCount
; i
++)
3686 if (desc
->fields
[i
]->value
== value
)
3692 return WS_E_INVALID_FORMAT
;
3695 static HRESULT
write_type_field( struct writer
*, const WS_FIELD_DESCRIPTION
*, const char *, ULONG
);
3697 static HRESULT
write_type_union( struct writer
*writer
, const WS_UNION_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3698 const void *value
, ULONG size
)
3705 if (size
< sizeof(enum_value
)) return E_INVALIDARG
;
3706 if ((hr
= get_value_ptr( option
, value
, size
, desc
->size
, &ptr
)) != S_OK
) return hr
;
3708 enum_value
= *(int *)(char *)ptr
+ desc
->enumOffset
;
3709 if (enum_value
== desc
->noneEnumValue
&& option
== WS_WRITE_NILLABLE_VALUE
) return S_OK
;
3711 if ((hr
= find_index( desc
, enum_value
, &i
)) != S_OK
) return hr
;
3712 return write_type_field( writer
, &desc
->fields
[i
]->field
, ptr
, desc
->fields
[i
]->field
.offset
);
3715 static HRESULT
write_type( struct writer
*, WS_TYPE_MAPPING
, WS_TYPE
, const void *, WS_WRITE_OPTION
,
3716 const void *, ULONG
);
3718 static HRESULT
write_type_array( struct writer
*writer
, const WS_FIELD_DESCRIPTION
*desc
, const char *buf
,
3722 ULONG i
, size
, offset
= 0;
3723 WS_WRITE_OPTION option
;
3725 if (!(option
= get_field_write_option( desc
->type
, desc
->options
))) return E_INVALIDARG
;
3727 /* wrapper element */
3728 if (desc
->localName
&& ((hr
= write_element_node( writer
, NULL
, desc
->localName
, desc
->ns
)) != S_OK
))
3731 if (option
== WS_WRITE_REQUIRED_VALUE
|| option
== WS_WRITE_NILLABLE_VALUE
)
3732 size
= get_type_size( desc
->type
, desc
->typeDescription
);
3734 size
= sizeof(const void *);
3736 for (i
= 0; i
< count
; i
++)
3738 if (desc
->type
== WS_UNION_TYPE
)
3740 if ((hr
= write_type_union( writer
, desc
->typeDescription
, option
, buf
+ offset
, size
)) != S_OK
)
3745 if ((hr
= write_element_node( writer
, NULL
, desc
->itemLocalName
, desc
->itemNs
)) != S_OK
) return hr
;
3746 if ((hr
= write_type( writer
, WS_ELEMENT_TYPE_MAPPING
, desc
->type
, desc
->typeDescription
, option
,
3747 buf
+ offset
, size
)) != S_OK
) return hr
;
3748 if ((hr
= write_endelement_node( writer
)) != S_OK
) return hr
;
3753 if (desc
->localName
) hr
= write_endelement_node( writer
);
3757 static HRESULT
write_type_field( struct writer
*writer
, const WS_FIELD_DESCRIPTION
*desc
, const char *buf
,
3761 WS_TYPE_MAPPING mapping
;
3762 WS_WRITE_OPTION option
;
3763 ULONG count
, size
, field_options
= desc
->options
;
3764 const char *ptr
= buf
+ offset
;
3766 if (field_options
& ~(WS_FIELD_POINTER
|WS_FIELD_OPTIONAL
|WS_FIELD_NILLABLE
))
3768 FIXME( "options 0x%x not supported\n", desc
->options
);
3772 /* zero-terminated strings are always pointers */
3773 if (desc
->type
== WS_WSZ_TYPE
) field_options
|= WS_FIELD_POINTER
;
3775 if (field_options
& WS_FIELD_POINTER
)
3776 size
= sizeof(const void *);
3778 size
= get_type_size( desc
->type
, desc
->typeDescription
);
3780 if (is_nil_value( ptr
, size
))
3782 if (field_options
& WS_FIELD_OPTIONAL
) return S_OK
;
3783 if (field_options
& WS_FIELD_NILLABLE
)
3785 if (field_options
& WS_FIELD_POINTER
) option
= WS_WRITE_NILLABLE_POINTER
;
3786 else option
= WS_WRITE_NILLABLE_VALUE
;
3790 if (field_options
& WS_FIELD_POINTER
) option
= WS_WRITE_REQUIRED_POINTER
;
3791 else option
= WS_WRITE_REQUIRED_VALUE
;
3796 if (field_options
& WS_FIELD_POINTER
) option
= WS_WRITE_REQUIRED_POINTER
;
3797 else option
= WS_WRITE_REQUIRED_VALUE
;
3800 switch (desc
->mapping
)
3802 case WS_ATTRIBUTE_FIELD_MAPPING
:
3803 if (!desc
->localName
|| !desc
->ns
) return E_INVALIDARG
;
3804 if ((hr
= write_add_attribute( writer
, NULL
, desc
->localName
, desc
->ns
, FALSE
)) != S_OK
)
3806 writer
->state
= WRITER_STATE_STARTATTRIBUTE
;
3808 mapping
= WS_ATTRIBUTE_TYPE_MAPPING
;
3811 case WS_ELEMENT_FIELD_MAPPING
:
3812 if ((hr
= write_element_node( writer
, NULL
, desc
->localName
, desc
->ns
)) != S_OK
) return hr
;
3813 mapping
= WS_ELEMENT_TYPE_MAPPING
;
3816 case WS_ELEMENT_CHOICE_FIELD_MAPPING
:
3817 if (desc
->type
!= WS_UNION_TYPE
|| !desc
->typeDescription
) return E_INVALIDARG
;
3818 option
= (field_options
& WS_FIELD_OPTIONAL
) ? WS_WRITE_NILLABLE_VALUE
: WS_WRITE_REQUIRED_VALUE
;
3819 return write_type_union( writer
, desc
->typeDescription
, option
, ptr
, size
);
3821 case WS_REPEATING_ELEMENT_FIELD_MAPPING
:
3822 case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING
:
3823 count
= *(const ULONG
*)(buf
+ desc
->countOffset
);
3824 return write_type_array( writer
, desc
, *(const char **)ptr
, count
);
3826 case WS_TEXT_FIELD_MAPPING
:
3827 switch (writer
->state
)
3829 case WRITER_STATE_STARTELEMENT
:
3830 mapping
= WS_ELEMENT_CONTENT_TYPE_MAPPING
;
3833 case WRITER_STATE_STARTATTRIBUTE
:
3834 mapping
= WS_ATTRIBUTE_TYPE_MAPPING
;
3838 FIXME( "unhandled writer state %u\n", writer
->state
);
3844 FIXME( "field mapping %u not supported\n", desc
->mapping
);
3848 if ((hr
= write_type( writer
, mapping
, desc
->type
, desc
->typeDescription
, option
, ptr
, size
)) != S_OK
)
3853 case WS_ATTRIBUTE_TYPE_MAPPING
:
3854 writer
->state
= WRITER_STATE_STARTELEMENT
;
3857 case WS_ELEMENT_TYPE_MAPPING
:
3858 if ((hr
= write_endelement_node( writer
)) != S_OK
) return hr
;
3867 static HRESULT
write_type_struct( struct writer
*writer
, WS_TYPE_MAPPING mapping
,
3868 const WS_STRUCT_DESCRIPTION
*desc
, WS_WRITE_OPTION option
,
3869 const void *value
, ULONG size
)
3875 if (!desc
) return E_INVALIDARG
;
3876 if (desc
->structOptions
) FIXME( "struct options 0x%x not supported\n", desc
->structOptions
);
3878 if ((hr
= get_value_ptr( option
, value
, size
, desc
->size
, &ptr
)) != S_OK
) return hr
;
3880 for (i
= 0; i
< desc
->fieldCount
; i
++)
3882 offset
= desc
->fields
[i
]->offset
;
3883 if ((hr
= write_type_field( writer
, desc
->fields
[i
], ptr
, offset
)) != S_OK
) return hr
;
3889 static HRESULT
write_type( struct writer
*writer
, WS_TYPE_MAPPING mapping
, WS_TYPE type
,
3890 const void *desc
, WS_WRITE_OPTION option
, const void *value
,
3896 return write_type_bool( writer
, mapping
, desc
, option
, value
, size
);
3899 return write_type_int8( writer
, mapping
, desc
, option
, value
, size
);
3902 return write_type_int16( writer
, mapping
, desc
, option
, value
, size
);
3905 return write_type_int32( writer
, mapping
, desc
, option
, value
, size
);
3908 return write_type_int64( writer
, mapping
, desc
, option
, value
, size
);
3911 return write_type_uint8( writer
, mapping
, desc
, option
, value
, size
);
3913 case WS_UINT16_TYPE
:
3914 return write_type_uint16( writer
, mapping
, desc
, option
, value
, size
);
3916 case WS_UINT32_TYPE
:
3917 return write_type_uint32( writer
, mapping
, desc
, option
, value
, size
);
3919 case WS_UINT64_TYPE
:
3920 return write_type_uint64( writer
, mapping
, desc
, option
, value
, size
);
3922 case WS_DOUBLE_TYPE
:
3923 return write_type_double( writer
, mapping
, desc
, option
, value
, size
);
3925 case WS_DATETIME_TYPE
:
3926 return write_type_datetime( writer
, mapping
, desc
, option
, value
, size
);
3929 return write_type_guid( writer
, mapping
, desc
, option
, value
, size
);
3931 case WS_UNIQUE_ID_TYPE
:
3932 return write_type_unique_id( writer
, mapping
, desc
, option
, value
, size
);
3934 case WS_STRING_TYPE
:
3935 return write_type_string( writer
, mapping
, desc
, option
, value
, size
);
3938 return write_type_wsz( writer
, mapping
, desc
, option
, value
, size
);
3941 return write_type_bytes( writer
, mapping
, desc
, option
, value
, size
);
3943 case WS_XML_STRING_TYPE
:
3944 return write_type_xml_string( writer
, mapping
, desc
, option
, value
, size
);
3946 case WS_XML_QNAME_TYPE
:
3947 return write_type_qname( writer
, mapping
, desc
, option
, value
, size
);
3949 case WS_STRUCT_TYPE
:
3950 return write_type_struct( writer
, mapping
, desc
, option
, value
, size
);
3953 FIXME( "type %u not supported\n", type
);
3958 /**************************************************************************
3959 * WsWriteAttribute [webservices.@]
3961 HRESULT WINAPI
WsWriteAttribute( WS_XML_WRITER
*handle
, const WS_ATTRIBUTE_DESCRIPTION
*desc
,
3962 WS_WRITE_OPTION option
, const void *value
, ULONG size
,
3965 struct writer
*writer
= (struct writer
*)handle
;
3968 TRACE( "%p %p %u %p %u %p\n", handle
, desc
, option
, value
, size
, error
);
3969 if (error
) FIXME( "ignoring error parameter\n" );
3971 if (!writer
|| !desc
|| !desc
->attributeLocalName
|| !desc
->attributeNs
|| !value
)
3972 return E_INVALIDARG
;
3974 EnterCriticalSection( &writer
->cs
);
3976 if (writer
->magic
!= WRITER_MAGIC
)
3978 LeaveCriticalSection( &writer
->cs
);
3979 return E_INVALIDARG
;
3982 if (writer
->state
!= WRITER_STATE_STARTELEMENT
) hr
= WS_E_INVALID_OPERATION
;
3983 else if ((hr
= write_add_attribute( writer
, NULL
, desc
->attributeLocalName
, desc
->attributeNs
, FALSE
)) == S_OK
)
3985 writer
->state
= WRITER_STATE_STARTATTRIBUTE
;
3986 hr
= write_type( writer
, WS_ATTRIBUTE_TYPE_MAPPING
, desc
->type
, desc
->typeDescription
, option
, value
, size
);
3989 LeaveCriticalSection( &writer
->cs
);
3990 TRACE( "returning %08x\n", hr
);
3994 /**************************************************************************
3995 * WsWriteElement [webservices.@]
3997 HRESULT WINAPI
WsWriteElement( WS_XML_WRITER
*handle
, const WS_ELEMENT_DESCRIPTION
*desc
,
3998 WS_WRITE_OPTION option
, const void *value
, ULONG size
,
4001 struct writer
*writer
= (struct writer
*)handle
;
4004 TRACE( "%p %p %u %p %u %p\n", handle
, desc
, option
, value
, size
, error
);
4005 if (error
) FIXME( "ignoring error parameter\n" );
4007 if (!writer
|| !desc
|| !desc
->elementLocalName
|| !desc
->elementNs
|| !value
)
4008 return E_INVALIDARG
;
4010 EnterCriticalSection( &writer
->cs
);
4012 if (writer
->magic
!= WRITER_MAGIC
)
4014 LeaveCriticalSection( &writer
->cs
);
4015 return E_INVALIDARG
;
4018 if ((hr
= write_element_node( writer
, NULL
, desc
->elementLocalName
, desc
->elementNs
)) != S_OK
) goto done
;
4020 if ((hr
= write_type( writer
, WS_ANY_ELEMENT_TYPE_MAPPING
, desc
->type
, desc
->typeDescription
,
4021 option
, value
, size
)) != S_OK
) goto done
;
4023 hr
= write_endelement_node( writer
);
4026 LeaveCriticalSection( &writer
->cs
);
4027 TRACE( "returning %08x\n", hr
);
4031 /**************************************************************************
4032 * WsWriteType [webservices.@]
4034 HRESULT WINAPI
WsWriteType( WS_XML_WRITER
*handle
, WS_TYPE_MAPPING mapping
, WS_TYPE type
,
4035 const void *desc
, WS_WRITE_OPTION option
, const void *value
,
4036 ULONG size
, WS_ERROR
*error
)
4038 struct writer
*writer
= (struct writer
*)handle
;
4041 TRACE( "%p %u %u %p %u %p %u %p\n", handle
, mapping
, type
, desc
, option
, value
,
4043 if (error
) FIXME( "ignoring error parameter\n" );
4045 if (!writer
|| !value
) return E_INVALIDARG
;
4047 EnterCriticalSection( &writer
->cs
);
4049 if (writer
->magic
!= WRITER_MAGIC
)
4051 LeaveCriticalSection( &writer
->cs
);
4052 return E_INVALIDARG
;
4057 case WS_ATTRIBUTE_TYPE_MAPPING
:
4058 if (writer
->state
!= WRITER_STATE_STARTATTRIBUTE
) hr
= WS_E_INVALID_FORMAT
;
4059 else hr
= write_type( writer
, mapping
, type
, desc
, option
, value
, size
);
4062 case WS_ELEMENT_TYPE_MAPPING
:
4063 case WS_ELEMENT_CONTENT_TYPE_MAPPING
:
4064 case WS_ANY_ELEMENT_TYPE_MAPPING
:
4065 hr
= write_type( writer
, mapping
, type
, desc
, option
, value
, size
);
4069 FIXME( "mapping %u not implemented\n", mapping
);
4073 LeaveCriticalSection( &writer
->cs
);
4074 TRACE( "returning %08x\n", hr
);
4078 WS_TYPE
map_value_type( WS_VALUE_TYPE type
)
4082 case WS_BOOL_VALUE_TYPE
: return WS_BOOL_TYPE
;
4083 case WS_INT8_VALUE_TYPE
: return WS_INT8_TYPE
;
4084 case WS_INT16_VALUE_TYPE
: return WS_INT16_TYPE
;
4085 case WS_INT32_VALUE_TYPE
: return WS_INT32_TYPE
;
4086 case WS_INT64_VALUE_TYPE
: return WS_INT64_TYPE
;
4087 case WS_UINT8_VALUE_TYPE
: return WS_UINT8_TYPE
;
4088 case WS_UINT16_VALUE_TYPE
: return WS_UINT16_TYPE
;
4089 case WS_UINT32_VALUE_TYPE
: return WS_UINT32_TYPE
;
4090 case WS_UINT64_VALUE_TYPE
: return WS_UINT64_TYPE
;
4091 case WS_FLOAT_VALUE_TYPE
: return WS_FLOAT_TYPE
;
4092 case WS_DOUBLE_VALUE_TYPE
: return WS_DOUBLE_TYPE
;
4093 case WS_DECIMAL_VALUE_TYPE
: return WS_DECIMAL_TYPE
;
4094 case WS_DATETIME_VALUE_TYPE
: return WS_DATETIME_TYPE
;
4095 case WS_TIMESPAN_VALUE_TYPE
: return WS_TIMESPAN_TYPE
;
4096 case WS_GUID_VALUE_TYPE
: return WS_GUID_TYPE
;
4098 FIXME( "unhandled type %u\n", type
);
4103 /**************************************************************************
4104 * WsWriteValue [webservices.@]
4106 HRESULT WINAPI
WsWriteValue( WS_XML_WRITER
*handle
, WS_VALUE_TYPE value_type
, const void *value
,
4107 ULONG size
, WS_ERROR
*error
)
4109 struct writer
*writer
= (struct writer
*)handle
;
4110 WS_TYPE_MAPPING mapping
;
4114 TRACE( "%p %u %p %u %p\n", handle
, value_type
, value
, size
, error
);
4115 if (error
) FIXME( "ignoring error parameter\n" );
4117 if (!writer
|| !value
|| (type
= map_value_type( value_type
)) == ~0u) return E_INVALIDARG
;
4119 EnterCriticalSection( &writer
->cs
);
4121 if (writer
->magic
!= WRITER_MAGIC
)
4123 LeaveCriticalSection( &writer
->cs
);
4124 return E_INVALIDARG
;
4127 switch (writer
->state
)
4129 case WRITER_STATE_STARTATTRIBUTE
:
4130 mapping
= WS_ATTRIBUTE_TYPE_MAPPING
;
4133 case WRITER_STATE_STARTELEMENT
:
4134 mapping
= WS_ELEMENT_TYPE_MAPPING
;
4138 hr
= WS_E_INVALID_FORMAT
;
4141 if (hr
== S_OK
) hr
= write_type( writer
, mapping
, type
, NULL
, WS_WRITE_REQUIRED_VALUE
, value
, size
);
4143 LeaveCriticalSection( &writer
->cs
);
4144 TRACE( "returning %08x\n", hr
);
4148 /**************************************************************************
4149 * WsWriteArray [webservices.@]
4151 HRESULT WINAPI
WsWriteArray( WS_XML_WRITER
*handle
, const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
,
4152 WS_VALUE_TYPE value_type
, const void *array
, ULONG size
, ULONG offset
,
4153 ULONG count
, WS_ERROR
*error
)
4155 struct writer
*writer
= (struct writer
*)handle
;
4160 TRACE( "%p %s %s %u %p %u %u %u %p\n", handle
, debugstr_xmlstr(localname
), debugstr_xmlstr(ns
),
4161 value_type
, array
, size
, offset
, count
, error
);
4162 if (error
) FIXME( "ignoring error parameter\n" );
4164 if (!writer
) return E_INVALIDARG
;
4166 EnterCriticalSection( &writer
->cs
);
4168 if (writer
->magic
!= WRITER_MAGIC
)
4170 LeaveCriticalSection( &writer
->cs
);
4171 return E_INVALIDARG
;
4174 if (!writer
->output_type
)
4176 hr
= WS_E_INVALID_OPERATION
;
4180 if (!localname
|| !ns
|| (type
= map_value_type( value_type
)) == ~0u)
4186 type_size
= get_type_size( type
, NULL
);
4187 if (size
% type_size
|| (offset
+ count
) * type_size
> size
|| (count
&& !array
))
4193 for (i
= offset
; i
< count
; i
++)
4195 const char *ptr
= (const char *)array
+ (offset
+ i
) * type_size
;
4196 if ((hr
= write_element_node( writer
, NULL
, localname
, ns
)) != S_OK
) goto done
;
4197 if ((hr
= write_type( writer
, WS_ELEMENT_TYPE_MAPPING
, type
, NULL
, WS_WRITE_REQUIRED_POINTER
,
4198 &ptr
, sizeof(ptr
) )) != S_OK
) goto done
;
4199 if ((hr
= write_endelement_node( writer
)) != S_OK
) goto done
;
4203 LeaveCriticalSection( &writer
->cs
);
4204 TRACE( "returning %08x\n", hr
);
4208 /**************************************************************************
4209 * WsWriteXmlBuffer [webservices.@]
4211 HRESULT WINAPI
WsWriteXmlBuffer( WS_XML_WRITER
*handle
, WS_XML_BUFFER
*buffer
, WS_ERROR
*error
)
4213 struct writer
*writer
= (struct writer
*)handle
;
4214 struct xmlbuf
*xmlbuf
= (struct xmlbuf
*)buffer
;
4217 TRACE( "%p %p %p\n", handle
, buffer
, error
);
4218 if (error
) FIXME( "ignoring error parameter\n" );
4220 if (!writer
|| !xmlbuf
) return E_INVALIDARG
;
4222 EnterCriticalSection( &writer
->cs
);
4224 if (writer
->magic
!= WRITER_MAGIC
)
4226 LeaveCriticalSection( &writer
->cs
);
4227 return E_INVALIDARG
;
4230 if (xmlbuf
->encoding
!= writer
->output_enc
|| xmlbuf
->charset
!= writer
->output_charset
)
4232 FIXME( "no support for different encoding and/or charset\n" );
4237 if ((hr
= write_commit( writer
)) != S_OK
) goto done
;
4238 if ((hr
= write_grow_buffer( writer
, xmlbuf
->bytes
.length
)) != S_OK
) goto done
;
4239 write_bytes( writer
, xmlbuf
->bytes
.bytes
, xmlbuf
->bytes
.length
);
4242 LeaveCriticalSection( &writer
->cs
);
4243 TRACE( "returning %08x\n", hr
);
4247 /**************************************************************************
4248 * WsWriteXmlBufferToBytes [webservices.@]
4250 HRESULT WINAPI
WsWriteXmlBufferToBytes( WS_XML_WRITER
*handle
, WS_XML_BUFFER
*buffer
,
4251 const WS_XML_WRITER_ENCODING
*encoding
,
4252 const WS_XML_WRITER_PROPERTY
*properties
, ULONG count
,
4253 WS_HEAP
*heap
, void **bytes
, ULONG
*size
, WS_ERROR
*error
)
4255 struct writer
*writer
= (struct writer
*)handle
;
4256 struct xmlbuf
*xmlbuf
= (struct xmlbuf
*)buffer
;
4261 TRACE( "%p %p %p %p %u %p %p %p %p\n", handle
, buffer
, encoding
, properties
, count
, heap
,
4262 bytes
, size
, error
);
4263 if (error
) FIXME( "ignoring error parameter\n" );
4265 if (!writer
|| !xmlbuf
|| !heap
|| !bytes
) return E_INVALIDARG
;
4267 if (encoding
&& encoding
->encodingType
!= WS_XML_WRITER_ENCODING_TYPE_TEXT
)
4269 FIXME( "encoding type %u not supported\n", encoding
->encodingType
);
4273 EnterCriticalSection( &writer
->cs
);
4275 if (writer
->magic
!= WRITER_MAGIC
)
4277 LeaveCriticalSection( &writer
->cs
);
4278 return E_INVALIDARG
;
4281 for (i
= 0; i
< count
; i
++)
4283 hr
= prop_set( writer
->prop
, writer
->prop_count
, properties
[i
].id
, properties
[i
].value
,
4284 properties
[i
].valueSize
);
4285 if (hr
!= S_OK
) goto done
;
4288 if (!(buf
= ws_alloc( heap
, xmlbuf
->bytes
.length
))) hr
= WS_E_QUOTA_EXCEEDED
;
4291 memcpy( buf
, xmlbuf
->bytes
.bytes
, xmlbuf
->bytes
.length
);
4293 *size
= xmlbuf
->bytes
.length
;
4297 LeaveCriticalSection( &writer
->cs
);
4298 TRACE( "returning %08x\n", hr
);
4302 /**************************************************************************
4303 * WsWriteXmlnsAttribute [webservices.@]
4305 HRESULT WINAPI
WsWriteXmlnsAttribute( WS_XML_WRITER
*handle
, const WS_XML_STRING
*prefix
,
4306 const WS_XML_STRING
*ns
, BOOL single
, WS_ERROR
*error
)
4308 struct writer
*writer
= (struct writer
*)handle
;
4311 TRACE( "%p %s %s %d %p\n", handle
, debugstr_xmlstr(prefix
), debugstr_xmlstr(ns
),
4313 if (error
) FIXME( "ignoring error parameter\n" );
4315 if (!writer
|| !ns
) return E_INVALIDARG
;
4317 EnterCriticalSection( &writer
->cs
);
4319 if (writer
->magic
!= WRITER_MAGIC
)
4321 LeaveCriticalSection( &writer
->cs
);
4322 return E_INVALIDARG
;
4325 if (writer
->state
!= WRITER_STATE_STARTELEMENT
) hr
= WS_E_INVALID_OPERATION
;
4326 else if (!namespace_in_scope( &writer
->current
->hdr
, prefix
, ns
))
4327 hr
= add_namespace_attribute( writer
, prefix
, ns
, single
);
4329 LeaveCriticalSection( &writer
->cs
);
4330 TRACE( "returning %08x\n", hr
);
4334 static HRESULT
write_qualified_name( struct writer
*writer
, const WS_XML_STRING
*prefix
,
4335 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
)
4337 WS_XML_QNAME_TEXT qname
= {{WS_XML_TEXT_TYPE_QNAME
}};
4340 if ((hr
= write_commit( writer
)) != S_OK
) return hr
;
4341 if (!prefix
&& ((hr
= find_prefix( writer
, ns
, &prefix
)) != S_OK
)) return hr
;
4343 qname
.prefix
= (WS_XML_STRING
*)prefix
;
4344 qname
.localName
= (WS_XML_STRING
*)localname
;
4345 qname
.ns
= (WS_XML_STRING
*)ns
;
4347 if ((hr
= write_add_text_node( writer
, &qname
.text
)) != S_OK
) return hr
;
4348 return write_text( writer
, ((const WS_XML_TEXT_NODE
*)writer
->current
)->text
, 0 );
4351 /**************************************************************************
4352 * WsWriteQualifiedName [webservices.@]
4354 HRESULT WINAPI
WsWriteQualifiedName( WS_XML_WRITER
*handle
, const WS_XML_STRING
*prefix
,
4355 const WS_XML_STRING
*localname
, const WS_XML_STRING
*ns
,
4358 struct writer
*writer
= (struct writer
*)handle
;
4361 TRACE( "%p %s %s %s %p\n", handle
, debugstr_xmlstr(prefix
), debugstr_xmlstr(localname
),
4362 debugstr_xmlstr(ns
), error
);
4363 if (error
) FIXME( "ignoring error parameter\n" );
4365 if (!writer
) return E_INVALIDARG
;
4367 EnterCriticalSection( &writer
->cs
);
4369 if (writer
->magic
!= WRITER_MAGIC
)
4371 LeaveCriticalSection( &writer
->cs
);
4372 return E_INVALIDARG
;
4375 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
4376 else if (writer
->state
!= WRITER_STATE_STARTELEMENT
) hr
= WS_E_INVALID_FORMAT
;
4377 else if (!localname
|| (!prefix
&& !ns
)) hr
= E_INVALIDARG
;
4378 else hr
= write_qualified_name( writer
, prefix
, localname
, ns
);
4380 LeaveCriticalSection( &writer
->cs
);
4381 TRACE( "returning %08x\n", hr
);
4385 static HRESULT
write_move_to( struct writer
*writer
, WS_MOVE_TO move
, BOOL
*found
)
4387 BOOL success
= FALSE
;
4388 struct node
*node
= writer
->current
;
4392 case WS_MOVE_TO_ROOT_ELEMENT
:
4393 success
= move_to_root_element( writer
->root
, &node
);
4396 case WS_MOVE_TO_NEXT_ELEMENT
:
4397 success
= move_to_next_element( &node
);
4400 case WS_MOVE_TO_PREVIOUS_ELEMENT
:
4401 success
= move_to_prev_element( &node
);
4404 case WS_MOVE_TO_CHILD_ELEMENT
:
4405 success
= move_to_child_element( &node
);
4408 case WS_MOVE_TO_END_ELEMENT
:
4409 success
= move_to_end_element( &node
);
4412 case WS_MOVE_TO_PARENT_ELEMENT
:
4413 success
= move_to_parent_element( &node
);
4416 case WS_MOVE_TO_FIRST_NODE
:
4417 success
= move_to_first_node( &node
);
4420 case WS_MOVE_TO_NEXT_NODE
:
4421 success
= move_to_next_node( &node
);
4424 case WS_MOVE_TO_PREVIOUS_NODE
:
4425 success
= move_to_prev_node( &node
);
4428 case WS_MOVE_TO_CHILD_NODE
:
4429 success
= move_to_child_node( &node
);
4432 case WS_MOVE_TO_BOF
:
4433 success
= move_to_bof( writer
->root
, &node
);
4436 case WS_MOVE_TO_EOF
:
4437 success
= move_to_eof( writer
->root
, &node
);
4441 FIXME( "unhandled move %u\n", move
);
4445 if (success
&& node
== writer
->root
) return E_INVALIDARG
;
4446 writer
->current
= node
;
4453 return success
? S_OK
: WS_E_INVALID_FORMAT
;
4456 /**************************************************************************
4457 * WsMoveWriter [webservices.@]
4459 HRESULT WINAPI
WsMoveWriter( WS_XML_WRITER
*handle
, WS_MOVE_TO move
, BOOL
*found
, WS_ERROR
*error
)
4461 struct writer
*writer
= (struct writer
*)handle
;
4464 TRACE( "%p %u %p %p\n", handle
, move
, found
, error
);
4465 if (error
) FIXME( "ignoring error parameter\n" );
4467 if (!writer
) return E_INVALIDARG
;
4469 EnterCriticalSection( &writer
->cs
);
4471 if (writer
->magic
!= WRITER_MAGIC
)
4473 LeaveCriticalSection( &writer
->cs
);
4474 return E_INVALIDARG
;
4477 if (writer
->output_type
!= WS_XML_WRITER_OUTPUT_TYPE_BUFFER
) hr
= WS_E_INVALID_OPERATION
;
4478 else hr
= write_move_to( writer
, move
, found
);
4480 LeaveCriticalSection( &writer
->cs
);
4481 TRACE( "returning %08x\n", hr
);
4485 /**************************************************************************
4486 * WsGetWriterPosition [webservices.@]
4488 HRESULT WINAPI
WsGetWriterPosition( WS_XML_WRITER
*handle
, WS_XML_NODE_POSITION
*pos
, WS_ERROR
*error
)
4490 struct writer
*writer
= (struct writer
*)handle
;
4493 TRACE( "%p %p %p\n", handle
, pos
, error
);
4494 if (error
) FIXME( "ignoring error parameter\n" );
4496 if (!writer
|| !pos
) return E_INVALIDARG
;
4498 EnterCriticalSection( &writer
->cs
);
4500 if (writer
->magic
!= WRITER_MAGIC
)
4502 LeaveCriticalSection( &writer
->cs
);
4503 return E_INVALIDARG
;
4506 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
4509 pos
->buffer
= (WS_XML_BUFFER
*)writer
->output_buf
;
4510 pos
->node
= writer
->current
;
4513 LeaveCriticalSection( &writer
->cs
);
4514 TRACE( "returning %08x\n", hr
);
4518 /**************************************************************************
4519 * WsSetWriterPosition [webservices.@]
4521 HRESULT WINAPI
WsSetWriterPosition( WS_XML_WRITER
*handle
, const WS_XML_NODE_POSITION
*pos
, WS_ERROR
*error
)
4523 struct writer
*writer
= (struct writer
*)handle
;
4526 TRACE( "%p %p %p\n", handle
, pos
, error
);
4527 if (error
) FIXME( "ignoring error parameter\n" );
4529 if (!writer
|| !pos
) return E_INVALIDARG
;
4531 EnterCriticalSection( &writer
->cs
);
4533 if (writer
->magic
!= WRITER_MAGIC
|| (struct xmlbuf
*)pos
->buffer
!= writer
->output_buf
)
4535 LeaveCriticalSection( &writer
->cs
);
4536 return E_INVALIDARG
;
4539 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
4540 else writer
->current
= pos
->node
;
4542 LeaveCriticalSection( &writer
->cs
);
4543 TRACE( "returning %08x\n", hr
);
4547 static HRESULT
write_add_comment_node( struct writer
*writer
, const WS_XML_STRING
*value
)
4549 struct node
*node
, *parent
;
4550 WS_XML_COMMENT_NODE
*comment
;
4552 if (!(parent
= find_parent( writer
))) return WS_E_INVALID_FORMAT
;
4553 if (!(node
= alloc_node( WS_XML_NODE_TYPE_COMMENT
))) return E_OUTOFMEMORY
;
4554 comment
= (WS_XML_COMMENT_NODE
*)node
;
4556 if (value
->length
&& !(comment
->value
.bytes
= heap_alloc( value
->length
)))
4559 return E_OUTOFMEMORY
;
4561 memcpy( comment
->value
.bytes
, value
->bytes
, value
->length
);
4562 comment
->value
.length
= value
->length
;
4564 write_insert_node( writer
, parent
, node
);
4568 static HRESULT
write_comment_text( struct writer
*writer
)
4570 const WS_XML_COMMENT_NODE
*comment
= (const WS_XML_COMMENT_NODE
*)writer
->current
;
4573 if ((hr
= write_grow_buffer( writer
, comment
->value
.length
+ 7 )) != S_OK
) return hr
;
4574 write_bytes( writer
, (const BYTE
*)"<!--", 4 );
4575 write_bytes( writer
, comment
->value
.bytes
, comment
->value
.length
);
4576 write_bytes( writer
, (const BYTE
*)"-->", 3 );
4580 static HRESULT
write_comment_bin( struct writer
*writer
)
4582 const WS_XML_COMMENT_NODE
*comment
= (const WS_XML_COMMENT_NODE
*)writer
->current
;
4585 if ((hr
= write_grow_buffer( writer
, 1 )) != S_OK
) return hr
;
4586 write_char( writer
, RECORD_COMMENT
);
4587 return write_string( writer
, comment
->value
.bytes
, comment
->value
.length
);
4590 static HRESULT
write_comment( struct writer
*writer
)
4592 switch (writer
->output_enc
)
4594 case WS_XML_WRITER_ENCODING_TYPE_TEXT
: return write_comment_text( writer
);
4595 case WS_XML_WRITER_ENCODING_TYPE_BINARY
: return write_comment_bin( writer
);
4597 ERR( "unhandled encoding %u\n", writer
->output_enc
);
4598 return WS_E_NOT_SUPPORTED
;
4602 static HRESULT
write_comment_node( struct writer
*writer
, const WS_XML_STRING
*value
)
4605 if ((hr
= write_commit( writer
)) != S_OK
) return hr
;
4606 if ((hr
= write_add_comment_node( writer
, value
)) != S_OK
) return hr
;
4607 if ((hr
= write_comment( writer
)) != S_OK
) return hr
;
4608 writer
->state
= WRITER_STATE_COMMENT
;
4612 static HRESULT
write_set_attributes( struct writer
*writer
, WS_XML_ATTRIBUTE
**attrs
, ULONG count
)
4617 for (i
= 0; i
< count
; i
++)
4619 const WS_XML_STRING
*prefix
= attrs
[i
]->prefix
;
4620 const WS_XML_STRING
*localname
= attrs
[i
]->localName
;
4621 const WS_XML_STRING
*ns
= attrs
[i
]->ns
;
4622 BOOL single
= attrs
[i
]->singleQuote
;
4624 if (attrs
[i
]->isXmlNs
)
4626 if ((hr
= add_namespace_attribute( writer
, prefix
, ns
, single
)) != S_OK
) return hr
;
4630 if ((hr
= write_add_attribute( writer
, prefix
, localname
, ns
, single
)) != S_OK
) return hr
;
4631 if ((hr
= write_set_attribute_value( writer
, attrs
[i
]->value
)) != S_OK
) return hr
;
4637 static HRESULT
write_node( struct writer
*writer
, const WS_XML_NODE
*node
)
4641 switch (node
->nodeType
)
4643 case WS_XML_NODE_TYPE_ELEMENT
:
4645 const WS_XML_ELEMENT_NODE
*elem
= (const WS_XML_ELEMENT_NODE
*)node
;
4646 if ((hr
= write_element_node( writer
, elem
->prefix
, elem
->localName
, elem
->ns
)) != S_OK
) return hr
;
4647 return write_set_attributes( writer
, elem
->attributes
, elem
->attributeCount
);
4649 case WS_XML_NODE_TYPE_TEXT
:
4651 const WS_XML_TEXT_NODE
*text
= (const WS_XML_TEXT_NODE
*)node
;
4652 return write_text_node( writer
, text
->text
);
4654 case WS_XML_NODE_TYPE_END_ELEMENT
:
4655 return write_endelement_node( writer
);
4657 case WS_XML_NODE_TYPE_COMMENT
:
4659 const WS_XML_COMMENT_NODE
*comment
= (const WS_XML_COMMENT_NODE
*)node
;
4660 return write_comment_node( writer
, &comment
->value
);
4662 case WS_XML_NODE_TYPE_CDATA
:
4663 return write_cdata_node( writer
);
4665 case WS_XML_NODE_TYPE_END_CDATA
:
4666 return write_endcdata_node( writer
);
4668 case WS_XML_NODE_TYPE_EOF
:
4669 case WS_XML_NODE_TYPE_BOF
:
4673 WARN( "unknown node type %u\n", node
->nodeType
);
4674 return E_INVALIDARG
;
4678 /**************************************************************************
4679 * WsWriteNode [webservices.@]
4681 HRESULT WINAPI
WsWriteNode( WS_XML_WRITER
*handle
, const WS_XML_NODE
*node
, WS_ERROR
*error
)
4683 struct writer
*writer
= (struct writer
*)handle
;
4686 TRACE( "%p %p %p\n", handle
, node
, error
);
4687 if (error
) FIXME( "ignoring error parameter\n" );
4689 if (!writer
|| !node
) return E_INVALIDARG
;
4691 EnterCriticalSection( &writer
->cs
);
4693 if (writer
->magic
!= WRITER_MAGIC
)
4695 LeaveCriticalSection( &writer
->cs
);
4696 return E_INVALIDARG
;
4699 if (!writer
->output_type
) hr
= WS_E_INVALID_OPERATION
;
4700 else hr
= write_node( writer
, node
);
4702 LeaveCriticalSection( &writer
->cs
);
4703 TRACE( "returning %08x\n", hr
);
4707 static HRESULT
write_tree_node( struct writer
*writer
)
4711 switch (node_type( writer
->current
))
4713 case WS_XML_NODE_TYPE_ELEMENT
:
4714 if (writer
->state
== WRITER_STATE_STARTELEMENT
&& (hr
= write_endstartelement( writer
)) != S_OK
)
4716 if ((hr
= write_startelement( writer
)) != S_OK
) return hr
;
4717 writer
->state
= WRITER_STATE_STARTELEMENT
;
4720 case WS_XML_NODE_TYPE_TEXT
:
4721 if (writer
->state
== WRITER_STATE_STARTELEMENT
&& (hr
= write_endstartelement( writer
)) != S_OK
)
4723 if ((hr
= write_text( writer
, ((const WS_XML_TEXT_NODE
*)writer
->current
)->text
, 0 )) != S_OK
) return hr
;
4724 writer
->state
= WRITER_STATE_TEXT
;
4727 case WS_XML_NODE_TYPE_END_ELEMENT
:
4728 if ((hr
= write_close_element( writer
, writer
->current
->parent
)) != S_OK
) return hr
;
4729 writer
->state
= WRITER_STATE_ENDELEMENT
;
4732 case WS_XML_NODE_TYPE_COMMENT
:
4733 if (writer
->state
== WRITER_STATE_STARTELEMENT
&& (hr
= write_endstartelement( writer
)) != S_OK
)
4735 if ((hr
= write_comment( writer
)) != S_OK
) return hr
;
4736 writer
->state
= WRITER_STATE_COMMENT
;
4739 case WS_XML_NODE_TYPE_CDATA
:
4740 if (writer
->state
== WRITER_STATE_STARTELEMENT
&& (hr
= write_endstartelement( writer
)) != S_OK
)
4742 if ((hr
= write_cdata( writer
)) != S_OK
) return hr
;
4743 writer
->state
= WRITER_STATE_STARTCDATA
;
4746 case WS_XML_NODE_TYPE_END_CDATA
:
4747 if ((hr
= write_endcdata( writer
)) != S_OK
) return hr
;
4748 writer
->state
= WRITER_STATE_ENDCDATA
;
4751 case WS_XML_NODE_TYPE_EOF
:
4752 case WS_XML_NODE_TYPE_BOF
:
4756 ERR( "unknown node type %u\n", node_type(writer
->current
) );
4757 return E_INVALIDARG
;
4761 static HRESULT
write_tree( struct writer
*writer
)
4765 if ((hr
= write_tree_node( writer
)) != S_OK
) return hr
;
4768 if (node_type( writer
->current
) == WS_XML_NODE_TYPE_EOF
) break;
4769 if (move_to_child_node( &writer
->current
))
4771 if ((hr
= write_tree_node( writer
)) != S_OK
) return hr
;
4774 if (move_to_next_node( &writer
->current
))
4776 if ((hr
= write_tree_node( writer
)) != S_OK
) return hr
;
4779 if (!move_to_parent_node( &writer
->current
) || !move_to_next_node( &writer
->current
))
4781 ERR( "invalid tree\n" );
4782 return WS_E_INVALID_FORMAT
;
4784 if ((hr
= write_tree_node( writer
)) != S_OK
) return hr
;
4789 static void write_rewind( struct writer
*writer
)
4791 writer
->write_pos
= 0;
4792 writer
->current
= writer
->root
;
4793 writer
->state
= WRITER_STATE_INITIAL
;
4796 /**************************************************************************
4797 * WsCopyNode [webservices.@]
4799 HRESULT WINAPI
WsCopyNode( WS_XML_WRITER
*handle
, WS_XML_READER
*reader
, WS_ERROR
*error
)
4801 struct writer
*writer
= (struct writer
*)handle
;
4802 struct node
*parent
, *current
, *node
= NULL
;
4805 TRACE( "%p %p %p\n", handle
, reader
, error
);
4806 if (error
) FIXME( "ignoring error parameter\n" );
4808 if (!writer
) return E_INVALIDARG
;
4810 EnterCriticalSection( &writer
->cs
);
4812 if (writer
->magic
!= WRITER_MAGIC
)
4814 LeaveCriticalSection( &writer
->cs
);
4815 return E_INVALIDARG
;
4818 if (!(parent
= find_parent( writer
))) hr
= WS_E_INVALID_FORMAT
;
4821 if ((hr
= copy_node( reader
, writer
->output_enc
, &node
)) != S_OK
) goto done
;
4822 current
= writer
->current
;
4823 write_insert_node( writer
, parent
, node
);
4825 write_rewind( writer
);
4826 if ((hr
= write_tree( writer
)) != S_OK
) goto done
;
4827 writer
->current
= current
;
4829 WsMoveReader( reader
, WS_MOVE_TO_NEXT_NODE
, NULL
, NULL
);
4833 LeaveCriticalSection( &writer
->cs
);
4834 TRACE( "returning %08x\n", hr
);
4838 static HRESULT
write_param( struct writer
*writer
, const WS_FIELD_DESCRIPTION
*desc
, const void *value
)
4840 return write_type_field( writer
, desc
, value
, 0 );
4843 static ULONG
get_array_len( const WS_PARAMETER_DESCRIPTION
*params
, ULONG count
, ULONG index
, const void **args
)
4846 for (i
= 0; i
< count
; i
++)
4848 if (params
[i
].inputMessageIndex
!= index
|| params
[i
].parameterType
!= WS_PARAMETER_TYPE_ARRAY_COUNT
)
4850 if (args
[i
]) ret
= *(const ULONG
*)args
[i
];
4856 static HRESULT
write_param_array( struct writer
*writer
, const WS_FIELD_DESCRIPTION
*desc
, const void *value
,
4859 return write_type_array( writer
, desc
, value
, len
);
4862 HRESULT
write_input_params( WS_XML_WRITER
*handle
, const WS_ELEMENT_DESCRIPTION
*desc
,
4863 const WS_PARAMETER_DESCRIPTION
*params
, ULONG count
, const void **args
)
4865 struct writer
*writer
= (struct writer
*)handle
;
4866 const WS_STRUCT_DESCRIPTION
*desc_struct
;
4867 const WS_FIELD_DESCRIPTION
*desc_field
;
4871 if (desc
->type
!= WS_STRUCT_TYPE
|| !(desc_struct
= desc
->typeDescription
)) return E_INVALIDARG
;
4873 EnterCriticalSection( &writer
->cs
);
4875 if (writer
->magic
!= WRITER_MAGIC
)
4877 LeaveCriticalSection( &writer
->cs
);
4878 return E_INVALIDARG
;
4881 if ((hr
= write_element_node( writer
, NULL
, desc
->elementLocalName
, desc
->elementNs
)) != S_OK
) goto done
;
4883 for (i
= 0; i
< count
; i
++)
4885 if (params
[i
].inputMessageIndex
== INVALID_PARAMETER_INDEX
) continue;
4886 if (params
[i
].parameterType
== WS_PARAMETER_TYPE_MESSAGES
)
4888 FIXME( "messages type not supported\n" );
4892 if ((hr
= get_param_desc( desc_struct
, params
[i
].inputMessageIndex
, &desc_field
)) != S_OK
) goto done
;
4893 if (params
[i
].parameterType
== WS_PARAMETER_TYPE_NORMAL
)
4895 if ((hr
= write_param( writer
, desc_field
, args
[i
] )) != S_OK
) goto done
;
4897 else if (params
[i
].parameterType
== WS_PARAMETER_TYPE_ARRAY
)
4899 const void *ptr
= *(const void **)args
[i
];
4900 ULONG len
= get_array_len( params
, count
, params
[i
].inputMessageIndex
, args
);
4901 if ((hr
= write_param_array( writer
, desc_field
, ptr
, len
)) != S_OK
) goto done
;
4905 hr
= write_endelement_node( writer
);
4908 LeaveCriticalSection( &writer
->cs
);
4912 HRESULT
writer_set_lookup( WS_XML_WRITER
*handle
, BOOL enable
)
4914 struct writer
*writer
= (struct writer
*)handle
;
4916 EnterCriticalSection( &writer
->cs
);
4918 if (writer
->magic
!= WRITER_MAGIC
)
4920 LeaveCriticalSection( &writer
->cs
);
4921 return E_INVALIDARG
;
4924 writer
->dict_do_lookup
= enable
;
4926 LeaveCriticalSection( &writer
->cs
);
4930 HRESULT
writer_set_dict_callback( WS_XML_WRITER
*handle
, WS_DYNAMIC_STRING_CALLBACK cb
, void *state
)
4932 struct writer
*writer
= (struct writer
*)handle
;
4934 EnterCriticalSection( &writer
->cs
);
4936 if (writer
->magic
!= WRITER_MAGIC
)
4938 LeaveCriticalSection( &writer
->cs
);
4939 return E_INVALIDARG
;
4942 writer
->dict_cb
= cb
;
4943 writer
->dict_cb_state
= state
;
4945 LeaveCriticalSection( &writer
->cs
);