webservices: Implement WsGetDictionary.
[wine.git] / dlls / webservices / reader.c
blobd59de3bad0d805cfb4f91f630fcd680e7ec4943b
1 /*
2 * Copyright 2015, 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winnls.h"
24 #include "webservices.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
28 #include "webservices_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
32 const char *debugstr_xmlstr( const WS_XML_STRING *str )
34 if (!str) return "(null)";
35 return debugstr_an( (const char *)str->bytes, str->length );
38 ULONG prop_size( const struct prop_desc *desc, ULONG count )
40 ULONG i, ret = count * sizeof(struct prop);
41 for (i = 0; i < count; i++) ret += desc[i].size;
42 return ret;
45 void prop_init( const struct prop_desc *desc, ULONG count, struct prop *prop, void *data )
47 ULONG i;
48 char *ptr = data;
49 for (i = 0; i < count; i++)
51 prop[i].value = ptr;
52 prop[i].size = desc[i].size;
53 prop[i].readonly = desc[i].readonly;
54 prop[i].writeonly = desc[i].writeonly;
55 ptr += prop[i].size;
59 HRESULT prop_set( const struct prop *prop, ULONG count, ULONG id, const void *value, ULONG size )
61 if (id >= count || size != prop[id].size || prop[id].readonly) return E_INVALIDARG;
62 memcpy( prop[id].value, value, size );
63 return S_OK;
66 HRESULT prop_get( const struct prop *prop, ULONG count, ULONG id, void *buf, ULONG size )
68 if (id >= count || size != prop[id].size || prop[id].writeonly) return E_INVALIDARG;
69 memcpy( buf, prop[id].value, prop[id].size );
70 return S_OK;
73 static CRITICAL_SECTION dict_cs;
74 static CRITICAL_SECTION_DEBUG dict_cs_debug =
76 0, 0, &dict_cs,
77 {&dict_cs_debug.ProcessLocksList,
78 &dict_cs_debug.ProcessLocksList},
79 0, 0, {(DWORD_PTR)(__FILE__ ": dict_cs")}
81 static CRITICAL_SECTION dict_cs = {&dict_cs_debug, -1, 0, 0, 0, 0};
83 static ULONG dict_size, *dict_sorted;
84 static WS_XML_DICTIONARY dict_builtin =
86 {0x82704485,0x222a,0x4f7c,{0xb9,0x7b,0xe9,0xa4,0x62,0xa9,0x66,0x2b}}
89 /**************************************************************************
90 * WsGetDictionary [webservices.@]
92 HRESULT WINAPI WsGetDictionary( WS_ENCODING encoding, WS_XML_DICTIONARY **dict, WS_ERROR *error )
94 TRACE( "%u %p %p\n", encoding, dict, error );
95 if (error) FIXME( "ignoring error parameter\n" );
97 if (!dict) return E_INVALIDARG;
99 if (encoding == WS_ENCODING_XML_BINARY_1 || encoding == WS_ENCODING_XML_BINARY_SESSION_1)
100 *dict = &dict_builtin;
101 else
102 *dict = NULL;
104 return S_OK;
107 static inline int cmp_string( const unsigned char *str, ULONG len, const unsigned char *str2, ULONG len2 )
109 if (len < len2) return -1;
110 else if (len > len2) return 1;
111 while (len--)
113 if (*str == *str2) { str++; str2++; }
114 else return *str - *str2;
116 return 0;
119 /* return -1 and string id if found, sort index if not found */
120 static int find_string( const unsigned char *data, ULONG len, ULONG *id )
122 int i, c, min = 0, max = dict_builtin.stringCount - 1;
123 while (min <= max)
125 i = (min + max) / 2;
126 c = cmp_string( data, len,
127 dict_builtin.strings[dict_sorted[i]].bytes,
128 dict_builtin.strings[dict_sorted[i]].length );
129 if (c < 0)
130 max = i - 1;
131 else if (c > 0)
132 min = i + 1;
133 else
135 *id = dict_builtin.strings[dict_sorted[i]].id;
136 return -1;
139 return max + 1;
142 #define MIN_DICTIONARY_SIZE 256
143 #define MAX_DICTIONARY_SIZE 2048
145 static BOOL grow_dict( ULONG size )
147 WS_XML_STRING *tmp;
148 ULONG new_size, *tmp_sorted;
150 if (dict_size >= dict_builtin.stringCount + size) return TRUE;
151 if (dict_size + size > MAX_DICTIONARY_SIZE) return FALSE;
153 if (!dict_builtin.strings)
155 new_size = max( MIN_DICTIONARY_SIZE, size );
156 if (!(dict_builtin.strings = heap_alloc( new_size * sizeof(WS_XML_STRING) ))) return FALSE;
157 if (!(dict_sorted = heap_alloc( new_size * sizeof(ULONG) )))
159 heap_free( dict_builtin.strings );
160 dict_builtin.strings = NULL;
161 return FALSE;
163 dict_size = new_size;
164 return TRUE;
167 new_size = max( dict_size * 2, size );
168 if (!(tmp = heap_realloc( dict_builtin.strings, new_size * sizeof(*tmp) ))) return FALSE;
169 dict_builtin.strings = tmp;
170 if (!(tmp_sorted = heap_realloc( dict_sorted, new_size * sizeof(*tmp_sorted) ))) return FALSE;
171 dict_sorted = tmp_sorted;
173 dict_size = new_size;
174 return TRUE;
177 static BOOL insert_string( unsigned char *data, ULONG len, int i, ULONG *ret_id )
179 ULONG id = dict_builtin.stringCount;
180 if (!grow_dict( 1 )) return FALSE;
181 memmove( &dict_sorted[i] + 1, &dict_sorted[i], (dict_builtin.stringCount - i) * sizeof(WS_XML_STRING *) );
182 dict_sorted[i] = id;
184 dict_builtin.strings[id].length = len;
185 dict_builtin.strings[id].bytes = data;
186 dict_builtin.strings[id].dictionary = &dict_builtin;
187 dict_builtin.strings[id].id = id;
188 dict_builtin.stringCount++;
189 *ret_id = id;
190 return TRUE;
193 static HRESULT add_xml_string( WS_XML_STRING *str )
195 int index;
196 ULONG id;
198 if (str->dictionary) return S_OK;
200 EnterCriticalSection( &dict_cs );
201 if ((index = find_string( str->bytes, str->length, &id )) == -1)
203 heap_free( str->bytes );
204 *str = dict_builtin.strings[id];
205 LeaveCriticalSection( &dict_cs );
206 return S_OK;
208 if (insert_string( str->bytes, str->length, index, &id ))
210 *str = dict_builtin.strings[id];
211 LeaveCriticalSection( &dict_cs );
212 return S_OK;
214 LeaveCriticalSection( &dict_cs );
215 return WS_E_QUOTA_EXCEEDED;
218 WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len )
220 WS_XML_STRING *ret;
222 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
223 if ((ret->length = len) && !(ret->bytes = heap_alloc( len )))
225 heap_free( ret );
226 return NULL;
228 if (data)
230 memcpy( ret->bytes, data, len );
231 if (add_xml_string( ret ) != S_OK) WARN( "string not added to dictionary\n" );
233 return ret;
236 void free_xml_string( WS_XML_STRING *str )
238 if (!str) return;
239 if (!str->dictionary) heap_free( str->bytes );
240 heap_free( str );
243 WS_XML_STRING *dup_xml_string( const WS_XML_STRING *src )
245 WS_XML_STRING *ret;
246 unsigned char *data;
247 int index;
248 ULONG id;
250 if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
251 if (src->dictionary)
253 *ret = *src;
254 return ret;
257 EnterCriticalSection( &dict_cs );
258 if ((index = find_string( src->bytes, src->length, &id )) == -1)
260 *ret = dict_builtin.strings[id];
261 LeaveCriticalSection( &dict_cs );
262 return ret;
264 if (!(data = heap_alloc( src->length )))
266 heap_free( ret );
267 LeaveCriticalSection( &dict_cs );
268 return NULL;
270 memcpy( data, src->bytes, src->length );
271 if (insert_string( data, src->length, index, &id ))
273 *ret = dict_builtin.strings[id];
274 LeaveCriticalSection( &dict_cs );
275 return ret;
277 LeaveCriticalSection( &dict_cs );
279 WARN( "string not added to dictionary\n" );
280 ret->length = src->length;
281 ret->bytes = data;
282 ret->dictionary = NULL;
283 ret->id = 0;
284 return ret;
287 struct node *alloc_node( WS_XML_NODE_TYPE type )
289 struct node *ret;
291 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
292 ret->hdr.node.nodeType = type;
293 list_init( &ret->entry );
294 list_init( &ret->children );
295 return ret;
298 void free_attribute( WS_XML_ATTRIBUTE *attr )
300 if (!attr) return;
301 free_xml_string( attr->prefix );
302 free_xml_string( attr->localName );
303 free_xml_string( attr->ns );
304 heap_free( attr->value );
305 heap_free( attr );
308 void free_node( struct node *node )
310 if (!node) return;
311 switch (node_type( node ))
313 case WS_XML_NODE_TYPE_ELEMENT:
315 WS_XML_ELEMENT_NODE *elem = &node->hdr;
316 ULONG i;
318 for (i = 0; i < elem->attributeCount; i++) free_attribute( elem->attributes[i] );
319 heap_free( elem->attributes );
320 free_xml_string( elem->prefix );
321 free_xml_string( elem->localName );
322 free_xml_string( elem->ns );
323 break;
325 case WS_XML_NODE_TYPE_TEXT:
327 WS_XML_TEXT_NODE *text = (WS_XML_TEXT_NODE *)node;
328 heap_free( text->text );
329 break;
331 case WS_XML_NODE_TYPE_COMMENT:
333 WS_XML_COMMENT_NODE *comment = (WS_XML_COMMENT_NODE *)node;
334 heap_free( comment->value.bytes );
335 break;
337 case WS_XML_NODE_TYPE_CDATA:
338 case WS_XML_NODE_TYPE_END_CDATA:
339 case WS_XML_NODE_TYPE_END_ELEMENT:
340 case WS_XML_NODE_TYPE_EOF:
341 case WS_XML_NODE_TYPE_BOF:
342 break;
344 default:
345 ERR( "unhandled type %u\n", node_type( node ) );
346 break;
348 heap_free( node );
351 void destroy_nodes( struct node *node )
353 struct list *ptr;
355 if (!node) return;
356 while ((ptr = list_head( &node->children )))
358 struct node *child = LIST_ENTRY( ptr, struct node, entry );
359 list_remove( &child->entry );
360 destroy_nodes( child );
362 free_node( node );
365 static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
367 WS_XML_ATTRIBUTE *dst;
368 const WS_XML_STRING *prefix = src->prefix;
369 const WS_XML_STRING *localname = src->localName;
370 const WS_XML_STRING *ns = src->localName;
371 const WS_XML_TEXT *text = src->value;
373 if (!(dst = heap_alloc( sizeof(*dst) ))) return NULL;
374 dst->singleQuote = src->singleQuote;
375 dst->isXmlNs = src->isXmlNs;
377 if (!prefix) dst->prefix = NULL;
378 else if (!(dst->prefix = dup_xml_string( prefix ))) goto error;
379 if (!(dst->localName = dup_xml_string( localname ))) goto error;
380 if (!(dst->ns = dup_xml_string( ns ))) goto error;
382 if (text)
384 WS_XML_UTF8_TEXT *utf8;
385 const WS_XML_UTF8_TEXT *utf8_src = (const WS_XML_UTF8_TEXT *)text;
386 if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length ))) goto error;
387 dst->value = &utf8->text;
390 return dst;
392 error:
393 free_attribute( dst );
394 return NULL;
397 static WS_XML_ATTRIBUTE **dup_attributes( WS_XML_ATTRIBUTE * const *src, ULONG count )
399 WS_XML_ATTRIBUTE **dst;
400 ULONG i;
402 if (!(dst = heap_alloc( sizeof(*dst) * count ))) return NULL;
403 for (i = 0; i < count; i++)
405 if (!(dst[i] = dup_attribute( src[i] )))
407 for (; i > 0; i--) free_attribute( dst[i - 1] );
408 heap_free( dst );
409 return NULL;
412 return dst;
415 static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
417 struct node *node;
418 WS_XML_ELEMENT_NODE *dst;
419 ULONG count = src->attributeCount;
420 WS_XML_ATTRIBUTE **attrs = src->attributes;
421 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
422 const WS_XML_STRING *localname = src->localName;
423 const WS_XML_STRING *ns = src->ns;
425 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
426 dst = &node->hdr;
428 if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
429 dst->attributeCount = count;
431 if (prefix && !(dst->prefix = dup_xml_string( prefix ))) goto error;
432 if (localname && !(dst->localName = dup_xml_string( localname ))) goto error;
433 if (ns && !(dst->ns = dup_xml_string( ns ))) goto error;
434 return node;
436 error:
437 free_node( node );
438 return NULL;
441 static struct node *dup_text_node( const WS_XML_TEXT_NODE *src )
443 struct node *node;
444 WS_XML_TEXT_NODE *dst;
446 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
447 dst = (WS_XML_TEXT_NODE *)node;
449 if (src->text)
451 WS_XML_UTF8_TEXT *utf8;
452 const WS_XML_UTF8_TEXT *utf8_src = (const WS_XML_UTF8_TEXT *)src->text;
453 if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length )))
455 free_node( node );
456 return NULL;
458 dst->text = &utf8->text;
460 return node;
463 static struct node *dup_comment_node( const WS_XML_COMMENT_NODE *src )
465 struct node *node;
466 WS_XML_COMMENT_NODE *dst;
468 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return NULL;
469 dst = (WS_XML_COMMENT_NODE *)node;
471 if (src->value.length && !(dst->value.bytes = heap_alloc( src->value.length )))
473 free_node( node );
474 return NULL;
476 memcpy( dst->value.bytes, src->value.bytes, src->value.length );
477 dst->value.length = src->value.length;
478 return node;
481 static struct node *dup_node( const struct node *src )
483 switch (node_type( src ))
485 case WS_XML_NODE_TYPE_ELEMENT:
486 return dup_element_node( &src->hdr );
488 case WS_XML_NODE_TYPE_TEXT:
489 return dup_text_node( (const WS_XML_TEXT_NODE *)src );
491 case WS_XML_NODE_TYPE_COMMENT:
492 return dup_comment_node( (const WS_XML_COMMENT_NODE *)src );
494 case WS_XML_NODE_TYPE_CDATA:
495 case WS_XML_NODE_TYPE_END_CDATA:
496 case WS_XML_NODE_TYPE_END_ELEMENT:
497 case WS_XML_NODE_TYPE_EOF:
498 case WS_XML_NODE_TYPE_BOF:
499 return alloc_node( node_type( src ) );
501 default:
502 ERR( "unhandled type %u\n", node_type( src ) );
503 break;
505 return NULL;
508 static HRESULT dup_tree( struct node **dst, const struct node *src )
510 struct node *parent;
511 const struct node *child;
513 if (!*dst && !(*dst = dup_node( src ))) return E_OUTOFMEMORY;
514 parent = *dst;
516 LIST_FOR_EACH_ENTRY( child, &src->children, struct node, entry )
518 HRESULT hr = E_OUTOFMEMORY;
519 struct node *new_child;
521 if (!(new_child = dup_node( child )) || (hr = dup_tree( &new_child, child )) != S_OK)
523 destroy_nodes( *dst );
524 return hr;
526 new_child->parent = parent;
527 list_add_tail( &parent->children, &new_child->entry );
529 return S_OK;
532 static const struct prop_desc reader_props[] =
534 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_DEPTH */
535 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_FRAGMENT */
536 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
537 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_READ_DECLARATION */
538 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_READER_PROPERTY_CHARSET */
539 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_ROW */
540 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_COLUMN */
541 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_UTF8_TRIM_SIZE */
542 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_BUFFER_SIZE */
543 { sizeof(BOOL), TRUE }, /* WS_XML_READER_PROPERTY_IN_ATTRIBUTE */
544 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_ROOT_MIME_PART_SIZE */
545 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_MIME_HEADERS_SIZE */
546 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_MIME_PARTS */
547 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
548 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_NAMESPACES */
551 enum reader_state
553 READER_STATE_INITIAL,
554 READER_STATE_BOF,
555 READER_STATE_STARTELEMENT,
556 READER_STATE_STARTATTRIBUTE,
557 READER_STATE_STARTCDATA,
558 READER_STATE_CDATA,
559 READER_STATE_TEXT,
560 READER_STATE_ENDELEMENT,
561 READER_STATE_ENDCDATA,
562 READER_STATE_COMMENT,
563 READER_STATE_EOF
566 struct prefix
568 WS_XML_STRING *str;
569 WS_XML_STRING *ns;
572 struct reader
574 ULONG magic;
575 CRITICAL_SECTION cs;
576 ULONG read_size;
577 ULONG read_pos;
578 const unsigned char *read_bufptr;
579 enum reader_state state;
580 struct node *root;
581 struct node *current;
582 ULONG current_attr;
583 struct node *last;
584 struct prefix *prefixes;
585 ULONG nb_prefixes;
586 ULONG nb_prefixes_allocated;
587 WS_XML_READER_ENCODING_TYPE input_enc;
588 WS_XML_READER_INPUT_TYPE input_type;
589 struct xmlbuf *input_buf;
590 const unsigned char *input_data;
591 ULONG input_size;
592 ULONG text_conv_offset;
593 WS_XML_DICTIONARY *dict;
594 ULONG prop_count;
595 struct prop prop[sizeof(reader_props)/sizeof(reader_props[0])];
598 #define READER_MAGIC (('R' << 24) | ('E' << 16) | ('A' << 8) | 'D')
600 static struct reader *alloc_reader(void)
602 static const ULONG count = sizeof(reader_props)/sizeof(reader_props[0]);
603 struct reader *ret;
604 ULONG size = sizeof(*ret) + prop_size( reader_props, count );
606 if (!(ret = heap_alloc_zero( size ))) return NULL;
607 if (!(ret->prefixes = heap_alloc_zero( sizeof(*ret->prefixes) )))
609 heap_free( ret );
610 return NULL;
612 ret->nb_prefixes = ret->nb_prefixes_allocated = 1;
614 ret->magic = READER_MAGIC;
615 InitializeCriticalSection( &ret->cs );
616 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
618 prop_init( reader_props, count, ret->prop, &ret[1] );
619 ret->prop_count = count;
620 return ret;
623 static void clear_prefixes( struct prefix *prefixes, ULONG count )
625 ULONG i;
626 for (i = 0; i < count; i++)
628 free_xml_string( prefixes[i].str );
629 prefixes[i].str = NULL;
630 free_xml_string( prefixes[i].ns );
631 prefixes[i].ns = NULL;
635 static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
637 if (str)
639 free_xml_string( prefix->str );
640 if (!(prefix->str = dup_xml_string( str ))) return E_OUTOFMEMORY;
642 if (prefix->ns) free_xml_string( prefix->ns );
643 if (!(prefix->ns = dup_xml_string( ns ))) return E_OUTOFMEMORY;
644 return S_OK;
647 static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING *ns )
649 ULONG i;
650 HRESULT hr;
652 for (i = 0; i < reader->nb_prefixes; i++)
654 if (WsXmlStringEquals( prefix, reader->prefixes[i].str, NULL ) == S_OK)
655 return set_prefix( &reader->prefixes[i], NULL, ns );
657 if (i >= reader->nb_prefixes_allocated)
659 ULONG new_size = reader->nb_prefixes_allocated * sizeof(*reader->prefixes) * 2;
660 struct prefix *tmp = heap_realloc_zero( reader->prefixes, new_size );
661 if (!tmp) return E_OUTOFMEMORY;
662 reader->prefixes = tmp;
663 reader->nb_prefixes_allocated *= 2;
665 if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr;
666 reader->nb_prefixes++;
667 return S_OK;
670 static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_STRING *prefix )
672 ULONG i;
673 for (i = 0; i < reader->nb_prefixes; i++)
675 if (WsXmlStringEquals( prefix, reader->prefixes[i].str, NULL ) == S_OK)
676 return reader->prefixes[i].ns;
678 return NULL;
681 static void read_insert_eof( struct reader *reader, struct node *eof )
683 if (!reader->root) reader->root = eof;
684 else
686 eof->parent = reader->root;
687 list_add_tail( &reader->root->children, &eof->entry );
689 reader->current = reader->last = eof;
692 static void read_insert_bof( struct reader *reader, struct node *bof )
694 reader->root->parent = bof;
695 list_add_tail( &bof->children, &reader->root->entry );
696 reader->current = reader->last = reader->root = bof;
699 static void read_insert_node( struct reader *reader, struct node *parent, struct node *node )
701 node->parent = parent;
702 list_add_before( list_tail( &parent->children ), &node->entry );
703 reader->current = reader->last = node;
706 static void free_reader( struct reader *reader )
708 destroy_nodes( reader->root );
709 clear_prefixes( reader->prefixes, reader->nb_prefixes );
710 heap_free( reader->prefixes );
711 reader->cs.DebugInfo->Spare[0] = 0;
712 DeleteCriticalSection( &reader->cs );
713 heap_free( reader );
716 static HRESULT init_reader( struct reader *reader )
718 static const WS_XML_STRING empty = {0, NULL};
719 struct node *node;
720 HRESULT hr;
722 reader->state = READER_STATE_INITIAL;
723 destroy_nodes( reader->root );
724 reader->root = reader->current = NULL;
725 reader->current_attr = 0;
726 clear_prefixes( reader->prefixes, reader->nb_prefixes );
727 reader->nb_prefixes = 1;
728 if ((hr = bind_prefix( reader, &empty, &empty )) != S_OK) return hr;
730 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
731 read_insert_eof( reader, node );
732 reader->input_enc = WS_XML_READER_ENCODING_TYPE_TEXT;
733 reader->dict = &dict_builtin;
734 return S_OK;
737 /**************************************************************************
738 * WsCreateReader [webservices.@]
740 HRESULT WINAPI WsCreateReader( const WS_XML_READER_PROPERTY *properties, ULONG count,
741 WS_XML_READER **handle, WS_ERROR *error )
743 struct reader *reader;
744 ULONG i, max_depth = 32, max_attrs = 128, max_ns = 32;
745 WS_CHARSET charset = WS_CHARSET_UTF8;
746 BOOL read_decl = TRUE;
747 HRESULT hr;
749 TRACE( "%p %u %p %p\n", properties, count, handle, error );
750 if (error) FIXME( "ignoring error parameter\n" );
752 if (!handle) return E_INVALIDARG;
753 if (!(reader = alloc_reader())) return E_OUTOFMEMORY;
755 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
756 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
757 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_READ_DECLARATION, &read_decl, sizeof(read_decl) );
758 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset, sizeof(charset) );
759 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
761 for (i = 0; i < count; i++)
763 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
764 properties[i].valueSize );
765 if (hr != S_OK)
767 free_reader( reader );
768 return hr;
772 if ((hr = init_reader( reader )) != S_OK)
774 free_reader( reader );
775 return hr;
778 *handle = (WS_XML_READER *)reader;
779 return S_OK;
782 /**************************************************************************
783 * WsFreeReader [webservices.@]
785 void WINAPI WsFreeReader( WS_XML_READER *handle )
787 struct reader *reader = (struct reader *)handle;
789 TRACE( "%p\n", handle );
791 if (!reader) return;
793 EnterCriticalSection( &reader->cs );
795 if (reader->magic != READER_MAGIC)
797 LeaveCriticalSection( &reader->cs );
798 return;
801 reader->magic = 0;
803 LeaveCriticalSection( &reader->cs );
804 free_reader( reader );
807 /**************************************************************************
808 * WsFillReader [webservices.@]
810 HRESULT WINAPI WsFillReader( WS_XML_READER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
811 WS_ERROR *error )
813 struct reader *reader = (struct reader *)handle;
815 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
816 if (error) FIXME( "ignoring error parameter\n" );
818 if (!reader) return E_INVALIDARG;
820 EnterCriticalSection( &reader->cs );
822 if (reader->magic != READER_MAGIC)
824 LeaveCriticalSection( &reader->cs );
825 return E_INVALIDARG;
828 /* FIXME: add support for stream input */
829 reader->read_size = min( min_size, reader->input_size );
830 reader->read_pos = 0;
832 LeaveCriticalSection( &reader->cs );
833 return S_OK;
836 /**************************************************************************
837 * WsGetNamespaceFromPrefix [webservices.@]
839 HRESULT WINAPI WsGetNamespaceFromPrefix( WS_XML_READER *handle, const WS_XML_STRING *prefix,
840 BOOL required, const WS_XML_STRING **ns, WS_ERROR *error )
842 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
843 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
844 static const WS_XML_STRING empty_ns = {0, NULL};
845 static const WS_XML_STRING xml_ns = {36, (BYTE *)"http://www.w3.org/XML/1998/namespace"};
846 static const WS_XML_STRING xmlns_ns = {29, (BYTE *)"http://www.w3.org/2000/xmlns/"};
847 struct reader *reader = (struct reader *)handle;
848 BOOL found = FALSE;
850 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(prefix), required, ns, error );
851 if (error) FIXME( "ignoring error parameter\n" );
853 if (!reader || !prefix || !ns) return E_INVALIDARG;
855 EnterCriticalSection( &reader->cs );
857 if (reader->magic != READER_MAGIC)
859 LeaveCriticalSection( &reader->cs );
860 return E_INVALIDARG;
863 if (reader->state != READER_STATE_STARTELEMENT)
865 LeaveCriticalSection( &reader->cs );
866 return WS_E_INVALID_OPERATION;
869 if (!prefix->length)
871 *ns = &empty_ns;
872 found = TRUE;
874 else if (WsXmlStringEquals( prefix, &xml, NULL ) == S_OK)
876 *ns = &xml_ns;
877 found = TRUE;
879 else if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
881 *ns = &xmlns_ns;
882 found = TRUE;
884 else
886 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
887 ULONG i;
889 for (i = 0; i < elem->attributeCount; i++)
891 if (!elem->attributes[i]->isXmlNs) continue;
892 if (WsXmlStringEquals( prefix, elem->attributes[i]->prefix, NULL ) == S_OK)
894 *ns = elem->attributes[i]->ns;
895 found = TRUE;
896 break;
901 LeaveCriticalSection( &reader->cs );
903 if (!found)
905 if (required) return WS_E_INVALID_FORMAT;
906 *ns = NULL;
907 return S_FALSE;
910 return S_OK;
913 /**************************************************************************
914 * WsGetReaderNode [webservices.@]
916 HRESULT WINAPI WsGetReaderNode( WS_XML_READER *handle, const WS_XML_NODE **node,
917 WS_ERROR *error )
919 struct reader *reader = (struct reader *)handle;
921 TRACE( "%p %p %p\n", handle, node, error );
922 if (error) FIXME( "ignoring error parameter\n" );
924 if (!reader || !node) return E_INVALIDARG;
926 EnterCriticalSection( &reader->cs );
928 if (reader->magic != READER_MAGIC)
930 LeaveCriticalSection( &reader->cs );
931 return E_INVALIDARG;
934 *node = &reader->current->hdr.node;
936 LeaveCriticalSection( &reader->cs );
937 return S_OK;
940 /**************************************************************************
941 * WsGetReaderProperty [webservices.@]
943 HRESULT WINAPI WsGetReaderProperty( WS_XML_READER *handle, WS_XML_READER_PROPERTY_ID id,
944 void *buf, ULONG size, WS_ERROR *error )
946 struct reader *reader = (struct reader *)handle;
947 HRESULT hr;
949 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
950 if (error) FIXME( "ignoring error parameter\n" );
952 if (!reader) return E_INVALIDARG;
954 EnterCriticalSection( &reader->cs );
956 if (reader->magic != READER_MAGIC)
958 LeaveCriticalSection( &reader->cs );
959 return E_INVALIDARG;
962 if (!reader->input_type)
964 LeaveCriticalSection( &reader->cs );
965 return WS_E_INVALID_OPERATION;
968 if (id == WS_XML_READER_PROPERTY_CHARSET)
970 WS_CHARSET charset;
971 if ((hr = prop_get( reader->prop, reader->prop_count, id, &charset, size )) != S_OK) goto done;
972 if (!charset)
974 hr = WS_E_INVALID_FORMAT;
975 goto done;
977 *(WS_CHARSET *)buf = charset;
978 hr = S_OK;
980 else hr = prop_get( reader->prop, reader->prop_count, id, buf, size );
982 done:
983 LeaveCriticalSection( &reader->cs );
984 return hr;
987 /**************************************************************************
988 * WsGetXmlAttribute [webservices.@]
990 HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *attr,
991 WS_HEAP *heap, WCHAR **str, ULONG *len, WS_ERROR *error )
993 FIXME( "%p %s %p %p %p %p: stub\n", handle, debugstr_xmlstr(attr), heap, str, len, error );
994 return E_NOTIMPL;
997 WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len )
999 WS_XML_UTF8_TEXT *ret;
1001 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
1002 ret->text.textType = WS_XML_TEXT_TYPE_UTF8;
1003 ret->value.length = len;
1004 ret->value.bytes = len ? (BYTE *)(ret + 1) : NULL;
1005 ret->value.dictionary = NULL;
1006 ret->value.id = 0;
1007 if (data) memcpy( ret->value.bytes, data, len );
1008 return ret;
1011 static inline BOOL read_end_of_data( struct reader *reader )
1013 return reader->read_pos >= reader->read_size;
1016 static inline const unsigned char *read_current_ptr( struct reader *reader )
1018 return &reader->read_bufptr[reader->read_pos];
1021 static inline HRESULT read_peek( struct reader *reader, unsigned char *byte )
1023 if (reader->read_pos >= reader->read_size) return WS_E_INVALID_FORMAT;
1024 *byte = reader->read_bufptr[reader->read_pos];
1025 return S_OK;
1028 static inline HRESULT read_byte( struct reader *reader, unsigned char *byte )
1030 if (reader->read_pos >= reader->read_size) return WS_E_INVALID_FORMAT;
1031 *byte = reader->read_bufptr[reader->read_pos++];
1032 return S_OK;
1035 static inline HRESULT read_bytes( struct reader *reader, unsigned char *bytes, unsigned int len )
1037 if (reader->read_pos + len > reader->read_size) return WS_E_INVALID_FORMAT;
1038 memcpy( bytes, reader->read_bufptr + reader->read_pos, len );
1039 reader->read_pos += len;
1040 return S_OK;
1043 /* UTF-8 support based on libs/wine/utf8.c */
1045 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
1046 static const char utf8_length[128] =
1048 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
1049 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
1050 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
1051 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
1052 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
1053 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
1054 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
1055 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
1058 /* first byte mask depending on UTF-8 sequence length */
1059 static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
1061 /* minimum Unicode value depending on UTF-8 sequence length */
1062 static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
1064 static inline unsigned int read_utf8_char( struct reader *reader, unsigned int *skip )
1066 unsigned int len, res;
1067 unsigned char ch = reader->read_bufptr[reader->read_pos];
1068 const unsigned char *end;
1070 if (reader->read_pos >= reader->read_size) return 0;
1072 if (ch < 0x80)
1074 *skip = 1;
1075 return ch;
1077 len = utf8_length[ch - 0x80];
1078 if (reader->read_pos + len >= reader->read_size) return 0;
1079 end = reader->read_bufptr + reader->read_pos + len + 1;
1080 res = ch & utf8_mask[len];
1082 switch (len)
1084 case 3:
1085 if ((ch = end[-3] ^ 0x80) >= 0x40) break;
1086 res = (res << 6) | ch;
1087 case 2:
1088 if ((ch = end[-2] ^ 0x80) >= 0x40) break;
1089 res = (res << 6) | ch;
1090 case 1:
1091 if ((ch = end[-1] ^ 0x80) >= 0x40) break;
1092 res = (res << 6) | ch;
1093 if (res < utf8_minval[len]) break;
1094 *skip = len + 1;
1095 return res;
1098 return 0;
1101 static inline void read_skip( struct reader *reader, unsigned int count )
1103 if (reader->read_pos + count > reader->read_size) return;
1104 reader->read_pos += count;
1107 static inline void read_rewind( struct reader *reader, unsigned int count )
1109 reader->read_pos -= count;
1112 static inline BOOL read_isnamechar( unsigned int ch )
1114 /* FIXME: incomplete */
1115 return (ch >= 'A' && ch <= 'Z') ||
1116 (ch >= 'a' && ch <= 'z') ||
1117 (ch >= '0' && ch <= '9') ||
1118 ch == '_' || ch == '-' || ch == '.' || ch == ':';
1121 static inline BOOL read_isspace( unsigned int ch )
1123 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
1126 static inline void read_skip_whitespace( struct reader *reader )
1128 while (reader->read_pos < reader->read_size && read_isspace( reader->read_bufptr[reader->read_pos] ))
1129 reader->read_pos++;
1132 static inline int read_cmp( struct reader *reader, const char *str, int len )
1134 const unsigned char *ptr = read_current_ptr( reader );
1136 if (len < 0) len = strlen( str );
1137 if (reader->read_pos + len > reader->read_size) return -1;
1138 while (len--)
1140 if (*str != *ptr) return *ptr - *str;
1141 str++; ptr++;
1143 return 0;
1146 static HRESULT read_xmldecl( struct reader *reader )
1148 if (!reader->read_size) return WS_E_INVALID_FORMAT;
1150 if (read_cmp( reader, "<", 1 ) || read_cmp( reader, "<?", 2 ))
1152 reader->state = READER_STATE_BOF;
1153 return S_OK;
1155 if (read_cmp( reader, "<?xml ", 6 )) return WS_E_INVALID_FORMAT;
1156 read_skip( reader, 6 );
1158 /* FIXME: parse attributes */
1159 while (reader->read_pos < reader->read_size && reader->read_bufptr[reader->read_pos] != '?')
1160 reader->read_pos++;
1162 if (read_cmp( reader, "?>", 2 )) return WS_E_INVALID_FORMAT;
1163 read_skip( reader, 2 );
1165 reader->state = READER_STATE_BOF;
1166 return S_OK;
1169 HRESULT append_attribute( WS_XML_ELEMENT_NODE *elem, WS_XML_ATTRIBUTE *attr )
1171 if (elem->attributeCount)
1173 WS_XML_ATTRIBUTE **tmp;
1174 if (!(tmp = heap_realloc( elem->attributes, (elem->attributeCount + 1) * sizeof(attr) )))
1175 return E_OUTOFMEMORY;
1176 elem->attributes = tmp;
1178 else if (!(elem->attributes = heap_alloc( sizeof(attr) ))) return E_OUTOFMEMORY;
1179 elem->attributes[elem->attributeCount++] = attr;
1180 return S_OK;
1183 static HRESULT split_name( const unsigned char *str, ULONG len, const unsigned char **prefix,
1184 ULONG *prefix_len, const unsigned char **localname, ULONG *localname_len )
1186 const unsigned char *ptr = str;
1188 *prefix = NULL;
1189 *prefix_len = 0;
1191 *localname = str;
1192 *localname_len = len;
1194 while (len--)
1196 if (*ptr == ':')
1198 if (ptr == str) return WS_E_INVALID_FORMAT;
1199 *prefix = str;
1200 *prefix_len = ptr - str;
1201 *localname = ptr + 1;
1202 *localname_len = len;
1203 break;
1205 ptr++;
1207 return S_OK;
1210 static HRESULT parse_name( const unsigned char *str, ULONG len, WS_XML_STRING **prefix, WS_XML_STRING **localname )
1212 const unsigned char *localname_ptr, *prefix_ptr;
1213 ULONG localname_len, prefix_len;
1214 HRESULT hr;
1216 if ((hr = split_name( str, len, &prefix_ptr, &prefix_len, &localname_ptr, &localname_len )) != S_OK) return hr;
1217 if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY;
1218 if (!(*localname = alloc_xml_string( localname_ptr, localname_len )))
1220 free_xml_string( *prefix );
1221 *prefix = NULL;
1222 return E_OUTOFMEMORY;
1224 return S_OK;
1227 static int codepoint_to_utf8( int cp, unsigned char *dst )
1229 if (!cp) return -1;
1230 if (cp < 0x80)
1232 *dst = cp;
1233 return 1;
1235 if (cp < 0x800)
1237 dst[1] = 0x80 | (cp & 0x3f);
1238 cp >>= 6;
1239 dst[0] = 0xc0 | cp;
1240 return 2;
1242 if ((cp >= 0xd800 && cp <= 0xdfff) || cp == 0xfffe || cp == 0xffff) return -1;
1243 if (cp < 0x10000)
1245 dst[2] = 0x80 | (cp & 0x3f);
1246 cp >>= 6;
1247 dst[1] = 0x80 | (cp & 0x3f);
1248 cp >>= 6;
1249 dst[0] = 0xe0 | cp;
1250 return 3;
1252 if (cp >= 0x110000) return -1;
1253 dst[3] = 0x80 | (cp & 0x3f);
1254 cp >>= 6;
1255 dst[2] = 0x80 | (cp & 0x3f);
1256 cp >>= 6;
1257 dst[1] = 0x80 | (cp & 0x3f);
1258 cp >>= 6;
1259 dst[0] = 0xf0 | cp;
1260 return 4;
1263 static HRESULT decode_text( const unsigned char *str, ULONG len, unsigned char *ret, ULONG *ret_len )
1265 const unsigned char *p = str;
1266 unsigned char *q = ret;
1268 *ret_len = 0;
1269 while (len)
1271 if (*p == '&')
1273 p++; len--;
1274 if (!len) return WS_E_INVALID_FORMAT;
1276 if (len >= 3 && !memcmp( p, "lt;", 3 ))
1278 *q++ = '<';
1279 p += 3;
1280 len -= 3;
1282 else if (len >= 3 && !memcmp( p, "gt;", 3 ))
1284 *q++ = '>';
1285 p += 3;
1286 len -= 3;
1288 else if (len >= 5 && !memcmp( p, "quot;", 5 ))
1290 *q++ = '"';
1291 p += 5;
1292 len -= 5;
1294 else if (len >= 4 && !memcmp( p, "amp;", 4 ))
1296 *q++ = '&';
1297 p += 4;
1298 len -= 4;
1300 else if (len >= 5 && !memcmp( p, "apos;", 5 ))
1302 *q++ = '\'';
1303 p += 5;
1304 len -= 5;
1306 else if (*p == '#')
1308 ULONG start, nb_digits, i;
1309 int len_utf8, cp = 0;
1311 p++; len--;
1312 if (!len) return WS_E_INVALID_FORMAT;
1313 if (*p == 'x')
1315 p++; len--;
1317 start = len;
1318 while (len && isxdigit( *p )) { p++; len--; };
1319 if (!len) return WS_E_INVALID_FORMAT;
1321 p -= nb_digits = start - len;
1322 if (!nb_digits || nb_digits > 6 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1323 for (i = 0; i < nb_digits; i++)
1325 cp *= 16;
1326 if (*p >= '0' && *p <= '9') cp += *p - '0';
1327 else if (*p >= 'a' && *p <= 'f') cp += *p - 'a' + 10;
1328 else cp += *p - 'A' + 10;
1329 p++;
1332 else if (isdigit( *p ))
1334 while (len && *p == '0') { p++; len--; };
1335 if (!len) return WS_E_INVALID_FORMAT;
1337 start = len;
1338 while (len && isdigit( *p )) { p++; len--; };
1339 if (!len) return WS_E_INVALID_FORMAT;
1341 p -= nb_digits = start - len;
1342 if (!nb_digits || nb_digits > 7 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1343 for (i = 0; i < nb_digits; i++)
1345 cp *= 10;
1346 cp += *p - '0';
1347 p++;
1350 else return WS_E_INVALID_FORMAT;
1351 p++; len--;
1352 if ((len_utf8 = codepoint_to_utf8( cp, q )) < 0) return WS_E_INVALID_FORMAT;
1353 *ret_len += len_utf8;
1354 q += len_utf8;
1355 continue;
1357 else return WS_E_INVALID_FORMAT;
1359 else
1361 *q++ = *p++;
1362 len--;
1364 *ret_len += 1;
1366 return S_OK;
1369 static HRESULT read_attribute_value_text( struct reader *reader, WS_XML_ATTRIBUTE *attr )
1371 WS_XML_UTF8_TEXT *utf8 = NULL;
1372 unsigned int len, ch, skip, quote;
1373 const unsigned char *start;
1374 HRESULT hr = E_OUTOFMEMORY;
1376 read_skip_whitespace( reader );
1377 if (read_cmp( reader, "=", 1 )) return WS_E_INVALID_FORMAT;
1378 read_skip( reader, 1 );
1380 read_skip_whitespace( reader );
1381 if (read_cmp( reader, "\"", 1 ) && read_cmp( reader, "'", 1 )) return WS_E_INVALID_FORMAT;
1382 quote = read_utf8_char( reader, &skip );
1383 read_skip( reader, 1 );
1385 len = 0;
1386 start = read_current_ptr( reader );
1387 for (;;)
1389 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1390 if (ch == quote) break;
1391 read_skip( reader, skip );
1392 len += skip;
1394 read_skip( reader, 1 );
1396 if (attr->isXmlNs)
1398 if (!(attr->ns = alloc_xml_string( start, len ))) goto error;
1399 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1400 if (!(utf8 = alloc_utf8_text( NULL, 0 )))
1402 hr = E_OUTOFMEMORY;
1403 goto error;
1406 else
1408 if (!(utf8 = alloc_utf8_text( NULL, len ))) goto error;
1409 if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK) goto error;
1412 attr->value = &utf8->text;
1413 attr->singleQuote = (quote == '\'');
1414 return S_OK;
1416 error:
1417 heap_free( utf8 );
1418 return hr;
1421 static inline BOOL is_text_type( unsigned char type )
1423 return (type >= RECORD_ZERO_TEXT && type <= RECORD_QNAME_DICTIONARY_TEXT_WITH_ENDELEMENT);
1426 static HRESULT read_int31( struct reader *reader, ULONG *len )
1428 unsigned char byte;
1429 HRESULT hr;
1431 if ((hr = read_byte( reader, &byte )) != S_OK) return hr;
1432 *len = byte & 0x7f;
1433 if (!(byte & 0x80)) return S_OK;
1435 if ((hr = read_byte( reader, &byte )) != S_OK) return hr;
1436 *len += (byte & 0x7f) << 7;
1437 if (!(byte & 0x80)) return S_OK;
1439 if ((hr = read_byte( reader, &byte )) != S_OK) return hr;
1440 *len += (byte & 0x7f) << 14;
1441 if (!(byte & 0x80)) return S_OK;
1443 if ((hr = read_byte( reader, &byte )) != S_OK) return hr;
1444 *len += (byte & 0x7f) << 21;
1445 if (!(byte & 0x80)) return S_OK;
1447 if ((hr = read_byte( reader, &byte )) != S_OK) return hr;
1448 *len += (byte & 0x07) << 28;
1449 return S_OK;
1452 static HRESULT read_string( struct reader *reader, WS_XML_STRING **str )
1454 ULONG len;
1455 HRESULT hr;
1456 if ((hr = read_int31( reader, &len )) != S_OK) return hr;
1457 if (!(*str = alloc_xml_string( NULL, len ))) return E_OUTOFMEMORY;
1458 if ((hr = read_bytes( reader, (*str)->bytes, len )) == S_OK)
1460 if (add_xml_string( *str ) != S_OK) WARN( "string not added to dictionary\n" );
1461 return S_OK;
1463 free_xml_string( *str );
1464 return hr;
1467 static HRESULT read_dict_string( struct reader *reader, WS_XML_STRING **str )
1469 ULONG id;
1470 HRESULT hr;
1471 if ((hr = read_int31( reader, &id )) != S_OK) return hr;
1472 if (!reader->dict || (id >>= 1) >= reader->dict->stringCount) return WS_E_INVALID_FORMAT;
1473 if (!(*str = alloc_xml_string( NULL, 0 ))) return E_OUTOFMEMORY;
1474 *(*str) = reader->dict->strings[id];
1475 return S_OK;
1478 static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE *attr )
1480 WS_XML_UTF8_TEXT *utf8 = NULL;
1481 unsigned char type;
1482 HRESULT hr;
1483 ULONG len;
1485 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
1486 if (!is_text_type( type )) return WS_E_INVALID_FORMAT;
1488 switch (type)
1490 case RECORD_CHARS8_TEXT:
1492 unsigned char len8;
1493 if ((hr = read_byte( reader, &len8 )) != S_OK) return hr;
1494 len = len8;
1495 break;
1497 default:
1498 ERR( "unhandled record type %02x\n", type );
1499 return WS_E_NOT_SUPPORTED;
1502 if (!(utf8 = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY;
1503 if (!len) utf8->value.bytes = (BYTE *)(utf8 + 1); /* quirk */
1504 if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK)
1506 heap_free( utf8 );
1507 return hr;
1510 attr->value = &utf8->text;
1511 return S_OK;
1514 static HRESULT read_attribute_text( struct reader *reader, WS_XML_ATTRIBUTE **ret )
1516 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
1517 WS_XML_ATTRIBUTE *attr;
1518 unsigned int len = 0, ch, skip;
1519 const unsigned char *start;
1520 WS_XML_STRING *prefix, *localname;
1521 HRESULT hr = WS_E_INVALID_FORMAT;
1523 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1525 start = read_current_ptr( reader );
1526 for (;;)
1528 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1529 if (!read_isnamechar( ch )) break;
1530 read_skip( reader, skip );
1531 len += skip;
1533 if (!len) goto error;
1535 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) goto error;
1536 if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
1538 free_xml_string( prefix );
1539 attr->isXmlNs = 1;
1540 if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length )))
1542 free_xml_string( localname );
1543 hr = E_OUTOFMEMORY;
1544 goto error;
1546 attr->localName = localname;
1548 else if (!prefix->length && WsXmlStringEquals( localname, &xmlns, NULL ) == S_OK)
1550 attr->isXmlNs = 1;
1551 attr->prefix = prefix;
1552 attr->localName = localname;
1554 else
1556 attr->prefix = prefix;
1557 attr->localName = localname;
1560 if ((hr = read_attribute_value_text( reader, attr )) != S_OK) goto error;
1562 *ret = attr;
1563 return S_OK;
1565 error:
1566 free_attribute( attr );
1567 return hr;
1570 static inline BOOL is_attribute_type( unsigned char type )
1572 return (type >= RECORD_SHORT_ATTRIBUTE && type <= RECORD_PREFIX_ATTRIBUTE_Z);
1575 static HRESULT read_attribute_bin( struct reader *reader, WS_XML_ATTRIBUTE **ret )
1577 WS_XML_ATTRIBUTE *attr;
1578 unsigned char type = 0;
1579 HRESULT hr;
1581 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
1582 if (!is_attribute_type( type )) return WS_E_INVALID_FORMAT;
1583 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1585 if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
1587 unsigned char ch = type - RECORD_PREFIX_ATTRIBUTE_A + 'a';
1588 if (!(attr->prefix = alloc_xml_string( &ch, 1 )))
1590 hr = E_OUTOFMEMORY;
1591 goto error;
1593 if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error;
1594 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1596 else if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
1598 unsigned char ch = type - RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + 'a';
1599 if (!(attr->prefix = alloc_xml_string( &ch, 1 )))
1601 hr = E_OUTOFMEMORY;
1602 goto error;
1604 if ((hr = read_dict_string( reader, &attr->localName )) != S_OK) goto error;
1605 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1607 else
1609 switch (type)
1611 case RECORD_SHORT_ATTRIBUTE:
1612 if (!(attr->prefix = alloc_xml_string( NULL, 0 )))
1614 hr = E_OUTOFMEMORY;
1615 goto error;
1617 if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error;
1618 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1619 break;
1621 case RECORD_ATTRIBUTE:
1622 if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error;
1623 if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error;
1624 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1625 break;
1627 case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
1628 if (!(attr->prefix = alloc_xml_string( NULL, 0 )))
1630 hr = E_OUTOFMEMORY;
1631 goto error;
1633 if ((hr = read_dict_string( reader, &attr->localName )) != S_OK) goto error;
1634 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1635 break;
1637 case RECORD_DICTIONARY_ATTRIBUTE:
1638 if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error;
1639 if ((hr = read_dict_string( reader, &attr->localName )) != S_OK) goto error;
1640 if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error;
1641 break;
1643 case RECORD_SHORT_XMLNS_ATTRIBUTE:
1644 if (!(attr->prefix = alloc_xml_string( NULL, 0 )))
1646 hr = E_OUTOFMEMORY;
1647 goto error;
1649 if ((hr = read_string( reader, &attr->ns )) != S_OK) goto error;
1650 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1651 attr->isXmlNs = 1;
1652 break;
1654 case RECORD_XMLNS_ATTRIBUTE:
1655 if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error;
1656 if ((hr = read_string( reader, &attr->ns )) != S_OK) goto error;
1657 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1658 attr->isXmlNs = 1;
1659 break;
1661 case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
1662 if (!(attr->prefix = alloc_xml_string( NULL, 0 )))
1664 hr = E_OUTOFMEMORY;
1665 goto error;
1667 if ((hr = read_dict_string( reader, &attr->ns )) != S_OK) goto error;
1668 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1669 attr->isXmlNs = 1;
1670 break;
1672 case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
1673 if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error;
1674 if ((hr = read_dict_string( reader, &attr->ns )) != S_OK) goto error;
1675 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1676 attr->isXmlNs = 1;
1677 break;
1679 default:
1680 ERR( "unhandled record type %02x\n", type );
1681 return WS_E_NOT_SUPPORTED;
1685 *ret = attr;
1686 return S_OK;
1688 error:
1689 free_attribute( attr );
1690 return hr;
1693 static inline struct node *find_parent( struct reader *reader )
1695 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT)
1697 if (is_valid_parent( reader->current->parent->parent )) return reader->current->parent->parent;
1698 return NULL;
1700 if (is_valid_parent( reader->current )) return reader->current;
1701 if (is_valid_parent( reader->current->parent )) return reader->current->parent;
1702 return NULL;
1705 static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1707 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
1708 const WS_XML_STRING *ns;
1709 ULONG i;
1711 if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT;
1712 if (!(elem->ns = dup_xml_string( ns ))) return E_OUTOFMEMORY;
1714 for (i = 0; i < elem->attributeCount; i++)
1716 WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1717 if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue;
1718 if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT;
1719 if (!(attr->ns = alloc_xml_string( NULL, ns->length ))) return E_OUTOFMEMORY;
1720 if (attr->ns->length) memcpy( attr->ns->bytes, ns->bytes, ns->length );
1722 return S_OK;
1725 static WS_XML_ELEMENT_NODE *alloc_element_pair(void)
1727 struct node *node, *end;
1728 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
1729 if (!(end = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT )))
1731 free_node( node );
1732 return NULL;
1734 list_add_tail( &node->children, &end->entry );
1735 end->parent = node;
1736 return &node->hdr;
1739 static HRESULT read_attributes_text( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1741 WS_XML_ATTRIBUTE *attr;
1742 HRESULT hr;
1744 reader->current_attr = 0;
1745 for (;;)
1747 read_skip_whitespace( reader );
1748 if (!read_cmp( reader, ">", 1 ) || !read_cmp( reader, "/>", 2 )) break;
1749 if ((hr = read_attribute_text( reader, &attr )) != S_OK) return hr;
1750 if ((hr = append_attribute( elem, attr )) != S_OK)
1752 free_attribute( attr );
1753 return hr;
1755 reader->current_attr++;
1757 return S_OK;
1760 static HRESULT read_element_text( struct reader *reader )
1762 unsigned int len = 0, ch, skip;
1763 const unsigned char *start;
1764 struct node *node = NULL, *parent;
1765 WS_XML_ELEMENT_NODE *elem;
1766 HRESULT hr = WS_E_INVALID_FORMAT;
1768 if (read_end_of_data( reader ))
1770 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1771 reader->last = reader->current;
1772 reader->state = READER_STATE_EOF;
1773 return S_OK;
1776 if (read_cmp( reader, "<", 1 )) return WS_E_INVALID_FORMAT;
1777 read_skip( reader, 1 );
1778 if (!read_isnamechar( read_utf8_char( reader, &skip )))
1780 read_rewind( reader, 1 );
1781 return WS_E_INVALID_FORMAT;
1784 if (!(elem = alloc_element_pair())) return E_OUTOFMEMORY;
1785 node = (struct node *)elem;
1787 start = read_current_ptr( reader );
1788 for (;;)
1790 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1791 if (!read_isnamechar( ch )) break;
1792 read_skip( reader, skip );
1793 len += skip;
1795 if (!len) goto error;
1797 if (!(parent = find_parent( reader ))) goto error;
1798 if ((hr = parse_name( start, len, &elem->prefix, &elem->localName )) != S_OK) goto error;
1800 if ((hr = read_attributes_text( reader, elem )) != S_OK) goto error;
1801 if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
1803 read_insert_node( reader, parent, node );
1804 reader->state = READER_STATE_STARTELEMENT;
1805 return S_OK;
1807 error:
1808 destroy_nodes( node );
1809 return hr;
1812 static inline BOOL is_element_type( unsigned char type )
1814 return (type >= RECORD_SHORT_ELEMENT && type <= RECORD_PREFIX_ELEMENT_Z);
1817 static HRESULT read_attributes_bin( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1819 WS_XML_ATTRIBUTE *attr;
1820 unsigned char type;
1821 HRESULT hr;
1823 reader->current_attr = 0;
1824 for (;;)
1826 if ((hr = read_peek( reader, &type )) != S_OK) return hr;
1827 if (!is_attribute_type( type )) break;
1828 if ((hr = read_attribute_bin( reader, &attr )) != S_OK) return hr;
1829 if ((hr = append_attribute( elem, attr )) != S_OK)
1831 free_attribute( attr );
1832 return hr;
1834 reader->current_attr++;
1836 return S_OK;
1839 static HRESULT read_element_bin( struct reader *reader )
1841 struct node *node = NULL, *parent;
1842 WS_XML_ELEMENT_NODE *elem;
1843 unsigned char type;
1844 HRESULT hr;
1846 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
1847 if (!is_element_type( type )) return WS_E_INVALID_FORMAT;
1849 if (!(elem = alloc_element_pair())) return E_OUTOFMEMORY;
1850 node = (struct node *)elem;
1852 if (type >= RECORD_PREFIX_ELEMENT_A && type <= RECORD_PREFIX_ELEMENT_Z)
1854 unsigned char ch = type - RECORD_PREFIX_ELEMENT_A + 'a';
1855 if (!(elem->prefix = alloc_xml_string( &ch, 1 )))
1857 hr = E_OUTOFMEMORY;
1858 goto error;
1860 if ((hr = read_string( reader, &elem->localName )) != S_OK) goto error;
1862 else if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
1864 unsigned char ch = type - RECORD_PREFIX_DICTIONARY_ELEMENT_A + 'a';
1865 if (!(elem->prefix = alloc_xml_string( &ch, 1 )))
1867 hr = E_OUTOFMEMORY;
1868 goto error;
1870 if ((hr = read_dict_string( reader, &elem->localName )) != S_OK) goto error;
1872 else
1874 switch (type)
1876 case RECORD_SHORT_ELEMENT:
1877 if (!(elem->prefix = alloc_xml_string( NULL, 0 )))
1879 hr = E_OUTOFMEMORY;
1880 goto error;
1882 if ((hr = read_string( reader, &elem->localName )) != S_OK) goto error;
1883 break;
1885 case RECORD_ELEMENT:
1886 if ((hr = read_string( reader, &elem->prefix )) != S_OK) goto error;
1887 if ((hr = read_string( reader, &elem->localName )) != S_OK) goto error;
1888 break;
1890 case RECORD_SHORT_DICTIONARY_ELEMENT:
1891 if (!(elem->prefix = alloc_xml_string( NULL, 0 )))
1893 hr = E_OUTOFMEMORY;
1894 goto error;
1896 if ((hr = read_dict_string( reader, &elem->localName )) != S_OK) goto error;
1897 break;
1899 case RECORD_DICTIONARY_ELEMENT:
1900 if ((hr = read_string( reader, &elem->prefix )) != S_OK) goto error;
1901 if ((hr = read_dict_string( reader, &elem->localName )) != S_OK) goto error;
1902 break;
1904 default:
1905 ERR( "unhandled record type %02x\n", type );
1906 return WS_E_NOT_SUPPORTED;
1910 if (!(parent = find_parent( reader )))
1912 hr = WS_E_INVALID_FORMAT;
1913 goto error;
1916 if ((hr = read_attributes_bin( reader, elem )) != S_OK) goto error;
1917 if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
1919 read_insert_node( reader, parent, node );
1920 reader->state = READER_STATE_STARTELEMENT;
1921 return S_OK;
1923 error:
1924 destroy_nodes( node );
1925 return hr;
1928 static HRESULT read_text_text( struct reader *reader )
1930 unsigned int len = 0, ch, skip;
1931 const unsigned char *start;
1932 struct node *node, *parent;
1933 WS_XML_TEXT_NODE *text;
1934 WS_XML_UTF8_TEXT *utf8;
1935 HRESULT hr;
1937 start = read_current_ptr( reader );
1938 for (;;)
1940 if (read_end_of_data( reader )) break;
1941 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1942 if (ch == '<') break;
1943 read_skip( reader, skip );
1944 len += skip;
1947 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1949 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1950 text = (WS_XML_TEXT_NODE *)node;
1951 if (!(utf8 = alloc_utf8_text( NULL, len )))
1953 heap_free( node );
1954 return E_OUTOFMEMORY;
1956 if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK)
1958 heap_free( utf8 );
1959 heap_free( node );
1960 return hr;
1962 text->text = &utf8->text;
1964 read_insert_node( reader, parent, node );
1965 reader->state = READER_STATE_TEXT;
1966 reader->text_conv_offset = 0;
1967 return S_OK;
1970 static HRESULT read_text_bin( struct reader *reader )
1972 unsigned char type;
1973 struct node *node, *parent;
1974 WS_XML_TEXT_NODE *text;
1975 WS_XML_UTF8_TEXT *utf8;
1976 ULONG len;
1977 HRESULT hr;
1979 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
1980 if (!is_text_type( type )) return WS_E_INVALID_FORMAT;
1982 switch (type)
1984 case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
1986 unsigned char len8;
1987 if ((hr = read_byte( reader, &len8 )) != S_OK) return hr;
1988 len = len8;
1989 break;
1991 default:
1992 ERR( "unhandled record type %02x\n", type );
1993 return WS_E_NOT_SUPPORTED;
1996 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1998 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1999 text = (WS_XML_TEXT_NODE *)node;
2000 if (!(utf8 = alloc_utf8_text( NULL, len )))
2002 heap_free( node );
2003 return E_OUTOFMEMORY;
2005 if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK)
2007 heap_free( utf8 );
2008 heap_free( node );
2009 return hr;
2011 text->text = &utf8->text;
2013 read_insert_node( reader, parent, node );
2014 reader->state = READER_STATE_TEXT;
2015 reader->text_conv_offset = 0;
2016 return S_OK;
2019 static HRESULT read_node_text( struct reader * );
2021 static HRESULT read_startelement_text( struct reader *reader )
2023 read_skip_whitespace( reader );
2024 if (!read_cmp( reader, "/>", 2 ))
2026 read_skip( reader, 2 );
2027 reader->current = LIST_ENTRY( list_tail( &reader->current->children ), struct node, entry );
2028 reader->last = reader->current;
2029 reader->state = READER_STATE_ENDELEMENT;
2030 return S_OK;
2032 else if (!read_cmp( reader, ">", 1 ))
2034 read_skip( reader, 1 );
2035 return read_node_text( reader );
2037 return WS_E_INVALID_FORMAT;
2040 static HRESULT read_node_bin( struct reader * );
2042 static HRESULT read_startelement_bin( struct reader *reader )
2044 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return WS_E_INVALID_FORMAT;
2045 return read_node_bin( reader );
2048 static HRESULT read_startelement( struct reader *reader )
2050 switch (reader->input_enc)
2052 case WS_XML_READER_ENCODING_TYPE_TEXT: return read_startelement_text( reader );
2053 case WS_XML_READER_ENCODING_TYPE_BINARY: return read_startelement_bin( reader );
2054 default:
2055 ERR( "unhandled encoding %u\n", reader->input_enc );
2056 return WS_E_NOT_SUPPORTED;
2060 static HRESULT read_to_startelement_text( struct reader *reader, BOOL *found )
2062 HRESULT hr;
2064 switch (reader->state)
2066 case READER_STATE_INITIAL:
2067 if ((hr = read_xmldecl( reader )) != S_OK) return hr;
2068 break;
2070 case READER_STATE_STARTELEMENT:
2071 if (found) *found = TRUE;
2072 return S_OK;
2074 default:
2075 break;
2078 read_skip_whitespace( reader );
2079 if ((hr = read_element_text( reader )) == S_OK && found)
2081 if (reader->state == READER_STATE_STARTELEMENT)
2082 *found = TRUE;
2083 else
2084 *found = FALSE;
2087 return hr;
2090 static HRESULT read_to_startelement_bin( struct reader *reader, BOOL *found )
2092 HRESULT hr;
2094 if (reader->state == READER_STATE_STARTELEMENT)
2096 if (found) *found = TRUE;
2097 return S_OK;
2100 if ((hr = read_element_bin( reader )) == S_OK && found)
2102 if (reader->state == READER_STATE_STARTELEMENT)
2103 *found = TRUE;
2104 else
2105 *found = FALSE;
2108 return hr;
2111 static HRESULT read_to_startelement( struct reader *reader, BOOL *found )
2113 switch (reader->input_enc)
2115 case WS_XML_READER_ENCODING_TYPE_TEXT: return read_to_startelement_text( reader, found );
2116 case WS_XML_READER_ENCODING_TYPE_BINARY: return read_to_startelement_bin( reader, found );
2117 default:
2118 ERR( "unhandled encoding %u\n", reader->input_enc );
2119 return WS_E_NOT_SUPPORTED;
2123 static int cmp_name( const unsigned char *name1, ULONG len1, const unsigned char *name2, ULONG len2 )
2125 ULONG i;
2126 if (len1 != len2) return 1;
2127 for (i = 0; i < len1; i++) { if (toupper( name1[i] ) != toupper( name2[i] )) return 1; }
2128 return 0;
2131 static struct node *find_startelement( struct reader *reader, const WS_XML_STRING *prefix,
2132 const WS_XML_STRING *localname )
2134 struct node *parent;
2135 const WS_XML_STRING *str;
2137 for (parent = reader->current; parent; parent = parent->parent)
2139 if (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
2141 str = parent->hdr.prefix;
2142 if (cmp_name( str->bytes, str->length, prefix->bytes, prefix->length )) continue;
2143 str = parent->hdr.localName;
2144 if (cmp_name( str->bytes, str->length, localname->bytes, localname->length )) continue;
2145 return parent;
2148 return NULL;
2151 static HRESULT read_endelement_text( struct reader *reader )
2153 struct node *parent;
2154 unsigned int len = 0, ch, skip;
2155 const unsigned char *start;
2156 WS_XML_STRING *prefix, *localname;
2157 HRESULT hr;
2159 if (read_cmp( reader, "</", 2 )) return WS_E_INVALID_FORMAT;
2160 read_skip( reader, 2 );
2162 start = read_current_ptr( reader );
2163 for (;;)
2165 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
2166 if (ch == '>')
2168 read_skip( reader, 1 );
2169 break;
2171 if (!read_isnamechar( ch )) return WS_E_INVALID_FORMAT;
2172 read_skip( reader, skip );
2173 len += skip;
2176 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) return hr;
2177 parent = find_startelement( reader, prefix, localname );
2178 free_xml_string( prefix );
2179 free_xml_string( localname );
2180 if (!parent) return WS_E_INVALID_FORMAT;
2182 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
2183 reader->last = reader->current;
2184 reader->state = READER_STATE_ENDELEMENT;
2185 return S_OK;
2188 static HRESULT read_endelement_bin( struct reader *reader )
2190 struct node *parent;
2191 unsigned char type;
2192 HRESULT hr;
2194 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
2195 if (type != RECORD_ENDELEMENT) return WS_E_INVALID_FORMAT;
2197 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2199 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
2200 reader->last = reader->current;
2201 reader->state = READER_STATE_ENDELEMENT;
2202 return S_OK;
2205 static HRESULT read_endelement( struct reader *reader )
2207 if (reader->state == READER_STATE_EOF) return WS_E_INVALID_FORMAT;
2209 if (read_end_of_data( reader ))
2211 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
2212 reader->last = reader->current;
2213 reader->state = READER_STATE_EOF;
2214 return S_OK;
2217 switch (reader->input_enc)
2219 case WS_XML_READER_ENCODING_TYPE_TEXT: return read_endelement_text( reader );
2220 case WS_XML_READER_ENCODING_TYPE_BINARY: return read_endelement_bin( reader );
2221 default:
2222 ERR( "unhandled encoding %u\n", reader->input_enc );
2223 return WS_E_NOT_SUPPORTED;
2227 static HRESULT read_comment_text( struct reader *reader )
2229 unsigned int len = 0, ch, skip;
2230 const unsigned char *start;
2231 struct node *node, *parent;
2232 WS_XML_COMMENT_NODE *comment;
2234 if (read_cmp( reader, "<!--", 4 )) return WS_E_INVALID_FORMAT;
2235 read_skip( reader, 4 );
2237 start = read_current_ptr( reader );
2238 for (;;)
2240 if (!read_cmp( reader, "-->", 3 ))
2242 read_skip( reader, 3 );
2243 break;
2245 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
2246 read_skip( reader, skip );
2247 len += skip;
2250 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2252 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2253 comment = (WS_XML_COMMENT_NODE *)node;
2254 if (!(comment->value.bytes = heap_alloc( len )))
2256 heap_free( node );
2257 return E_OUTOFMEMORY;
2259 memcpy( comment->value.bytes, start, len );
2260 comment->value.length = len;
2262 read_insert_node( reader, parent, node );
2263 reader->state = READER_STATE_COMMENT;
2264 return S_OK;
2267 static HRESULT read_comment_bin( struct reader *reader )
2269 struct node *node, *parent;
2270 WS_XML_COMMENT_NODE *comment;
2271 unsigned char type;
2272 ULONG len;
2273 HRESULT hr;
2275 if ((hr = read_byte( reader, &type )) != S_OK) return hr;
2276 if (type != RECORD_COMMENT) return WS_E_INVALID_FORMAT;
2277 if ((hr = read_int31( reader, &len )) != S_OK) return hr;
2279 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2281 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2282 comment = (WS_XML_COMMENT_NODE *)node;
2283 if (!(comment->value.bytes = heap_alloc( len )))
2285 heap_free( node );
2286 return E_OUTOFMEMORY;
2288 if ((hr = read_bytes( reader, comment->value.bytes, len )) != S_OK)
2290 free_node( node );
2291 return E_OUTOFMEMORY;
2293 comment->value.length = len;
2295 read_insert_node( reader, parent, node );
2296 reader->state = READER_STATE_COMMENT;
2297 return S_OK;
2300 static HRESULT read_startcdata( struct reader *reader )
2302 struct node *node, *endnode, *parent;
2304 if (read_cmp( reader, "<![CDATA[", 9 )) return WS_E_INVALID_FORMAT;
2305 read_skip( reader, 9 );
2307 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2309 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2310 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_CDATA )))
2312 heap_free( node );
2313 return E_OUTOFMEMORY;
2315 list_add_tail( &node->children, &endnode->entry );
2316 endnode->parent = node;
2318 read_insert_node( reader, parent, node );
2319 reader->state = READER_STATE_STARTCDATA;
2320 return S_OK;
2323 static HRESULT read_cdata( struct reader *reader )
2325 unsigned int len = 0, ch, skip;
2326 const unsigned char *start;
2327 struct node *node;
2328 WS_XML_TEXT_NODE *text;
2329 WS_XML_UTF8_TEXT *utf8;
2331 start = read_current_ptr( reader );
2332 for (;;)
2334 if (!read_cmp( reader, "]]>", 3 )) break;
2335 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
2336 read_skip( reader, skip );
2337 len += skip;
2340 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2341 text = (WS_XML_TEXT_NODE *)node;
2342 if (!(utf8 = alloc_utf8_text( start, len )))
2344 heap_free( node );
2345 return E_OUTOFMEMORY;
2347 text->text = &utf8->text;
2349 read_insert_node( reader, reader->current, node );
2350 reader->state = READER_STATE_CDATA;
2351 return S_OK;
2354 static HRESULT read_endcdata( struct reader *reader )
2356 struct node *parent;
2358 if (read_cmp( reader, "]]>", 3 )) return WS_E_INVALID_FORMAT;
2359 read_skip( reader, 3 );
2361 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT) parent = reader->current->parent;
2362 else parent = reader->current;
2364 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
2365 reader->last = reader->current;
2366 reader->state = READER_STATE_ENDCDATA;
2367 return S_OK;
2370 static HRESULT read_node_text( struct reader *reader )
2372 HRESULT hr;
2374 for (;;)
2376 if (read_end_of_data( reader ))
2378 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
2379 reader->last = reader->current;
2380 reader->state = READER_STATE_EOF;
2381 return S_OK;
2383 if (reader->state == READER_STATE_STARTCDATA) return read_cdata( reader );
2384 else if (reader->state == READER_STATE_CDATA) return read_endcdata( reader );
2385 else if (!read_cmp( reader, "<?", 2 ))
2387 hr = read_xmldecl( reader );
2388 if (FAILED( hr )) return hr;
2390 else if (!read_cmp( reader, "</", 2 )) return read_endelement_text( reader );
2391 else if (!read_cmp( reader, "<![CDATA[", 9 )) return read_startcdata( reader );
2392 else if (!read_cmp( reader, "<!--", 4 )) return read_comment_text( reader );
2393 else if (!read_cmp( reader, "<", 1 )) return read_element_text( reader );
2394 else if (!read_cmp( reader, "/>", 2 ) || !read_cmp( reader, ">", 1 )) return read_startelement_text( reader );
2395 else return read_text_text( reader );
2399 static HRESULT read_node_bin( struct reader *reader )
2401 unsigned char type;
2402 HRESULT hr;
2404 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT)
2406 reader->current = LIST_ENTRY( list_tail( &reader->current->parent->children ), struct node, entry );
2407 reader->last = reader->current;
2408 reader->state = READER_STATE_ENDELEMENT;
2409 return S_OK;
2411 if (read_end_of_data( reader ))
2413 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
2414 reader->last = reader->current;
2415 reader->state = READER_STATE_EOF;
2416 return S_OK;
2419 if ((hr = read_peek( reader, &type )) != S_OK) return hr;
2420 if (type == RECORD_ENDELEMENT)
2422 return read_endelement_bin( reader );
2424 else if (type == RECORD_COMMENT)
2426 return read_comment_bin( reader );
2428 else if (type >= RECORD_SHORT_ELEMENT && type <= RECORD_PREFIX_ELEMENT_Z)
2430 return read_element_bin( reader );
2432 else if (type >= RECORD_ZERO_TEXT && type <= RECORD_QNAME_DICTIONARY_TEXT_WITH_ENDELEMENT)
2434 return read_text_bin( reader );
2436 FIXME( "unhandled record type %02x\n", type );
2437 return WS_E_NOT_SUPPORTED;
2440 static HRESULT read_node( struct reader *reader )
2442 switch (reader->input_enc)
2444 case WS_XML_READER_ENCODING_TYPE_TEXT: return read_node_text( reader );
2445 case WS_XML_READER_ENCODING_TYPE_BINARY: return read_node_bin( reader );
2446 default:
2447 ERR( "unhandled encoding %u\n", reader->input_enc );
2448 return WS_E_NOT_SUPPORTED;
2452 HRESULT copy_node( WS_XML_READER *handle, struct node **node )
2454 struct reader *reader = (struct reader *)handle;
2455 const struct list *ptr;
2456 const struct node *start;
2457 HRESULT hr;
2459 EnterCriticalSection( &reader->cs );
2461 if (reader->magic != READER_MAGIC)
2463 LeaveCriticalSection( &reader->cs );
2464 return E_INVALIDARG;
2467 if (reader->current != reader->root) ptr = &reader->current->entry;
2468 else /* copy whole tree */
2470 if (!read_end_of_data( reader ))
2472 for (;;)
2474 if ((hr = read_node( reader )) != S_OK) goto done;
2475 if (node_type( reader->current ) == WS_XML_NODE_TYPE_EOF) break;
2478 ptr = list_head( &reader->root->children );
2481 start = LIST_ENTRY( ptr, struct node, entry );
2482 if (node_type( start ) == WS_XML_NODE_TYPE_EOF) hr = WS_E_INVALID_OPERATION;
2483 else hr = dup_tree( node, start );
2485 done:
2486 LeaveCriticalSection( &reader->cs );
2487 return hr;
2490 /**************************************************************************
2491 * WsReadEndElement [webservices.@]
2493 HRESULT WINAPI WsReadEndElement( WS_XML_READER *handle, WS_ERROR *error )
2495 struct reader *reader = (struct reader *)handle;
2496 HRESULT hr;
2498 TRACE( "%p %p\n", handle, error );
2499 if (error) FIXME( "ignoring error parameter\n" );
2501 if (!reader) return E_INVALIDARG;
2503 EnterCriticalSection( &reader->cs );
2505 if (reader->magic != READER_MAGIC)
2507 LeaveCriticalSection( &reader->cs );
2508 return E_INVALIDARG;
2511 hr = read_endelement( reader );
2513 LeaveCriticalSection( &reader->cs );
2514 return hr;
2517 /**************************************************************************
2518 * WsReadNode [webservices.@]
2520 HRESULT WINAPI WsReadNode( WS_XML_READER *handle, WS_ERROR *error )
2522 struct reader *reader = (struct reader *)handle;
2523 HRESULT hr;
2525 TRACE( "%p %p\n", handle, error );
2526 if (error) FIXME( "ignoring error parameter\n" );
2528 if (!reader) return E_INVALIDARG;
2530 EnterCriticalSection( &reader->cs );
2532 if (reader->magic != READER_MAGIC)
2534 LeaveCriticalSection( &reader->cs );
2535 return E_INVALIDARG;
2538 hr = read_node( reader );
2540 LeaveCriticalSection( &reader->cs );
2541 return hr;
2544 static HRESULT skip_node( struct reader *reader )
2546 const struct node *parent;
2547 HRESULT hr;
2549 if (node_type( reader->current ) == WS_XML_NODE_TYPE_EOF) return WS_E_INVALID_OPERATION;
2550 if (node_type( reader->current ) == WS_XML_NODE_TYPE_ELEMENT) parent = reader->current;
2551 else parent = NULL;
2553 for (;;)
2555 if ((hr = read_node( reader ) != S_OK) || !parent) break;
2556 if (node_type( reader->current ) != WS_XML_NODE_TYPE_END_ELEMENT) continue;
2557 if (reader->current->parent == parent) return read_node( reader );
2560 return hr;
2563 /**************************************************************************
2564 * WsSkipNode [webservices.@]
2566 HRESULT WINAPI WsSkipNode( WS_XML_READER *handle, WS_ERROR *error )
2568 struct reader *reader = (struct reader *)handle;
2569 HRESULT hr;
2571 TRACE( "%p %p\n", handle, error );
2572 if (error) FIXME( "ignoring error parameter\n" );
2574 if (!reader) return E_INVALIDARG;
2576 EnterCriticalSection( &reader->cs );
2578 if (reader->magic != READER_MAGIC)
2580 LeaveCriticalSection( &reader->cs );
2581 return E_INVALIDARG;
2584 hr = skip_node( reader );
2586 LeaveCriticalSection( &reader->cs );
2587 return hr;
2590 /**************************************************************************
2591 * WsReadStartElement [webservices.@]
2593 HRESULT WINAPI WsReadStartElement( WS_XML_READER *handle, WS_ERROR *error )
2595 struct reader *reader = (struct reader *)handle;
2596 HRESULT hr;
2598 TRACE( "%p %p\n", handle, error );
2599 if (error) FIXME( "ignoring error parameter\n" );
2601 if (!reader) return E_INVALIDARG;
2603 EnterCriticalSection( &reader->cs );
2605 if (reader->magic != READER_MAGIC)
2607 LeaveCriticalSection( &reader->cs );
2608 return E_INVALIDARG;
2611 hr = read_startelement( reader );
2613 LeaveCriticalSection( &reader->cs );
2614 return hr;
2617 /**************************************************************************
2618 * WsReadToStartElement [webservices.@]
2620 HRESULT WINAPI WsReadToStartElement( WS_XML_READER *handle, const WS_XML_STRING *localname,
2621 const WS_XML_STRING *ns, BOOL *found, WS_ERROR *error )
2623 struct reader *reader = (struct reader *)handle;
2624 HRESULT hr;
2626 TRACE( "%p %s %s %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns), found, error );
2627 if (error) FIXME( "ignoring error parameter\n" );
2629 if (!reader) return E_INVALIDARG;
2630 if (localname || ns) FIXME( "name and/or namespace not verified\n" );
2632 EnterCriticalSection( &reader->cs );
2634 if (reader->magic != READER_MAGIC)
2636 LeaveCriticalSection( &reader->cs );
2637 return E_INVALIDARG;
2640 hr = read_to_startelement( reader, found );
2642 LeaveCriticalSection( &reader->cs );
2643 return hr;
2646 BOOL move_to_root_element( struct node *root, struct node **current )
2648 struct list *ptr;
2649 struct node *node;
2651 if (!(ptr = list_head( &root->children ))) return FALSE;
2652 node = LIST_ENTRY( ptr, struct node, entry );
2653 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT)
2655 *current = node;
2656 return TRUE;
2658 while ((ptr = list_next( &root->children, &node->entry )))
2660 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2661 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2663 *current = next;
2664 return TRUE;
2666 node = next;
2668 return FALSE;
2671 BOOL move_to_next_element( struct node **current )
2673 struct list *ptr;
2674 struct node *node = *current, *parent = (*current)->parent;
2676 if (!parent) return FALSE;
2677 while ((ptr = list_next( &parent->children, &node->entry )))
2679 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2680 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2682 *current = next;
2683 return TRUE;
2685 node = next;
2687 return FALSE;
2690 BOOL move_to_prev_element( struct node **current )
2692 struct list *ptr;
2693 struct node *node = *current, *parent = (*current)->parent;
2695 if (!parent) return FALSE;
2696 while ((ptr = list_prev( &parent->children, &node->entry )))
2698 struct node *prev = LIST_ENTRY( ptr, struct node, entry );
2699 if (node_type( prev ) == WS_XML_NODE_TYPE_ELEMENT)
2701 *current = prev;
2702 return TRUE;
2704 node = prev;
2706 return FALSE;
2709 BOOL move_to_child_element( struct node **current )
2711 struct list *ptr;
2712 struct node *child, *node = *current;
2714 if (!(ptr = list_head( &node->children ))) return FALSE;
2715 child = LIST_ENTRY( ptr, struct node, entry );
2716 if (node_type( child ) == WS_XML_NODE_TYPE_ELEMENT)
2718 *current = child;
2719 return TRUE;
2721 while ((ptr = list_next( &node->children, &child->entry )))
2723 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2724 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2726 *current = next;
2727 return TRUE;
2729 child = next;
2731 return FALSE;
2734 BOOL move_to_end_element( struct node **current )
2736 struct list *ptr;
2737 struct node *node = *current;
2739 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
2741 if ((ptr = list_tail( &node->children )))
2743 struct node *tail = LIST_ENTRY( ptr, struct node, entry );
2744 if (node_type( tail ) == WS_XML_NODE_TYPE_END_ELEMENT)
2746 *current = tail;
2747 return TRUE;
2750 return FALSE;
2753 BOOL move_to_parent_element( struct node **current )
2755 struct node *parent = (*current)->parent;
2757 if (parent && (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT ||
2758 node_type( parent ) == WS_XML_NODE_TYPE_BOF))
2760 *current = parent;
2761 return TRUE;
2763 return FALSE;
2766 BOOL move_to_first_node( struct node **current )
2768 struct list *ptr;
2769 struct node *node = *current;
2771 if ((ptr = list_head( &node->parent->children )))
2773 *current = LIST_ENTRY( ptr, struct node, entry );
2774 return TRUE;
2776 return FALSE;
2779 BOOL move_to_next_node( struct node **current )
2781 struct list *ptr;
2782 struct node *node = *current;
2784 if ((ptr = list_next( &node->parent->children, &node->entry )))
2786 *current = LIST_ENTRY( ptr, struct node, entry );
2787 return TRUE;
2789 return FALSE;
2792 BOOL move_to_prev_node( struct node **current )
2794 struct list *ptr;
2795 struct node *node = *current;
2797 if ((ptr = list_prev( &node->parent->children, &node->entry )))
2799 *current = LIST_ENTRY( ptr, struct node, entry );
2800 return TRUE;
2802 return FALSE;
2805 BOOL move_to_bof( struct node *root, struct node **current )
2807 *current = root;
2808 return TRUE;
2811 BOOL move_to_eof( struct node *root, struct node **current )
2813 struct list *ptr;
2814 if ((ptr = list_tail( &root->children )))
2816 *current = LIST_ENTRY( ptr, struct node, entry );
2817 return TRUE;
2819 return FALSE;
2822 BOOL move_to_child_node( struct node **current )
2824 struct list *ptr;
2825 struct node *node = *current;
2827 if ((ptr = list_head( &node->children )))
2829 *current = LIST_ENTRY( ptr, struct node, entry );
2830 return TRUE;
2832 return FALSE;
2835 BOOL move_to_parent_node( struct node **current )
2837 struct node *parent = (*current)->parent;
2838 if (!parent) return FALSE;
2839 *current = parent;
2840 return TRUE;
2843 static HRESULT read_move_to( struct reader *reader, WS_MOVE_TO move, BOOL *found )
2845 BOOL success = FALSE;
2846 HRESULT hr = S_OK;
2848 if (!read_end_of_data( reader ))
2850 while (reader->state != READER_STATE_EOF && (hr = read_node( reader )) == S_OK) { /* nothing */ };
2851 if (hr != S_OK) return hr;
2853 switch (move)
2855 case WS_MOVE_TO_ROOT_ELEMENT:
2856 success = move_to_root_element( reader->root, &reader->current );
2857 break;
2859 case WS_MOVE_TO_NEXT_ELEMENT:
2860 success = move_to_next_element( &reader->current );
2861 break;
2863 case WS_MOVE_TO_PREVIOUS_ELEMENT:
2864 success = move_to_prev_element( &reader->current );
2865 break;
2867 case WS_MOVE_TO_CHILD_ELEMENT:
2868 success = move_to_child_element( &reader->current );
2869 break;
2871 case WS_MOVE_TO_END_ELEMENT:
2872 success = move_to_end_element( &reader->current );
2873 break;
2875 case WS_MOVE_TO_PARENT_ELEMENT:
2876 success = move_to_parent_element( &reader->current );
2877 break;
2879 case WS_MOVE_TO_FIRST_NODE:
2880 success = move_to_first_node( &reader->current );
2881 break;
2883 case WS_MOVE_TO_NEXT_NODE:
2884 success = move_to_next_node( &reader->current );
2885 break;
2887 case WS_MOVE_TO_PREVIOUS_NODE:
2888 success = move_to_prev_node( &reader->current );
2889 break;
2891 case WS_MOVE_TO_CHILD_NODE:
2892 success = move_to_child_node( &reader->current );
2893 break;
2895 case WS_MOVE_TO_BOF:
2896 success = move_to_bof( reader->root, &reader->current );
2897 break;
2899 case WS_MOVE_TO_EOF:
2900 success = move_to_eof( reader->root, &reader->current );
2901 break;
2903 default:
2904 FIXME( "unhandled move %u\n", move );
2905 return E_NOTIMPL;
2908 if (found)
2910 *found = success;
2911 return S_OK;
2913 return success ? S_OK : WS_E_INVALID_FORMAT;
2916 /**************************************************************************
2917 * WsMoveReader [webservices.@]
2919 HRESULT WINAPI WsMoveReader( WS_XML_READER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2921 struct reader *reader = (struct reader *)handle;
2922 HRESULT hr;
2924 TRACE( "%p %u %p %p\n", handle, move, found, error );
2925 if (error) FIXME( "ignoring error parameter\n" );
2927 if (!reader) return E_INVALIDARG;
2929 EnterCriticalSection( &reader->cs );
2931 if (reader->magic != READER_MAGIC)
2933 LeaveCriticalSection( &reader->cs );
2934 return E_INVALIDARG;
2937 if (!reader->input_type)
2939 LeaveCriticalSection( &reader->cs );
2940 return WS_E_INVALID_OPERATION;
2943 hr = read_move_to( reader, move, found );
2945 LeaveCriticalSection( &reader->cs );
2946 return hr;
2949 /**************************************************************************
2950 * WsReadStartAttribute [webservices.@]
2952 HRESULT WINAPI WsReadStartAttribute( WS_XML_READER *handle, ULONG index, WS_ERROR *error )
2954 struct reader *reader = (struct reader *)handle;
2955 const WS_XML_ELEMENT_NODE *elem;
2957 TRACE( "%p %u %p\n", handle, index, error );
2958 if (error) FIXME( "ignoring error parameter\n" );
2960 if (!reader) return E_INVALIDARG;
2962 EnterCriticalSection( &reader->cs );
2964 if (reader->magic != READER_MAGIC)
2966 LeaveCriticalSection( &reader->cs );
2967 return E_INVALIDARG;
2970 elem = &reader->current->hdr;
2971 if (reader->state != READER_STATE_STARTELEMENT || index >= elem->attributeCount)
2973 LeaveCriticalSection( &reader->cs );
2974 return WS_E_INVALID_FORMAT;
2977 reader->current_attr = index;
2978 reader->state = READER_STATE_STARTATTRIBUTE;
2980 LeaveCriticalSection( &reader->cs );
2981 return S_OK;
2984 /**************************************************************************
2985 * WsReadEndAttribute [webservices.@]
2987 HRESULT WINAPI WsReadEndAttribute( WS_XML_READER *handle, WS_ERROR *error )
2989 struct reader *reader = (struct reader *)handle;
2991 TRACE( "%p %p\n", handle, error );
2992 if (error) FIXME( "ignoring error parameter\n" );
2994 if (!reader) return E_INVALIDARG;
2996 EnterCriticalSection( &reader->cs );
2998 if (reader->magic != READER_MAGIC)
3000 LeaveCriticalSection( &reader->cs );
3001 return E_INVALIDARG;
3004 if (reader->state != READER_STATE_STARTATTRIBUTE)
3006 LeaveCriticalSection( &reader->cs );
3007 return WS_E_INVALID_FORMAT;
3010 reader->state = READER_STATE_STARTELEMENT;
3012 LeaveCriticalSection( &reader->cs );
3013 return S_OK;
3016 static HRESULT find_namespace( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING **ns )
3018 const struct node *node;
3019 for (node = reader->current->parent; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
3021 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
3022 ULONG i;
3023 for (i = 0; i < elem->attributeCount; i++)
3025 if (!elem->attributes[i]->isXmlNs) continue;
3026 if (WsXmlStringEquals( elem->attributes[i]->prefix, prefix, NULL ) != S_OK) continue;
3027 *ns = elem->attributes[i]->ns;
3028 return S_OK;
3031 return WS_E_INVALID_FORMAT;
3034 static HRESULT read_qualified_name( struct reader *reader, WS_HEAP *heap, WS_XML_STRING *prefix_ret,
3035 WS_XML_STRING *localname_ret, WS_XML_STRING *ns_ret )
3037 const WS_XML_TEXT_NODE *node = (const WS_XML_TEXT_NODE *)reader->current;
3038 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)node->text;
3039 unsigned char *prefix_bytes, *localname_bytes, *ns_bytes;
3040 const unsigned char *ptr = utf8->value.bytes;
3041 WS_XML_STRING prefix, localname, empty = {0, NULL};
3042 const WS_XML_STRING *ns = &empty;
3043 ULONG len = utf8->value.length;
3044 HRESULT hr;
3046 while (len && read_isspace( *ptr )) { ptr++; len--; }
3047 while (len && read_isspace( ptr[len - 1] )) { len--; }
3048 if (!len) return WS_E_INVALID_FORMAT;
3050 if ((hr = split_name( ptr, len, (const unsigned char **)&prefix.bytes, &prefix.length,
3051 (const unsigned char **)&localname.bytes, &localname.length )) != S_OK) return hr;
3053 if (!localname.length) return WS_E_INVALID_FORMAT;
3054 if (prefix.length && (hr = find_namespace( reader, &prefix, &ns )) != S_OK) return hr;
3056 if (!(prefix_bytes = ws_alloc( heap, prefix.length ))) return WS_E_QUOTA_EXCEEDED;
3057 memcpy( prefix_bytes, prefix.bytes, prefix.length );
3059 if (!(localname_bytes = ws_alloc( heap, localname.length )))
3061 ws_free( heap, prefix_bytes, prefix.length );
3062 return WS_E_QUOTA_EXCEEDED;
3064 memcpy( localname_bytes, localname.bytes, localname.length );
3066 if (!(ns_bytes = ws_alloc( heap, ns->length )))
3068 ws_free( heap, prefix_bytes, prefix.length );
3069 ws_free( heap, localname_bytes, localname.length );
3070 return WS_E_QUOTA_EXCEEDED;
3072 memcpy( ns_bytes, ns->bytes, ns->length );
3074 prefix_ret->bytes = prefix_bytes;
3075 prefix_ret->length = prefix.length;
3077 localname_ret->bytes = localname_bytes;
3078 localname_ret->length = localname.length;
3080 ns_ret->bytes = ns_bytes;
3081 ns_ret->length = ns->length;
3083 return S_OK;
3086 /**************************************************************************
3087 * WsReadQualifiedName [webservices.@]
3089 HRESULT WINAPI WsReadQualifiedName( WS_XML_READER *handle, WS_HEAP *heap, WS_XML_STRING *prefix,
3090 WS_XML_STRING *localname, WS_XML_STRING *ns,
3091 WS_ERROR *error )
3093 struct reader *reader = (struct reader *)handle;
3094 HRESULT hr;
3096 TRACE( "%p %p %p %p %p %p\n", handle, heap, prefix, localname, ns, error );
3097 if (error) FIXME( "ignoring error parameter\n" );
3099 if (!reader || !heap) return E_INVALIDARG;
3101 EnterCriticalSection( &reader->cs );
3103 if (reader->magic != READER_MAGIC)
3105 LeaveCriticalSection( &reader->cs );
3106 return E_INVALIDARG;
3109 if (!reader->input_type)
3111 LeaveCriticalSection( &reader->cs );
3112 return WS_E_INVALID_OPERATION;
3115 if (!localname)
3117 LeaveCriticalSection( &reader->cs );
3118 return E_INVALIDARG;
3121 if (reader->state != READER_STATE_TEXT)
3123 LeaveCriticalSection( &reader->cs );
3124 return WS_E_INVALID_FORMAT;
3127 hr = read_qualified_name( reader, heap, prefix, localname, ns );
3129 LeaveCriticalSection( &reader->cs );
3130 return hr;
3133 static WCHAR *xmltext_to_widechar( WS_HEAP *heap, const WS_XML_TEXT *text )
3135 WCHAR *ret;
3137 switch (text->textType)
3139 case WS_XML_TEXT_TYPE_UTF8:
3141 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
3142 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
3143 if (!(ret = ws_alloc( heap, (len + 1) * sizeof(WCHAR) ))) return NULL;
3144 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, ret, len );
3145 ret[len] = 0;
3146 break;
3148 default:
3149 FIXME( "unhandled type %u\n", text->textType );
3150 return NULL;
3153 return ret;
3156 #define MAX_INT8 0x7f
3157 #define MIN_INT8 (-MAX_INT8 - 1)
3158 #define MAX_INT16 0x7fff
3159 #define MIN_INT16 (-MAX_INT16 - 1)
3160 #define MAX_INT32 0x7fffffff
3161 #define MIN_INT32 (-MAX_INT32 - 1)
3162 #define MAX_INT64 (((INT64)0x7fffffff << 32) | 0xffffffff)
3163 #define MIN_INT64 (-MAX_INT64 - 1)
3164 #define MAX_UINT8 0xff
3165 #define MAX_UINT16 0xffff
3166 #define MAX_UINT32 0xffffffff
3167 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
3169 static HRESULT str_to_int64( const unsigned char *str, ULONG len, INT64 min, INT64 max, INT64 *ret )
3171 BOOL negative = FALSE;
3172 const unsigned char *ptr = str;
3174 *ret = 0;
3175 while (len && read_isspace( *ptr )) { ptr++; len--; }
3176 while (len && read_isspace( ptr[len - 1] )) { len--; }
3177 if (!len) return WS_E_INVALID_FORMAT;
3179 if (*ptr == '-')
3181 negative = TRUE;
3182 ptr++;
3183 len--;
3185 if (!len) return WS_E_INVALID_FORMAT;
3187 while (len--)
3189 int val;
3191 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
3192 val = *ptr - '0';
3193 if (negative) val = -val;
3195 if ((!negative && (*ret > max / 10 || *ret * 10 > max - val)) ||
3196 (negative && (*ret < min / 10 || *ret * 10 < min - val)))
3198 return WS_E_NUMERIC_OVERFLOW;
3200 *ret = *ret * 10 + val;
3201 ptr++;
3204 return S_OK;
3207 static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, UINT64 *ret )
3209 const unsigned char *ptr = str;
3211 *ret = 0;
3212 while (len && read_isspace( *ptr )) { ptr++; len--; }
3213 while (len && read_isspace( ptr[len - 1] )) { len--; }
3214 if (!len) return WS_E_INVALID_FORMAT;
3216 while (len--)
3218 unsigned int val;
3220 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
3221 val = *ptr - '0';
3223 if ((*ret > max / 10 || *ret * 10 > max - val)) return WS_E_NUMERIC_OVERFLOW;
3224 *ret = *ret * 10 + val;
3225 ptr++;
3228 return S_OK;
3231 BOOL set_fpword( unsigned short new, unsigned short *old )
3233 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3234 unsigned short fpword;
3236 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
3237 *old = fpword;
3238 fpword = new;
3239 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
3240 return TRUE;
3241 #else
3242 FIXME( "not implemented\n" );
3243 return FALSE;
3244 #endif
3247 void restore_fpword( unsigned short fpword )
3249 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3250 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
3251 #else
3252 FIXME( "not implemented\n" );
3253 #endif
3256 static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret )
3258 static const unsigned __int64 nan = 0xfff8000000000000;
3259 static const unsigned __int64 inf = 0x7ff0000000000000;
3260 static const unsigned __int64 inf_min = 0xfff0000000000000;
3261 HRESULT hr = WS_E_INVALID_FORMAT;
3262 const unsigned char *p = str, *q;
3263 int sign = 1, exp_sign = 1, exp = 0, exp_tmp = 0, neg_exp, i, nb_digits, have_digits;
3264 unsigned __int64 val = 0, tmp;
3265 long double exp_val = 1.0, exp_mul = 10.0;
3266 unsigned short fpword;
3268 while (len && read_isspace( *p )) { p++; len--; }
3269 while (len && read_isspace( p[len - 1] )) { len--; }
3270 if (!len) return WS_E_INVALID_FORMAT;
3272 if (len == 3 && !memcmp( p, "NaN", 3 ))
3274 *(unsigned __int64 *)ret = nan;
3275 return S_OK;
3277 else if (len == 3 && !memcmp( p, "INF", 3 ))
3279 *(unsigned __int64 *)ret = inf;
3280 return S_OK;
3282 else if (len == 4 && !memcmp( p, "-INF", 4 ))
3284 *(unsigned __int64 *)ret = inf_min;
3285 return S_OK;
3288 *ret = 0.0;
3289 if (*p == '-')
3291 sign = -1;
3292 p++; len--;
3294 else if (*p == '+') { p++; len--; };
3295 if (!len) return S_OK;
3297 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
3299 q = p;
3300 while (len && isdigit( *q )) { q++; len--; }
3301 have_digits = nb_digits = q - p;
3302 for (i = 0; i < nb_digits; i++)
3304 tmp = val * 10 + p[i] - '0';
3305 if (val > MAX_UINT64 / 10 || tmp < val)
3307 for (; i < nb_digits; i++) exp++;
3308 break;
3310 val = tmp;
3313 if (len)
3315 if (*q == '.')
3317 p = ++q; len--;
3318 while (len && isdigit( *q )) { q++; len--; };
3319 have_digits |= nb_digits = q - p;
3320 for (i = 0; i < nb_digits; i++)
3322 tmp = val * 10 + p[i] - '0';
3323 if (val > MAX_UINT64 / 10 || tmp < val) break;
3324 val = tmp;
3325 exp--;
3328 if (len > 1 && tolower(*q) == 'e')
3330 if (!have_digits) goto done;
3331 p = ++q; len--;
3332 if (*p == '-')
3334 exp_sign = -1;
3335 p++; len--;
3337 else if (*p == '+') { p++; len--; };
3339 q = p;
3340 while (len && isdigit( *q )) { q++; len--; };
3341 nb_digits = q - p;
3342 if (!nb_digits || len) goto done;
3343 for (i = 0; i < nb_digits; i++)
3345 if (exp_tmp > MAX_INT32 / 10 || (exp_tmp = exp_tmp * 10 + p[i] - '0') < 0)
3346 exp_tmp = MAX_INT32;
3348 exp_tmp *= exp_sign;
3350 if (exp < 0 && exp_tmp < 0 && exp + exp_tmp >= 0) exp = MIN_INT32;
3351 else if (exp > 0 && exp_tmp > 0 && exp + exp_tmp < 0) exp = MAX_INT32;
3352 else exp += exp_tmp;
3355 if (!have_digits || len) goto done;
3357 if ((neg_exp = exp < 0)) exp = -exp;
3358 for (; exp; exp >>= 1)
3360 if (exp & 1) exp_val *= exp_mul;
3361 exp_mul *= exp_mul;
3364 *ret = sign * (neg_exp ? val / exp_val : val * exp_val);
3365 hr = S_OK;
3367 done:
3368 restore_fpword( fpword );
3369 return hr;
3372 static HRESULT str_to_guid( const unsigned char *str, ULONG len, GUID *ret )
3374 static const unsigned char hex[] =
3376 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
3377 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
3378 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
3379 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
3380 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
3381 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
3382 0,10,11,12,13,14,15 /* 0x60 */
3384 const unsigned char *p = str;
3385 ULONG i;
3387 while (len && read_isspace( *p )) { p++; len--; }
3388 while (len && read_isspace( p[len - 1] )) { len--; }
3389 if (len != 36) return WS_E_INVALID_FORMAT;
3391 if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-')
3392 return WS_E_INVALID_FORMAT;
3394 for (i = 0; i < 36; i++)
3396 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
3397 if (p[i] > 'f' || (!hex[p[i]] && p[i] != '0')) return WS_E_INVALID_FORMAT;
3400 ret->Data1 = hex[p[0]] << 28 | hex[p[1]] << 24 | hex[p[2]] << 20 | hex[p[3]] << 16 |
3401 hex[p[4]] << 12 | hex[p[5]] << 8 | hex[p[6]] << 4 | hex[p[7]];
3403 ret->Data2 = hex[p[9]] << 12 | hex[p[10]] << 8 | hex[p[11]] << 4 | hex[p[12]];
3404 ret->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[16]] << 4 | hex[p[17]];
3406 ret->Data4[0] = hex[p[19]] << 4 | hex[p[20]];
3407 ret->Data4[1] = hex[p[21]] << 4 | hex[p[22]];
3408 ret->Data4[2] = hex[p[24]] << 4 | hex[p[25]];
3409 ret->Data4[3] = hex[p[26]] << 4 | hex[p[27]];
3410 ret->Data4[4] = hex[p[28]] << 4 | hex[p[29]];
3411 ret->Data4[5] = hex[p[30]] << 4 | hex[p[31]];
3412 ret->Data4[6] = hex[p[32]] << 4 | hex[p[33]];
3413 ret->Data4[7] = hex[p[34]] << 4 | hex[p[35]];
3415 return S_OK;
3418 static inline unsigned char decode_char( unsigned char c )
3420 if (c >= 'A' && c <= 'Z') return c - 'A';
3421 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
3422 if (c >= '0' && c <= '9') return c - '0' + 52;
3423 if (c == '+') return 62;
3424 if (c == '/') return 63;
3425 return 64;
3428 static ULONG decode_base64( const unsigned char *base64, ULONG len, unsigned char *buf )
3430 ULONG i = 0;
3431 unsigned char c0, c1, c2, c3;
3432 const unsigned char *p = base64;
3434 while (len > 4)
3436 if ((c0 = decode_char( p[0] )) > 63) return 0;
3437 if ((c1 = decode_char( p[1] )) > 63) return 0;
3438 if ((c2 = decode_char( p[2] )) > 63) return 0;
3439 if ((c3 = decode_char( p[3] )) > 63) return 0;
3440 buf[i + 0] = (c0 << 2) | (c1 >> 4);
3441 buf[i + 1] = (c1 << 4) | (c2 >> 2);
3442 buf[i + 2] = (c2 << 6) | c3;
3443 len -= 4;
3444 i += 3;
3445 p += 4;
3447 if (p[2] == '=')
3449 if ((c0 = decode_char( p[0] )) > 63) return 0;
3450 if ((c1 = decode_char( p[1] )) > 63) return 0;
3451 buf[i] = (c0 << 2) | (c1 >> 4);
3452 i++;
3454 else if (p[3] == '=')
3456 if ((c0 = decode_char( p[0] )) > 63) return 0;
3457 if ((c1 = decode_char( p[1] )) > 63) return 0;
3458 if ((c2 = decode_char( p[2] )) > 63) return 0;
3459 buf[i + 0] = (c0 << 2) | (c1 >> 4);
3460 buf[i + 1] = (c1 << 4) | (c2 >> 2);
3461 i += 2;
3463 else
3465 if ((c0 = decode_char( p[0] )) > 63) return 0;
3466 if ((c1 = decode_char( p[1] )) > 63) return 0;
3467 if ((c2 = decode_char( p[2] )) > 63) return 0;
3468 if ((c3 = decode_char( p[3] )) > 63) return 0;
3469 buf[i + 0] = (c0 << 2) | (c1 >> 4);
3470 buf[i + 1] = (c1 << 4) | (c2 >> 2);
3471 buf[i + 2] = (c2 << 6) | c3;
3472 i += 3;
3474 return i;
3477 static HRESULT str_to_bytes( const unsigned char *str, ULONG len, WS_HEAP *heap, WS_BYTES *ret )
3479 const unsigned char *p = str;
3481 while (len && read_isspace( *p )) { p++; len--; }
3482 while (len && read_isspace( p[len - 1] )) { len--; }
3484 if (len % 4) return WS_E_INVALID_FORMAT;
3485 if (!(ret->bytes = ws_alloc( heap, len * 3 / 4 ))) return WS_E_QUOTA_EXCEEDED;
3486 ret->length = decode_base64( p, len, ret->bytes );
3487 return S_OK;
3490 static const int month_offsets[2][12] =
3492 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
3493 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
3496 static inline int valid_day( int year, int month, int day )
3498 return day > 0 && day <= month_days[leap_year( year )][month - 1];
3501 static inline int leap_days_before( int year )
3503 return (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
3506 static HRESULT str_to_datetime( const unsigned char *bytes, ULONG len, WS_DATETIME *ret )
3508 const unsigned char *p = bytes, *q;
3509 int year, month, day, hour, min, sec, sec_frac = 0, tz_hour, tz_min, tz_neg;
3511 while (len && read_isspace( *p )) { p++; len--; }
3512 while (len && read_isspace( p[len - 1] )) { len--; }
3514 q = p;
3515 while (len && isdigit( *q )) { q++; len--; };
3516 if (q - p != 4 || !len || *q != '-') return WS_E_INVALID_FORMAT;
3517 year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
3518 if (year < 1) return WS_E_INVALID_FORMAT;
3520 p = ++q; len--;
3521 while (len && isdigit( *q )) { q++; len--; };
3522 if (q - p != 2 || !len || *q != '-') return WS_E_INVALID_FORMAT;
3523 month = (p[0] - '0') * 10 + p[1] - '0';
3524 if (month < 1 || month > 12) return WS_E_INVALID_FORMAT;
3526 p = ++q; len--;
3527 while (len && isdigit( *q )) { q++; len--; };
3528 if (q - p != 2 || !len || *q != 'T') return WS_E_INVALID_FORMAT;
3529 day = (p[0] - '0') * 10 + p[1] - '0';
3530 if (!valid_day( year, month, day )) return WS_E_INVALID_FORMAT;
3532 p = ++q; len--;
3533 while (len && isdigit( *q )) { q++; len--; };
3534 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3535 hour = (p[0] - '0') * 10 + p[1] - '0';
3536 if (hour > 24) return WS_E_INVALID_FORMAT;
3538 p = ++q; len--;
3539 while (len && isdigit( *q )) { q++; len--; };
3540 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3541 min = (p[0] - '0') * 10 + p[1] - '0';
3542 if (min > 59 || (min > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
3544 p = ++q; len--;
3545 while (len && isdigit( *q )) { q++; len--; };
3546 if (q - p != 2 || !len) return WS_E_INVALID_FORMAT;
3547 sec = (p[0] - '0') * 10 + p[1] - '0';
3548 if (sec > 59 || (sec > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
3550 if (*q == '.')
3552 unsigned int i, nb_digits, mul = TICKS_PER_SEC / 10;
3553 p = ++q; len--;
3554 while (len && isdigit( *q )) { q++; len--; };
3555 nb_digits = q - p;
3556 if (nb_digits < 1 || nb_digits > 7) return WS_E_INVALID_FORMAT;
3557 for (i = 0; i < nb_digits; i++)
3559 sec_frac += (p[i] - '0') * mul;
3560 mul /= 10;
3563 if (*q == 'Z')
3565 if (--len) return WS_E_INVALID_FORMAT;
3566 tz_hour = tz_min = tz_neg = 0;
3567 ret->format = WS_DATETIME_FORMAT_UTC;
3569 else if (*q == '+' || *q == '-')
3571 tz_neg = (*q == '-') ? 1 : 0;
3573 p = ++q; len--;
3574 while (len && isdigit( *q )) { q++; len--; };
3575 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3576 tz_hour = (p[0] - '0') * 10 + p[1] - '0';
3577 if (tz_hour > 14) return WS_E_INVALID_FORMAT;
3579 p = ++q; len--;
3580 while (len && isdigit( *q )) { q++; len--; };
3581 if (q - p != 2 || len) return WS_E_INVALID_FORMAT;
3582 tz_min = (p[0] - '0') * 10 + p[1] - '0';
3583 if (tz_min > 59 || (tz_min > 0 && tz_hour == 14)) return WS_E_INVALID_FORMAT;
3585 ret->format = WS_DATETIME_FORMAT_LOCAL;
3587 else return WS_E_INVALID_FORMAT;
3589 ret->ticks = ((year - 1) * 365 + leap_days_before( year )) * TICKS_PER_DAY;
3590 ret->ticks += month_offsets[leap_year( year )][month - 1] * TICKS_PER_DAY;
3591 ret->ticks += (day - 1) * TICKS_PER_DAY;
3592 ret->ticks += hour * TICKS_PER_HOUR;
3593 ret->ticks += min * TICKS_PER_MIN;
3594 ret->ticks += sec * TICKS_PER_SEC;
3595 ret->ticks += sec_frac;
3597 if (tz_neg)
3599 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN + ret->ticks > TICKS_MAX)
3600 return WS_E_INVALID_FORMAT;
3601 ret->ticks += tz_hour * TICKS_PER_HOUR;
3602 ret->ticks += tz_min * TICKS_PER_MIN;
3604 else
3606 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN > ret->ticks)
3607 return WS_E_INVALID_FORMAT;
3608 ret->ticks -= tz_hour * TICKS_PER_HOUR;
3609 ret->ticks -= tz_min * TICKS_PER_MIN;
3612 return S_OK;
3615 /**************************************************************************
3616 * WsDateTimeToFileTime [webservices.@]
3618 HRESULT WINAPI WsDateTimeToFileTime( const WS_DATETIME *dt, FILETIME *ft, WS_ERROR *error )
3620 unsigned __int64 ticks;
3622 TRACE( "%p %p %p\n", dt, ft, error );
3623 if (error) FIXME( "ignoring error parameter\n" );
3625 if (!dt || !ft) return E_INVALIDARG;
3627 if (dt->ticks < TICKS_1601_01_01) return WS_E_INVALID_FORMAT;
3628 ticks = dt->ticks - TICKS_1601_01_01;
3629 ft->dwHighDateTime = ticks >> 32;
3630 ft->dwLowDateTime = (DWORD)ticks;
3631 return S_OK;
3634 /**************************************************************************
3635 * WsFileTimeToDateTime [webservices.@]
3637 HRESULT WINAPI WsFileTimeToDateTime( const FILETIME *ft, WS_DATETIME *dt, WS_ERROR *error )
3639 unsigned __int64 ticks;
3641 TRACE( "%p %p %p\n", ft, dt, error );
3642 if (error) FIXME( "ignoring error parameter\n" );
3644 if (!dt || !ft) return E_INVALIDARG;
3646 ticks = ((unsigned __int64)ft->dwHighDateTime << 32) | ft->dwLowDateTime;
3647 if (ticks > MAX_UINT64 - TICKS_1601_01_01) return WS_E_NUMERIC_OVERFLOW;
3648 if (ticks + TICKS_1601_01_01 > TICKS_MAX) return WS_E_INVALID_FORMAT;
3649 dt->ticks = ticks + TICKS_1601_01_01;
3650 dt->format = WS_DATETIME_FORMAT_UTC;
3651 return S_OK;
3654 static HRESULT read_get_node_text( struct reader *reader, WS_XML_UTF8_TEXT **ret )
3656 WS_XML_TEXT_NODE *text;
3658 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT)
3659 return WS_E_INVALID_FORMAT;
3661 text = (WS_XML_TEXT_NODE *)&reader->current->hdr.node;
3662 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
3664 FIXME( "text type %u not supported\n", text->text->textType );
3665 return E_NOTIMPL;
3667 *ret = (WS_XML_UTF8_TEXT *)text->text;
3668 return S_OK;
3671 static HRESULT read_get_attribute_text( struct reader *reader, ULONG index, WS_XML_UTF8_TEXT **ret )
3673 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3674 WS_XML_ATTRIBUTE *attr;
3676 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
3677 return WS_E_INVALID_FORMAT;
3679 attr = elem->attributes[index];
3680 if (attr->value->textType != WS_XML_TEXT_TYPE_UTF8)
3682 FIXME( "text type %u not supported\n", attr->value->textType );
3683 return E_NOTIMPL;
3685 *ret = (WS_XML_UTF8_TEXT *)attr->value;
3686 return S_OK;
3689 static BOOL find_attribute( struct reader *reader, const WS_XML_STRING *localname,
3690 const WS_XML_STRING *ns, ULONG *index )
3692 ULONG i;
3693 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3695 if (!localname)
3697 *index = reader->current_attr;
3698 return TRUE;
3700 for (i = 0; i < elem->attributeCount; i++)
3702 const WS_XML_STRING *localname2 = elem->attributes[i]->localName;
3703 const WS_XML_STRING *ns2 = elem->attributes[i]->ns;
3705 if (!cmp_name( localname->bytes, localname->length, localname2->bytes, localname2->length ) &&
3706 !cmp_name( ns->bytes, ns->length, ns2->bytes, ns2->length ))
3708 *index = i;
3709 return TRUE;
3712 return FALSE;
3715 /**************************************************************************
3716 * WsFindAttribute [webservices.@]
3718 HRESULT WINAPI WsFindAttribute( WS_XML_READER *handle, const WS_XML_STRING *localname,
3719 const WS_XML_STRING *ns, BOOL required, ULONG *index,
3720 WS_ERROR *error )
3722 struct reader *reader = (struct reader *)handle;
3723 HRESULT hr = S_OK;
3725 TRACE( "%p %s %s %d %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3726 required, index, error );
3727 if (error) FIXME( "ignoring error parameter\n" );
3729 if (!reader || !localname || !ns || !index) return E_INVALIDARG;
3731 EnterCriticalSection( &reader->cs );
3733 if (reader->magic != READER_MAGIC)
3735 LeaveCriticalSection( &reader->cs );
3736 return E_INVALIDARG;
3739 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
3741 LeaveCriticalSection( &reader->cs );
3742 return WS_E_INVALID_OPERATION;
3745 if (!find_attribute( reader, localname, ns, index ))
3747 if (required) hr = WS_E_INVALID_FORMAT;
3748 else
3750 *index = ~0u;
3751 hr = S_FALSE;
3755 LeaveCriticalSection( &reader->cs );
3756 return hr;
3759 static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
3760 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3761 WS_XML_UTF8_TEXT **ret, BOOL *found )
3763 switch (mapping)
3765 case WS_ATTRIBUTE_TYPE_MAPPING:
3767 ULONG index;
3768 if (!(*found = find_attribute( reader, localname, ns, &index ))) return S_OK;
3769 return read_get_attribute_text( reader, index, ret );
3771 case WS_ELEMENT_TYPE_MAPPING:
3772 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3773 case WS_ANY_ELEMENT_TYPE_MAPPING:
3775 HRESULT hr;
3776 *found = TRUE;
3777 if (localname)
3779 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3781 if (WsXmlStringEquals( localname, elem->localName, NULL ) != S_OK ||
3782 WsXmlStringEquals( ns, elem->ns, NULL ) != S_OK)
3784 *found = FALSE;
3785 return S_OK;
3787 if ((hr = read_startelement( reader )) != S_OK) return hr;
3789 return read_get_node_text( reader, ret );
3791 default:
3792 FIXME( "mapping %u not supported\n", mapping );
3793 return E_NOTIMPL;
3797 static HRESULT read_type_bool( struct reader *reader, WS_TYPE_MAPPING mapping,
3798 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3799 const WS_BOOL_DESCRIPTION *desc, WS_READ_OPTION option,
3800 WS_HEAP *heap, void *ret, ULONG size )
3802 WS_XML_UTF8_TEXT *utf8;
3803 HRESULT hr;
3804 BOOL found, val = FALSE;
3806 if (desc)
3808 FIXME( "description not supported\n" );
3809 return E_NOTIMPL;
3811 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3812 if (found)
3814 ULONG len = utf8->value.length;
3815 if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) val = TRUE;
3816 else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) val = TRUE;
3817 else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) val = FALSE;
3818 else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) val = FALSE;
3819 else return WS_E_INVALID_FORMAT;
3822 switch (option)
3824 case WS_READ_REQUIRED_VALUE:
3825 if (!found) return WS_E_INVALID_FORMAT;
3826 /* fall through */
3828 case WS_READ_NILLABLE_VALUE:
3829 if (size != sizeof(BOOL)) return E_INVALIDARG;
3830 *(BOOL *)ret = val;
3831 break;
3833 case WS_READ_REQUIRED_POINTER:
3834 if (!found) return WS_E_INVALID_FORMAT;
3835 /* fall through */
3837 case WS_READ_OPTIONAL_POINTER:
3838 case WS_READ_NILLABLE_POINTER:
3840 BOOL *heap_val = NULL;
3841 if (size != sizeof(heap_val)) return E_INVALIDARG;
3842 if (found)
3844 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3845 *heap_val = val;
3847 *(BOOL **)ret = heap_val;
3848 break;
3850 default:
3851 FIXME( "read option %u not supported\n", option );
3852 return E_NOTIMPL;
3855 return S_OK;
3858 static HRESULT read_type_int8( struct reader *reader, WS_TYPE_MAPPING mapping,
3859 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3860 const WS_INT8_DESCRIPTION *desc, WS_READ_OPTION option,
3861 WS_HEAP *heap, void *ret, ULONG size )
3863 WS_XML_UTF8_TEXT *utf8;
3864 HRESULT hr;
3865 INT64 val = 0;
3866 BOOL found;
3868 if (desc)
3870 FIXME( "description not supported\n" );
3871 return E_NOTIMPL;
3873 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3874 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
3875 return hr;
3877 switch (option)
3879 case WS_READ_REQUIRED_VALUE:
3880 if (!found) return WS_E_INVALID_FORMAT;
3881 /* fall through */
3883 case WS_READ_NILLABLE_VALUE:
3884 if (size != sizeof(INT8)) return E_INVALIDARG;
3885 *(INT8 *)ret = val;
3886 break;
3888 case WS_READ_REQUIRED_POINTER:
3889 if (!found) return WS_E_INVALID_FORMAT;
3890 /* fall through */
3892 case WS_READ_OPTIONAL_POINTER:
3893 case WS_READ_NILLABLE_POINTER:
3895 INT8 *heap_val = NULL;
3896 if (size != sizeof(heap_val)) return E_INVALIDARG;
3897 if (found)
3899 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3900 *heap_val = val;
3902 *(INT8 **)ret = heap_val;
3903 break;
3905 default:
3906 FIXME( "read option %u not supported\n", option );
3907 return E_NOTIMPL;
3910 return S_OK;
3913 static HRESULT read_type_int16( struct reader *reader, WS_TYPE_MAPPING mapping,
3914 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3915 const WS_INT16_DESCRIPTION *desc, WS_READ_OPTION option,
3916 WS_HEAP *heap, void *ret, ULONG size )
3918 WS_XML_UTF8_TEXT *utf8;
3919 HRESULT hr;
3920 INT64 val = 0;
3921 BOOL found;
3923 if (desc)
3925 FIXME( "description not supported\n" );
3926 return E_NOTIMPL;
3928 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3929 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
3930 return hr;
3932 switch (option)
3934 case WS_READ_REQUIRED_VALUE:
3935 if (!found) return WS_E_INVALID_FORMAT;
3936 /* fall through */
3938 case WS_READ_NILLABLE_VALUE:
3939 if (size != sizeof(INT16)) return E_INVALIDARG;
3940 *(INT16 *)ret = val;
3941 break;
3943 case WS_READ_REQUIRED_POINTER:
3944 if (!found) return WS_E_INVALID_FORMAT;
3945 /* fall through */
3947 case WS_READ_OPTIONAL_POINTER:
3948 case WS_READ_NILLABLE_POINTER:
3950 INT16 *heap_val = NULL;
3951 if (size != sizeof(heap_val)) return E_INVALIDARG;
3952 if (found)
3954 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3955 *heap_val = val;
3957 *(INT16 **)ret = heap_val;
3958 break;
3960 default:
3961 FIXME( "read option %u not supported\n", option );
3962 return E_NOTIMPL;
3965 return S_OK;
3968 static HRESULT read_type_int32( struct reader *reader, WS_TYPE_MAPPING mapping,
3969 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3970 const WS_INT32_DESCRIPTION *desc, WS_READ_OPTION option,
3971 WS_HEAP *heap, void *ret, ULONG size )
3973 WS_XML_UTF8_TEXT *utf8;
3974 HRESULT hr;
3975 INT64 val = 0;
3976 BOOL found;
3978 if (desc)
3980 FIXME( "description not supported\n" );
3981 return E_NOTIMPL;
3983 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3984 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
3985 return hr;
3987 switch (option)
3989 case WS_READ_REQUIRED_VALUE:
3990 if (!found) return WS_E_INVALID_FORMAT;
3991 /* fall through */
3993 case WS_READ_NILLABLE_VALUE:
3994 if (size != sizeof(INT32)) return E_INVALIDARG;
3995 *(INT32 *)ret = val;
3996 break;
3998 case WS_READ_REQUIRED_POINTER:
3999 if (!found) return WS_E_INVALID_FORMAT;
4000 /* fall through */
4002 case WS_READ_OPTIONAL_POINTER:
4003 case WS_READ_NILLABLE_POINTER:
4005 INT32 *heap_val = NULL;
4006 if (size != sizeof(heap_val)) return E_INVALIDARG;
4007 if (found)
4009 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4010 *heap_val = val;
4012 *(INT32 **)ret = heap_val;
4013 break;
4015 default:
4016 FIXME( "read option %u not supported\n", option );
4017 return E_NOTIMPL;
4020 return S_OK;
4023 static HRESULT read_type_int64( struct reader *reader, WS_TYPE_MAPPING mapping,
4024 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4025 const WS_INT64_DESCRIPTION *desc, WS_READ_OPTION option,
4026 WS_HEAP *heap, void *ret, ULONG size )
4028 WS_XML_UTF8_TEXT *utf8;
4029 HRESULT hr;
4030 INT64 val = 0;
4031 BOOL found;
4033 if (desc)
4035 FIXME( "description not supported\n" );
4036 return E_NOTIMPL;
4038 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4039 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
4040 return hr;
4042 switch (option)
4044 case WS_READ_REQUIRED_VALUE:
4045 if (!found) return WS_E_INVALID_FORMAT;
4046 /* fall through */
4048 case WS_READ_NILLABLE_VALUE:
4049 if (size != sizeof(INT64)) return E_INVALIDARG;
4050 *(INT64 *)ret = val;
4051 break;
4053 case WS_READ_REQUIRED_POINTER:
4054 if (!found) return WS_E_INVALID_FORMAT;
4055 /* fall through */
4057 case WS_READ_OPTIONAL_POINTER:
4058 case WS_READ_NILLABLE_POINTER:
4060 INT64 *heap_val = NULL;
4061 if (size != sizeof(heap_val)) return E_INVALIDARG;
4062 if (found)
4064 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4065 *heap_val = val;
4067 *(INT64 **)ret = heap_val;
4068 break;
4070 default:
4071 FIXME( "read option %u not supported\n", option );
4072 return E_NOTIMPL;
4075 return S_OK;
4078 static HRESULT read_type_uint8( struct reader *reader, WS_TYPE_MAPPING mapping,
4079 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4080 const WS_UINT8_DESCRIPTION *desc, WS_READ_OPTION option,
4081 WS_HEAP *heap, void *ret, ULONG size )
4083 WS_XML_UTF8_TEXT *utf8;
4084 HRESULT hr;
4085 UINT64 val = 0;
4086 BOOL found;
4088 if (desc)
4090 FIXME( "description not supported\n" );
4091 return E_NOTIMPL;
4093 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4094 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
4095 return hr;
4097 switch (option)
4099 case WS_READ_REQUIRED_VALUE:
4100 if (!found) return WS_E_INVALID_FORMAT;
4101 /* fall through */
4103 case WS_READ_NILLABLE_VALUE:
4104 if (size != sizeof(UINT8)) return E_INVALIDARG;
4105 *(UINT8 *)ret = val;
4106 break;
4108 case WS_READ_REQUIRED_POINTER:
4109 if (!found) return WS_E_INVALID_FORMAT;
4110 /* fall through */
4112 case WS_READ_OPTIONAL_POINTER:
4113 case WS_READ_NILLABLE_POINTER:
4115 UINT8 *heap_val = NULL;
4116 if (size != sizeof(heap_val)) return E_INVALIDARG;
4117 if (found)
4119 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4120 *heap_val = val;
4122 *(UINT8 **)ret = heap_val;
4123 break;
4125 default:
4126 FIXME( "read option %u not supported\n", option );
4127 return E_NOTIMPL;
4130 return S_OK;
4133 static HRESULT read_type_uint16( struct reader *reader, WS_TYPE_MAPPING mapping,
4134 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4135 const WS_UINT16_DESCRIPTION *desc, WS_READ_OPTION option,
4136 WS_HEAP *heap, void *ret, ULONG size )
4138 WS_XML_UTF8_TEXT *utf8;
4139 HRESULT hr;
4140 UINT64 val = 0;
4141 BOOL found;
4143 if (desc)
4145 FIXME( "description not supported\n" );
4146 return E_NOTIMPL;
4148 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4149 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
4150 return hr;
4152 switch (option)
4154 case WS_READ_REQUIRED_VALUE:
4155 if (!found) return WS_E_INVALID_FORMAT;
4156 /* fall through */
4158 case WS_READ_NILLABLE_VALUE:
4159 if (size != sizeof(UINT16)) return E_INVALIDARG;
4160 *(UINT16 *)ret = val;
4161 break;
4163 case WS_READ_REQUIRED_POINTER:
4164 if (!found) return WS_E_INVALID_FORMAT;
4165 /* fall through */
4167 case WS_READ_OPTIONAL_POINTER:
4168 case WS_READ_NILLABLE_POINTER:
4170 UINT16 *heap_val = NULL;
4171 if (size != sizeof(heap_val)) return E_INVALIDARG;
4172 if (found)
4174 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4175 *heap_val = val;
4177 *(UINT16 **)ret = heap_val;
4178 break;
4180 default:
4181 FIXME( "read option %u not supported\n", option );
4182 return E_NOTIMPL;
4185 return S_OK;
4188 static HRESULT read_type_uint32( struct reader *reader, WS_TYPE_MAPPING mapping,
4189 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4190 const WS_UINT32_DESCRIPTION *desc, WS_READ_OPTION option,
4191 WS_HEAP *heap, void *ret, ULONG size )
4193 WS_XML_UTF8_TEXT *utf8;
4194 HRESULT hr;
4195 UINT64 val = 0;
4196 BOOL found;
4198 if (desc)
4200 FIXME( "description not supported\n" );
4201 return E_NOTIMPL;
4203 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4204 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
4205 return hr;
4207 switch (option)
4209 case WS_READ_REQUIRED_VALUE:
4210 if (!found) return WS_E_INVALID_FORMAT;
4211 /* fall through */
4213 case WS_READ_NILLABLE_VALUE:
4214 if (size != sizeof(UINT32)) return E_INVALIDARG;
4215 *(UINT32 *)ret = val;
4216 break;
4218 case WS_READ_REQUIRED_POINTER:
4219 if (!found) return WS_E_INVALID_FORMAT;
4220 /* fall through */
4222 case WS_READ_OPTIONAL_POINTER:
4223 case WS_READ_NILLABLE_POINTER:
4225 UINT32 *heap_val = NULL;
4226 if (size != sizeof(heap_val)) return E_INVALIDARG;
4227 if (found)
4229 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4230 *heap_val = val;
4232 *(UINT32 **)ret = heap_val;
4233 break;
4235 default:
4236 FIXME( "read option %u not supported\n", option );
4237 return E_NOTIMPL;
4240 return S_OK;
4243 static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
4244 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4245 const WS_UINT64_DESCRIPTION *desc, WS_READ_OPTION option,
4246 WS_HEAP *heap, void *ret, ULONG size )
4248 WS_XML_UTF8_TEXT *utf8;
4249 HRESULT hr;
4250 UINT64 val = 0;
4251 BOOL found;
4253 if (desc)
4255 FIXME( "description not supported\n" );
4256 return E_NOTIMPL;
4258 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4259 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
4260 return hr;
4262 switch (option)
4264 case WS_READ_REQUIRED_VALUE:
4265 if (!found) return WS_E_INVALID_FORMAT;
4266 /* fall through */
4268 case WS_READ_NILLABLE_VALUE:
4269 if (size != sizeof(UINT64)) return E_INVALIDARG;
4270 *(UINT64 *)ret = val;
4271 break;
4273 case WS_READ_REQUIRED_POINTER:
4274 if (!found) return WS_E_INVALID_FORMAT;
4275 /* fall through */
4277 case WS_READ_OPTIONAL_POINTER:
4278 case WS_READ_NILLABLE_POINTER:
4280 UINT64 *heap_val = NULL;
4281 if (size != sizeof(heap_val)) return E_INVALIDARG;
4282 if (found)
4284 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4285 *heap_val = val;
4287 *(UINT64 **)ret = heap_val;
4288 break;
4290 default:
4291 FIXME( "read option %u not supported\n", option );
4292 return E_NOTIMPL;
4295 return S_OK;
4298 static HRESULT read_type_double( struct reader *reader, WS_TYPE_MAPPING mapping,
4299 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4300 const WS_DOUBLE_DESCRIPTION *desc, WS_READ_OPTION option,
4301 WS_HEAP *heap, void *ret, ULONG size )
4303 WS_XML_UTF8_TEXT *utf8;
4304 HRESULT hr;
4305 double val = 0.0;
4306 BOOL found;
4308 if (desc) FIXME( "ignoring description\n" );
4310 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4311 if (found && (hr = str_to_double( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
4313 switch (option)
4315 case WS_READ_REQUIRED_VALUE:
4316 if (!found) return WS_E_INVALID_FORMAT;
4317 /* fall through */
4319 case WS_READ_NILLABLE_VALUE:
4320 if (size != sizeof(double)) return E_INVALIDARG;
4321 *(double *)ret = val;
4322 break;
4324 case WS_READ_REQUIRED_POINTER:
4325 if (!found) return WS_E_INVALID_FORMAT;
4326 /* fall through */
4328 case WS_READ_OPTIONAL_POINTER:
4329 case WS_READ_NILLABLE_POINTER:
4331 double *heap_val = NULL;
4332 if (size != sizeof(heap_val)) return E_INVALIDARG;
4333 if (found)
4335 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4336 *heap_val = val;
4338 *(double **)ret = heap_val;
4339 break;
4341 default:
4342 FIXME( "read option %u not supported\n", option );
4343 return E_NOTIMPL;
4346 return S_OK;
4349 static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
4350 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4351 const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
4352 WS_HEAP *heap, WCHAR **ret, ULONG size )
4354 WS_XML_UTF8_TEXT *utf8;
4355 HRESULT hr;
4356 WCHAR *str = NULL;
4357 BOOL found;
4359 if (desc)
4361 FIXME( "description not supported\n" );
4362 return E_NOTIMPL;
4364 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4365 if (found && !(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
4367 switch (option)
4369 case WS_READ_REQUIRED_POINTER:
4370 if (!found) return WS_E_INVALID_FORMAT;
4371 /* fall through */
4373 case WS_READ_OPTIONAL_POINTER:
4374 case WS_READ_NILLABLE_POINTER:
4375 if (size != sizeof(str)) return E_INVALIDARG;
4376 *ret = str;
4377 break;
4379 default:
4380 FIXME( "read option %u not supported\n", option );
4381 return E_NOTIMPL;
4384 return S_OK;
4387 static HRESULT get_enum_value( const WS_XML_UTF8_TEXT *text, const WS_ENUM_DESCRIPTION *desc, int *ret )
4389 ULONG i;
4390 for (i = 0; i < desc->valueCount; i++)
4392 if (WsXmlStringEquals( &text->value, desc->values[i].name, NULL ) == S_OK)
4394 *ret = desc->values[i].value;
4395 return S_OK;
4398 return WS_E_INVALID_FORMAT;
4401 static HRESULT read_type_enum( struct reader *reader, WS_TYPE_MAPPING mapping,
4402 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4403 const WS_ENUM_DESCRIPTION *desc, WS_READ_OPTION option,
4404 WS_HEAP *heap, void *ret, ULONG size )
4406 WS_XML_UTF8_TEXT *utf8;
4407 HRESULT hr;
4408 int val = 0;
4409 BOOL found;
4411 if (!desc) return E_INVALIDARG;
4413 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4414 if (found && (hr = get_enum_value( utf8, desc, &val )) != S_OK) return hr;
4416 switch (option)
4418 case WS_READ_REQUIRED_VALUE:
4419 if (!found) return WS_E_INVALID_FORMAT;
4420 /* fall through */
4422 case WS_READ_NILLABLE_VALUE:
4423 if (size != sizeof(int)) return E_INVALIDARG;
4424 *(int *)ret = val;
4425 break;
4427 case WS_READ_REQUIRED_POINTER:
4428 if (!found) return WS_E_INVALID_FORMAT;
4429 /* fall through */
4431 case WS_READ_OPTIONAL_POINTER:
4432 case WS_READ_NILLABLE_POINTER:
4434 int *heap_val = NULL;
4435 if (size != sizeof(heap_val)) return E_INVALIDARG;
4436 if (found)
4438 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4439 *heap_val = val;
4441 *(int **)ret = heap_val;
4442 break;
4444 default:
4445 FIXME( "read option %u not supported\n", option );
4446 return E_NOTIMPL;
4449 return S_OK;
4452 static HRESULT read_type_datetime( struct reader *reader, WS_TYPE_MAPPING mapping,
4453 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4454 const WS_DATETIME_DESCRIPTION *desc, WS_READ_OPTION option,
4455 WS_HEAP *heap, void *ret, ULONG size )
4457 WS_XML_UTF8_TEXT *utf8;
4458 HRESULT hr;
4459 WS_DATETIME val = {0, WS_DATETIME_FORMAT_UTC};
4460 BOOL found;
4462 if (desc) FIXME( "ignoring description\n" );
4464 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4465 if (found && (hr = str_to_datetime( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
4467 switch (option)
4469 case WS_READ_REQUIRED_VALUE:
4470 if (!found) return WS_E_INVALID_FORMAT;
4471 /* fall through */
4473 case WS_READ_NILLABLE_VALUE:
4474 if (size != sizeof(WS_DATETIME)) return E_INVALIDARG;
4475 *(WS_DATETIME *)ret = val;
4476 break;
4478 case WS_READ_REQUIRED_POINTER:
4479 if (!found) return WS_E_INVALID_FORMAT;
4480 /* fall through */
4482 case WS_READ_OPTIONAL_POINTER:
4483 case WS_READ_NILLABLE_POINTER:
4485 WS_DATETIME *heap_val = NULL;
4486 if (size != sizeof(heap_val)) return E_INVALIDARG;
4487 if (found)
4489 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4490 *heap_val = val;
4492 *(WS_DATETIME **)ret = heap_val;
4493 break;
4495 default:
4496 FIXME( "read option %u not supported\n", option );
4497 return E_NOTIMPL;
4500 return S_OK;
4503 static HRESULT read_type_guid( struct reader *reader, WS_TYPE_MAPPING mapping,
4504 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4505 const WS_GUID_DESCRIPTION *desc, WS_READ_OPTION option,
4506 WS_HEAP *heap, void *ret, ULONG size )
4508 WS_XML_UTF8_TEXT *utf8;
4509 GUID val = {0};
4510 HRESULT hr;
4511 BOOL found;
4513 if (desc) FIXME( "ignoring description\n" );
4515 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4516 if (found && (hr = str_to_guid( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
4518 switch (option)
4520 case WS_READ_REQUIRED_VALUE:
4521 if (!found) return WS_E_INVALID_FORMAT;
4522 /* fall through */
4524 case WS_READ_NILLABLE_VALUE:
4525 if (size != sizeof(GUID)) return E_INVALIDARG;
4526 *(GUID *)ret = val;
4527 break;
4529 case WS_READ_REQUIRED_POINTER:
4530 if (!found) return WS_E_INVALID_FORMAT;
4531 /* fall through */
4533 case WS_READ_OPTIONAL_POINTER:
4534 case WS_READ_NILLABLE_POINTER:
4536 GUID *heap_val = NULL;
4537 if (size != sizeof(heap_val)) return E_INVALIDARG;
4538 if (found)
4540 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4541 *heap_val = val;
4543 *(GUID **)ret = heap_val;
4544 break;
4546 default:
4547 FIXME( "read option %u not supported\n", option );
4548 return E_NOTIMPL;
4551 return S_OK;
4554 static HRESULT read_type_bytes( struct reader *reader, WS_TYPE_MAPPING mapping,
4555 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4556 const WS_BYTES_DESCRIPTION *desc, WS_READ_OPTION option,
4557 WS_HEAP *heap, void *ret, ULONG size )
4559 WS_XML_UTF8_TEXT *utf8;
4560 WS_BYTES val = {0};
4561 HRESULT hr;
4562 BOOL found;
4564 if (desc) FIXME( "ignoring description\n" );
4566 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4567 if (found && (hr = str_to_bytes( utf8->value.bytes, utf8->value.length, heap, &val )) != S_OK)
4568 return hr;
4570 switch (option)
4572 case WS_READ_REQUIRED_VALUE:
4573 if (!found) return WS_E_INVALID_FORMAT;
4574 /* fall through */
4576 case WS_READ_NILLABLE_VALUE:
4577 if (size != sizeof(WS_BYTES)) return E_INVALIDARG;
4578 *(WS_BYTES *)ret = val;
4579 break;
4581 case WS_READ_REQUIRED_POINTER:
4582 if (!found) return WS_E_INVALID_FORMAT;
4583 /* fall through */
4585 case WS_READ_OPTIONAL_POINTER:
4586 case WS_READ_NILLABLE_POINTER:
4588 WS_BYTES *heap_val = NULL;
4589 if (size != sizeof(heap_val)) return E_INVALIDARG;
4590 if (found)
4592 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4593 *heap_val = val;
4595 *(WS_BYTES **)ret = heap_val;
4596 break;
4598 default:
4599 FIXME( "read option %u not supported\n", option );
4600 return E_NOTIMPL;
4603 return S_OK;
4606 static BOOL is_empty_text_node( const struct node *node )
4608 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4609 const WS_XML_UTF8_TEXT *utf8;
4610 ULONG i;
4612 if (node_type( node ) != WS_XML_NODE_TYPE_TEXT) return FALSE;
4613 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
4615 ERR( "unhandled text type %u\n", text->text->textType );
4616 return FALSE;
4618 utf8 = (const WS_XML_UTF8_TEXT *)text->text;
4619 for (i = 0; i < utf8->value.length; i++) if (!read_isspace( utf8->value.bytes[i] )) return FALSE;
4620 return TRUE;
4623 static HRESULT read_next_node( struct reader *reader )
4625 if (reader->current == reader->last) return read_node( reader );
4626 if (move_to_child_node( &reader->current )) return S_OK;
4627 if (move_to_next_node( &reader->current )) return S_OK;
4628 if (!move_to_parent_node( &reader->current )) return WS_E_INVALID_FORMAT;
4629 if (move_to_next_node( &reader->current )) return S_OK;
4630 return WS_E_INVALID_FORMAT;
4633 /* skips comment and empty text nodes */
4634 static HRESULT read_type_next_node( struct reader *reader )
4636 for (;;)
4638 HRESULT hr;
4639 WS_XML_NODE_TYPE type;
4641 if ((hr = read_next_node( reader )) != S_OK) return hr;
4642 type = node_type( reader->current );
4643 if (type == WS_XML_NODE_TYPE_COMMENT ||
4644 (type == WS_XML_NODE_TYPE_TEXT && is_empty_text_node( reader->current ))) continue;
4645 return S_OK;
4649 static BOOL match_current_element( struct reader *reader, const WS_XML_STRING *localname,
4650 const WS_XML_STRING *ns )
4652 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
4653 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
4654 return WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK &&
4655 WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK;
4658 static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname,
4659 const WS_XML_STRING *ns )
4661 struct node *node;
4662 ULONG attr;
4663 HRESULT hr;
4665 if (!localname) return S_OK; /* assume reader is already correctly positioned */
4666 if (reader->current == reader->last)
4668 BOOL found;
4669 if ((hr = read_to_startelement( reader, &found )) != S_OK) return hr;
4670 if (!found) return WS_E_INVALID_FORMAT;
4672 if (match_current_element( reader, localname, ns )) return S_OK;
4674 node = reader->current;
4675 attr = reader->current_attr;
4677 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
4678 if (match_current_element( reader, localname, ns )) return S_OK;
4680 reader->current = node;
4681 reader->current_attr = attr;
4683 return WS_E_INVALID_FORMAT;
4686 ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
4688 switch (type)
4690 case WS_INT8_TYPE:
4691 case WS_UINT8_TYPE:
4692 return sizeof(INT8);
4694 case WS_INT16_TYPE:
4695 case WS_UINT16_TYPE:
4696 return sizeof(INT16);
4698 case WS_BOOL_TYPE:
4699 case WS_INT32_TYPE:
4700 case WS_UINT32_TYPE:
4701 case WS_ENUM_TYPE:
4702 return sizeof(INT32);
4704 case WS_INT64_TYPE:
4705 case WS_UINT64_TYPE:
4706 return sizeof(INT64);
4708 case WS_DOUBLE_TYPE:
4709 return sizeof(double);
4711 case WS_DATETIME_TYPE:
4712 return sizeof(WS_DATETIME);
4714 case WS_GUID_TYPE:
4715 return sizeof(GUID);
4717 case WS_STRING_TYPE:
4718 return sizeof(WS_STRING);
4720 case WS_WSZ_TYPE:
4721 return sizeof(WCHAR *);
4723 case WS_BYTES_TYPE:
4724 return sizeof(WS_BYTES);
4726 case WS_XML_STRING_TYPE:
4727 return sizeof(WS_XML_STRING);
4729 case WS_STRUCT_TYPE:
4730 return desc->size;
4732 case WS_DESCRIPTION_TYPE:
4733 return sizeof(WS_STRUCT_DESCRIPTION *);
4735 default:
4736 ERR( "unhandled type %u\n", type );
4737 return 0;
4741 static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options )
4743 if (options & WS_FIELD_POINTER)
4745 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
4746 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
4747 return WS_READ_REQUIRED_POINTER;
4750 switch (type)
4752 case WS_BOOL_TYPE:
4753 case WS_INT8_TYPE:
4754 case WS_INT16_TYPE:
4755 case WS_INT32_TYPE:
4756 case WS_INT64_TYPE:
4757 case WS_UINT8_TYPE:
4758 case WS_UINT16_TYPE:
4759 case WS_UINT32_TYPE:
4760 case WS_UINT64_TYPE:
4761 case WS_DOUBLE_TYPE:
4762 case WS_DATETIME_TYPE:
4763 case WS_GUID_TYPE:
4764 case WS_STRING_TYPE:
4765 case WS_BYTES_TYPE:
4766 case WS_XML_STRING_TYPE:
4767 case WS_STRUCT_TYPE:
4768 case WS_ENUM_TYPE:
4769 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_READ_NILLABLE_VALUE;
4770 return WS_READ_REQUIRED_VALUE;
4772 case WS_WSZ_TYPE:
4773 case WS_DESCRIPTION_TYPE:
4774 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
4775 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
4776 return WS_READ_REQUIRED_POINTER;
4778 default:
4779 FIXME( "unhandled type %u\n", type );
4780 return 0;
4784 static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
4785 const WS_XML_STRING *, const void *, WS_READ_OPTION, WS_HEAP *,
4786 void *, ULONG );
4788 static HRESULT read_type_repeating_element( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4789 WS_HEAP *heap, void **ret, ULONG *count )
4791 HRESULT hr;
4792 ULONG item_size, nb_items = 0, nb_allocated = 1, offset = 0;
4793 WS_READ_OPTION option;
4794 char *buf;
4796 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
4798 /* wrapper element */
4799 if (desc->localName && ((hr = read_type_next_element_node( reader, desc->localName, desc->ns )) != S_OK))
4800 return hr;
4802 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
4803 item_size = get_type_size( desc->type, desc->typeDescription );
4804 else
4805 item_size = sizeof(void *);
4807 if (!(buf = ws_alloc_zero( heap, item_size ))) return WS_E_QUOTA_EXCEEDED;
4808 for (;;)
4810 if (nb_items >= nb_allocated)
4812 SIZE_T old_size = nb_allocated * item_size, new_size = old_size * 2;
4813 if (!(buf = ws_realloc_zero( heap, buf, old_size, new_size )))
4814 return WS_E_QUOTA_EXCEEDED;
4815 nb_allocated *= 2;
4817 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs,
4818 desc->typeDescription, option, heap, buf + offset, item_size );
4819 if (hr == WS_E_INVALID_FORMAT) break;
4820 if (hr != S_OK)
4822 ws_free( heap, buf, nb_allocated * item_size );
4823 return hr;
4825 offset += item_size;
4826 nb_items++;
4829 if (desc->localName && ((hr = read_type_next_node( reader )) != S_OK)) return hr;
4831 if (desc->itemRange && (nb_items < desc->itemRange->minItemCount || nb_items > desc->itemRange->maxItemCount))
4833 TRACE( "number of items %u out of range (%u-%u)\n", nb_items, desc->itemRange->minItemCount,
4834 desc->itemRange->maxItemCount );
4835 ws_free( heap, buf, nb_allocated * item_size );
4836 return WS_E_INVALID_FORMAT;
4839 *count = nb_items;
4840 *ret = buf;
4842 return S_OK;
4845 static HRESULT read_type_text( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4846 WS_READ_OPTION option, WS_HEAP *heap, void *ret, ULONG size )
4848 HRESULT hr;
4849 if (reader->current == reader->last)
4851 BOOL found;
4852 if ((hr = read_to_startelement( reader, &found )) != S_OK) return S_OK;
4853 if (!found) return WS_E_INVALID_FORMAT;
4855 if ((hr = read_next_node( reader )) != S_OK) return hr;
4856 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT) return WS_E_INVALID_FORMAT;
4858 return read_type( reader, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, NULL, NULL,
4859 desc->typeDescription, option, heap, ret, size );
4862 static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4863 WS_HEAP *heap, char *buf, ULONG offset )
4865 char *ptr;
4866 WS_READ_OPTION option;
4867 ULONG size;
4868 HRESULT hr;
4870 if (!desc) return E_INVALIDARG;
4871 if (desc->options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
4873 FIXME( "options %08x not supported\n", desc->options );
4874 return E_NOTIMPL;
4876 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
4878 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
4879 size = get_type_size( desc->type, desc->typeDescription );
4880 else
4881 size = sizeof(void *);
4883 ptr = buf + offset;
4884 switch (desc->mapping)
4886 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
4887 FIXME( "WS_TYPE_ATTRIBUTE_FIELD_MAPPING not supported\n" );
4888 return S_OK;
4890 case WS_ATTRIBUTE_FIELD_MAPPING:
4891 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4892 desc->typeDescription, option, heap, ptr, size );
4893 break;
4895 case WS_ELEMENT_FIELD_MAPPING:
4896 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4897 desc->typeDescription, option, heap, ptr, size );
4898 break;
4900 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
4902 ULONG count;
4903 hr = read_type_repeating_element( reader, desc, heap, (void **)ptr, &count );
4904 if (hr == S_OK) *(ULONG *)(buf + desc->countOffset) = count;
4905 break;
4907 case WS_TEXT_FIELD_MAPPING:
4908 hr = read_type_text( reader, desc, option, heap, ptr, size );
4909 break;
4911 default:
4912 FIXME( "unhandled field mapping %u\n", desc->mapping );
4913 return E_NOTIMPL;
4916 if (hr == WS_E_INVALID_FORMAT)
4918 switch (option)
4920 case WS_READ_REQUIRED_VALUE:
4921 case WS_READ_REQUIRED_POINTER:
4922 return WS_E_INVALID_FORMAT;
4924 case WS_READ_NILLABLE_VALUE:
4925 if (desc->defaultValue) memcpy( ptr, desc->defaultValue->value, desc->defaultValue->valueSize );
4926 return S_OK;
4928 case WS_READ_OPTIONAL_POINTER:
4929 case WS_READ_NILLABLE_POINTER:
4930 *(void **)ptr = NULL;
4931 return S_OK;
4933 default:
4934 ERR( "unhandled option %u\n", option );
4935 return E_NOTIMPL;
4939 return hr;
4942 static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
4943 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4944 const WS_STRUCT_DESCRIPTION *desc, WS_READ_OPTION option,
4945 WS_HEAP *heap, void *ret, ULONG size )
4947 ULONG i, offset;
4948 HRESULT hr;
4949 char *buf;
4951 if (!desc) return E_INVALIDARG;
4952 if (desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4954 FIXME( "struct options %08x not supported\n",
4955 desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT );
4958 switch (option)
4960 case WS_READ_REQUIRED_POINTER:
4961 case WS_READ_OPTIONAL_POINTER:
4962 case WS_READ_NILLABLE_POINTER:
4963 if (size != sizeof(void *)) return E_INVALIDARG;
4964 if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
4965 break;
4967 case WS_READ_REQUIRED_VALUE:
4968 case WS_READ_NILLABLE_VALUE:
4969 if (size != desc->size) return E_INVALIDARG;
4970 buf = ret;
4971 break;
4973 default:
4974 FIXME( "unhandled read option %u\n", option );
4975 return E_NOTIMPL;
4978 for (i = 0; i < desc->fieldCount; i++)
4980 offset = desc->fields[i]->offset;
4981 if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, offset )) != S_OK)
4982 break;
4985 switch (option)
4987 case WS_READ_REQUIRED_POINTER:
4988 if (hr != S_OK)
4990 ws_free( heap, buf, desc->size );
4991 return hr;
4993 *(char **)ret = buf;
4994 break;
4996 case WS_READ_OPTIONAL_POINTER:
4997 case WS_READ_NILLABLE_POINTER:
4998 if (is_nil_value( buf, desc->size ))
5000 ws_free( heap, buf, desc->size );
5001 buf = NULL;
5003 *(char **)ret = buf;
5004 break;
5006 case WS_READ_REQUIRED_VALUE:
5007 case WS_READ_NILLABLE_VALUE:
5008 if (hr != S_OK) return hr;
5009 break;
5011 default:
5012 ERR( "unhandled read option %u\n", option );
5013 return E_NOTIMPL;
5016 if (desc->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
5018 struct node *parent = find_parent( reader );
5019 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
5021 return S_OK;
5024 static HRESULT start_mapping( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname,
5025 const WS_XML_STRING *ns )
5027 switch (mapping)
5029 case WS_ELEMENT_TYPE_MAPPING:
5030 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
5031 return read_type_next_element_node( reader, localname, ns );
5033 case WS_ANY_ELEMENT_TYPE_MAPPING:
5034 case WS_ATTRIBUTE_TYPE_MAPPING:
5035 return S_OK;
5037 default:
5038 FIXME( "unhandled mapping %u\n", mapping );
5039 return E_NOTIMPL;
5043 static HRESULT read_type_endelement_node( struct reader *reader )
5045 const struct node *parent = find_parent( reader );
5046 HRESULT hr;
5048 for (;;)
5050 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
5051 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT && reader->current->parent == parent)
5053 return S_OK;
5055 if (read_end_of_data( reader ) || !(parent->flags & NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT)) break;
5058 return WS_E_INVALID_FORMAT;
5061 static HRESULT end_mapping( struct reader *reader, WS_TYPE_MAPPING mapping )
5063 switch (mapping)
5065 case WS_ELEMENT_TYPE_MAPPING:
5066 return read_type_endelement_node( reader );
5068 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
5069 return read_type_next_node( reader );
5071 case WS_ATTRIBUTE_TYPE_MAPPING:
5072 default:
5073 return S_OK;
5077 static HRESULT is_nil_element( const WS_XML_ELEMENT_NODE *elem )
5079 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
5080 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
5081 ULONG i;
5083 for (i = 0; i < elem->attributeCount; i++)
5085 const WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)elem->attributes[i]->value;
5087 if (elem->attributes[i]->isXmlNs) continue;
5088 if (WsXmlStringEquals( elem->attributes[i]->localName, &localname, NULL ) == S_OK &&
5089 WsXmlStringEquals( elem->attributes[i]->ns, &ns, NULL ) == S_OK &&
5090 text->value.length == 4 && !memcmp( text->value.bytes, "true", 4 )) return TRUE;
5092 return FALSE;
5095 static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYPE type,
5096 const WS_XML_STRING *localname, const WS_XML_STRING *ns, const void *desc,
5097 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
5099 HRESULT hr;
5101 if ((hr = start_mapping( reader, mapping, localname, ns )) != S_OK) return hr;
5103 if (mapping == WS_ELEMENT_TYPE_MAPPING && is_nil_element( &reader->current->hdr ))
5105 if (option != WS_READ_NILLABLE_POINTER && option != WS_READ_NILLABLE_VALUE) return WS_E_INVALID_FORMAT;
5106 return end_mapping( reader, mapping );
5109 switch (type)
5111 case WS_BOOL_TYPE:
5112 if ((hr = read_type_bool( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5113 return hr;
5114 break;
5116 case WS_INT8_TYPE:
5117 if ((hr = read_type_int8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5118 return hr;
5119 break;
5121 case WS_INT16_TYPE:
5122 if ((hr = read_type_int16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5123 return hr;
5124 break;
5126 case WS_INT32_TYPE:
5127 if ((hr = read_type_int32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5128 return hr;
5129 break;
5131 case WS_INT64_TYPE:
5132 if ((hr = read_type_int64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5133 return hr;
5134 break;
5136 case WS_UINT8_TYPE:
5137 if ((hr = read_type_uint8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5138 return hr;
5139 break;
5141 case WS_UINT16_TYPE:
5142 if ((hr = read_type_uint16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5143 return hr;
5144 break;
5146 case WS_UINT32_TYPE:
5147 if ((hr = read_type_uint32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5148 return hr;
5149 break;
5151 case WS_UINT64_TYPE:
5152 if ((hr = read_type_uint64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5153 return hr;
5154 break;
5156 case WS_DOUBLE_TYPE:
5157 if ((hr = read_type_double( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5158 return hr;
5159 break;
5161 case WS_DATETIME_TYPE:
5162 if ((hr = read_type_datetime( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5163 return hr;
5164 break;
5166 case WS_GUID_TYPE:
5167 if ((hr = read_type_guid( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5168 return hr;
5169 break;
5171 case WS_WSZ_TYPE:
5172 if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5173 return hr;
5174 break;
5176 case WS_BYTES_TYPE:
5177 if ((hr = read_type_bytes( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5178 return hr;
5179 break;
5181 case WS_STRUCT_TYPE:
5182 if ((hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5183 return hr;
5184 break;
5186 case WS_ENUM_TYPE:
5187 if ((hr = read_type_enum( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
5188 return hr;
5189 break;
5191 default:
5192 FIXME( "type %u not supported\n", type );
5193 return E_NOTIMPL;
5196 return end_mapping( reader, mapping );
5199 /**************************************************************************
5200 * WsReadType [webservices.@]
5202 HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
5203 const void *desc, WS_READ_OPTION option, WS_HEAP *heap, void *value,
5204 ULONG size, WS_ERROR *error )
5206 struct reader *reader = (struct reader *)handle;
5207 HRESULT hr;
5209 TRACE( "%p %u %u %p %u %p %p %u %p\n", handle, mapping, type, desc, option, heap, value,
5210 size, error );
5211 if (error) FIXME( "ignoring error parameter\n" );
5213 if (!reader || !value) return E_INVALIDARG;
5215 EnterCriticalSection( &reader->cs );
5217 if (reader->magic != READER_MAGIC)
5219 LeaveCriticalSection( &reader->cs );
5220 return E_INVALIDARG;
5223 if ((hr = read_type( reader, mapping, type, NULL, NULL, desc, option, heap, value, size )) != S_OK)
5225 LeaveCriticalSection( &reader->cs );
5226 return hr;
5229 switch (mapping)
5231 case WS_ELEMENT_TYPE_MAPPING:
5232 hr = read_node( reader );
5233 break;
5235 default:
5236 break;
5239 if (hr == S_OK && !read_end_of_data( reader )) hr = WS_E_INVALID_FORMAT;
5241 LeaveCriticalSection( &reader->cs );
5242 return hr;
5245 /**************************************************************************
5246 * WsReadElement [webservices.@]
5248 HRESULT WINAPI WsReadElement( WS_XML_READER *handle, const WS_ELEMENT_DESCRIPTION *desc,
5249 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
5250 WS_ERROR *error )
5252 struct reader *reader = (struct reader *)handle;
5253 HRESULT hr;
5255 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
5256 if (error) FIXME( "ignoring error parameter\n" );
5258 if (!reader || !desc || !value) return E_INVALIDARG;
5260 EnterCriticalSection( &reader->cs );
5262 if (reader->magic != READER_MAGIC)
5264 LeaveCriticalSection( &reader->cs );
5265 return E_INVALIDARG;
5268 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->elementLocalName,
5269 desc->elementNs, desc->typeDescription, option, heap, value, size );
5271 LeaveCriticalSection( &reader->cs );
5272 return hr;
5275 /**************************************************************************
5276 * WsReadValue [webservices.@]
5278 HRESULT WINAPI WsReadValue( WS_XML_READER *handle, WS_VALUE_TYPE value_type, void *value, ULONG size,
5279 WS_ERROR *error )
5281 struct reader *reader = (struct reader *)handle;
5282 WS_TYPE type = map_value_type( value_type );
5283 HRESULT hr;
5285 TRACE( "%p %u %p %u %p\n", handle, type, value, size, error );
5286 if (error) FIXME( "ignoring error parameter\n" );
5288 if (!reader || !value || type == ~0u) return E_INVALIDARG;
5290 EnterCriticalSection( &reader->cs );
5292 if (reader->magic != READER_MAGIC)
5294 LeaveCriticalSection( &reader->cs );
5295 return E_INVALIDARG;
5298 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, type, NULL, NULL, NULL, WS_READ_REQUIRED_VALUE,
5299 NULL, value, size );
5301 LeaveCriticalSection( &reader->cs );
5302 return hr;
5305 /**************************************************************************
5306 * WsReadAttribute [webservices.@]
5308 HRESULT WINAPI WsReadAttribute( WS_XML_READER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
5309 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
5310 WS_ERROR *error )
5312 struct reader *reader = (struct reader *)handle;
5313 HRESULT hr;
5315 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
5316 if (error) FIXME( "ignoring error parameter\n" );
5318 if (!reader || !desc || !value) return E_INVALIDARG;
5320 EnterCriticalSection( &reader->cs );
5322 if (reader->magic != READER_MAGIC)
5324 LeaveCriticalSection( &reader->cs );
5325 return E_INVALIDARG;
5328 if (!reader->input_type)
5330 LeaveCriticalSection( &reader->cs );
5331 return WS_E_INVALID_OPERATION;
5334 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->attributeLocalName,
5335 desc->attributeNs, desc->typeDescription, option, heap, value, size );
5337 LeaveCriticalSection( &reader->cs );
5338 return hr;
5341 static inline BOOL is_utf8( const unsigned char *data, ULONG size, ULONG *offset )
5343 static const char bom[] = {0xef,0xbb,0xbf};
5344 const unsigned char *p = data;
5346 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
5347 (size > 2 && !(*offset = 0));
5350 static inline BOOL is_utf16le( const unsigned char *data, ULONG size, ULONG *offset )
5352 static const char bom[] = {0xff,0xfe};
5353 const unsigned char *p = data;
5355 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
5356 (size >= 4 && p[0] == '<' && !p[1] && !(*offset = 0));
5359 static WS_CHARSET detect_charset( const unsigned char *data, ULONG size, ULONG *offset )
5361 WS_CHARSET ret = 0;
5363 /* FIXME: parse xml declaration */
5365 if (is_utf16le( data, size, offset )) ret = WS_CHARSET_UTF16LE;
5366 else if (is_utf8( data, size, offset )) ret = WS_CHARSET_UTF8;
5367 else
5369 FIXME( "charset not recognized\n" );
5370 return 0;
5373 TRACE( "detected charset %u\n", ret );
5374 return ret;
5377 static void set_input_buffer( struct reader *reader, struct xmlbuf *buf, const unsigned char *data, ULONG size )
5379 reader->input_type = WS_XML_READER_INPUT_TYPE_BUFFER;
5380 reader->input_buf = buf;
5381 reader->input_data = data;
5382 reader->input_size = size;
5384 reader->read_size = reader->input_size;
5385 reader->read_pos = 0;
5386 reader->read_bufptr = reader->input_data;
5388 reader->text_conv_offset = 0;
5391 /**************************************************************************
5392 * WsSetInput [webservices.@]
5394 HRESULT WINAPI WsSetInput( WS_XML_READER *handle, const WS_XML_READER_ENCODING *encoding,
5395 const WS_XML_READER_INPUT *input, const WS_XML_READER_PROPERTY *properties,
5396 ULONG count, WS_ERROR *error )
5398 struct reader *reader = (struct reader *)handle;
5399 struct node *node;
5400 ULONG i, offset = 0;
5401 HRESULT hr;
5403 TRACE( "%p %p %p %p %u %p\n", handle, encoding, input, properties, count, error );
5404 if (error) FIXME( "ignoring error parameter\n" );
5406 if (!reader) return E_INVALIDARG;
5408 EnterCriticalSection( &reader->cs );
5410 if (reader->magic != READER_MAGIC)
5412 LeaveCriticalSection( &reader->cs );
5413 return E_INVALIDARG;
5416 for (i = 0; i < count; i++)
5418 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
5419 properties[i].valueSize );
5420 if (hr != S_OK) goto done;
5423 if ((hr = init_reader( reader )) != S_OK) goto done;
5425 switch (encoding->encodingType)
5427 case WS_XML_READER_ENCODING_TYPE_TEXT:
5429 WS_XML_READER_TEXT_ENCODING *text = (WS_XML_READER_TEXT_ENCODING *)encoding;
5430 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
5431 WS_CHARSET charset = text->charSet;
5433 if (input->inputType != WS_XML_READER_INPUT_TYPE_BUFFER)
5435 FIXME( "charset detection on input type %u not supported\n", input->inputType );
5436 hr = E_NOTIMPL;
5437 goto done;
5440 if (charset == WS_CHARSET_AUTO)
5441 charset = detect_charset( buf->encodedData, buf->encodedDataSize, &offset );
5443 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET,
5444 &charset, sizeof(charset) );
5445 if (hr != S_OK) goto done;
5447 reader->input_enc = WS_XML_READER_ENCODING_TYPE_TEXT;
5448 break;
5450 case WS_XML_READER_ENCODING_TYPE_BINARY:
5452 WS_XML_READER_BINARY_ENCODING *bin = (WS_XML_READER_BINARY_ENCODING *)encoding;
5453 reader->input_enc = WS_XML_READER_ENCODING_TYPE_BINARY;
5454 reader->dict = bin->staticDictionary;
5455 break;
5457 default:
5458 FIXME( "encoding type %u not supported\n", encoding->encodingType );
5459 hr = E_NOTIMPL;
5460 goto done;
5463 switch (input->inputType)
5465 case WS_XML_READER_INPUT_TYPE_BUFFER:
5467 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
5468 set_input_buffer( reader, NULL, (const unsigned char *)buf->encodedData + offset,
5469 buf->encodedDataSize - offset );
5470 break;
5472 default:
5473 FIXME( "input type %u not supported\n", input->inputType );
5474 hr = E_NOTIMPL;
5475 goto done;
5478 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
5479 else read_insert_bof( reader, node );
5481 done:
5482 LeaveCriticalSection( &reader->cs );
5483 return hr;
5486 /**************************************************************************
5487 * WsSetInputToBuffer [webservices.@]
5489 HRESULT WINAPI WsSetInputToBuffer( WS_XML_READER *handle, WS_XML_BUFFER *buffer,
5490 const WS_XML_READER_PROPERTY *properties, ULONG count,
5491 WS_ERROR *error )
5493 struct reader *reader = (struct reader *)handle;
5494 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
5495 WS_CHARSET charset;
5496 struct node *node;
5497 ULONG i, offset = 0;
5498 HRESULT hr;
5500 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
5501 if (error) FIXME( "ignoring error parameter\n" );
5503 if (!reader || !xmlbuf) return E_INVALIDARG;
5505 EnterCriticalSection( &reader->cs );
5507 if (reader->magic != READER_MAGIC)
5509 LeaveCriticalSection( &reader->cs );
5510 return E_INVALIDARG;
5513 for (i = 0; i < count; i++)
5515 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
5516 properties[i].valueSize );
5517 if (hr != S_OK) goto done;
5520 if ((hr = init_reader( reader )) != S_OK) goto done;
5522 charset = detect_charset( xmlbuf->bytes.bytes, xmlbuf->bytes.length, &offset );
5523 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset,
5524 sizeof(charset) );
5525 if (hr != S_OK) goto done;
5527 set_input_buffer( reader, xmlbuf, xmlbuf->bytes.bytes + offset, xmlbuf->bytes.length - offset );
5528 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
5529 else read_insert_bof( reader, node );
5531 done:
5532 LeaveCriticalSection( &reader->cs );
5533 return hr;
5536 /**************************************************************************
5537 * WsXmlStringEquals [webservices.@]
5539 HRESULT WINAPI WsXmlStringEquals( const WS_XML_STRING *str1, const WS_XML_STRING *str2, WS_ERROR *error )
5541 TRACE( "%s %s %p\n", debugstr_xmlstr(str1), debugstr_xmlstr(str2), error );
5542 if (error) FIXME( "ignoring error parameter\n" );
5544 if (!str1 || !str2) return E_INVALIDARG;
5546 if (str1->length != str2->length) return S_FALSE;
5547 if (!memcmp( str1->bytes, str2->bytes, str1->length )) return S_OK;
5548 return S_FALSE;
5551 /**************************************************************************
5552 * WsGetReaderPosition [webservices.@]
5554 HRESULT WINAPI WsGetReaderPosition( WS_XML_READER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
5556 struct reader *reader = (struct reader *)handle;
5558 TRACE( "%p %p %p\n", handle, pos, error );
5559 if (error) FIXME( "ignoring error parameter\n" );
5561 if (!reader || !pos) return E_INVALIDARG;
5563 EnterCriticalSection( &reader->cs );
5565 if (reader->magic != READER_MAGIC)
5567 LeaveCriticalSection( &reader->cs );
5568 return E_INVALIDARG;
5571 if (!reader->input_buf)
5573 LeaveCriticalSection( &reader->cs );
5574 return WS_E_INVALID_OPERATION;
5577 pos->buffer = (WS_XML_BUFFER *)reader->input_buf;
5578 pos->node = reader->current;
5580 LeaveCriticalSection( &reader->cs );
5581 return S_OK;
5584 /**************************************************************************
5585 * WsSetReaderPosition [webservices.@]
5587 HRESULT WINAPI WsSetReaderPosition( WS_XML_READER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
5589 struct reader *reader = (struct reader *)handle;
5591 TRACE( "%p %p %p\n", handle, pos, error );
5592 if (error) FIXME( "ignoring error parameter\n" );
5594 if (!reader || !pos) return E_INVALIDARG;
5596 EnterCriticalSection( &reader->cs );
5598 if (reader->magic != READER_MAGIC || (struct xmlbuf *)pos->buffer != reader->input_buf)
5600 LeaveCriticalSection( &reader->cs );
5601 return E_INVALIDARG;
5604 if (!reader->input_buf)
5606 LeaveCriticalSection( &reader->cs );
5607 return WS_E_INVALID_OPERATION;
5610 reader->current = pos->node;
5612 LeaveCriticalSection( &reader->cs );
5613 return S_OK;
5616 static HRESULT utf8_to_base64( const WS_XML_UTF8_TEXT *utf8, WS_XML_BASE64_TEXT *base64 )
5618 if (utf8->value.length % 4) return WS_E_INVALID_FORMAT;
5619 if (!(base64->bytes = heap_alloc( utf8->value.length * 3 / 4 ))) return E_OUTOFMEMORY;
5620 base64->length = decode_base64( utf8->value.bytes, utf8->value.length, base64->bytes );
5621 return S_OK;
5624 /**************************************************************************
5625 * WsReadBytes [webservices.@]
5627 HRESULT WINAPI WsReadBytes( WS_XML_READER *handle, void *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
5629 struct reader *reader = (struct reader *)handle;
5630 HRESULT hr;
5632 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
5633 if (error) FIXME( "ignoring error parameter\n" );
5635 if (!reader) return E_INVALIDARG;
5637 EnterCriticalSection( &reader->cs );
5639 if (reader->magic != READER_MAGIC)
5641 LeaveCriticalSection( &reader->cs );
5642 return E_INVALIDARG;
5645 if (!reader->input_type)
5647 LeaveCriticalSection( &reader->cs );
5648 return WS_E_INVALID_OPERATION;
5651 if (!count)
5653 LeaveCriticalSection( &reader->cs );
5654 return E_INVALIDARG;
5657 *count = 0;
5658 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
5660 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5661 WS_XML_BASE64_TEXT base64;
5663 if ((hr = utf8_to_base64( (const WS_XML_UTF8_TEXT *)text->text, &base64 )) != S_OK)
5665 LeaveCriticalSection( &reader->cs );
5666 return hr;
5668 if (reader->text_conv_offset == base64.length)
5670 heap_free( base64.bytes );
5671 hr = read_node( reader );
5672 LeaveCriticalSection( &reader->cs );
5673 return hr;
5675 *count = min( base64.length - reader->text_conv_offset, max_count );
5676 memcpy( bytes, base64.bytes + reader->text_conv_offset, *count );
5677 reader->text_conv_offset += *count;
5678 heap_free( base64.bytes );
5681 LeaveCriticalSection( &reader->cs );
5682 return S_OK;
5685 static HRESULT utf8_to_utf16( const WS_XML_UTF8_TEXT *utf8, WS_XML_UTF16_TEXT *utf16 )
5687 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
5688 if (!(utf16->bytes = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
5689 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, (WCHAR *)utf16->bytes, len );
5690 utf16->byteCount = len * sizeof(WCHAR);
5691 return S_OK;
5694 /**************************************************************************
5695 * WsReadChars [webservices.@]
5697 HRESULT WINAPI WsReadChars( WS_XML_READER *handle, WCHAR *chars, ULONG max_count, ULONG *count, WS_ERROR *error )
5699 struct reader *reader = (struct reader *)handle;
5701 TRACE( "%p %p %u %p %p\n", handle, chars, max_count, count, error );
5702 if (error) FIXME( "ignoring error parameter\n" );
5704 if (!reader) return E_INVALIDARG;
5706 EnterCriticalSection( &reader->cs );
5708 if (reader->magic != READER_MAGIC)
5710 LeaveCriticalSection( &reader->cs );
5711 return E_INVALIDARG;
5714 if (!reader->input_type)
5716 LeaveCriticalSection( &reader->cs );
5717 return WS_E_INVALID_OPERATION;
5720 if (!count)
5722 LeaveCriticalSection( &reader->cs );
5723 return E_INVALIDARG;
5726 *count = 0;
5727 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && chars)
5729 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5730 WS_XML_UTF16_TEXT utf16;
5731 HRESULT hr;
5733 if ((hr = utf8_to_utf16( (const WS_XML_UTF8_TEXT *)text->text, &utf16 )) != S_OK)
5735 LeaveCriticalSection( &reader->cs );
5736 return hr;
5738 if (reader->text_conv_offset == utf16.byteCount / sizeof(WCHAR))
5740 heap_free( utf16.bytes );
5741 hr = read_node( reader );
5742 LeaveCriticalSection( &reader->cs );
5743 return hr;
5745 *count = min( utf16.byteCount / sizeof(WCHAR) - reader->text_conv_offset, max_count );
5746 memcpy( chars, utf16.bytes + reader->text_conv_offset * sizeof(WCHAR), *count * sizeof(WCHAR) );
5747 reader->text_conv_offset += *count;
5748 heap_free( utf16.bytes );
5751 LeaveCriticalSection( &reader->cs );
5752 return S_OK;
5755 /**************************************************************************
5756 * WsReadCharsUtf8 [webservices.@]
5758 HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
5760 struct reader *reader = (struct reader *)handle;
5761 HRESULT hr;
5763 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
5764 if (error) FIXME( "ignoring error parameter\n" );
5766 if (!reader) return E_INVALIDARG;
5768 EnterCriticalSection( &reader->cs );
5770 if (reader->magic != READER_MAGIC)
5772 LeaveCriticalSection( &reader->cs );
5773 return E_INVALIDARG;
5776 if (!reader->input_type)
5778 LeaveCriticalSection( &reader->cs );
5779 return WS_E_INVALID_OPERATION;
5782 if (!count)
5784 LeaveCriticalSection( &reader->cs );
5785 return E_INVALIDARG;
5788 *count = 0;
5789 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
5791 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5792 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
5794 if (reader->text_conv_offset == utf8->value.length)
5796 hr = read_node( reader );
5797 LeaveCriticalSection( &reader->cs );
5798 return hr;
5800 *count = min( utf8->value.length - reader->text_conv_offset, max_count );
5801 memcpy( bytes, utf8->value.bytes + reader->text_conv_offset, *count );
5802 reader->text_conv_offset += *count;
5805 LeaveCriticalSection( &reader->cs );
5806 return S_OK;
5809 HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *desc, USHORT index, const WS_FIELD_DESCRIPTION **ret )
5811 if (index >= desc->fieldCount) return E_INVALIDARG;
5812 *ret = desc->fields[index];
5813 return S_OK;
5816 static ULONG get_field_size( const WS_FIELD_DESCRIPTION *desc )
5818 WS_READ_OPTION option;
5819 ULONG size;
5821 switch ((option = get_field_read_option( desc->type, desc->options )))
5823 case WS_READ_REQUIRED_POINTER:
5824 case WS_READ_OPTIONAL_POINTER:
5825 case WS_READ_NILLABLE_POINTER:
5826 size = sizeof(void *);
5827 break;
5829 case WS_READ_REQUIRED_VALUE:
5830 case WS_READ_NILLABLE_VALUE:
5831 size = get_type_size( desc->type, desc->typeDescription );
5832 break;
5834 default:
5835 WARN( "unhandled option %u\n", option );
5836 return 0;
5839 return size;
5842 static HRESULT read_param( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, void *ret )
5844 if (!ret && !(ret = ws_alloc_zero( heap, get_field_size(desc) ))) return WS_E_QUOTA_EXCEEDED;
5845 return read_type_struct_field( reader, desc, heap, ret, 0 );
5848 static HRESULT read_param_array( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap,
5849 void **ret, ULONG *count )
5851 if (!ret && !(ret = ws_alloc_zero( heap, sizeof(void **) ))) return WS_E_QUOTA_EXCEEDED;
5852 return read_type_repeating_element( reader, desc, heap, ret, count );
5855 static void set_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, ULONG len,
5856 const void **args )
5858 ULONG i, *ptr;
5859 for (i = 0; i < count; i++)
5861 if (params[i].outputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
5862 continue;
5863 if ((ptr = *(ULONG **)args[i])) *ptr = len;
5864 break;
5868 HRESULT read_output_params( WS_XML_READER *handle, WS_HEAP *heap, const WS_ELEMENT_DESCRIPTION *desc,
5869 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
5871 struct reader *reader = (struct reader *)handle;
5872 const WS_STRUCT_DESCRIPTION *desc_struct;
5873 const WS_FIELD_DESCRIPTION *desc_field;
5874 ULONG i, len;
5875 HRESULT hr;
5877 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
5879 EnterCriticalSection( &reader->cs );
5881 if (reader->magic != READER_MAGIC)
5883 LeaveCriticalSection( &reader->cs );
5884 return E_INVALIDARG;
5887 if ((hr = start_mapping( reader, WS_ELEMENT_TYPE_MAPPING, desc->elementLocalName, desc->elementNs )) != S_OK)
5888 goto done;
5890 for (i = 0; i < count; i++)
5892 if (params[i].outputMessageIndex == INVALID_PARAMETER_INDEX) continue;
5893 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
5895 FIXME( "messages type not supported\n" );
5896 hr = E_NOTIMPL;
5897 goto done;
5899 if ((hr = get_param_desc( desc_struct, params[i].outputMessageIndex, &desc_field )) != S_OK) goto done;
5900 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
5902 void *ptr = *(void **)args[i];
5903 if ((hr = read_param( reader, desc_field, heap, ptr )) != S_OK) goto done;
5905 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
5907 void **ptr = *(void ***)args[i];
5908 if ((hr = read_param_array( reader, desc_field, heap, ptr, &len )) != S_OK) goto done;
5909 set_array_len( params, count, params[i].outputMessageIndex, len, args );
5913 if (desc_struct->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
5915 struct node *parent = find_parent( reader );
5916 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
5919 hr = end_mapping( reader, WS_ELEMENT_TYPE_MAPPING );
5921 done:
5922 LeaveCriticalSection( &reader->cs );
5923 return hr;