webservices: Explicitly pass the offset to read_type_struct_field.
[wine.git] / dlls / webservices / reader.c
blob999479824a3946decc5a4243ef13bb79e21d4529
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 const struct prop_desc error_props[] =
75 { sizeof(ULONG), TRUE }, /* WS_ERROR_PROPERTY_STRING_COUNT */
76 { sizeof(ULONG), FALSE }, /* WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE */
77 { sizeof(LANGID), FALSE } /* WS_ERROR_PROPERTY_LANGID */
80 struct error
82 ULONG prop_count;
83 struct prop prop[sizeof(error_props)/sizeof(error_props[0])];
86 static struct error *alloc_error(void)
88 static const ULONG count = sizeof(error_props)/sizeof(error_props[0]);
89 struct error *ret;
90 ULONG size = sizeof(*ret) + prop_size( error_props, count );
92 if (!(ret = heap_alloc_zero( size ))) return NULL;
93 prop_init( error_props, count, ret->prop, &ret[1] );
94 ret->prop_count = count;
95 return ret;
98 /**************************************************************************
99 * WsCreateError [webservices.@]
101 HRESULT WINAPI WsCreateError( const WS_ERROR_PROPERTY *properties, ULONG count, WS_ERROR **handle )
103 struct error *error;
104 LANGID langid = GetUserDefaultUILanguage();
105 HRESULT hr;
106 ULONG i;
108 TRACE( "%p %u %p\n", properties, count, handle );
110 if (!handle) return E_INVALIDARG;
111 if (!(error = alloc_error())) return E_OUTOFMEMORY;
113 prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_LANGID, &langid, sizeof(langid) );
114 for (i = 0; i < count; i++)
116 if (properties[i].id == WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE)
118 heap_free( error );
119 return E_INVALIDARG;
121 hr = prop_set( error->prop, error->prop_count, properties[i].id, properties[i].value,
122 properties[i].valueSize );
123 if (hr != S_OK)
125 heap_free( error );
126 return hr;
130 *handle = (WS_ERROR *)error;
131 return S_OK;
134 /**************************************************************************
135 * WsFreeError [webservices.@]
137 void WINAPI WsFreeError( WS_ERROR *handle )
139 struct error *error = (struct error *)handle;
141 TRACE( "%p\n", handle );
142 heap_free( error );
145 /**************************************************************************
146 * WsResetError [webservices.@]
148 HRESULT WINAPI WsResetError( WS_ERROR *handle )
150 struct error *error = (struct error *)handle;
151 ULONG code;
153 TRACE( "%p\n", handle );
155 if (!handle) return E_INVALIDARG;
157 /* FIXME: release strings added with WsAddErrorString when it's implemented, reset string count */
158 code = 0;
159 return prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE, &code, sizeof(code) );
162 static const struct prop_desc heap_props[] =
164 { sizeof(SIZE_T), FALSE }, /* WS_HEAP_PROPERTY_MAX_SIZE */
165 { sizeof(SIZE_T), FALSE }, /* WS_HEAP_PROPERTY_TRIM_SIZE */
166 { sizeof(SIZE_T), TRUE }, /* WS_HEAP_PROPERTY_REQUESTED_SIZE */
167 { sizeof(SIZE_T), TRUE } /* WS_HEAP_PROPERTY_ACTUAL_SIZE */
170 struct heap
172 HANDLE handle;
173 ULONG prop_count;
174 struct prop prop[sizeof(heap_props)/sizeof(heap_props[0])];
177 static BOOL ensure_heap( struct heap *heap )
179 SIZE_T size;
180 if (heap->handle) return TRUE;
181 if (prop_get( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_MAX_SIZE, &size, sizeof(size) ) != S_OK)
182 return FALSE;
183 if (!(heap->handle = HeapCreate( 0, 0, size ))) return FALSE;
184 return TRUE;
187 void *ws_alloc( WS_HEAP *handle, SIZE_T size )
189 struct heap *heap = (struct heap *)handle;
190 if (!ensure_heap( heap )) return NULL;
191 return HeapAlloc( heap->handle, 0, size );
194 static void *ws_alloc_zero( WS_HEAP *handle, SIZE_T size )
196 struct heap *heap = (struct heap *)handle;
197 if (!ensure_heap( heap )) return NULL;
198 return HeapAlloc( heap->handle, HEAP_ZERO_MEMORY, size );
201 void *ws_realloc( WS_HEAP *handle, void *ptr, SIZE_T size )
203 struct heap *heap = (struct heap *)handle;
204 if (!ensure_heap( heap )) return NULL;
205 return HeapReAlloc( heap->handle, 0, ptr, size );
208 static void *ws_realloc_zero( WS_HEAP *handle, void *ptr, SIZE_T size )
210 struct heap *heap = (struct heap *)handle;
211 if (!ensure_heap( heap )) return NULL;
212 return HeapReAlloc( heap->handle, HEAP_ZERO_MEMORY, ptr, size );
215 void ws_free( WS_HEAP *handle, void *ptr )
217 struct heap *heap = (struct heap *)handle;
218 if (!heap->handle) return;
219 HeapFree( heap->handle, 0, ptr );
222 /**************************************************************************
223 * WsAlloc [webservices.@]
225 HRESULT WINAPI WsAlloc( WS_HEAP *handle, SIZE_T size, void **ptr, WS_ERROR *error )
227 void *mem;
229 TRACE( "%p %u %p %p\n", handle, (ULONG)size, ptr, error );
230 if (error) FIXME( "ignoring error parameter\n" );
232 if (!handle || !ptr) return E_INVALIDARG;
234 if (!(mem = ws_alloc( handle, size ))) return E_OUTOFMEMORY;
235 *ptr = mem;
236 return S_OK;
239 static struct heap *alloc_heap(void)
241 static const ULONG count = sizeof(heap_props)/sizeof(heap_props[0]);
242 struct heap *ret;
243 ULONG size = sizeof(*ret) + prop_size( heap_props, count );
245 if (!(ret = heap_alloc_zero( size ))) return NULL;
246 prop_init( heap_props, count, ret->prop, &ret[1] );
247 ret->prop_count = count;
248 return ret;
251 /**************************************************************************
252 * WsCreateHeap [webservices.@]
254 HRESULT WINAPI WsCreateHeap( SIZE_T max_size, SIZE_T trim_size, const WS_HEAP_PROPERTY *properties,
255 ULONG count, WS_HEAP **handle, WS_ERROR *error )
257 struct heap *heap;
259 TRACE( "%u %u %p %u %p %p\n", (ULONG)max_size, (ULONG)trim_size, properties, count, handle, error );
260 if (error) FIXME( "ignoring error parameter\n" );
262 if (!handle || count) return E_INVALIDARG;
263 if (!(heap = alloc_heap())) return E_OUTOFMEMORY;
265 prop_set( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_MAX_SIZE, &max_size, sizeof(max_size) );
266 prop_set( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_TRIM_SIZE, &trim_size, sizeof(trim_size) );
268 *handle = (WS_HEAP *)heap;
269 return S_OK;
272 /**************************************************************************
273 * WsFreeHeap [webservices.@]
275 void WINAPI WsFreeHeap( WS_HEAP *handle )
277 struct heap *heap = (struct heap *)handle;
279 TRACE( "%p\n", handle );
281 if (!heap) return;
282 HeapDestroy( heap->handle );
283 heap_free( heap );
286 /**************************************************************************
287 * WsResetHeap [webservices.@]
289 HRESULT WINAPI WsResetHeap( WS_HEAP *handle, WS_ERROR *error )
291 struct heap *heap = (struct heap *)handle;
293 TRACE( "%p %p\n", handle, error );
294 if (error) FIXME( "ignoring error parameter\n" );
296 if (!heap) return E_INVALIDARG;
298 HeapDestroy( heap->handle );
299 heap->handle = NULL;
300 return S_OK;
303 struct node *alloc_node( WS_XML_NODE_TYPE type )
305 struct node *ret;
307 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
308 ret->hdr.node.nodeType = type;
309 list_init( &ret->entry );
310 list_init( &ret->children );
311 return ret;
314 void free_attribute( WS_XML_ATTRIBUTE *attr )
316 if (!attr) return;
317 heap_free( attr->prefix );
318 heap_free( attr->localName );
319 heap_free( attr->ns );
320 heap_free( attr->value );
321 heap_free( attr );
324 void free_node( struct node *node )
326 if (!node) return;
327 switch (node_type( node ))
329 case WS_XML_NODE_TYPE_ELEMENT:
331 WS_XML_ELEMENT_NODE *elem = &node->hdr;
332 ULONG i;
334 for (i = 0; i < elem->attributeCount; i++) free_attribute( elem->attributes[i] );
335 heap_free( elem->attributes );
336 heap_free( elem->prefix );
337 heap_free( elem->localName );
338 heap_free( elem->ns );
339 break;
341 case WS_XML_NODE_TYPE_TEXT:
343 WS_XML_TEXT_NODE *text = (WS_XML_TEXT_NODE *)node;
344 heap_free( text->text );
345 break;
347 case WS_XML_NODE_TYPE_COMMENT:
349 WS_XML_COMMENT_NODE *comment = (WS_XML_COMMENT_NODE *)node;
350 heap_free( comment->value.bytes );
351 break;
353 case WS_XML_NODE_TYPE_CDATA:
354 case WS_XML_NODE_TYPE_END_CDATA:
355 case WS_XML_NODE_TYPE_END_ELEMENT:
356 case WS_XML_NODE_TYPE_EOF:
357 case WS_XML_NODE_TYPE_BOF:
358 break;
360 default:
361 ERR( "unhandled type %u\n", node_type( node ) );
362 break;
364 heap_free( node );
367 void destroy_nodes( struct node *node )
369 struct list *ptr;
371 if (!node) return;
372 while ((ptr = list_head( &node->children )))
374 struct node *child = LIST_ENTRY( ptr, struct node, entry );
375 list_remove( &child->entry );
376 destroy_nodes( child );
378 free_node( node );
381 static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
383 WS_XML_ATTRIBUTE *dst;
384 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
385 const WS_XML_STRING *localname = src->localName;
386 const WS_XML_STRING *ns = src->localName;
388 if (!(dst = heap_alloc( sizeof(*dst) ))) return NULL;
389 dst->singleQuote = src->singleQuote;
390 dst->isXmlNs = src->isXmlNs;
391 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
392 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
393 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
394 return dst;
396 error:
397 free_attribute( dst );
398 return NULL;
401 static WS_XML_ATTRIBUTE **dup_attributes( WS_XML_ATTRIBUTE * const *src, ULONG count )
403 WS_XML_ATTRIBUTE **dst;
404 ULONG i;
406 if (!(dst = heap_alloc( sizeof(*dst) * count ))) return NULL;
407 for (i = 0; i < count; i++)
409 if (!(dst[i] = dup_attribute( src[i] )))
411 for (; i > 0; i--) free_attribute( dst[i - 1] );
412 heap_free( dst );
413 return NULL;
416 return dst;
419 static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
421 struct node *node;
422 WS_XML_ELEMENT_NODE *dst;
423 ULONG count = src->attributeCount;
424 WS_XML_ATTRIBUTE **attrs = src->attributes;
425 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
426 const WS_XML_STRING *localname = src->localName;
427 const WS_XML_STRING *ns = src->ns;
429 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
430 dst = &node->hdr;
432 if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
433 dst->attributeCount = count;
435 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
436 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
437 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
438 return node;
440 error:
441 free_node( node );
442 return NULL;
445 static struct node *dup_text_node( const WS_XML_TEXT_NODE *src )
447 struct node *node;
448 WS_XML_TEXT_NODE *dst;
450 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
451 dst = (WS_XML_TEXT_NODE *)node;
453 if (src->text)
455 WS_XML_UTF8_TEXT *utf8;
456 const WS_XML_UTF8_TEXT *utf8_src = (WS_XML_UTF8_TEXT *)src->text;
457 if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length )))
459 free_node( node );
460 return NULL;
462 dst->text = &utf8->text;
464 return node;
467 static struct node *dup_comment_node( const WS_XML_COMMENT_NODE *src )
469 struct node *node;
470 WS_XML_COMMENT_NODE *dst;
472 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return NULL;
473 dst = (WS_XML_COMMENT_NODE *)node;
475 if (src->value.length && !(dst->value.bytes = heap_alloc( src->value.length )))
477 free_node( node );
478 return NULL;
480 memcpy( dst->value.bytes, src->value.bytes, src->value.length );
481 dst->value.length = src->value.length;
482 return node;
485 static struct node *dup_node( const struct node *src )
487 switch (node_type( src ))
489 case WS_XML_NODE_TYPE_ELEMENT:
490 return dup_element_node( &src->hdr );
492 case WS_XML_NODE_TYPE_TEXT:
493 return dup_text_node( (const WS_XML_TEXT_NODE *)src );
495 case WS_XML_NODE_TYPE_COMMENT:
496 return dup_comment_node( (const WS_XML_COMMENT_NODE *)src );
498 case WS_XML_NODE_TYPE_CDATA:
499 case WS_XML_NODE_TYPE_END_CDATA:
500 case WS_XML_NODE_TYPE_END_ELEMENT:
501 case WS_XML_NODE_TYPE_EOF:
502 case WS_XML_NODE_TYPE_BOF:
503 return alloc_node( node_type( src ) );
505 default:
506 ERR( "unhandled type %u\n", node_type( src ) );
507 break;
509 return NULL;
512 static HRESULT dup_tree( struct node **dst, const struct node *src )
514 struct node *parent;
515 const struct node *child;
517 if (!*dst && !(*dst = dup_node( src ))) return E_OUTOFMEMORY;
518 parent = *dst;
520 LIST_FOR_EACH_ENTRY( child, &src->children, struct node, entry )
522 HRESULT hr = E_OUTOFMEMORY;
523 struct node *new_child;
525 if (!(new_child = dup_node( child )) || (hr = dup_tree( &new_child, child )) != S_OK)
527 destroy_nodes( *dst );
528 return hr;
530 new_child->parent = parent;
531 list_add_tail( &parent->children, &new_child->entry );
533 return S_OK;
536 static const struct prop_desc reader_props[] =
538 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_DEPTH */
539 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_FRAGMENT */
540 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
541 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_READ_DECLARATION */
542 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_READER_PROPERTY_CHARSET */
543 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_ROW */
544 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_COLUMN */
545 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_UTF8_TRIM_SIZE */
546 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_BUFFER_SIZE */
547 { sizeof(BOOL), TRUE }, /* WS_XML_READER_PROPERTY_IN_ATTRIBUTE */
548 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_ROOT_MIME_PART_SIZE */
549 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_MIME_HEADERS_SIZE */
550 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_MIME_PARTS */
551 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
552 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_NAMESPACES */
555 enum reader_state
557 READER_STATE_INITIAL,
558 READER_STATE_BOF,
559 READER_STATE_STARTELEMENT,
560 READER_STATE_STARTATTRIBUTE,
561 READER_STATE_STARTCDATA,
562 READER_STATE_CDATA,
563 READER_STATE_TEXT,
564 READER_STATE_ENDELEMENT,
565 READER_STATE_ENDCDATA,
566 READER_STATE_COMMENT,
567 READER_STATE_EOF
570 struct prefix
572 WS_XML_STRING str;
573 WS_XML_STRING ns;
576 struct reader
578 ULONG read_size;
579 ULONG read_pos;
580 const unsigned char *read_bufptr;
581 enum reader_state state;
582 struct node *root;
583 struct node *current;
584 ULONG current_attr;
585 struct node *last;
586 struct prefix *prefixes;
587 ULONG nb_prefixes;
588 ULONG nb_prefixes_allocated;
589 WS_XML_READER_INPUT_TYPE input_type;
590 struct xmlbuf *input_buf;
591 const unsigned char *input_data;
592 ULONG input_size;
593 ULONG text_conv_offset;
594 ULONG prop_count;
595 struct prop prop[sizeof(reader_props)/sizeof(reader_props[0])];
598 static struct reader *alloc_reader(void)
600 static const ULONG count = sizeof(reader_props)/sizeof(reader_props[0]);
601 struct reader *ret;
602 ULONG size = sizeof(*ret) + prop_size( reader_props, count );
604 if (!(ret = heap_alloc_zero( size ))) return NULL;
605 if (!(ret->prefixes = heap_alloc_zero( sizeof(*ret->prefixes) )))
607 heap_free( ret );
608 return NULL;
610 ret->nb_prefixes = ret->nb_prefixes_allocated = 1;
612 prop_init( reader_props, count, ret->prop, &ret[1] );
613 ret->prop_count = count;
614 return ret;
617 static void clear_prefixes( struct prefix *prefixes, ULONG count )
619 ULONG i;
620 for (i = 0; i < count; i++)
622 heap_free( prefixes[i].str.bytes );
623 prefixes[i].str.bytes = NULL;
624 prefixes[i].str.length = 0;
626 heap_free( prefixes[i].ns.bytes );
627 prefixes[i].ns.bytes = NULL;
628 prefixes[i].ns.length = 0;
632 static void free_reader( struct reader *reader )
634 if (!reader) return;
635 destroy_nodes( reader->root );
636 clear_prefixes( reader->prefixes, reader->nb_prefixes );
637 heap_free( reader->prefixes );
638 heap_free( reader );
641 HRESULT copy_node( WS_XML_READER *handle, struct node **node )
643 struct reader *reader = (struct reader *)handle;
644 return dup_tree( node, reader->current );
647 static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
649 if (str)
651 heap_free( prefix->str.bytes );
652 if (!(prefix->str.bytes = heap_alloc( str->length ))) return E_OUTOFMEMORY;
653 memcpy( prefix->str.bytes, str->bytes, str->length );
654 prefix->str.length = str->length;
657 heap_free( prefix->ns.bytes );
658 if (!(prefix->ns.bytes = heap_alloc( ns->length ))) return E_OUTOFMEMORY;
659 memcpy( prefix->ns.bytes, ns->bytes, ns->length );
660 prefix->ns.length = ns->length;
662 return S_OK;
665 static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING *ns )
667 ULONG i;
668 HRESULT hr;
670 for (i = 0; i < reader->nb_prefixes; i++)
672 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
673 return set_prefix( &reader->prefixes[i], NULL, ns );
675 if (i >= reader->nb_prefixes_allocated)
677 ULONG new_size = reader->nb_prefixes_allocated * sizeof(*reader->prefixes) * 2;
678 struct prefix *tmp = heap_realloc_zero( reader->prefixes, new_size );
679 if (!tmp) return E_OUTOFMEMORY;
680 reader->prefixes = tmp;
681 reader->nb_prefixes_allocated *= 2;
684 if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr;
685 reader->nb_prefixes++;
686 return S_OK;
689 static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_STRING *prefix )
691 ULONG i;
692 for (i = 0; i < reader->nb_prefixes; i++)
694 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
695 return &reader->prefixes[i].ns;
697 return NULL;
700 static void read_insert_eof( struct reader *reader, struct node *eof )
702 if (!reader->root) reader->root = eof;
703 else
705 eof->parent = reader->root;
706 list_add_tail( &reader->root->children, &eof->entry );
708 reader->current = reader->last = eof;
711 static void read_insert_bof( struct reader *reader, struct node *bof )
713 reader->root->parent = bof;
714 list_add_tail( &bof->children, &reader->root->entry );
715 reader->current = reader->last = reader->root = bof;
718 static void read_insert_node( struct reader *reader, struct node *parent, struct node *node )
720 node->parent = parent;
721 list_add_before( list_tail( &parent->children ), &node->entry );
722 reader->current = reader->last = node;
725 static HRESULT read_init_state( struct reader *reader )
727 struct node *node;
729 destroy_nodes( reader->root );
730 reader->root = NULL;
731 reader->input_buf = NULL;
732 clear_prefixes( reader->prefixes, reader->nb_prefixes );
733 reader->nb_prefixes = 1;
734 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
735 read_insert_eof( reader, node );
736 reader->state = READER_STATE_INITIAL;
737 return S_OK;
740 /**************************************************************************
741 * WsCreateReader [webservices.@]
743 HRESULT WINAPI WsCreateReader( const WS_XML_READER_PROPERTY *properties, ULONG count,
744 WS_XML_READER **handle, WS_ERROR *error )
746 struct reader *reader;
747 ULONG i, max_depth = 32, max_attrs = 128, max_ns = 32;
748 WS_CHARSET charset = WS_CHARSET_UTF8;
749 BOOL read_decl = TRUE;
750 HRESULT hr;
752 TRACE( "%p %u %p %p\n", properties, count, handle, error );
753 if (error) FIXME( "ignoring error parameter\n" );
755 if (!handle) return E_INVALIDARG;
756 if (!(reader = alloc_reader())) return E_OUTOFMEMORY;
758 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
759 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
760 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_READ_DECLARATION, &read_decl, sizeof(read_decl) );
761 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset, sizeof(charset) );
762 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
764 for (i = 0; i < count; i++)
766 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
767 properties[i].valueSize );
768 if (hr != S_OK)
770 free_reader( reader );
771 return hr;
775 if ((hr = read_init_state( reader )) != S_OK)
777 free_reader( reader );
778 return hr;
781 *handle = (WS_XML_READER *)reader;
782 return S_OK;
785 /**************************************************************************
786 * WsFreeReader [webservices.@]
788 void WINAPI WsFreeReader( WS_XML_READER *handle )
790 struct reader *reader = (struct reader *)handle;
792 TRACE( "%p\n", handle );
793 free_reader( reader );
796 /**************************************************************************
797 * WsFillReader [webservices.@]
799 HRESULT WINAPI WsFillReader( WS_XML_READER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
800 WS_ERROR *error )
802 struct reader *reader = (struct reader *)handle;
804 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
805 if (error) FIXME( "ignoring error parameter\n" );
807 if (!reader) return E_INVALIDARG;
809 /* FIXME: add support for stream input */
810 reader->read_size = min( min_size, reader->input_size );
811 reader->read_pos = 0;
813 return S_OK;
816 /**************************************************************************
817 * WsGetErrorProperty [webservices.@]
819 HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, void *buf,
820 ULONG size )
822 struct error *error = (struct error *)handle;
824 TRACE( "%p %u %p %u\n", handle, id, buf, size );
825 return prop_get( error->prop, error->prop_count, id, buf, size );
828 /**************************************************************************
829 * WsGetErrorString [webservices.@]
831 HRESULT WINAPI WsGetErrorString( WS_ERROR *handle, ULONG index, WS_STRING *str )
833 FIXME( "%p %u %p: stub\n", handle, index, str );
834 return E_NOTIMPL;
837 /**************************************************************************
838 * WsGetHeapProperty [webservices.@]
840 HRESULT WINAPI WsGetHeapProperty( WS_HEAP *handle, WS_HEAP_PROPERTY_ID id, void *buf,
841 ULONG size, WS_ERROR *error )
843 struct heap *heap = (struct heap *)handle;
845 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
846 if (error) FIXME( "ignoring error parameter\n" );
848 return prop_get( heap->prop, heap->prop_count, id, buf, size );
851 /**************************************************************************
852 * WsGetNamespaceFromPrefix [webservices.@]
854 HRESULT WINAPI WsGetNamespaceFromPrefix( WS_XML_READER *handle, const WS_XML_STRING *prefix,
855 BOOL required, const WS_XML_STRING **ns, WS_ERROR *error )
857 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
858 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
859 static const WS_XML_STRING empty_ns = {0, NULL};
860 static const WS_XML_STRING xml_ns = {36, (BYTE *)"http://www.w3.org/XML/1998/namespace"};
861 static const WS_XML_STRING xmlns_ns = {29, (BYTE *)"http://www.w3.org/2000/xmlns/"};
862 struct reader *reader = (struct reader *)handle;
863 BOOL found = FALSE;
865 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(prefix), required, ns, error );
866 if (error) FIXME( "ignoring error parameter\n" );
868 if (!reader || !prefix || !ns) return E_INVALIDARG;
869 if (reader->state != READER_STATE_STARTELEMENT) return WS_E_INVALID_OPERATION;
871 if (!prefix->length)
873 *ns = &empty_ns;
874 found = TRUE;
876 else if (WsXmlStringEquals( prefix, &xml, NULL ) == S_OK)
878 *ns = &xml_ns;
879 found = TRUE;
881 else if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
883 *ns = &xmlns_ns;
884 found = TRUE;
886 else
888 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
889 ULONG i;
891 for (i = 0; i < elem->attributeCount; i++)
893 if (!elem->attributes[i]->isXmlNs) continue;
894 if (WsXmlStringEquals( prefix, elem->attributes[i]->prefix, NULL ) == S_OK)
896 *ns = elem->attributes[i]->ns;
897 found = TRUE;
898 break;
903 if (!found)
905 if (required) return WS_E_INVALID_FORMAT;
906 *ns = NULL;
907 return S_FALSE;
909 return S_OK;
912 /**************************************************************************
913 * WsGetReaderNode [webservices.@]
915 HRESULT WINAPI WsGetReaderNode( WS_XML_READER *handle, const WS_XML_NODE **node,
916 WS_ERROR *error )
918 struct reader *reader = (struct reader *)handle;
920 TRACE( "%p %p %p\n", handle, node, error );
921 if (error) FIXME( "ignoring error parameter\n" );
923 if (!reader || !node) return E_INVALIDARG;
925 *node = &reader->current->hdr.node;
926 return S_OK;
929 /**************************************************************************
930 * WsGetReaderProperty [webservices.@]
932 HRESULT WINAPI WsGetReaderProperty( WS_XML_READER *handle, WS_XML_READER_PROPERTY_ID id,
933 void *buf, ULONG size, WS_ERROR *error )
935 struct reader *reader = (struct reader *)handle;
937 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
938 if (error) FIXME( "ignoring error parameter\n" );
940 if (!reader->input_type) return WS_E_INVALID_OPERATION;
942 if (id == WS_XML_READER_PROPERTY_CHARSET)
944 WS_CHARSET charset;
945 HRESULT hr;
947 if ((hr = prop_get( reader->prop, reader->prop_count, id, &charset, size )) != S_OK) return hr;
948 if (!charset) return WS_E_INVALID_FORMAT;
949 *(WS_CHARSET *)buf = charset;
950 return S_OK;
952 return prop_get( reader->prop, reader->prop_count, id, buf, size );
955 /**************************************************************************
956 * WsGetXmlAttribute [webservices.@]
958 HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *attr,
959 WS_HEAP *heap, WCHAR **str, ULONG *len, WS_ERROR *error )
961 FIXME( "%p %s %p %p %p %p: stub\n", handle, debugstr_xmlstr(attr), heap, str, len, error );
962 return E_NOTIMPL;
965 WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len )
967 WS_XML_STRING *ret;
969 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
970 ret->length = len;
971 ret->bytes = len ? (BYTE *)(ret + 1) : NULL;
972 ret->dictionary = NULL;
973 ret->id = 0;
974 if (data) memcpy( ret->bytes, data, len );
975 return ret;
978 WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len )
980 WS_XML_UTF8_TEXT *ret;
982 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
983 ret->text.textType = WS_XML_TEXT_TYPE_UTF8;
984 ret->value.length = len;
985 ret->value.bytes = len ? (BYTE *)(ret + 1) : NULL;
986 ret->value.dictionary = NULL;
987 ret->value.id = 0;
988 if (data) memcpy( ret->value.bytes, data, len );
989 return ret;
992 static inline BOOL read_end_of_data( struct reader *reader )
994 return reader->read_pos >= reader->read_size;
997 static inline const unsigned char *read_current_ptr( struct reader *reader )
999 return &reader->read_bufptr[reader->read_pos];
1002 /* UTF-8 support based on libs/wine/utf8.c */
1004 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
1005 static const char utf8_length[128] =
1007 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
1008 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
1009 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
1010 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
1011 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
1012 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
1013 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
1014 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
1017 /* first byte mask depending on UTF-8 sequence length */
1018 static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
1020 /* minimum Unicode value depending on UTF-8 sequence length */
1021 static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
1023 static inline unsigned int read_utf8_char( struct reader *reader, unsigned int *skip )
1025 unsigned int len, res;
1026 unsigned char ch = reader->read_bufptr[reader->read_pos];
1027 const unsigned char *end;
1029 if (reader->read_pos >= reader->read_size) return 0;
1031 if (ch < 0x80)
1033 *skip = 1;
1034 return ch;
1036 len = utf8_length[ch - 0x80];
1037 if (reader->read_pos + len >= reader->read_size) return 0;
1038 end = reader->read_bufptr + reader->read_pos + len;
1039 res = ch & utf8_mask[len];
1041 switch (len)
1043 case 3:
1044 if ((ch = end[-3] ^ 0x80) >= 0x40) break;
1045 res = (res << 6) | ch;
1046 case 2:
1047 if ((ch = end[-2] ^ 0x80) >= 0x40) break;
1048 res = (res << 6) | ch;
1049 case 1:
1050 if ((ch = end[-1] ^ 0x80) >= 0x40) break;
1051 res = (res << 6) | ch;
1052 if (res < utf8_minval[len]) break;
1053 *skip = len + 1;
1054 return res;
1057 return 0;
1060 static inline void read_skip( struct reader *reader, unsigned int count )
1062 if (reader->read_pos + count > reader->read_size) return;
1063 reader->read_pos += count;
1066 static inline void read_rewind( struct reader *reader, unsigned int count )
1068 reader->read_pos -= count;
1071 static inline BOOL read_isnamechar( unsigned int ch )
1073 /* FIXME: incomplete */
1074 return (ch >= 'A' && ch <= 'Z') ||
1075 (ch >= 'a' && ch <= 'z') ||
1076 (ch >= '0' && ch <= '9') ||
1077 ch == '_' || ch == '-' || ch == '.' || ch == ':';
1080 static inline BOOL read_isspace( unsigned int ch )
1082 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
1085 static inline void read_skip_whitespace( struct reader *reader )
1087 while (reader->read_pos < reader->read_size && read_isspace( reader->read_bufptr[reader->read_pos] ))
1088 reader->read_pos++;
1091 static inline int read_cmp( struct reader *reader, const char *str, int len )
1093 const unsigned char *ptr = read_current_ptr( reader );
1095 if (len < 0) len = strlen( str );
1096 if (reader->read_pos + len > reader->read_size) return -1;
1097 while (len--)
1099 if (*str != *ptr) return *ptr - *str;
1100 str++; ptr++;
1102 return 0;
1105 static HRESULT read_xmldecl( struct reader *reader )
1107 if (!reader->read_size) return WS_E_INVALID_FORMAT;
1109 if (read_cmp( reader, "<", 1 ) || read_cmp( reader, "<?", 2 ))
1111 reader->state = READER_STATE_BOF;
1112 return S_OK;
1114 if (read_cmp( reader, "<?xml ", 6 )) return WS_E_INVALID_FORMAT;
1115 read_skip( reader, 6 );
1117 /* FIXME: parse attributes */
1118 while (reader->read_pos < reader->read_size && reader->read_bufptr[reader->read_pos] != '?')
1119 reader->read_pos++;
1121 if (read_cmp( reader, "?>", 2 )) return WS_E_INVALID_FORMAT;
1122 read_skip( reader, 2 );
1124 reader->state = READER_STATE_BOF;
1125 return S_OK;
1128 HRESULT append_attribute( WS_XML_ELEMENT_NODE *elem, WS_XML_ATTRIBUTE *attr )
1130 if (elem->attributeCount)
1132 WS_XML_ATTRIBUTE **tmp;
1133 if (!(tmp = heap_realloc( elem->attributes, (elem->attributeCount + 1) * sizeof(attr) )))
1134 return E_OUTOFMEMORY;
1135 elem->attributes = tmp;
1137 else if (!(elem->attributes = heap_alloc( sizeof(attr) ))) return E_OUTOFMEMORY;
1138 elem->attributes[elem->attributeCount++] = attr;
1139 return S_OK;
1142 static HRESULT parse_name( const unsigned char *str, unsigned int len,
1143 WS_XML_STRING **prefix, WS_XML_STRING **localname )
1145 const unsigned char *name_ptr = str, *prefix_ptr = NULL;
1146 unsigned int i, name_len = len, prefix_len = 0;
1148 for (i = 0; i < len; i++)
1150 if (str[i] == ':')
1152 prefix_ptr = str;
1153 prefix_len = i;
1154 name_ptr = &str[i + 1];
1155 name_len -= i + 1;
1156 break;
1159 if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY;
1160 if (!(*localname = alloc_xml_string( name_ptr, name_len )))
1162 heap_free( *prefix );
1163 return E_OUTOFMEMORY;
1165 return S_OK;
1168 static int codepoint_to_utf8( int cp, unsigned char *dst )
1170 if (!cp)
1171 return -1;
1172 if (cp < 0x80)
1174 *dst = cp;
1175 return 1;
1177 if (cp < 0x800)
1179 dst[1] = 0x80 | (cp & 0x3f);
1180 cp >>= 6;
1181 dst[0] = 0xc0 | cp;
1182 return 2;
1184 if ((cp >= 0xd800 && cp <= 0xdfff) || cp == 0xfffe || cp == 0xffff) return -1;
1185 if (cp < 0x10000)
1187 dst[2] = 0x80 | (cp & 0x3f);
1188 cp >>= 6;
1189 dst[1] = 0x80 | (cp & 0x3f);
1190 cp >>= 6;
1191 dst[0] = 0xe0 | cp;
1192 return 3;
1194 if (cp >= 0x110000) return -1;
1195 dst[3] = 0x80 | (cp & 0x3f);
1196 cp >>= 6;
1197 dst[2] = 0x80 | (cp & 0x3f);
1198 cp >>= 6;
1199 dst[1] = 0x80 | (cp & 0x3f);
1200 cp >>= 6;
1201 dst[0] = 0xf0 | cp;
1202 return 4;
1205 static HRESULT decode_text( const unsigned char *str, ULONG len, unsigned char *ret, ULONG *ret_len )
1207 const unsigned char *p = str;
1208 unsigned char *q = ret;
1210 *ret_len = 0;
1211 while (len)
1213 if (*p == '&')
1215 p++; len--;
1216 if (!len) return WS_E_INVALID_FORMAT;
1218 if (len >= 3 && !memcmp( p, "lt;", 3 ))
1220 *q++ = '<';
1221 p += 3;
1222 len -= 3;
1224 else if (len >= 3 && !memcmp( p, "gt;", 3 ))
1226 *q++ = '>';
1227 p += 3;
1228 len -= 3;
1230 else if (len >= 5 && !memcmp( p, "quot;", 5 ))
1232 *q++ = '"';
1233 p += 5;
1234 len -= 5;
1236 else if (len >= 4 && !memcmp( p, "amp;", 4 ))
1238 *q++ = '&';
1239 p += 4;
1240 len -= 4;
1242 else if (len >= 5 && !memcmp( p, "apos;", 5 ))
1244 *q++ = '\'';
1245 p += 5;
1246 len -= 5;
1248 else if (*p == '#')
1250 ULONG start, nb_digits, i;
1251 int len_utf8, cp = 0;
1253 p++; len--;
1254 if (!len) return WS_E_INVALID_FORMAT;
1255 else if (*p == 'x')
1257 p++; len--;
1259 start = len;
1260 while (len && isxdigit( *p )) { p++; len--; };
1261 if (!len) return WS_E_INVALID_FORMAT;
1263 p -= nb_digits = start - len;
1264 if (!nb_digits || nb_digits > 6 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1265 for (i = 0; i < nb_digits; i++)
1267 cp *= 16;
1268 if (*p >= '0' && *p <= '9') cp += *p - '0';
1269 else if (*p >= 'a' && *p <= 'f') cp += *p - 'a' + 10;
1270 else cp += *p - 'A' + 10;
1271 p++;
1274 else if (isdigit( *p ))
1276 while (len && *p == '0') { p++; len--; };
1277 if (!len) return WS_E_INVALID_FORMAT;
1279 start = len;
1280 while (len && isdigit( *p )) { p++; len--; };
1281 if (!len) return WS_E_INVALID_FORMAT;
1283 p -= nb_digits = start - len;
1284 if (!nb_digits || nb_digits > 7 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1285 for (i = 0; i < nb_digits; i++)
1287 cp *= 10;
1288 cp += *p - '0';
1289 p++;
1292 else return WS_E_INVALID_FORMAT;
1293 p++; len--;
1294 if ((len_utf8 = codepoint_to_utf8( cp, q )) < 0) return WS_E_INVALID_FORMAT;
1295 *ret_len += len_utf8;
1296 q += len_utf8;
1297 continue;
1299 else return WS_E_INVALID_FORMAT;
1301 else
1303 *q++ = *p++;
1304 len--;
1306 *ret_len += 1;
1308 return S_OK;
1311 static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
1313 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
1314 WS_XML_ATTRIBUTE *attr;
1315 WS_XML_UTF8_TEXT *text = NULL;
1316 unsigned int len = 0, ch, skip, quote;
1317 const unsigned char *start;
1318 WS_XML_STRING *prefix, *localname;
1319 HRESULT hr = WS_E_INVALID_FORMAT;
1321 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1323 start = read_current_ptr( reader );
1324 for (;;)
1326 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1327 if (!read_isnamechar( ch )) break;
1328 read_skip( reader, skip );
1329 len += skip;
1331 if (!len) goto error;
1333 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) goto error;
1334 hr = E_OUTOFMEMORY;
1335 if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
1337 heap_free( prefix );
1338 attr->isXmlNs = 1;
1339 if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length )))
1341 heap_free( localname );
1342 goto error;
1344 attr->localName = localname;
1346 else if (!prefix->length && WsXmlStringEquals( localname, &xmlns, NULL ) == S_OK)
1348 attr->isXmlNs = 1;
1349 attr->prefix = prefix;
1350 attr->localName = localname;
1352 else
1354 attr->prefix = prefix;
1355 attr->localName = localname;
1358 hr = WS_E_INVALID_FORMAT;
1359 read_skip_whitespace( reader );
1360 if (read_cmp( reader, "=", 1 )) goto error;
1361 read_skip( reader, 1 );
1363 read_skip_whitespace( reader );
1364 if (read_cmp( reader, "\"", 1 ) && read_cmp( reader, "'", 1 )) goto error;
1365 quote = read_utf8_char( reader, &skip );
1366 read_skip( reader, 1 );
1368 len = 0;
1369 start = read_current_ptr( reader );
1370 for (;;)
1372 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1373 if (ch == quote) break;
1374 read_skip( reader, skip );
1375 len += skip;
1377 read_skip( reader, 1 );
1379 hr = E_OUTOFMEMORY;
1380 if (attr->isXmlNs)
1382 if (!(attr->ns = alloc_xml_string( start, len ))) goto error;
1383 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1384 if (!(text = alloc_utf8_text( NULL, 0 ))) goto error;
1386 else
1388 if (!(text = alloc_utf8_text( NULL, len ))) goto error;
1389 if ((hr = decode_text( start, len, text->value.bytes, &text->value.length )) != S_OK) goto error;
1392 attr->value = &text->text;
1393 attr->singleQuote = (quote == '\'');
1395 *ret = attr;
1396 return S_OK;
1398 error:
1399 heap_free( text );
1400 free_attribute( attr );
1401 return hr;
1404 static struct node *find_parent( struct reader *reader )
1406 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT)
1408 if (is_valid_parent( reader->current->parent->parent )) return reader->current->parent->parent;
1409 return NULL;
1411 else if (is_valid_parent( reader->current )) return reader->current;
1412 else if (is_valid_parent( reader->current->parent )) return reader->current->parent;
1413 return NULL;
1416 static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1418 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
1419 const WS_XML_STRING *ns;
1420 ULONG i;
1422 if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT;
1423 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1424 if (!elem->ns->length) elem->ns->bytes = (BYTE *)(elem->ns + 1); /* quirk */
1426 for (i = 0; i < elem->attributeCount; i++)
1428 WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1429 if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue;
1430 if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT;
1431 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1433 return S_OK;
1436 static HRESULT read_element( struct reader *reader )
1438 unsigned int len = 0, ch, skip;
1439 const unsigned char *start;
1440 struct node *node = NULL, *endnode, *parent;
1441 WS_XML_ELEMENT_NODE *elem;
1442 WS_XML_ATTRIBUTE *attr = NULL;
1443 HRESULT hr = WS_E_INVALID_FORMAT;
1445 if (read_end_of_data( reader ))
1447 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1448 reader->last = reader->current;
1449 reader->state = READER_STATE_EOF;
1450 return S_OK;
1453 if (read_cmp( reader, "<", 1 )) goto error;
1454 read_skip( reader, 1 );
1455 if (!read_isnamechar( read_utf8_char( reader, &skip )))
1457 read_rewind( reader, 1 );
1458 goto error;
1461 start = read_current_ptr( reader );
1462 for (;;)
1464 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1465 if (!read_isnamechar( ch )) break;
1466 read_skip( reader, skip );
1467 len += skip;
1469 if (!len) goto error;
1471 if (!(parent = find_parent( reader ))) goto error;
1473 hr = E_OUTOFMEMORY;
1474 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) goto error;
1475 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) goto error;
1476 list_add_tail( &node->children, &endnode->entry );
1477 endnode->parent = node;
1479 elem = (WS_XML_ELEMENT_NODE *)node;
1480 if ((hr = parse_name( start, len, &elem->prefix, &elem->localName )) != S_OK) goto error;
1482 reader->current_attr = 0;
1483 for (;;)
1485 read_skip_whitespace( reader );
1486 if (!read_cmp( reader, ">", 1 ) || !read_cmp( reader, "/>", 2 )) break;
1487 if ((hr = read_attribute( reader, &attr )) != S_OK) goto error;
1488 if ((hr = append_attribute( elem, attr )) != S_OK)
1490 free_attribute( attr );
1491 goto error;
1493 reader->current_attr++;
1495 if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
1497 read_insert_node( reader, parent, node );
1498 reader->state = READER_STATE_STARTELEMENT;
1499 return S_OK;
1501 error:
1502 destroy_nodes( node );
1503 return hr;
1506 static HRESULT read_text( struct reader *reader )
1508 unsigned int len = 0, ch, skip;
1509 const unsigned char *start;
1510 struct node *node, *parent;
1511 WS_XML_TEXT_NODE *text;
1512 WS_XML_UTF8_TEXT *utf8;
1513 HRESULT hr;
1515 start = read_current_ptr( reader );
1516 for (;;)
1518 if (read_end_of_data( reader )) break;
1519 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1520 if (ch == '<') break;
1521 read_skip( reader, skip );
1522 len += skip;
1525 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1527 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1528 text = (WS_XML_TEXT_NODE *)node;
1529 if (!(utf8 = alloc_utf8_text( NULL, len )))
1531 heap_free( node );
1532 return E_OUTOFMEMORY;
1534 if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK)
1536 heap_free( utf8 );
1537 heap_free( node );
1538 return hr;
1540 text->text = &utf8->text;
1542 read_insert_node( reader, parent, node );
1543 reader->state = READER_STATE_TEXT;
1544 reader->text_conv_offset = 0;
1545 return S_OK;
1548 static HRESULT read_node( struct reader * );
1550 static HRESULT read_startelement( struct reader *reader )
1552 read_skip_whitespace( reader );
1553 if (!read_cmp( reader, "/>", 2 ))
1555 read_skip( reader, 2 );
1556 reader->current = LIST_ENTRY( list_tail( &reader->current->children ), struct node, entry );
1557 reader->last = reader->current;
1558 reader->state = READER_STATE_ENDELEMENT;
1559 return S_OK;
1561 else if (!read_cmp( reader, ">", 1 ))
1563 read_skip( reader, 1 );
1564 return read_node( reader );
1566 return WS_E_INVALID_FORMAT;
1569 static HRESULT read_to_startelement( struct reader *reader, BOOL *found )
1571 HRESULT hr;
1573 switch (reader->state)
1575 case READER_STATE_INITIAL:
1576 if ((hr = read_xmldecl( reader )) != S_OK) return hr;
1577 break;
1579 case READER_STATE_STARTELEMENT:
1580 if (found) *found = TRUE;
1581 return S_OK;
1583 default:
1584 break;
1587 read_skip_whitespace( reader );
1588 if ((hr = read_element( reader )) == S_OK && found)
1590 if (reader->state == READER_STATE_STARTELEMENT)
1591 *found = TRUE;
1592 else
1593 *found = FALSE;
1596 return hr;
1599 static int cmp_name( const unsigned char *name1, ULONG len1, const unsigned char *name2, ULONG len2 )
1601 ULONG i;
1602 if (len1 != len2) return 1;
1603 for (i = 0; i < len1; i++) { if (toupper( name1[i] ) != toupper( name2[i] )) return 1; }
1604 return 0;
1607 static struct node *read_find_startelement( struct reader *reader, const WS_XML_STRING *prefix,
1608 const WS_XML_STRING *localname )
1610 struct node *parent;
1611 const WS_XML_STRING *str;
1613 for (parent = reader->current; parent; parent = parent->parent)
1615 if (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1617 str = parent->hdr.prefix;
1618 if (cmp_name( str->bytes, str->length, prefix->bytes, prefix->length )) continue;
1619 str = parent->hdr.localName;
1620 if (cmp_name( str->bytes, str->length, localname->bytes, localname->length )) continue;
1621 return parent;
1624 return NULL;
1627 static HRESULT read_endelement( struct reader *reader )
1629 struct node *parent;
1630 unsigned int len = 0, ch, skip;
1631 const unsigned char *start;
1632 WS_XML_STRING *prefix, *localname;
1633 HRESULT hr;
1635 if (reader->state == READER_STATE_EOF) return WS_E_INVALID_FORMAT;
1637 if (read_end_of_data( reader ))
1639 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1640 reader->last = reader->current;
1641 reader->state = READER_STATE_EOF;
1642 return S_OK;
1645 if (read_cmp( reader, "</", 2 )) return WS_E_INVALID_FORMAT;
1646 read_skip( reader, 2 );
1648 start = read_current_ptr( reader );
1649 for (;;)
1651 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1652 if (ch == '>')
1654 read_skip( reader, 1 );
1655 break;
1657 if (!read_isnamechar( ch )) return WS_E_INVALID_FORMAT;
1658 read_skip( reader, skip );
1659 len += skip;
1662 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) return hr;
1663 parent = read_find_startelement( reader, prefix, localname );
1664 heap_free( prefix );
1665 heap_free( localname );
1666 if (!parent) return WS_E_INVALID_FORMAT;
1668 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
1669 reader->last = reader->current;
1670 reader->state = READER_STATE_ENDELEMENT;
1671 return S_OK;
1674 static HRESULT read_comment( struct reader *reader )
1676 unsigned int len = 0, ch, skip;
1677 const unsigned char *start;
1678 struct node *node, *parent;
1679 WS_XML_COMMENT_NODE *comment;
1681 if (read_cmp( reader, "<!--", 4 )) return WS_E_INVALID_FORMAT;
1682 read_skip( reader, 4 );
1684 start = read_current_ptr( reader );
1685 for (;;)
1687 if (!read_cmp( reader, "-->", 3 ))
1689 read_skip( reader, 3 );
1690 break;
1692 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1693 read_skip( reader, skip );
1694 len += skip;
1697 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1699 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
1700 comment = (WS_XML_COMMENT_NODE *)node;
1701 if (!(comment->value.bytes = heap_alloc( len )))
1703 heap_free( node );
1704 return E_OUTOFMEMORY;
1706 memcpy( comment->value.bytes, start, len );
1707 comment->value.length = len;
1709 read_insert_node( reader, parent, node );
1710 reader->state = READER_STATE_COMMENT;
1711 return S_OK;
1714 static HRESULT read_startcdata( struct reader *reader )
1716 struct node *node, *endnode, *parent;
1718 if (read_cmp( reader, "<![CDATA[", 9 )) return WS_E_INVALID_FORMAT;
1719 read_skip( reader, 9 );
1721 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1723 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1724 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_CDATA )))
1726 heap_free( node );
1727 return E_OUTOFMEMORY;
1729 list_add_tail( &node->children, &endnode->entry );
1730 endnode->parent = node;
1732 read_insert_node( reader, parent, node );
1733 reader->state = READER_STATE_STARTCDATA;
1734 return S_OK;
1737 static HRESULT read_cdata( struct reader *reader )
1739 unsigned int len = 0, ch, skip;
1740 const unsigned char *start;
1741 struct node *node;
1742 WS_XML_TEXT_NODE *text;
1743 WS_XML_UTF8_TEXT *utf8;
1745 start = read_current_ptr( reader );
1746 for (;;)
1748 if (!read_cmp( reader, "]]>", 3 )) break;
1749 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1750 read_skip( reader, skip );
1751 len += skip;
1754 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1755 text = (WS_XML_TEXT_NODE *)node;
1756 if (!(utf8 = alloc_utf8_text( start, len )))
1758 heap_free( node );
1759 return E_OUTOFMEMORY;
1761 text->text = &utf8->text;
1763 read_insert_node( reader, reader->current, node );
1764 reader->state = READER_STATE_CDATA;
1765 return S_OK;
1768 static HRESULT read_endcdata( struct reader *reader )
1770 struct node *parent;
1772 if (read_cmp( reader, "]]>", 3 )) return WS_E_INVALID_FORMAT;
1773 read_skip( reader, 3 );
1775 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT) parent = reader->current->parent;
1776 else parent = reader->current;
1778 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
1779 reader->last = reader->current;
1780 reader->state = READER_STATE_ENDCDATA;
1781 return S_OK;
1784 static HRESULT read_node( struct reader *reader )
1786 HRESULT hr;
1788 for (;;)
1790 if (read_end_of_data( reader ))
1792 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1793 reader->last = reader->current;
1794 reader->state = READER_STATE_EOF;
1795 return S_OK;
1797 if (reader->state == READER_STATE_STARTCDATA) return read_cdata( reader );
1798 else if (reader->state == READER_STATE_CDATA) return read_endcdata( reader );
1799 else if (!read_cmp( reader, "<?", 2 ))
1801 hr = read_xmldecl( reader );
1802 if (FAILED( hr )) return hr;
1804 else if (!read_cmp( reader, "</", 2 )) return read_endelement( reader );
1805 else if (!read_cmp( reader, "<![CDATA[", 9 )) return read_startcdata( reader );
1806 else if (!read_cmp( reader, "<!--", 4 )) return read_comment( reader );
1807 else if (!read_cmp( reader, "<", 1 )) return read_element( reader );
1808 else if (!read_cmp( reader, "/>", 2 ) || !read_cmp( reader, ">", 1 )) return read_startelement( reader );
1809 else return read_text( reader );
1813 /**************************************************************************
1814 * WsReadEndElement [webservices.@]
1816 HRESULT WINAPI WsReadEndElement( WS_XML_READER *handle, WS_ERROR *error )
1818 struct reader *reader = (struct reader *)handle;
1820 TRACE( "%p %p\n", handle, error );
1821 if (error) FIXME( "ignoring error parameter\n" );
1823 if (!reader) return E_INVALIDARG;
1824 return read_endelement( reader );
1827 /**************************************************************************
1828 * WsReadNode [webservices.@]
1830 HRESULT WINAPI WsReadNode( WS_XML_READER *handle, WS_ERROR *error )
1832 struct reader *reader = (struct reader *)handle;
1834 TRACE( "%p %p\n", handle, error );
1835 if (error) FIXME( "ignoring error parameter\n" );
1837 if (!reader) return E_INVALIDARG;
1838 return read_node( reader );
1841 /**************************************************************************
1842 * WsReadStartElement [webservices.@]
1844 HRESULT WINAPI WsReadStartElement( WS_XML_READER *handle, WS_ERROR *error )
1846 struct reader *reader = (struct reader *)handle;
1848 TRACE( "%p %p\n", handle, error );
1849 if (error) FIXME( "ignoring error parameter\n" );
1851 if (!reader) return E_INVALIDARG;
1852 return read_startelement( reader );
1855 /**************************************************************************
1856 * WsReadToStartElement [webservices.@]
1858 HRESULT WINAPI WsReadToStartElement( WS_XML_READER *handle, const WS_XML_STRING *localname,
1859 const WS_XML_STRING *ns, BOOL *found, WS_ERROR *error )
1861 struct reader *reader = (struct reader *)handle;
1863 TRACE( "%p %s %s %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns), found, error );
1864 if (error) FIXME( "ignoring error parameter\n" );
1866 if (!reader) return E_INVALIDARG;
1867 if (localname || ns) FIXME( "name and/or namespace not verified\n" );
1869 return read_to_startelement( reader, found );
1872 BOOL move_to_root_element( struct node *root, struct node **current )
1874 struct list *ptr;
1875 struct node *node;
1877 if (!(ptr = list_head( &root->children ))) return FALSE;
1878 node = LIST_ENTRY( ptr, struct node, entry );
1879 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT)
1881 *current = node;
1882 return TRUE;
1884 while ((ptr = list_next( &root->children, &node->entry )))
1886 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1887 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1889 *current = next;
1890 return TRUE;
1892 node = next;
1894 return FALSE;
1897 BOOL move_to_next_element( struct node **current )
1899 struct list *ptr;
1900 struct node *node = *current, *parent = (*current)->parent;
1902 if (!parent) return FALSE;
1903 while ((ptr = list_next( &parent->children, &node->entry )))
1905 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1906 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1908 *current = next;
1909 return TRUE;
1911 node = next;
1913 return FALSE;
1916 BOOL move_to_prev_element( struct node **current )
1918 struct list *ptr;
1919 struct node *node = *current, *parent = (*current)->parent;
1921 if (!parent) return FALSE;
1922 while ((ptr = list_prev( &parent->children, &node->entry )))
1924 struct node *prev = LIST_ENTRY( ptr, struct node, entry );
1925 if (node_type( prev ) == WS_XML_NODE_TYPE_ELEMENT)
1927 *current = prev;
1928 return TRUE;
1930 node = prev;
1932 return FALSE;
1935 BOOL move_to_child_element( struct node **current )
1937 struct list *ptr;
1938 struct node *child, *node = *current;
1940 if (!(ptr = list_head( &node->children ))) return FALSE;
1941 child = LIST_ENTRY( ptr, struct node, entry );
1942 if (node_type( child ) == WS_XML_NODE_TYPE_ELEMENT)
1944 *current = child;
1945 return TRUE;
1947 while ((ptr = list_next( &node->children, &child->entry )))
1949 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1950 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1952 *current = next;
1953 return TRUE;
1955 child = next;
1957 return FALSE;
1960 BOOL move_to_end_element( struct node **current )
1962 struct list *ptr;
1963 struct node *node = *current;
1965 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
1967 if ((ptr = list_tail( &node->children )))
1969 struct node *tail = LIST_ENTRY( ptr, struct node, entry );
1970 if (node_type( tail ) == WS_XML_NODE_TYPE_END_ELEMENT)
1972 *current = tail;
1973 return TRUE;
1976 return FALSE;
1979 BOOL move_to_parent_element( struct node **current )
1981 struct node *parent = (*current)->parent;
1983 if (parent && (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT ||
1984 node_type( parent ) == WS_XML_NODE_TYPE_BOF))
1986 *current = parent;
1987 return TRUE;
1989 return FALSE;
1992 BOOL move_to_first_node( struct node **current )
1994 struct list *ptr;
1995 struct node *node = *current;
1997 if ((ptr = list_head( &node->parent->children )))
1999 *current = LIST_ENTRY( ptr, struct node, entry );
2000 return TRUE;
2002 return FALSE;
2005 BOOL move_to_next_node( struct node **current )
2007 struct list *ptr;
2008 struct node *node = *current;
2010 if ((ptr = list_next( &node->parent->children, &node->entry )))
2012 *current = LIST_ENTRY( ptr, struct node, entry );
2013 return TRUE;
2015 return FALSE;
2018 BOOL move_to_prev_node( struct node **current )
2020 struct list *ptr;
2021 struct node *node = *current;
2023 if ((ptr = list_prev( &node->parent->children, &node->entry )))
2025 *current = LIST_ENTRY( ptr, struct node, entry );
2026 return TRUE;
2028 return FALSE;
2031 BOOL move_to_bof( struct node *root, struct node **current )
2033 *current = root;
2034 return TRUE;
2037 BOOL move_to_eof( struct node *root, struct node **current )
2039 struct list *ptr;
2040 if ((ptr = list_tail( &root->children )))
2042 *current = LIST_ENTRY( ptr, struct node, entry );
2043 return TRUE;
2045 return FALSE;
2048 BOOL move_to_child_node( struct node **current )
2050 struct list *ptr;
2051 struct node *node = *current;
2053 if ((ptr = list_head( &node->children )))
2055 *current = LIST_ENTRY( ptr, struct node, entry );
2056 return TRUE;
2058 return FALSE;
2061 BOOL move_to_parent_node( struct node **current )
2063 struct node *parent = (*current)->parent;
2064 if (!parent) return FALSE;
2065 *current = parent;
2066 return TRUE;
2069 static HRESULT read_move_to( struct reader *reader, WS_MOVE_TO move, BOOL *found )
2071 BOOL success = FALSE;
2072 HRESULT hr = S_OK;
2074 if (!read_end_of_data( reader ))
2076 while (reader->state != READER_STATE_EOF && (hr = read_node( reader )) == S_OK) { /* nothing */ };
2077 if (hr != S_OK) return hr;
2079 switch (move)
2081 case WS_MOVE_TO_ROOT_ELEMENT:
2082 success = move_to_root_element( reader->root, &reader->current );
2083 break;
2085 case WS_MOVE_TO_NEXT_ELEMENT:
2086 success = move_to_next_element( &reader->current );
2087 break;
2089 case WS_MOVE_TO_PREVIOUS_ELEMENT:
2090 success = move_to_prev_element( &reader->current );
2091 break;
2093 case WS_MOVE_TO_CHILD_ELEMENT:
2094 success = move_to_child_element( &reader->current );
2095 break;
2097 case WS_MOVE_TO_END_ELEMENT:
2098 success = move_to_end_element( &reader->current );
2099 break;
2101 case WS_MOVE_TO_PARENT_ELEMENT:
2102 success = move_to_parent_element( &reader->current );
2103 break;
2105 case WS_MOVE_TO_FIRST_NODE:
2106 success = move_to_first_node( &reader->current );
2107 break;
2109 case WS_MOVE_TO_NEXT_NODE:
2110 success = move_to_next_node( &reader->current );
2111 break;
2113 case WS_MOVE_TO_PREVIOUS_NODE:
2114 success = move_to_prev_node( &reader->current );
2115 break;
2117 case WS_MOVE_TO_CHILD_NODE:
2118 success = move_to_child_node( &reader->current );
2119 break;
2121 case WS_MOVE_TO_BOF:
2122 success = move_to_bof( reader->root, &reader->current );
2123 break;
2125 case WS_MOVE_TO_EOF:
2126 success = move_to_eof( reader->root, &reader->current );
2127 break;
2129 default:
2130 FIXME( "unhandled move %u\n", move );
2131 return E_NOTIMPL;
2134 if (found)
2136 *found = success;
2137 return S_OK;
2139 return success ? S_OK : WS_E_INVALID_FORMAT;
2142 /**************************************************************************
2143 * WsMoveReader [webservices.@]
2145 HRESULT WINAPI WsMoveReader( WS_XML_READER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2147 struct reader *reader = (struct reader *)handle;
2149 TRACE( "%p %u %p %p\n", handle, move, found, error );
2150 if (error) FIXME( "ignoring error parameter\n" );
2152 if (!reader) return E_INVALIDARG;
2153 if (!reader->input_type) return WS_E_INVALID_OPERATION;
2155 return read_move_to( reader, move, found );
2158 /**************************************************************************
2159 * WsReadStartAttribute [webservices.@]
2161 HRESULT WINAPI WsReadStartAttribute( WS_XML_READER *handle, ULONG index, WS_ERROR *error )
2163 struct reader *reader = (struct reader *)handle;
2164 WS_XML_ELEMENT_NODE *elem;
2166 TRACE( "%p %u %p\n", handle, index, error );
2167 if (error) FIXME( "ignoring error parameter\n" );
2169 if (!reader) return E_INVALIDARG;
2171 elem = &reader->current->hdr;
2172 if (reader->state != READER_STATE_STARTELEMENT || index >= elem->attributeCount)
2173 return WS_E_INVALID_FORMAT;
2175 reader->current_attr = index;
2176 reader->state = READER_STATE_STARTATTRIBUTE;
2177 return S_OK;
2180 /**************************************************************************
2181 * WsReadEndAttribute [webservices.@]
2183 HRESULT WINAPI WsReadEndAttribute( WS_XML_READER *handle, WS_ERROR *error )
2185 struct reader *reader = (struct reader *)handle;
2187 TRACE( "%p %p\n", handle, error );
2188 if (error) FIXME( "ignoring error parameter\n" );
2190 if (!reader) return E_INVALIDARG;
2192 if (reader->state != READER_STATE_STARTATTRIBUTE)
2193 return WS_E_INVALID_FORMAT;
2195 reader->state = READER_STATE_STARTELEMENT;
2196 return S_OK;
2199 static WCHAR *xmltext_to_widechar( WS_HEAP *heap, const WS_XML_TEXT *text )
2201 WCHAR *ret;
2203 switch (text->textType)
2205 case WS_XML_TEXT_TYPE_UTF8:
2207 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2208 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
2209 if (!(ret = ws_alloc( heap, (len + 1) * sizeof(WCHAR) ))) return NULL;
2210 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, ret, len );
2211 ret[len] = 0;
2212 break;
2214 default:
2215 FIXME( "unhandled type %u\n", text->textType );
2216 return NULL;
2219 return ret;
2222 #define MAX_INT8 0x7f
2223 #define MIN_INT8 (-MAX_INT8 - 1)
2224 #define MAX_INT16 0x7fff
2225 #define MIN_INT16 (-MAX_INT16 - 1)
2226 #define MAX_INT32 0x7fffffff
2227 #define MIN_INT32 (-MAX_INT32 - 1)
2228 #define MAX_INT64 (((INT64)0x7fffffff << 32) | 0xffffffff)
2229 #define MIN_INT64 (-MAX_INT64 - 1)
2230 #define MAX_UINT8 0xff
2231 #define MAX_UINT16 0xffff
2232 #define MAX_UINT32 0xffffffff
2233 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
2235 static HRESULT str_to_int64( const unsigned char *str, ULONG len, INT64 min, INT64 max, INT64 *ret )
2237 BOOL negative = FALSE;
2238 const unsigned char *ptr = str;
2240 *ret = 0;
2241 while (len && read_isspace( *ptr )) { ptr++; len--; }
2242 while (len && read_isspace( ptr[len - 1] )) { len--; }
2243 if (!len) return WS_E_INVALID_FORMAT;
2245 if (*ptr == '-')
2247 negative = TRUE;
2248 ptr++;
2249 len--;
2251 if (!len) return WS_E_INVALID_FORMAT;
2253 while (len--)
2255 int val;
2257 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2258 val = *ptr - '0';
2259 if (negative) val = -val;
2261 if ((!negative && (*ret > max / 10 || *ret * 10 > max - val)) ||
2262 (negative && (*ret < min / 10 || *ret * 10 < min - val)))
2264 return WS_E_NUMERIC_OVERFLOW;
2266 *ret = *ret * 10 + val;
2267 ptr++;
2270 return S_OK;
2273 static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, UINT64 *ret )
2275 const unsigned char *ptr = str;
2277 *ret = 0;
2278 while (len && read_isspace( *ptr )) { ptr++; len--; }
2279 while (len && read_isspace( ptr[len - 1] )) { len--; }
2280 if (!len) return WS_E_INVALID_FORMAT;
2282 while (len--)
2284 unsigned int val;
2286 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2287 val = *ptr - '0';
2289 if ((*ret > max / 10 || *ret * 10 > max - val)) return WS_E_NUMERIC_OVERFLOW;
2290 *ret = *ret * 10 + val;
2291 ptr++;
2294 return S_OK;
2297 #if defined(__i386__) || defined(__x86_64__)
2299 #define RC_DOWN 0x100;
2300 BOOL set_fp_rounding( unsigned short *save )
2302 #ifdef __GNUC__
2303 unsigned short fpword;
2305 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
2306 *save = fpword;
2307 fpword |= RC_DOWN;
2308 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2309 return TRUE;
2310 #else
2311 FIXME( "not implemented\n" );
2312 return FALSE;
2313 #endif
2315 void restore_fp_rounding( unsigned short fpword )
2317 #ifdef __GNUC__
2318 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2319 #else
2320 FIXME( "not implemented\n" );
2321 #endif
2323 #else
2324 BOOL set_fp_rounding( unsigned short *save )
2326 FIXME( "not implemented\n" );
2327 return FALSE;
2329 void restore_fp_rounding( unsigned short fpword )
2331 FIXME( "not implemented\n" );
2333 #endif
2335 static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret )
2337 static const unsigned __int64 nan = 0xfff8000000000000;
2338 static const unsigned __int64 inf = 0x7ff0000000000000;
2339 static const unsigned __int64 inf_min = 0xfff0000000000000;
2340 HRESULT hr = WS_E_INVALID_FORMAT;
2341 const unsigned char *p = str, *q;
2342 int sign = 1, exp_sign = 1, exp = 0, exp_tmp = 0, neg_exp, i, nb_digits, have_digits;
2343 unsigned __int64 val = 0, tmp;
2344 long double exp_val = 1.0, exp_mul = 10.0;
2345 unsigned short fpword;
2347 while (len && read_isspace( *p )) { p++; len--; }
2348 while (len && read_isspace( p[len - 1] )) { len--; }
2349 if (!len) return WS_E_INVALID_FORMAT;
2351 if (len == 3 && !memcmp( p, "NaN", 3 ))
2353 *(unsigned __int64 *)ret = nan;
2354 return S_OK;
2356 else if (len == 3 && !memcmp( p, "INF", 3 ))
2358 *(unsigned __int64 *)ret = inf;
2359 return S_OK;
2361 else if (len == 4 && !memcmp( p, "-INF", 4 ))
2363 *(unsigned __int64 *)ret = inf_min;
2364 return S_OK;
2367 *ret = 0.0;
2368 if (*p == '-')
2370 sign = -1;
2371 p++; len--;
2373 else if (*p == '+') { p++; len--; };
2374 if (!len) return S_OK;
2376 if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
2378 q = p;
2379 while (len && isdigit( *q )) { q++; len--; }
2380 have_digits = nb_digits = q - p;
2381 for (i = 0; i < nb_digits; i++)
2383 tmp = val * 10 + p[i] - '0';
2384 if (val > MAX_UINT64 / 10 || tmp < val)
2386 for (; i < nb_digits; i++) exp++;
2387 break;
2389 val = tmp;
2392 if (len)
2394 if (*q == '.')
2396 p = ++q; len--;
2397 while (len && isdigit( *q )) { q++; len--; };
2398 have_digits |= nb_digits = q - p;
2399 for (i = 0; i < nb_digits; i++)
2401 tmp = val * 10 + p[i] - '0';
2402 if (val > MAX_UINT64 / 10 || tmp < val) break;
2403 val = tmp;
2404 exp--;
2407 if (len > 1 && tolower(*q) == 'e')
2409 if (!have_digits) goto done;
2410 p = ++q; len--;
2411 if (*p == '-')
2413 exp_sign = -1;
2414 p++; len--;
2416 else if (*p == '+') { p++; len--; };
2418 q = p;
2419 while (len && isdigit( *q )) { q++; len--; };
2420 nb_digits = q - p;
2421 if (!nb_digits || len) goto done;
2422 for (i = 0; i < nb_digits; i++)
2424 if (exp_tmp > MAX_INT32 / 10 || (exp_tmp = exp_tmp * 10 + p[i] - '0') < 0)
2425 exp_tmp = MAX_INT32;
2427 exp_tmp *= exp_sign;
2429 if (exp < 0 && exp_tmp < 0 && exp + exp_tmp >= 0) exp = MIN_INT32;
2430 else if (exp > 0 && exp_tmp > 0 && exp + exp_tmp < 0) exp = MAX_INT32;
2431 else exp += exp_tmp;
2434 if (!have_digits || len) goto done;
2436 if ((neg_exp = exp < 0)) exp = -exp;
2437 for (; exp; exp >>= 1)
2439 if (exp & 1) exp_val *= exp_mul;
2440 exp_mul *= exp_mul;
2443 *ret = sign * (neg_exp ? val / exp_val : val * exp_val);
2444 hr = S_OK;
2446 done:
2447 restore_fp_rounding( fpword );
2448 return hr;
2451 static HRESULT str_to_guid( const unsigned char *str, ULONG len, GUID *ret )
2453 static const unsigned char hex[] =
2455 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
2456 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
2457 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
2458 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
2459 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
2460 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
2461 0,10,11,12,13,14,15 /* 0x60 */
2463 const unsigned char *p = str;
2464 ULONG i;
2466 while (len && read_isspace( *p )) { p++; len--; }
2467 while (len && read_isspace( p[len - 1] )) { len--; }
2468 if (len != 36) return WS_E_INVALID_FORMAT;
2470 if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-')
2471 return WS_E_INVALID_FORMAT;
2473 for (i = 0; i < 36; i++)
2475 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
2476 if (p[i] > 'f' || (!hex[p[i]] && p[i] != '0')) return WS_E_INVALID_FORMAT;
2479 ret->Data1 = hex[p[0]] << 28 | hex[p[1]] << 24 | hex[p[2]] << 20 | hex[p[3]] << 16 |
2480 hex[p[4]] << 12 | hex[p[5]] << 8 | hex[p[6]] << 4 | hex[p[7]];
2482 ret->Data2 = hex[p[9]] << 12 | hex[p[10]] << 8 | hex[p[11]] << 4 | hex[p[12]];
2483 ret->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[16]] << 4 | hex[p[17]];
2485 ret->Data4[0] = hex[p[19]] << 4 | hex[p[20]];
2486 ret->Data4[1] = hex[p[21]] << 4 | hex[p[22]];
2487 ret->Data4[2] = hex[p[24]] << 4 | hex[p[25]];
2488 ret->Data4[3] = hex[p[26]] << 4 | hex[p[27]];
2489 ret->Data4[4] = hex[p[28]] << 4 | hex[p[29]];
2490 ret->Data4[5] = hex[p[30]] << 4 | hex[p[31]];
2491 ret->Data4[6] = hex[p[32]] << 4 | hex[p[33]];
2492 ret->Data4[7] = hex[p[34]] << 4 | hex[p[35]];
2494 return S_OK;
2497 static inline unsigned char decode_char( unsigned char c )
2499 if (c >= 'A' && c <= 'Z') return c - 'A';
2500 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2501 if (c >= '0' && c <= '9') return c - '0' + 52;
2502 if (c == '+') return 62;
2503 if (c == '/') return 63;
2504 return 64;
2507 static ULONG decode_base64( const unsigned char *base64, ULONG len, unsigned char *buf )
2509 ULONG i = 0;
2510 unsigned char c0, c1, c2, c3;
2511 const unsigned char *p = base64;
2513 while (len > 4)
2515 if ((c0 = decode_char( p[0] )) > 63) return 0;
2516 if ((c1 = decode_char( p[1] )) > 63) return 0;
2517 if ((c2 = decode_char( p[2] )) > 63) return 0;
2518 if ((c3 = decode_char( p[3] )) > 63) return 0;
2519 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2520 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2521 buf[i + 2] = (c2 << 6) | c3;
2522 len -= 4;
2523 i += 3;
2524 p += 4;
2526 if (p[2] == '=')
2528 if ((c0 = decode_char( p[0] )) > 63) return 0;
2529 if ((c1 = decode_char( p[1] )) > 63) return 0;
2530 buf[i] = (c0 << 2) | (c1 >> 4);
2531 i++;
2533 else if (p[3] == '=')
2535 if ((c0 = decode_char( p[0] )) > 63) return 0;
2536 if ((c1 = decode_char( p[1] )) > 63) return 0;
2537 if ((c2 = decode_char( p[2] )) > 63) return 0;
2538 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2539 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2540 i += 2;
2542 else
2544 if ((c0 = decode_char( p[0] )) > 63) return 0;
2545 if ((c1 = decode_char( p[1] )) > 63) return 0;
2546 if ((c2 = decode_char( p[2] )) > 63) return 0;
2547 if ((c3 = decode_char( p[3] )) > 63) return 0;
2548 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2549 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2550 buf[i + 2] = (c2 << 6) | c3;
2551 i += 3;
2553 return i;
2556 static HRESULT str_to_bytes( const unsigned char *str, ULONG len, WS_HEAP *heap, WS_BYTES *ret )
2558 const unsigned char *p = str;
2560 while (len && read_isspace( *p )) { p++; len--; }
2561 while (len && read_isspace( p[len - 1] )) { len--; }
2563 if (len % 4) return WS_E_INVALID_FORMAT;
2564 if (!(ret->bytes = ws_alloc( heap, len * 3 / 4 ))) return WS_E_QUOTA_EXCEEDED;
2565 ret->length = decode_base64( p, len, ret->bytes );
2566 return S_OK;
2569 static const int month_offsets[2][12] =
2571 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
2572 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
2575 static inline int valid_day( int year, int month, int day )
2577 return day > 0 && day <= month_days[leap_year( year )][month - 1];
2580 static inline int leap_days_before( int year )
2582 return (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
2585 static HRESULT str_to_datetime( const unsigned char *bytes, ULONG len, WS_DATETIME *ret )
2587 const unsigned char *p = bytes, *q;
2588 int year, month, day, hour, min, sec, sec_frac = 0, tz_hour, tz_min, tz_neg;
2590 while (len && read_isspace( *p )) { p++; len--; }
2591 while (len && read_isspace( p[len - 1] )) { len--; }
2593 q = p;
2594 while (len && isdigit( *q )) { q++; len--; };
2595 if (q - p != 4 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2596 year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
2597 if (year < 1) return WS_E_INVALID_FORMAT;
2599 p = ++q; len--;
2600 while (len && isdigit( *q )) { q++; len--; };
2601 if (q - p != 2 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2602 month = (p[0] - '0') * 10 + p[1] - '0';
2603 if (month < 1 || month > 12) return WS_E_INVALID_FORMAT;
2605 p = ++q; len--;
2606 while (len && isdigit( *q )) { q++; len--; };
2607 if (q - p != 2 || !len || *q != 'T') return WS_E_INVALID_FORMAT;
2608 day = (p[0] - '0') * 10 + p[1] - '0';
2609 if (!valid_day( year, month, day )) return WS_E_INVALID_FORMAT;
2611 p = ++q; len--;
2612 while (len && isdigit( *q )) { q++; len--; };
2613 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2614 hour = (p[0] - '0') * 10 + p[1] - '0';
2615 if (hour > 24) return WS_E_INVALID_FORMAT;
2617 p = ++q; len--;
2618 while (len && isdigit( *q )) { q++; len--; };
2619 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2620 min = (p[0] - '0') * 10 + p[1] - '0';
2621 if (min > 59 || (min > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
2623 p = ++q; len--;
2624 while (len && isdigit( *q )) { q++; len--; };
2625 if (q - p != 2 || !len) return WS_E_INVALID_FORMAT;
2626 sec = (p[0] - '0') * 10 + p[1] - '0';
2627 if (sec > 59 || (sec > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
2629 if (*q == '.')
2631 unsigned int i, nb_digits, mul = TICKS_PER_SEC / 10;
2632 p = ++q; len--;
2633 while (len && isdigit( *q )) { q++; len--; };
2634 nb_digits = q - p;
2635 if (nb_digits < 1 || nb_digits > 7) return WS_E_INVALID_FORMAT;
2636 for (i = 0; i < nb_digits; i++)
2638 sec_frac += (p[i] - '0') * mul;
2639 mul /= 10;
2642 if (*q == 'Z')
2644 if (--len) return WS_E_INVALID_FORMAT;
2645 tz_hour = tz_min = tz_neg = 0;
2646 ret->format = WS_DATETIME_FORMAT_UTC;
2648 else if (*q == '+' || *q == '-')
2650 tz_neg = (*q == '-') ? 1 : 0;
2652 p = ++q; len--;
2653 while (len && isdigit( *q )) { q++; len--; };
2654 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2655 tz_hour = (p[0] - '0') * 10 + p[1] - '0';
2656 if (tz_hour > 14) return WS_E_INVALID_FORMAT;
2658 p = ++q; len--;
2659 while (len && isdigit( *q )) { q++; len--; };
2660 if (q - p != 2 || len) return WS_E_INVALID_FORMAT;
2661 tz_min = (p[0] - '0') * 10 + p[1] - '0';
2662 if (tz_min > 59 || (tz_min > 0 && tz_hour == 14)) return WS_E_INVALID_FORMAT;
2664 ret->format = WS_DATETIME_FORMAT_LOCAL;
2666 else return WS_E_INVALID_FORMAT;
2668 ret->ticks = ((year - 1) * 365 + leap_days_before( year )) * TICKS_PER_DAY;
2669 ret->ticks += month_offsets[leap_year( year )][month - 1] * TICKS_PER_DAY;
2670 ret->ticks += (day - 1) * TICKS_PER_DAY;
2671 ret->ticks += hour * TICKS_PER_HOUR;
2672 ret->ticks += min * TICKS_PER_MIN;
2673 ret->ticks += sec * TICKS_PER_SEC;
2674 ret->ticks += sec_frac;
2676 if (tz_neg)
2678 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN + ret->ticks > TICKS_MAX)
2679 return WS_E_INVALID_FORMAT;
2680 ret->ticks += tz_hour * TICKS_PER_HOUR;
2681 ret->ticks += tz_min * TICKS_PER_MIN;
2683 else
2685 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN > ret->ticks)
2686 return WS_E_INVALID_FORMAT;
2687 ret->ticks -= tz_hour * TICKS_PER_HOUR;
2688 ret->ticks -= tz_min * TICKS_PER_MIN;
2691 return S_OK;
2694 /**************************************************************************
2695 * WsDateTimeToFileTime [webservices.@]
2697 HRESULT WINAPI WsDateTimeToFileTime( const WS_DATETIME *dt, FILETIME *ft, WS_ERROR *error )
2699 unsigned __int64 ticks;
2701 TRACE( "%p %p %p\n", dt, ft, error );
2702 if (error) FIXME( "ignoring error parameter\n" );
2704 if (!dt || !ft) return E_INVALIDARG;
2706 if (dt->ticks < TICKS_1601_01_01) return WS_E_INVALID_FORMAT;
2707 ticks = dt->ticks - TICKS_1601_01_01;
2708 ft->dwHighDateTime = ticks >> 32;
2709 ft->dwLowDateTime = (DWORD)ticks;
2710 return S_OK;
2713 /**************************************************************************
2714 * WsFileTimeToDateTime [webservices.@]
2716 HRESULT WINAPI WsFileTimeToDateTime( const FILETIME *ft, WS_DATETIME *dt, WS_ERROR *error )
2718 unsigned __int64 ticks;
2720 TRACE( "%p %p %p\n", ft, dt, error );
2721 if (error) FIXME( "ignoring error parameter\n" );
2723 if (!dt || !ft) return E_INVALIDARG;
2725 ticks = ((unsigned __int64)ft->dwHighDateTime << 32) | ft->dwLowDateTime;
2726 if (ticks > MAX_UINT64 - TICKS_1601_01_01) return WS_E_NUMERIC_OVERFLOW;
2727 if (ticks + TICKS_1601_01_01 > TICKS_MAX) return WS_E_INVALID_FORMAT;
2728 dt->ticks = ticks + TICKS_1601_01_01;
2729 dt->format = WS_DATETIME_FORMAT_UTC;
2730 return S_OK;
2733 static HRESULT read_get_node_text( struct reader *reader, WS_XML_UTF8_TEXT **ret )
2735 WS_XML_TEXT_NODE *text;
2737 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT)
2738 return WS_E_INVALID_FORMAT;
2740 text = (WS_XML_TEXT_NODE *)&reader->current->hdr.node;
2741 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
2743 FIXME( "text type %u not supported\n", text->text->textType );
2744 return E_NOTIMPL;
2746 *ret = (WS_XML_UTF8_TEXT *)text->text;
2747 return S_OK;
2750 static HRESULT read_get_attribute_text( struct reader *reader, ULONG index, WS_XML_UTF8_TEXT **ret )
2752 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2753 WS_XML_ATTRIBUTE *attr;
2755 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
2756 return WS_E_INVALID_FORMAT;
2758 attr = elem->attributes[index];
2759 if (attr->value->textType != WS_XML_TEXT_TYPE_UTF8)
2761 FIXME( "text type %u not supported\n", attr->value->textType );
2762 return E_NOTIMPL;
2764 *ret = (WS_XML_UTF8_TEXT *)attr->value;
2765 return S_OK;
2768 static BOOL find_attribute( struct reader *reader, const WS_XML_STRING *localname,
2769 const WS_XML_STRING *ns, ULONG *index )
2771 ULONG i;
2772 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2774 if (!localname)
2776 *index = reader->current_attr;
2777 return TRUE;
2779 for (i = 0; i < elem->attributeCount; i++)
2781 const WS_XML_STRING *localname2 = elem->attributes[i]->localName;
2782 const WS_XML_STRING *ns2 = elem->attributes[i]->ns;
2784 if (!cmp_name( localname->bytes, localname->length, localname2->bytes, localname2->length ) &&
2785 !cmp_name( ns->bytes, ns->length, ns2->bytes, ns2->length ))
2787 *index = i;
2788 return TRUE;
2791 return FALSE;
2794 /**************************************************************************
2795 * WsFindAttribute [webservices.@]
2797 HRESULT WINAPI WsFindAttribute( WS_XML_READER *handle, const WS_XML_STRING *localname,
2798 const WS_XML_STRING *ns, BOOL required, ULONG *index,
2799 WS_ERROR *error )
2801 struct reader *reader = (struct reader *)handle;
2803 TRACE( "%p %s %s %d %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
2804 required, index, error );
2805 if (error) FIXME( "ignoring error parameter\n" );
2807 if (!reader || !localname || !ns || !index) return E_INVALIDARG;
2809 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
2810 return WS_E_INVALID_OPERATION;
2812 if (!find_attribute( reader, localname, ns, index ))
2814 if (required) return WS_E_INVALID_FORMAT;
2815 *index = ~0u;
2816 return S_FALSE;
2818 return S_OK;
2821 static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
2822 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2823 WS_XML_UTF8_TEXT **ret, BOOL *found )
2825 switch (mapping)
2827 case WS_ATTRIBUTE_TYPE_MAPPING:
2829 ULONG index;
2830 if (!(*found = find_attribute( reader, localname, ns, &index ))) return S_OK;
2831 return read_get_attribute_text( reader, index, ret );
2833 case WS_ELEMENT_TYPE_MAPPING:
2834 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2835 case WS_ANY_ELEMENT_TYPE_MAPPING:
2837 HRESULT hr;
2838 *found = TRUE;
2839 if (localname)
2841 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2843 if (WsXmlStringEquals( localname, elem->localName, NULL ) != S_OK ||
2844 WsXmlStringEquals( ns, elem->ns, NULL ) != S_OK)
2846 *found = FALSE;
2847 return S_OK;
2849 if ((hr = read_startelement( reader )) != S_OK) return hr;
2851 return read_get_node_text( reader, ret );
2853 default:
2854 FIXME( "mapping %u not supported\n", mapping );
2855 return E_NOTIMPL;
2859 static HRESULT read_type_bool( struct reader *reader, WS_TYPE_MAPPING mapping,
2860 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2861 const WS_BOOL_DESCRIPTION *desc, WS_READ_OPTION option,
2862 WS_HEAP *heap, void *ret, ULONG size )
2864 WS_XML_UTF8_TEXT *utf8;
2865 HRESULT hr;
2866 BOOL found, val = FALSE;
2868 if (desc)
2870 FIXME( "description not supported\n" );
2871 return E_NOTIMPL;
2873 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
2874 if (found)
2876 ULONG len = utf8->value.length;
2877 if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) val = TRUE;
2878 else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) val = TRUE;
2879 else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) val = FALSE;
2880 else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) val = FALSE;
2881 else return WS_E_INVALID_FORMAT;
2884 switch (option)
2886 case WS_READ_REQUIRED_VALUE:
2887 if (!found) return WS_E_INVALID_FORMAT;
2888 /* fall through */
2890 case WS_READ_NILLABLE_VALUE:
2891 if (size != sizeof(BOOL)) return E_INVALIDARG;
2892 *(BOOL *)ret = val;
2893 break;
2895 case WS_READ_REQUIRED_POINTER:
2896 if (!found) return WS_E_INVALID_FORMAT;
2897 /* fall through */
2899 case WS_READ_OPTIONAL_POINTER:
2900 case WS_READ_NILLABLE_POINTER:
2902 BOOL *heap_val = NULL;
2903 if (size != sizeof(heap_val)) return E_INVALIDARG;
2904 if (found)
2906 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
2907 *heap_val = val;
2909 *(BOOL **)ret = heap_val;
2910 break;
2912 default:
2913 FIXME( "read option %u not supported\n", option );
2914 return E_NOTIMPL;
2917 return S_OK;
2920 static HRESULT read_type_int8( struct reader *reader, WS_TYPE_MAPPING mapping,
2921 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2922 const WS_INT8_DESCRIPTION *desc, WS_READ_OPTION option,
2923 WS_HEAP *heap, void *ret, ULONG size )
2925 WS_XML_UTF8_TEXT *utf8;
2926 HRESULT hr;
2927 INT64 val = 0;
2928 BOOL found;
2930 if (desc)
2932 FIXME( "description not supported\n" );
2933 return E_NOTIMPL;
2935 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
2936 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
2937 return hr;
2939 switch (option)
2941 case WS_READ_REQUIRED_VALUE:
2942 if (!found) return WS_E_INVALID_FORMAT;
2943 /* fall through */
2945 case WS_READ_NILLABLE_VALUE:
2946 if (size != sizeof(INT8)) return E_INVALIDARG;
2947 *(INT8 *)ret = val;
2948 break;
2950 case WS_READ_REQUIRED_POINTER:
2951 if (!found) return WS_E_INVALID_FORMAT;
2952 /* fall through */
2954 case WS_READ_OPTIONAL_POINTER:
2955 case WS_READ_NILLABLE_POINTER:
2957 INT8 *heap_val = NULL;
2958 if (size != sizeof(heap_val)) return E_INVALIDARG;
2959 if (found)
2961 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
2962 *heap_val = val;
2964 *(INT8 **)ret = heap_val;
2965 break;
2967 default:
2968 FIXME( "read option %u not supported\n", option );
2969 return E_NOTIMPL;
2972 return S_OK;
2975 static HRESULT read_type_int16( struct reader *reader, WS_TYPE_MAPPING mapping,
2976 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2977 const WS_INT16_DESCRIPTION *desc, WS_READ_OPTION option,
2978 WS_HEAP *heap, void *ret, ULONG size )
2980 WS_XML_UTF8_TEXT *utf8;
2981 HRESULT hr;
2982 INT64 val = 0;
2983 BOOL found;
2985 if (desc)
2987 FIXME( "description not supported\n" );
2988 return E_NOTIMPL;
2990 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
2991 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
2992 return hr;
2994 switch (option)
2996 case WS_READ_REQUIRED_VALUE:
2997 if (!found) return WS_E_INVALID_FORMAT;
2998 /* fall through */
3000 case WS_READ_NILLABLE_VALUE:
3001 if (size != sizeof(INT16)) return E_INVALIDARG;
3002 *(INT16 *)ret = val;
3003 break;
3005 case WS_READ_REQUIRED_POINTER:
3006 if (!found) return WS_E_INVALID_FORMAT;
3007 /* fall through */
3009 case WS_READ_OPTIONAL_POINTER:
3010 case WS_READ_NILLABLE_POINTER:
3012 INT16 *heap_val = NULL;
3013 if (size != sizeof(heap_val)) return E_INVALIDARG;
3014 if (found)
3016 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3017 *heap_val = val;
3019 *(INT16 **)ret = heap_val;
3020 break;
3022 default:
3023 FIXME( "read option %u not supported\n", option );
3024 return E_NOTIMPL;
3027 return S_OK;
3030 static HRESULT read_type_int32( struct reader *reader, WS_TYPE_MAPPING mapping,
3031 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3032 const WS_INT32_DESCRIPTION *desc, WS_READ_OPTION option,
3033 WS_HEAP *heap, void *ret, ULONG size )
3035 WS_XML_UTF8_TEXT *utf8;
3036 HRESULT hr;
3037 INT64 val = 0;
3038 BOOL found;
3040 if (desc)
3042 FIXME( "description not supported\n" );
3043 return E_NOTIMPL;
3045 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3046 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
3047 return hr;
3049 switch (option)
3051 case WS_READ_REQUIRED_VALUE:
3052 if (!found) return WS_E_INVALID_FORMAT;
3053 /* fall through */
3055 case WS_READ_NILLABLE_VALUE:
3056 if (size != sizeof(INT32)) return E_INVALIDARG;
3057 *(INT32 *)ret = val;
3058 break;
3060 case WS_READ_REQUIRED_POINTER:
3061 if (!found) return WS_E_INVALID_FORMAT;
3062 /* fall through */
3064 case WS_READ_OPTIONAL_POINTER:
3065 case WS_READ_NILLABLE_POINTER:
3067 INT32 *heap_val = NULL;
3068 if (size != sizeof(heap_val)) return E_INVALIDARG;
3069 if (found)
3071 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3072 *heap_val = val;
3074 *(INT32 **)ret = heap_val;
3075 break;
3077 default:
3078 FIXME( "read option %u not supported\n", option );
3079 return E_NOTIMPL;
3082 return S_OK;
3085 static HRESULT read_type_int64( struct reader *reader, WS_TYPE_MAPPING mapping,
3086 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3087 const WS_INT64_DESCRIPTION *desc, WS_READ_OPTION option,
3088 WS_HEAP *heap, void *ret, ULONG size )
3090 WS_XML_UTF8_TEXT *utf8;
3091 HRESULT hr;
3092 INT64 val = 0;
3093 BOOL found;
3095 if (desc)
3097 FIXME( "description not supported\n" );
3098 return E_NOTIMPL;
3100 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3101 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
3102 return hr;
3104 switch (option)
3106 case WS_READ_REQUIRED_VALUE:
3107 if (!found) return WS_E_INVALID_FORMAT;
3108 /* fall through */
3110 case WS_READ_NILLABLE_VALUE:
3111 if (size != sizeof(INT64)) return E_INVALIDARG;
3112 *(INT64 *)ret = val;
3113 break;
3115 case WS_READ_REQUIRED_POINTER:
3116 if (!found) return WS_E_INVALID_FORMAT;
3117 /* fall through */
3119 case WS_READ_OPTIONAL_POINTER:
3120 case WS_READ_NILLABLE_POINTER:
3122 INT64 *heap_val = NULL;
3123 if (size != sizeof(heap_val)) return E_INVALIDARG;
3124 if (found)
3126 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3127 *heap_val = val;
3129 *(INT64 **)ret = heap_val;
3130 break;
3132 default:
3133 FIXME( "read option %u not supported\n", option );
3134 return E_NOTIMPL;
3137 return S_OK;
3140 static HRESULT read_type_uint8( struct reader *reader, WS_TYPE_MAPPING mapping,
3141 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3142 const WS_UINT8_DESCRIPTION *desc, WS_READ_OPTION option,
3143 WS_HEAP *heap, void *ret, ULONG size )
3145 WS_XML_UTF8_TEXT *utf8;
3146 HRESULT hr;
3147 UINT64 val = 0;
3148 BOOL found;
3150 if (desc)
3152 FIXME( "description not supported\n" );
3153 return E_NOTIMPL;
3155 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3156 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
3157 return hr;
3159 switch (option)
3161 case WS_READ_REQUIRED_VALUE:
3162 if (!found) return WS_E_INVALID_FORMAT;
3163 /* fall through */
3165 case WS_READ_NILLABLE_VALUE:
3166 if (size != sizeof(UINT8)) return E_INVALIDARG;
3167 *(UINT8 *)ret = val;
3168 break;
3170 case WS_READ_REQUIRED_POINTER:
3171 if (!found) return WS_E_INVALID_FORMAT;
3172 /* fall through */
3174 case WS_READ_OPTIONAL_POINTER:
3175 case WS_READ_NILLABLE_POINTER:
3177 UINT8 *heap_val = NULL;
3178 if (size != sizeof(heap_val)) return E_INVALIDARG;
3179 if (found)
3181 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3182 *heap_val = val;
3184 *(UINT8 **)ret = heap_val;
3185 break;
3187 default:
3188 FIXME( "read option %u not supported\n", option );
3189 return E_NOTIMPL;
3192 return S_OK;
3195 static HRESULT read_type_uint16( struct reader *reader, WS_TYPE_MAPPING mapping,
3196 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3197 const WS_UINT16_DESCRIPTION *desc, WS_READ_OPTION option,
3198 WS_HEAP *heap, void *ret, ULONG size )
3200 WS_XML_UTF8_TEXT *utf8;
3201 HRESULT hr;
3202 UINT64 val = 0;
3203 BOOL found;
3205 if (desc)
3207 FIXME( "description not supported\n" );
3208 return E_NOTIMPL;
3210 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3211 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
3212 return hr;
3214 switch (option)
3216 case WS_READ_REQUIRED_VALUE:
3217 if (!found) return WS_E_INVALID_FORMAT;
3218 /* fall through */
3220 case WS_READ_NILLABLE_VALUE:
3221 if (size != sizeof(UINT16)) return E_INVALIDARG;
3222 *(UINT16 *)ret = val;
3223 break;
3225 case WS_READ_REQUIRED_POINTER:
3226 if (!found) return WS_E_INVALID_FORMAT;
3227 /* fall through */
3229 case WS_READ_OPTIONAL_POINTER:
3230 case WS_READ_NILLABLE_POINTER:
3232 UINT16 *heap_val = NULL;
3233 if (size != sizeof(heap_val)) return E_INVALIDARG;
3234 if (found)
3236 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3237 *heap_val = val;
3239 *(UINT16 **)ret = heap_val;
3240 break;
3242 default:
3243 FIXME( "read option %u not supported\n", option );
3244 return E_NOTIMPL;
3247 return S_OK;
3250 static HRESULT read_type_uint32( struct reader *reader, WS_TYPE_MAPPING mapping,
3251 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3252 const WS_UINT32_DESCRIPTION *desc, WS_READ_OPTION option,
3253 WS_HEAP *heap, void *ret, ULONG size )
3255 WS_XML_UTF8_TEXT *utf8;
3256 HRESULT hr;
3257 UINT64 val = 0;
3258 BOOL found;
3260 if (desc)
3262 FIXME( "description not supported\n" );
3263 return E_NOTIMPL;
3265 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3266 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
3267 return hr;
3269 switch (option)
3271 case WS_READ_REQUIRED_VALUE:
3272 if (!found) return WS_E_INVALID_FORMAT;
3273 /* fall through */
3275 case WS_READ_NILLABLE_VALUE:
3276 if (size != sizeof(UINT32)) return E_INVALIDARG;
3277 *(UINT32 *)ret = val;
3278 break;
3280 case WS_READ_REQUIRED_POINTER:
3281 if (!found) return WS_E_INVALID_FORMAT;
3282 /* fall through */
3284 case WS_READ_OPTIONAL_POINTER:
3285 case WS_READ_NILLABLE_POINTER:
3287 UINT32 *heap_val = NULL;
3288 if (size != sizeof(heap_val)) return E_INVALIDARG;
3289 if (found)
3291 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3292 *heap_val = val;
3294 *(UINT32 **)ret = heap_val;
3295 break;
3297 default:
3298 FIXME( "read option %u not supported\n", option );
3299 return E_NOTIMPL;
3302 return S_OK;
3305 static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
3306 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3307 const WS_UINT64_DESCRIPTION *desc, WS_READ_OPTION option,
3308 WS_HEAP *heap, void *ret, ULONG size )
3310 WS_XML_UTF8_TEXT *utf8;
3311 HRESULT hr;
3312 UINT64 val = 0;
3313 BOOL found;
3315 if (desc)
3317 FIXME( "description not supported\n" );
3318 return E_NOTIMPL;
3320 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3321 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
3322 return hr;
3324 switch (option)
3326 case WS_READ_REQUIRED_VALUE:
3327 if (!found) return WS_E_INVALID_FORMAT;
3328 /* fall through */
3330 case WS_READ_NILLABLE_VALUE:
3331 if (size != sizeof(UINT64)) return E_INVALIDARG;
3332 *(UINT64 *)ret = val;
3333 break;
3335 case WS_READ_REQUIRED_POINTER:
3336 if (!found) return WS_E_INVALID_FORMAT;
3337 /* fall through */
3339 case WS_READ_OPTIONAL_POINTER:
3340 case WS_READ_NILLABLE_POINTER:
3342 UINT64 *heap_val = NULL;
3343 if (size != sizeof(heap_val)) return E_INVALIDARG;
3344 if (found)
3346 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3347 *heap_val = val;
3349 *(UINT64 **)ret = heap_val;
3350 break;
3352 default:
3353 FIXME( "read option %u not supported\n", option );
3354 return E_NOTIMPL;
3357 return S_OK;
3360 static HRESULT read_type_double( struct reader *reader, WS_TYPE_MAPPING mapping,
3361 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3362 const WS_DOUBLE_DESCRIPTION *desc, WS_READ_OPTION option,
3363 WS_HEAP *heap, void *ret, ULONG size )
3365 WS_XML_UTF8_TEXT *utf8;
3366 HRESULT hr;
3367 double val = 0.0;
3368 BOOL found;
3370 if (desc) FIXME( "ignoring description\n" );
3372 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3373 if (found && (hr = str_to_double( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3375 switch (option)
3377 case WS_READ_REQUIRED_VALUE:
3378 if (!found) return WS_E_INVALID_FORMAT;
3379 /* fall through */
3381 case WS_READ_NILLABLE_VALUE:
3382 if (size != sizeof(double)) return E_INVALIDARG;
3383 *(double *)ret = val;
3384 break;
3386 case WS_READ_REQUIRED_POINTER:
3387 if (!found) return WS_E_INVALID_FORMAT;
3388 /* fall through */
3390 case WS_READ_OPTIONAL_POINTER:
3391 case WS_READ_NILLABLE_POINTER:
3393 double *heap_val = NULL;
3394 if (size != sizeof(heap_val)) return E_INVALIDARG;
3395 if (found)
3397 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3398 *heap_val = val;
3400 *(double **)ret = heap_val;
3401 break;
3403 default:
3404 FIXME( "read option %u not supported\n", option );
3405 return E_NOTIMPL;
3408 return S_OK;
3411 static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
3412 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3413 const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
3414 WS_HEAP *heap, WCHAR **ret, ULONG size )
3416 WS_XML_UTF8_TEXT *utf8;
3417 HRESULT hr;
3418 WCHAR *str = NULL;
3419 BOOL found;
3421 if (desc)
3423 FIXME( "description not supported\n" );
3424 return E_NOTIMPL;
3426 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3427 if (found && !(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
3429 switch (option)
3431 case WS_READ_REQUIRED_POINTER:
3432 if (!found) return WS_E_INVALID_FORMAT;
3433 /* fall through */
3435 case WS_READ_OPTIONAL_POINTER:
3436 case WS_READ_NILLABLE_POINTER:
3437 if (size != sizeof(str)) return E_INVALIDARG;
3438 *ret = str;
3439 break;
3441 default:
3442 FIXME( "read option %u not supported\n", option );
3443 return E_NOTIMPL;
3446 return S_OK;
3449 static HRESULT get_enum_value( const WS_XML_UTF8_TEXT *text, const WS_ENUM_DESCRIPTION *desc, int *ret )
3451 ULONG i;
3452 for (i = 0; i < desc->valueCount; i++)
3454 if (WsXmlStringEquals( &text->value, desc->values[i].name, NULL ) == S_OK)
3456 *ret = desc->values[i].value;
3457 return S_OK;
3460 return WS_E_INVALID_FORMAT;
3463 static HRESULT read_type_enum( struct reader *reader, WS_TYPE_MAPPING mapping,
3464 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3465 const WS_ENUM_DESCRIPTION *desc, WS_READ_OPTION option,
3466 WS_HEAP *heap, void *ret, ULONG size )
3468 WS_XML_UTF8_TEXT *utf8;
3469 HRESULT hr;
3470 int val = 0;
3471 BOOL found;
3473 if (!desc) return E_INVALIDARG;
3475 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3476 if (found && (hr = get_enum_value( utf8, desc, &val )) != S_OK) return hr;
3478 switch (option)
3480 case WS_READ_REQUIRED_VALUE:
3481 if (!found) return WS_E_INVALID_FORMAT;
3482 /* fall through */
3484 case WS_READ_NILLABLE_VALUE:
3485 if (size != sizeof(int)) return E_INVALIDARG;
3486 *(int *)ret = val;
3487 break;
3489 case WS_READ_REQUIRED_POINTER:
3490 if (!found) return WS_E_INVALID_FORMAT;
3491 /* fall through */
3493 case WS_READ_OPTIONAL_POINTER:
3494 case WS_READ_NILLABLE_POINTER:
3496 int *heap_val = NULL;
3497 if (size != sizeof(heap_val)) return E_INVALIDARG;
3498 if (found)
3500 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3501 *heap_val = val;
3503 *(int **)ret = heap_val;
3504 break;
3506 default:
3507 FIXME( "read option %u not supported\n", option );
3508 return E_NOTIMPL;
3511 return S_OK;
3514 static HRESULT read_type_datetime( struct reader *reader, WS_TYPE_MAPPING mapping,
3515 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3516 const WS_DATETIME_DESCRIPTION *desc, WS_READ_OPTION option,
3517 WS_HEAP *heap, void *ret, ULONG size )
3519 WS_XML_UTF8_TEXT *utf8;
3520 HRESULT hr;
3521 WS_DATETIME val = {0, WS_DATETIME_FORMAT_UTC};
3522 BOOL found;
3524 if (desc) FIXME( "ignoring description\n" );
3526 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3527 if (found && (hr = str_to_datetime( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3529 switch (option)
3531 case WS_READ_REQUIRED_VALUE:
3532 if (!found) return WS_E_INVALID_FORMAT;
3533 /* fall through */
3535 case WS_READ_NILLABLE_VALUE:
3536 if (size != sizeof(WS_DATETIME)) return E_INVALIDARG;
3537 *(WS_DATETIME *)ret = val;
3538 break;
3540 case WS_READ_REQUIRED_POINTER:
3541 if (!found) return WS_E_INVALID_FORMAT;
3542 /* fall through */
3544 case WS_READ_OPTIONAL_POINTER:
3545 case WS_READ_NILLABLE_POINTER:
3547 WS_DATETIME *heap_val = NULL;
3548 if (size != sizeof(heap_val)) return E_INVALIDARG;
3549 if (found)
3551 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3552 *heap_val = val;
3554 *(WS_DATETIME **)ret = heap_val;
3555 break;
3557 default:
3558 FIXME( "read option %u not supported\n", option );
3559 return E_NOTIMPL;
3562 return S_OK;
3565 static HRESULT read_type_guid( struct reader *reader, WS_TYPE_MAPPING mapping,
3566 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3567 const WS_GUID_DESCRIPTION *desc, WS_READ_OPTION option,
3568 WS_HEAP *heap, void *ret, ULONG size )
3570 WS_XML_UTF8_TEXT *utf8;
3571 GUID val = {0};
3572 HRESULT hr;
3573 BOOL found;
3575 if (desc) FIXME( "ignoring description\n" );
3577 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3578 if (found && (hr = str_to_guid( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3580 switch (option)
3582 case WS_READ_REQUIRED_VALUE:
3583 if (!found) return WS_E_INVALID_FORMAT;
3584 /* fall through */
3586 case WS_READ_NILLABLE_VALUE:
3587 if (size != sizeof(GUID)) return E_INVALIDARG;
3588 *(GUID *)ret = val;
3589 break;
3591 case WS_READ_REQUIRED_POINTER:
3592 if (!found) return WS_E_INVALID_FORMAT;
3593 /* fall through */
3595 case WS_READ_OPTIONAL_POINTER:
3596 case WS_READ_NILLABLE_POINTER:
3598 GUID *heap_val = NULL;
3599 if (size != sizeof(heap_val)) return E_INVALIDARG;
3600 if (found)
3602 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3603 *heap_val = val;
3605 *(GUID **)ret = heap_val;
3606 break;
3608 default:
3609 FIXME( "read option %u not supported\n", option );
3610 return E_NOTIMPL;
3613 return S_OK;
3616 static HRESULT read_type_bytes( struct reader *reader, WS_TYPE_MAPPING mapping,
3617 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3618 const WS_BYTES_DESCRIPTION *desc, WS_READ_OPTION option,
3619 WS_HEAP *heap, void *ret, ULONG size )
3621 WS_XML_UTF8_TEXT *utf8;
3622 WS_BYTES val = {0};
3623 HRESULT hr;
3624 BOOL found;
3626 if (desc) FIXME( "ignoring description\n" );
3628 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3629 if (found && (hr = str_to_bytes( utf8->value.bytes, utf8->value.length, heap, &val )) != S_OK)
3630 return hr;
3632 switch (option)
3634 case WS_READ_REQUIRED_VALUE:
3635 if (!found) return WS_E_INVALID_FORMAT;
3636 /* fall through */
3638 case WS_READ_NILLABLE_VALUE:
3639 if (size != sizeof(WS_BYTES)) return E_INVALIDARG;
3640 *(WS_BYTES *)ret = val;
3641 break;
3643 case WS_READ_REQUIRED_POINTER:
3644 if (!found) return WS_E_INVALID_FORMAT;
3645 /* fall through */
3647 case WS_READ_OPTIONAL_POINTER:
3648 case WS_READ_NILLABLE_POINTER:
3650 WS_BYTES *heap_val = NULL;
3651 if (size != sizeof(heap_val)) return E_INVALIDARG;
3652 if (found)
3654 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3655 *heap_val = val;
3657 *(WS_BYTES **)ret = heap_val;
3658 break;
3660 default:
3661 FIXME( "read option %u not supported\n", option );
3662 return E_NOTIMPL;
3665 return S_OK;
3668 static BOOL is_empty_text_node( const struct node *node )
3670 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
3671 const WS_XML_UTF8_TEXT *utf8;
3672 ULONG i;
3674 if (node_type( node ) != WS_XML_NODE_TYPE_TEXT) return FALSE;
3675 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
3677 ERR( "unhandled text type %u\n", text->text->textType );
3678 return FALSE;
3680 utf8 = (const WS_XML_UTF8_TEXT *)text->text;
3681 for (i = 0; i < utf8->value.length; i++) if (!read_isspace( utf8->value.bytes[i] )) return FALSE;
3682 return TRUE;
3685 static HRESULT read_next_node( struct reader *reader )
3687 if (reader->current == reader->last) return read_node( reader );
3688 if (move_to_child_node( &reader->current )) return S_OK;
3689 if (move_to_next_node( &reader->current )) return S_OK;
3690 if (!move_to_parent_node( &reader->current )) return WS_E_INVALID_FORMAT;
3691 if (move_to_next_node( &reader->current )) return S_OK;
3692 return WS_E_INVALID_FORMAT;
3695 /* skips comment and empty text nodes */
3696 static HRESULT read_type_next_node( struct reader *reader )
3698 for (;;)
3700 HRESULT hr;
3701 WS_XML_NODE_TYPE type;
3703 if ((hr = read_next_node( reader )) != S_OK) return hr;
3704 type = node_type( reader->current );
3705 if (type == WS_XML_NODE_TYPE_COMMENT ||
3706 (type == WS_XML_NODE_TYPE_TEXT && is_empty_text_node( reader->current ))) continue;
3707 return S_OK;
3711 static BOOL match_current_element( struct reader *reader, const WS_XML_STRING *localname,
3712 const WS_XML_STRING *ns )
3714 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3715 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
3716 return WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK &&
3717 WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK;
3720 static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname,
3721 const WS_XML_STRING *ns )
3723 struct node *node;
3724 ULONG attr;
3725 HRESULT hr;
3727 if (!localname) return S_OK; /* assume reader is already correctly positioned */
3728 if (reader->current == reader->last)
3730 BOOL found;
3731 if ((hr = read_to_startelement( reader, &found )) != S_OK) return hr;
3732 if (!found) return WS_E_INVALID_FORMAT;
3734 if (match_current_element( reader, localname, ns )) return S_OK;
3736 node = reader->current;
3737 attr = reader->current_attr;
3739 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
3740 if (match_current_element( reader, localname, ns )) return S_OK;
3742 reader->current = node;
3743 reader->current_attr = attr;
3745 return WS_E_INVALID_FORMAT;
3748 ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
3750 switch (type)
3752 case WS_INT8_TYPE:
3753 case WS_UINT8_TYPE:
3754 return sizeof(INT8);
3756 case WS_INT16_TYPE:
3757 case WS_UINT16_TYPE:
3758 return sizeof(INT16);
3760 case WS_BOOL_TYPE:
3761 case WS_INT32_TYPE:
3762 case WS_UINT32_TYPE:
3763 case WS_ENUM_TYPE:
3764 return sizeof(INT32);
3766 case WS_INT64_TYPE:
3767 case WS_UINT64_TYPE:
3768 return sizeof(INT64);
3770 case WS_DOUBLE_TYPE:
3771 return sizeof(double);
3773 case WS_DATETIME_TYPE:
3774 return sizeof(WS_DATETIME);
3776 case WS_GUID_TYPE:
3777 return sizeof(GUID);
3779 case WS_STRING_TYPE:
3780 return sizeof(WS_STRING);
3782 case WS_WSZ_TYPE:
3783 return sizeof(WCHAR *);
3785 case WS_BYTES_TYPE:
3786 return sizeof(WS_BYTES);
3788 case WS_XML_STRING_TYPE:
3789 return sizeof(WS_XML_STRING);
3791 case WS_STRUCT_TYPE:
3792 return desc->size;
3794 case WS_DESCRIPTION_TYPE:
3795 return sizeof(WS_STRUCT_DESCRIPTION *);
3797 default:
3798 ERR( "unhandled type %u\n", type );
3799 return 0;
3803 static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options )
3805 if (options & WS_FIELD_POINTER)
3807 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
3808 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
3809 return WS_READ_REQUIRED_POINTER;
3812 switch (type)
3814 case WS_BOOL_TYPE:
3815 case WS_INT8_TYPE:
3816 case WS_INT16_TYPE:
3817 case WS_INT32_TYPE:
3818 case WS_INT64_TYPE:
3819 case WS_UINT8_TYPE:
3820 case WS_UINT16_TYPE:
3821 case WS_UINT32_TYPE:
3822 case WS_UINT64_TYPE:
3823 case WS_DOUBLE_TYPE:
3824 case WS_DATETIME_TYPE:
3825 case WS_GUID_TYPE:
3826 case WS_STRING_TYPE:
3827 case WS_BYTES_TYPE:
3828 case WS_XML_STRING_TYPE:
3829 case WS_STRUCT_TYPE:
3830 case WS_ENUM_TYPE:
3831 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_READ_NILLABLE_VALUE;
3832 return WS_READ_REQUIRED_VALUE;
3834 case WS_WSZ_TYPE:
3835 case WS_DESCRIPTION_TYPE:
3836 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
3837 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
3838 return WS_READ_REQUIRED_POINTER;
3840 default:
3841 FIXME( "unhandled type %u\n", type );
3842 return 0;
3846 static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
3847 const WS_XML_STRING *, const void *, WS_READ_OPTION, WS_HEAP *,
3848 void *, ULONG );
3850 static HRESULT read_type_repeating_element( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3851 WS_HEAP *heap, void **ret, ULONG *count )
3853 HRESULT hr;
3854 ULONG item_size, nb_items = 0, nb_allocated = 1, offset = 0;
3855 WS_READ_OPTION option;
3856 char *buf;
3858 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
3860 /* wrapper element */
3861 if (desc->localName && ((hr = read_type_next_element_node( reader, desc->localName, desc->ns )) != S_OK))
3862 return hr;
3864 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
3865 item_size = get_type_size( desc->type, desc->typeDescription );
3866 else
3867 item_size = sizeof(void *);
3869 if (!(buf = ws_alloc_zero( heap, item_size ))) return WS_E_QUOTA_EXCEEDED;
3870 for (;;)
3872 if (nb_items >= nb_allocated)
3874 if (!(buf = ws_realloc_zero( heap, buf, nb_allocated * 2 * item_size )))
3875 return WS_E_QUOTA_EXCEEDED;
3876 nb_allocated *= 2;
3878 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs,
3879 desc->typeDescription, option, heap, buf + offset, item_size );
3880 if (hr == WS_E_INVALID_FORMAT) break;
3881 if (hr != S_OK)
3883 ws_free( heap, buf );
3884 return hr;
3886 offset += item_size;
3887 nb_items++;
3890 if (desc->localName && ((hr = read_type_next_node( reader )) != S_OK)) return hr;
3892 if (desc->itemRange && (nb_items < desc->itemRange->minItemCount || nb_items > desc->itemRange->maxItemCount))
3894 TRACE( "number of items %u out of range (%u-%u)\n", nb_items, desc->itemRange->minItemCount,
3895 desc->itemRange->maxItemCount );
3896 ws_free( heap, buf );
3897 return WS_E_INVALID_FORMAT;
3900 *count = nb_items;
3901 *ret = buf;
3903 return S_OK;
3906 static HRESULT read_type_text( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3907 WS_READ_OPTION option, WS_HEAP *heap, void *ret, ULONG size )
3909 HRESULT hr;
3910 if (reader->current == reader->last)
3912 BOOL found;
3913 if ((hr = read_to_startelement( reader, &found )) != S_OK) return S_OK;
3914 if (!found) return WS_E_INVALID_FORMAT;
3916 if ((hr = read_next_node( reader )) != S_OK) return hr;
3917 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT) return WS_E_INVALID_FORMAT;
3919 return read_type( reader, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, NULL, NULL,
3920 desc->typeDescription, option, heap, ret, size );
3923 static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3924 WS_HEAP *heap, char *buf, ULONG offset )
3926 char *ptr;
3927 WS_READ_OPTION option;
3928 ULONG size;
3929 HRESULT hr;
3931 if (!desc) return E_INVALIDARG;
3932 if (desc->options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3934 FIXME( "options %08x not supported\n", desc->options );
3935 return E_NOTIMPL;
3937 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
3939 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
3940 size = get_type_size( desc->type, desc->typeDescription );
3941 else
3942 size = sizeof(void *);
3944 ptr = buf + offset;
3945 switch (desc->mapping)
3947 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
3948 FIXME( "WS_TYPE_ATTRIBUTE_FIELD_MAPPING not supported\n" );
3949 return S_OK;
3951 case WS_ATTRIBUTE_FIELD_MAPPING:
3952 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
3953 desc->typeDescription, option, heap, ptr, size );
3954 break;
3956 case WS_ELEMENT_FIELD_MAPPING:
3957 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
3958 desc->typeDescription, option, heap, ptr, size );
3959 break;
3961 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
3963 ULONG count;
3964 hr = read_type_repeating_element( reader, desc, heap, (void **)ptr, &count );
3965 if (hr == S_OK) *(ULONG *)(buf + desc->countOffset) = count;
3966 break;
3968 case WS_TEXT_FIELD_MAPPING:
3969 hr = read_type_text( reader, desc, option, heap, ptr, size );
3970 break;
3972 default:
3973 FIXME( "unhandled field mapping %u\n", desc->mapping );
3974 return E_NOTIMPL;
3977 if (hr == WS_E_INVALID_FORMAT)
3979 switch (option)
3981 case WS_READ_REQUIRED_VALUE:
3982 case WS_READ_REQUIRED_POINTER:
3983 return WS_E_INVALID_FORMAT;
3985 case WS_READ_NILLABLE_VALUE:
3986 if (desc->defaultValue) memcpy( ptr, desc->defaultValue->value, desc->defaultValue->valueSize );
3987 return S_OK;
3989 case WS_READ_OPTIONAL_POINTER:
3990 case WS_READ_NILLABLE_POINTER:
3991 *(void **)ptr = NULL;
3992 return S_OK;
3994 default:
3995 ERR( "unhandled option %u\n", option );
3996 return E_NOTIMPL;
4000 return hr;
4003 static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
4004 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4005 const WS_STRUCT_DESCRIPTION *desc, WS_READ_OPTION option,
4006 WS_HEAP *heap, void *ret, ULONG size )
4008 ULONG i, offset;
4009 HRESULT hr;
4010 char *buf;
4012 if (!desc) return E_INVALIDARG;
4013 if (desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4015 FIXME( "struct options %08x not supported\n",
4016 desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT );
4019 switch (option)
4021 case WS_READ_REQUIRED_POINTER:
4022 case WS_READ_OPTIONAL_POINTER:
4023 case WS_READ_NILLABLE_POINTER:
4024 if (size != sizeof(void *)) return E_INVALIDARG;
4025 if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
4026 break;
4028 case WS_READ_REQUIRED_VALUE:
4029 case WS_READ_NILLABLE_VALUE:
4030 if (size != desc->size) return E_INVALIDARG;
4031 buf = ret;
4032 break;
4034 default:
4035 FIXME( "unhandled read option %u\n", option );
4036 return E_NOTIMPL;
4039 for (i = 0; i < desc->fieldCount; i++)
4041 offset = desc->fields[i]->offset;
4042 if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, offset )) != S_OK)
4043 break;
4046 switch (option)
4048 case WS_READ_REQUIRED_POINTER:
4049 if (hr != S_OK)
4051 ws_free( heap, buf );
4052 return hr;
4054 *(char **)ret = buf;
4055 break;
4057 case WS_READ_OPTIONAL_POINTER:
4058 case WS_READ_NILLABLE_POINTER:
4059 if (is_nil_value( buf, desc->size ))
4061 ws_free( heap, buf );
4062 buf = NULL;
4064 *(char **)ret = buf;
4065 break;
4067 case WS_READ_REQUIRED_VALUE:
4068 case WS_READ_NILLABLE_VALUE:
4069 if (hr != S_OK) return hr;
4070 break;
4072 default:
4073 ERR( "unhandled read option %u\n", option );
4074 return E_NOTIMPL;
4077 if (desc->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4079 struct node *parent = find_parent( reader );
4080 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
4082 return S_OK;
4085 static HRESULT start_mapping( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname,
4086 const WS_XML_STRING *ns )
4088 switch (mapping)
4090 case WS_ELEMENT_TYPE_MAPPING:
4091 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4092 return read_type_next_element_node( reader, localname, ns );
4094 case WS_ANY_ELEMENT_TYPE_MAPPING:
4095 case WS_ATTRIBUTE_TYPE_MAPPING:
4096 return S_OK;
4098 default:
4099 FIXME( "unhandled mapping %u\n", mapping );
4100 return E_NOTIMPL;
4104 static HRESULT read_type_endelement_node( struct reader *reader )
4106 const struct node *parent = find_parent( reader );
4107 HRESULT hr;
4109 for (;;)
4111 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
4112 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT && reader->current->parent == parent)
4114 return S_OK;
4116 if (read_end_of_data( reader ) || !(parent->flags & NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT)) break;
4119 return WS_E_INVALID_FORMAT;
4122 static HRESULT end_mapping( struct reader *reader, WS_TYPE_MAPPING mapping )
4124 switch (mapping)
4126 case WS_ELEMENT_TYPE_MAPPING:
4127 return read_type_endelement_node( reader );
4129 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4130 return read_type_next_node( reader );
4132 case WS_ATTRIBUTE_TYPE_MAPPING:
4133 default:
4134 return S_OK;
4138 static HRESULT is_nil_element( const WS_XML_ELEMENT_NODE *elem )
4140 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
4141 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
4142 ULONG i;
4144 for (i = 0; i < elem->attributeCount; i++)
4146 const WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)elem->attributes[i]->value;
4148 if (elem->attributes[i]->isXmlNs) continue;
4149 if (WsXmlStringEquals( elem->attributes[i]->localName, &localname, NULL ) == S_OK &&
4150 WsXmlStringEquals( elem->attributes[i]->ns, &ns, NULL ) == S_OK &&
4151 text->value.length == 4 && !memcmp( text->value.bytes, "true", 4 )) return TRUE;
4153 return FALSE;
4156 static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYPE type,
4157 const WS_XML_STRING *localname, const WS_XML_STRING *ns, const void *desc,
4158 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
4160 HRESULT hr;
4162 if ((hr = start_mapping( reader, mapping, localname, ns )) != S_OK) return hr;
4164 if (mapping == WS_ELEMENT_TYPE_MAPPING && is_nil_element( &reader->current->hdr ))
4166 if (option != WS_READ_NILLABLE_POINTER && option != WS_READ_NILLABLE_VALUE) return WS_E_INVALID_FORMAT;
4167 return end_mapping( reader, mapping );
4170 switch (type)
4172 case WS_BOOL_TYPE:
4173 if ((hr = read_type_bool( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4174 return hr;
4175 break;
4177 case WS_INT8_TYPE:
4178 if ((hr = read_type_int8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4179 return hr;
4180 break;
4182 case WS_INT16_TYPE:
4183 if ((hr = read_type_int16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4184 return hr;
4185 break;
4187 case WS_INT32_TYPE:
4188 if ((hr = read_type_int32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4189 return hr;
4190 break;
4192 case WS_INT64_TYPE:
4193 if ((hr = read_type_int64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4194 return hr;
4195 break;
4197 case WS_UINT8_TYPE:
4198 if ((hr = read_type_uint8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4199 return hr;
4200 break;
4202 case WS_UINT16_TYPE:
4203 if ((hr = read_type_uint16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4204 return hr;
4205 break;
4207 case WS_UINT32_TYPE:
4208 if ((hr = read_type_uint32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4209 return hr;
4210 break;
4212 case WS_UINT64_TYPE:
4213 if ((hr = read_type_uint64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4214 return hr;
4215 break;
4217 case WS_DOUBLE_TYPE:
4218 if ((hr = read_type_double( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4219 return hr;
4220 break;
4222 case WS_DATETIME_TYPE:
4223 if ((hr = read_type_datetime( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4224 return hr;
4225 break;
4227 case WS_GUID_TYPE:
4228 if ((hr = read_type_guid( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4229 return hr;
4230 break;
4232 case WS_WSZ_TYPE:
4233 if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4234 return hr;
4235 break;
4237 case WS_BYTES_TYPE:
4238 if ((hr = read_type_bytes( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4239 return hr;
4240 break;
4242 case WS_STRUCT_TYPE:
4243 if ((hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4244 return hr;
4245 break;
4247 case WS_ENUM_TYPE:
4248 if ((hr = read_type_enum( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4249 return hr;
4250 break;
4252 default:
4253 FIXME( "type %u not supported\n", type );
4254 return E_NOTIMPL;
4257 return end_mapping( reader, mapping );
4260 /**************************************************************************
4261 * WsReadType [webservices.@]
4263 HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4264 const void *desc, WS_READ_OPTION option, WS_HEAP *heap, void *value,
4265 ULONG size, WS_ERROR *error )
4267 struct reader *reader = (struct reader *)handle;
4268 HRESULT hr;
4270 TRACE( "%p %u %u %p %u %p %p %u %p\n", handle, mapping, type, desc, option, heap, value,
4271 size, error );
4272 if (error) FIXME( "ignoring error parameter\n" );
4274 if (!reader || !value) return E_INVALIDARG;
4276 if ((hr = read_type( reader, mapping, type, NULL, NULL, desc, option, heap, value, size )) != S_OK)
4277 return hr;
4279 switch (mapping)
4281 case WS_ELEMENT_TYPE_MAPPING:
4282 if ((hr = read_node( reader )) != S_OK) return hr;
4283 break;
4285 default:
4286 break;
4289 if (!read_end_of_data( reader )) return WS_E_INVALID_FORMAT;
4290 return S_OK;
4293 /**************************************************************************
4294 * WsReadElement [webservices.@]
4296 HRESULT WINAPI WsReadElement( WS_XML_READER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4297 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
4298 WS_ERROR *error )
4300 struct reader *reader = (struct reader *)handle;
4302 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
4303 if (error) FIXME( "ignoring error parameter\n" );
4305 if (!reader || !desc || !value) return E_INVALIDARG;
4307 return read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->elementLocalName,
4308 desc->elementNs, desc->typeDescription, option, heap, value, size );
4311 /**************************************************************************
4312 * WsReadValue [webservices.@]
4314 HRESULT WINAPI WsReadValue( WS_XML_READER *handle, WS_VALUE_TYPE value_type, void *value, ULONG size,
4315 WS_ERROR *error )
4317 struct reader *reader = (struct reader *)handle;
4318 WS_TYPE type = map_value_type( value_type );
4320 TRACE( "%p %u %p %u %p\n", handle, type, value, size, error );
4321 if (error) FIXME( "ignoring error parameter\n" );
4323 if (!reader || !value || type == ~0u) return E_INVALIDARG;
4325 return read_type( reader, WS_ELEMENT_TYPE_MAPPING, type, NULL, NULL, NULL, WS_READ_REQUIRED_VALUE,
4326 NULL, value, size );
4329 /**************************************************************************
4330 * WsSetErrorProperty [webservices.@]
4332 HRESULT WINAPI WsSetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, const void *value,
4333 ULONG size )
4335 struct error *error = (struct error *)handle;
4337 TRACE( "%p %u %p %u\n", handle, id, value, size );
4339 if (id == WS_ERROR_PROPERTY_LANGID) return WS_E_INVALID_OPERATION;
4340 return prop_set( error->prop, error->prop_count, id, value, size );
4343 static inline BOOL is_utf8( const unsigned char *data, ULONG size, ULONG *offset )
4345 static const char bom[] = {0xef,0xbb,0xbf};
4346 const unsigned char *p = data;
4348 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4349 (size > 2 && !(*offset = 0));
4352 static inline BOOL is_utf16le( const unsigned char *data, ULONG size, ULONG *offset )
4354 static const char bom[] = {0xff,0xfe};
4355 const unsigned char *p = data;
4357 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4358 (size >= 4 && p[0] == '<' && !p[1] && !(*offset = 0));
4361 static WS_CHARSET detect_charset( const unsigned char *data, ULONG size, ULONG *offset )
4363 WS_CHARSET ret = 0;
4365 /* FIXME: parse xml declaration */
4367 if (is_utf16le( data, size, offset )) ret = WS_CHARSET_UTF16LE;
4368 else if (is_utf8( data, size, offset )) ret = WS_CHARSET_UTF8;
4369 else
4371 FIXME( "charset not recognized\n" );
4372 return 0;
4375 TRACE( "detected charset %u\n", ret );
4376 return ret;
4379 static void set_input_buffer( struct reader *reader, struct xmlbuf *buf, const unsigned char *data, ULONG size )
4381 reader->input_type = WS_XML_READER_INPUT_TYPE_BUFFER;
4382 reader->input_buf = buf;
4383 reader->input_data = data;
4384 reader->input_size = size;
4386 reader->read_size = reader->input_size;
4387 reader->read_pos = 0;
4388 reader->read_bufptr = reader->input_data;
4391 /**************************************************************************
4392 * WsSetInput [webservices.@]
4394 HRESULT WINAPI WsSetInput( WS_XML_READER *handle, const WS_XML_READER_ENCODING *encoding,
4395 const WS_XML_READER_INPUT *input, const WS_XML_READER_PROPERTY *properties,
4396 ULONG count, WS_ERROR *error )
4398 struct reader *reader = (struct reader *)handle;
4399 struct node *node;
4400 HRESULT hr;
4401 ULONG i, offset = 0;
4403 TRACE( "%p %p %p %p %u %p\n", handle, encoding, input, properties, count, error );
4404 if (error) FIXME( "ignoring error parameter\n" );
4406 if (!reader) return E_INVALIDARG;
4408 for (i = 0; i < count; i++)
4410 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4411 properties[i].valueSize );
4412 if (hr != S_OK) return hr;
4415 if ((hr = read_init_state( reader )) != S_OK) return hr;
4417 switch (encoding->encodingType)
4419 case WS_XML_READER_ENCODING_TYPE_TEXT:
4421 WS_XML_READER_TEXT_ENCODING *text = (WS_XML_READER_TEXT_ENCODING *)encoding;
4422 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4423 WS_CHARSET charset = text->charSet;
4425 if (input->inputType != WS_XML_READER_INPUT_TYPE_BUFFER)
4427 FIXME( "charset detection on input type %u not supported\n", input->inputType );
4428 return E_NOTIMPL;
4431 if (charset == WS_CHARSET_AUTO)
4432 charset = detect_charset( buf->encodedData, buf->encodedDataSize, &offset );
4434 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET,
4435 &charset, sizeof(charset) );
4436 if (hr != S_OK) return hr;
4437 break;
4439 default:
4440 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4441 return E_NOTIMPL;
4443 switch (input->inputType)
4445 case WS_XML_READER_INPUT_TYPE_BUFFER:
4447 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4448 set_input_buffer( reader, NULL, (const unsigned char *)buf->encodedData + offset,
4449 buf->encodedDataSize - offset );
4450 break;
4452 default:
4453 FIXME( "input type %u not supported\n", input->inputType );
4454 return E_NOTIMPL;
4457 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
4458 read_insert_bof( reader, node );
4459 return S_OK;
4462 /**************************************************************************
4463 * WsSetInputToBuffer [webservices.@]
4465 HRESULT WINAPI WsSetInputToBuffer( WS_XML_READER *handle, WS_XML_BUFFER *buffer,
4466 const WS_XML_READER_PROPERTY *properties, ULONG count,
4467 WS_ERROR *error )
4469 struct reader *reader = (struct reader *)handle;
4470 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4471 WS_CHARSET charset;
4472 struct node *node;
4473 HRESULT hr;
4474 ULONG i, offset = 0;
4476 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
4477 if (error) FIXME( "ignoring error parameter\n" );
4479 if (!reader || !xmlbuf) return E_INVALIDARG;
4481 for (i = 0; i < count; i++)
4483 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4484 properties[i].valueSize );
4485 if (hr != S_OK) return hr;
4488 if ((hr = read_init_state( reader )) != S_OK) return hr;
4490 charset = detect_charset( xmlbuf->ptr, xmlbuf->size, &offset );
4491 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET,
4492 &charset, sizeof(charset) );
4493 if (hr != S_OK) return hr;
4495 set_input_buffer( reader, xmlbuf, (const unsigned char *)xmlbuf->ptr + offset, xmlbuf->size - offset );
4496 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
4497 read_insert_bof( reader, node );
4498 return S_OK;
4501 /**************************************************************************
4502 * WsXmlStringEquals [webservices.@]
4504 HRESULT WINAPI WsXmlStringEquals( const WS_XML_STRING *str1, const WS_XML_STRING *str2, WS_ERROR *error )
4506 TRACE( "%s %s %p\n", debugstr_xmlstr(str1), debugstr_xmlstr(str2), error );
4507 if (error) FIXME( "ignoring error parameter\n" );
4509 if (!str1 || !str2) return E_INVALIDARG;
4511 if (str1->length != str2->length) return S_FALSE;
4512 if (!memcmp( str1->bytes, str2->bytes, str1->length )) return S_OK;
4513 return S_FALSE;
4516 /**************************************************************************
4517 * WsGetReaderPosition [webservices.@]
4519 HRESULT WINAPI WsGetReaderPosition( WS_XML_READER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4521 struct reader *reader = (struct reader *)handle;
4523 TRACE( "%p %p %p\n", handle, pos, error );
4524 if (error) FIXME( "ignoring error parameter\n" );
4526 if (!reader || !pos) return E_INVALIDARG;
4527 if (!reader->input_buf) return WS_E_INVALID_OPERATION;
4529 pos->buffer = (WS_XML_BUFFER *)reader->input_buf;
4530 pos->node = reader->current;
4531 return S_OK;
4534 /**************************************************************************
4535 * WsSetReaderPosition [webservices.@]
4537 HRESULT WINAPI WsSetReaderPosition( WS_XML_READER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4539 struct reader *reader = (struct reader *)handle;
4541 TRACE( "%p %p %p\n", handle, pos, error );
4542 if (error) FIXME( "ignoring error parameter\n" );
4544 if (!reader || !pos || (struct xmlbuf *)pos->buffer != reader->input_buf) return E_INVALIDARG;
4545 if (!reader->input_buf) return WS_E_INVALID_OPERATION;
4547 reader->current = pos->node;
4548 return S_OK;
4551 static HRESULT utf8_to_base64( const WS_XML_UTF8_TEXT *utf8, WS_XML_BASE64_TEXT *base64 )
4553 if (utf8->value.length % 4) return WS_E_INVALID_FORMAT;
4554 if (!(base64->bytes = heap_alloc( utf8->value.length * 3 / 4 ))) return E_OUTOFMEMORY;
4555 base64->length = decode_base64( utf8->value.bytes, utf8->value.length, base64->bytes );
4556 return S_OK;
4559 /**************************************************************************
4560 * WsReadBytes [webservices.@]
4562 HRESULT WINAPI WsReadBytes( WS_XML_READER *handle, void *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
4564 struct reader *reader = (struct reader *)handle;
4565 HRESULT hr;
4567 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
4568 if (error) FIXME( "ignoring error parameter\n" );
4570 if (!reader) return E_INVALIDARG;
4571 if (!reader->input_type) return WS_E_INVALID_OPERATION;
4572 if (!count) return E_INVALIDARG;
4574 *count = 0;
4575 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
4577 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4578 WS_XML_BASE64_TEXT base64;
4580 if ((hr = utf8_to_base64( (const WS_XML_UTF8_TEXT *)text->text, &base64 )) != S_OK) return hr;
4581 if (reader->text_conv_offset == base64.length)
4583 heap_free( base64.bytes );
4584 return read_node( reader );
4586 *count = min( base64.length - reader->text_conv_offset, max_count );
4587 memcpy( bytes, base64.bytes + reader->text_conv_offset, *count );
4588 reader->text_conv_offset += *count;
4589 heap_free( base64.bytes );
4592 return S_OK;
4595 static HRESULT utf8_to_utf16( const WS_XML_UTF8_TEXT *utf8, WS_XML_UTF16_TEXT *utf16 )
4597 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
4598 if (!(utf16->bytes = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
4599 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, (WCHAR *)utf16->bytes, len );
4600 utf16->byteCount = len * sizeof(WCHAR);
4601 return S_OK;
4604 /**************************************************************************
4605 * WsReadChars [webservices.@]
4607 HRESULT WINAPI WsReadChars( WS_XML_READER *handle, WCHAR *chars, ULONG max_count, ULONG *count, WS_ERROR *error )
4609 struct reader *reader = (struct reader *)handle;
4611 TRACE( "%p %p %u %p %p\n", handle, chars, max_count, count, error );
4612 if (error) FIXME( "ignoring error parameter\n" );
4614 if (!reader) return E_INVALIDARG;
4615 if (!reader->input_type) return WS_E_INVALID_OPERATION;
4616 if (!count) return E_INVALIDARG;
4618 *count = 0;
4619 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && chars)
4621 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4622 WS_XML_UTF16_TEXT utf16;
4623 HRESULT hr;
4625 if ((hr = utf8_to_utf16( (const WS_XML_UTF8_TEXT *)text->text, &utf16 )) != S_OK) return hr;
4626 if (reader->text_conv_offset == utf16.byteCount / sizeof(WCHAR))
4628 heap_free( utf16.bytes );
4629 return read_node( reader );
4631 *count = min( utf16.byteCount / sizeof(WCHAR) - reader->text_conv_offset, max_count );
4632 memcpy( chars, utf16.bytes + reader->text_conv_offset * sizeof(WCHAR), *count * sizeof(WCHAR) );
4633 reader->text_conv_offset += *count;
4634 heap_free( utf16.bytes );
4637 return S_OK;
4640 /**************************************************************************
4641 * WsReadCharsUtf8 [webservices.@]
4643 HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
4645 struct reader *reader = (struct reader *)handle;
4647 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
4648 if (error) FIXME( "ignoring error parameter\n" );
4650 if (!reader) return E_INVALIDARG;
4651 if (!reader->input_type) return WS_E_INVALID_OPERATION;
4652 if (!count) return E_INVALIDARG;
4654 *count = 0;
4655 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
4657 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4658 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
4660 if (reader->text_conv_offset == utf8->value.length) return read_node( reader );
4661 *count = min( utf8->value.length - reader->text_conv_offset, max_count );
4662 memcpy( bytes, utf8->value.bytes + reader->text_conv_offset, *count );
4663 reader->text_conv_offset += *count;
4666 return S_OK;