webservices: Protect readers with a critical section.
[wine.git] / dlls / webservices / reader.c
blob0951af767a26c1238681484d6750664d22337c07
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 magic;
83 CRITICAL_SECTION cs;
84 ULONG prop_count;
85 struct prop prop[sizeof(error_props)/sizeof(error_props[0])];
88 #define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O')
90 static struct error *alloc_error(void)
92 static const ULONG count = sizeof(error_props)/sizeof(error_props[0]);
93 struct error *ret;
94 ULONG size = sizeof(*ret) + prop_size( error_props, count );
96 if (!(ret = heap_alloc_zero( size ))) return NULL;
98 ret->magic = ERROR_MAGIC;
99 InitializeCriticalSection( &ret->cs );
100 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": error.cs");
102 prop_init( error_props, count, ret->prop, &ret[1] );
103 ret->prop_count = count;
104 return ret;
107 static void free_error( struct error *error )
109 error->cs.DebugInfo->Spare[0] = 0;
110 DeleteCriticalSection( &error->cs );
111 heap_free( error );
114 /**************************************************************************
115 * WsCreateError [webservices.@]
117 HRESULT WINAPI WsCreateError( const WS_ERROR_PROPERTY *properties, ULONG count, WS_ERROR **handle )
119 struct error *error;
120 LANGID langid = GetUserDefaultUILanguage();
121 HRESULT hr;
122 ULONG i;
124 TRACE( "%p %u %p\n", properties, count, handle );
126 if (!handle) return E_INVALIDARG;
127 if (!(error = alloc_error())) return E_OUTOFMEMORY;
129 prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_LANGID, &langid, sizeof(langid) );
130 for (i = 0; i < count; i++)
132 if (properties[i].id == WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE)
134 free_error( error );
135 return E_INVALIDARG;
137 hr = prop_set( error->prop, error->prop_count, properties[i].id, properties[i].value,
138 properties[i].valueSize );
139 if (hr != S_OK)
141 free_error( error );
142 return hr;
146 *handle = (WS_ERROR *)error;
147 return S_OK;
150 static void reset_error( struct error *error )
152 ULONG code = 0;
153 /* FIXME: release strings added with WsAddErrorString when it's implemented, reset string count */
154 prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE, &code, sizeof(code) );
157 /**************************************************************************
158 * WsFreeError [webservices.@]
160 void WINAPI WsFreeError( WS_ERROR *handle )
162 struct error *error = (struct error *)handle;
164 TRACE( "%p\n", handle );
166 if (!error) return;
168 EnterCriticalSection( &error->cs );
170 if (error->magic != ERROR_MAGIC)
172 LeaveCriticalSection( &error->cs );
173 return;
176 reset_error( error );
177 error->magic = 0;
179 LeaveCriticalSection( &error->cs );
180 free_error( error );
183 /**************************************************************************
184 * WsResetError [webservices.@]
186 HRESULT WINAPI WsResetError( WS_ERROR *handle )
188 struct error *error = (struct error *)handle;
190 TRACE( "%p\n", handle );
192 if (!error) return E_INVALIDARG;
194 EnterCriticalSection( &error->cs );
196 if (error->magic != ERROR_MAGIC)
198 LeaveCriticalSection( &error->cs );
199 return E_INVALIDARG;
202 reset_error( error );
204 LeaveCriticalSection( &error->cs );
205 return S_OK;
208 /**************************************************************************
209 * WsGetErrorProperty [webservices.@]
211 HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, void *buf,
212 ULONG size )
214 struct error *error = (struct error *)handle;
215 HRESULT hr;
217 TRACE( "%p %u %p %u\n", handle, id, buf, size );
219 if (!error) return E_INVALIDARG;
221 EnterCriticalSection( &error->cs );
223 if (error->magic != ERROR_MAGIC)
225 LeaveCriticalSection( &error->cs );
226 return E_INVALIDARG;
229 hr = prop_get( error->prop, error->prop_count, id, buf, size );
231 LeaveCriticalSection( &error->cs );
232 return hr;
235 /**************************************************************************
236 * WsGetErrorString [webservices.@]
238 HRESULT WINAPI WsGetErrorString( WS_ERROR *handle, ULONG index, WS_STRING *str )
240 FIXME( "%p %u %p: stub\n", handle, index, str );
241 return E_NOTIMPL;
244 /**************************************************************************
245 * WsSetErrorProperty [webservices.@]
247 HRESULT WINAPI WsSetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, const void *value,
248 ULONG size )
250 struct error *error = (struct error *)handle;
251 HRESULT hr;
253 TRACE( "%p %u %p %u\n", handle, id, value, size );
255 if (!error) return E_INVALIDARG;
257 EnterCriticalSection( &error->cs );
259 if (error->magic != ERROR_MAGIC)
261 LeaveCriticalSection( &error->cs );
262 return E_INVALIDARG;
265 if (id == WS_ERROR_PROPERTY_LANGID)
267 LeaveCriticalSection( &error->cs );
268 return WS_E_INVALID_OPERATION;
271 hr = prop_set( error->prop, error->prop_count, id, value, size );
273 LeaveCriticalSection( &error->cs );
274 return hr;
277 static const struct prop_desc heap_props[] =
279 { sizeof(SIZE_T), FALSE }, /* WS_HEAP_PROPERTY_MAX_SIZE */
280 { sizeof(SIZE_T), FALSE }, /* WS_HEAP_PROPERTY_TRIM_SIZE */
281 { sizeof(SIZE_T), TRUE }, /* WS_HEAP_PROPERTY_REQUESTED_SIZE */
282 { sizeof(SIZE_T), TRUE } /* WS_HEAP_PROPERTY_ACTUAL_SIZE */
285 struct heap
287 ULONG magic;
288 CRITICAL_SECTION cs;
289 HANDLE handle;
290 SIZE_T max_size;
291 SIZE_T allocated;
292 ULONG prop_count;
293 struct prop prop[sizeof(heap_props)/sizeof(heap_props[0])];
296 #define HEAP_MAGIC (('H' << 24) | ('E' << 16) | ('A' << 8) | 'P')
298 static BOOL ensure_heap( struct heap *heap )
300 SIZE_T size;
301 if (heap->handle) return TRUE;
302 prop_get( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_MAX_SIZE, &size, sizeof(size) );
303 if (!(heap->handle = HeapCreate( 0, 0, 0 ))) return FALSE;
304 heap->max_size = size;
305 heap->allocated = 0;
306 return TRUE;
309 void *ws_alloc( WS_HEAP *handle, SIZE_T size )
311 struct heap *heap = (struct heap *)handle;
312 void *ret = NULL;
314 EnterCriticalSection( &heap->cs );
316 if (heap->magic != HEAP_MAGIC) goto done;
317 if (!ensure_heap( heap ) || size > heap->max_size - heap->allocated) goto done;
318 if ((ret = HeapAlloc( heap->handle, 0, size ))) heap->allocated += size;
320 done:
321 LeaveCriticalSection( &heap->cs );
322 return ret;
325 static void *ws_alloc_zero( WS_HEAP *handle, SIZE_T size )
327 struct heap *heap = (struct heap *)handle;
328 void *ret = NULL;
330 EnterCriticalSection( &heap->cs );
332 if (heap->magic != HEAP_MAGIC) goto done;
333 if (!ensure_heap( heap ) || size > heap->max_size - heap->allocated) goto done;
334 if ((ret = HeapAlloc( heap->handle, HEAP_ZERO_MEMORY, size ))) heap->allocated += size;
336 done:
337 LeaveCriticalSection( &heap->cs );
338 return ret;
341 void *ws_realloc( WS_HEAP *handle, void *ptr, SIZE_T old_size, SIZE_T new_size )
343 struct heap *heap = (struct heap *)handle;
344 void *ret = NULL;
346 EnterCriticalSection( &heap->cs );
348 if (heap->magic != HEAP_MAGIC || !ensure_heap( heap )) goto done;
349 if (new_size >= old_size)
351 SIZE_T size = new_size - old_size;
352 if (size > heap->max_size - heap->allocated) goto done;
353 if ((ret = HeapReAlloc( heap->handle, 0, ptr, new_size ))) heap->allocated += size;
355 else
357 SIZE_T size = old_size - new_size;
358 if ((ret = HeapReAlloc( heap->handle, 0, ptr, new_size ))) heap->allocated -= size;
361 done:
362 LeaveCriticalSection( &heap->cs );
363 return ret;
366 static void *ws_realloc_zero( WS_HEAP *handle, void *ptr, SIZE_T old_size, SIZE_T new_size )
368 struct heap *heap = (struct heap *)handle;
369 void *ret = NULL;
371 EnterCriticalSection( &heap->cs );
373 if (heap->magic != HEAP_MAGIC || !ensure_heap( heap )) goto done;
374 if (new_size >= old_size)
376 SIZE_T size = new_size - old_size;
377 if (size > heap->max_size - heap->allocated) goto done;
378 if ((ret = HeapReAlloc( heap->handle, HEAP_ZERO_MEMORY, ptr, new_size ))) heap->allocated += size;
380 else
382 SIZE_T size = old_size - new_size;
383 if ((ret = HeapReAlloc( heap->handle, HEAP_ZERO_MEMORY, ptr, new_size ))) heap->allocated -= size;
386 done:
387 LeaveCriticalSection( &heap->cs );
388 return ret;
391 void ws_free( WS_HEAP *handle, void *ptr, SIZE_T size )
393 struct heap *heap = (struct heap *)handle;
395 EnterCriticalSection( &heap->cs );
397 if (heap->magic == HEAP_MAGIC)
399 HeapFree( heap->handle, 0, ptr );
400 heap->allocated -= size;
403 LeaveCriticalSection( &heap->cs );
406 /**************************************************************************
407 * WsAlloc [webservices.@]
409 HRESULT WINAPI WsAlloc( WS_HEAP *handle, SIZE_T size, void **ptr, WS_ERROR *error )
411 void *mem;
413 TRACE( "%p %u %p %p\n", handle, (ULONG)size, ptr, error );
414 if (error) FIXME( "ignoring error parameter\n" );
416 if (!handle || !ptr) return E_INVALIDARG;
417 if (!(mem = ws_alloc( handle, size ))) return WS_E_QUOTA_EXCEEDED;
418 *ptr = mem;
419 return S_OK;
422 static struct heap *alloc_heap(void)
424 static const ULONG count = sizeof(heap_props)/sizeof(heap_props[0]);
425 struct heap *ret;
426 ULONG size = sizeof(*ret) + prop_size( heap_props, count );
428 if (!(ret = heap_alloc_zero( size ))) return NULL;
430 ret->magic = HEAP_MAGIC;
431 InitializeCriticalSection( &ret->cs );
432 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": heap.cs");
434 prop_init( heap_props, count, ret->prop, &ret[1] );
435 ret->prop_count = count;
436 return ret;
439 /**************************************************************************
440 * WsCreateHeap [webservices.@]
442 HRESULT WINAPI WsCreateHeap( SIZE_T max_size, SIZE_T trim_size, const WS_HEAP_PROPERTY *properties,
443 ULONG count, WS_HEAP **handle, WS_ERROR *error )
445 struct heap *heap;
447 TRACE( "%u %u %p %u %p %p\n", (ULONG)max_size, (ULONG)trim_size, properties, count, handle, error );
448 if (error) FIXME( "ignoring error parameter\n" );
450 if (!handle || count) return E_INVALIDARG;
451 if (!(heap = alloc_heap())) return E_OUTOFMEMORY;
453 prop_set( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_MAX_SIZE, &max_size, sizeof(max_size) );
454 prop_set( heap->prop, heap->prop_count, WS_HEAP_PROPERTY_TRIM_SIZE, &trim_size, sizeof(trim_size) );
456 *handle = (WS_HEAP *)heap;
457 return S_OK;
460 static void reset_heap( struct heap *heap )
462 HeapDestroy( heap->handle );
463 heap->handle = NULL;
464 heap->max_size = heap->allocated = 0;
467 /**************************************************************************
468 * WsFreeHeap [webservices.@]
470 void WINAPI WsFreeHeap( WS_HEAP *handle )
472 struct heap *heap = (struct heap *)handle;
474 TRACE( "%p\n", handle );
476 if (!heap) return;
478 EnterCriticalSection( &heap->cs );
480 if (heap->magic != HEAP_MAGIC)
482 LeaveCriticalSection( &heap->cs );
483 return;
486 reset_heap( heap );
487 heap->magic = 0;
489 LeaveCriticalSection( &heap->cs );
491 heap->cs.DebugInfo->Spare[0] = 0;
492 DeleteCriticalSection( &heap->cs );
493 heap_free( heap );
496 /**************************************************************************
497 * WsResetHeap [webservices.@]
499 HRESULT WINAPI WsResetHeap( WS_HEAP *handle, WS_ERROR *error )
501 struct heap *heap = (struct heap *)handle;
503 TRACE( "%p %p\n", handle, error );
504 if (error) FIXME( "ignoring error parameter\n" );
506 if (!heap) return E_INVALIDARG;
508 EnterCriticalSection( &heap->cs );
510 if (heap->magic != HEAP_MAGIC)
512 LeaveCriticalSection( &heap->cs );
513 return E_INVALIDARG;
516 reset_heap( heap );
518 LeaveCriticalSection( &heap->cs );
519 return S_OK;
522 /**************************************************************************
523 * WsGetHeapProperty [webservices.@]
525 HRESULT WINAPI WsGetHeapProperty( WS_HEAP *handle, WS_HEAP_PROPERTY_ID id, void *buf,
526 ULONG size, WS_ERROR *error )
528 struct heap *heap = (struct heap *)handle;
529 HRESULT hr = S_OK;
531 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
532 if (error) FIXME( "ignoring error parameter\n" );
534 if (!heap) return E_INVALIDARG;
536 EnterCriticalSection( &heap->cs );
538 if (heap->magic != HEAP_MAGIC)
540 LeaveCriticalSection( &heap->cs );
541 return E_INVALIDARG;
544 switch (id)
546 case WS_HEAP_PROPERTY_REQUESTED_SIZE:
547 case WS_HEAP_PROPERTY_ACTUAL_SIZE:
549 SIZE_T *heap_size = buf;
550 if (!buf || size != sizeof(heap_size)) hr = E_INVALIDARG;
551 else *heap_size = heap->allocated;
552 break;
554 default:
555 hr = prop_get( heap->prop, heap->prop_count, id, buf, size );
558 LeaveCriticalSection( &heap->cs );
559 return hr;
562 struct node *alloc_node( WS_XML_NODE_TYPE type )
564 struct node *ret;
566 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
567 ret->hdr.node.nodeType = type;
568 list_init( &ret->entry );
569 list_init( &ret->children );
570 return ret;
573 void free_attribute( WS_XML_ATTRIBUTE *attr )
575 if (!attr) return;
576 heap_free( attr->prefix );
577 heap_free( attr->localName );
578 heap_free( attr->ns );
579 heap_free( attr->value );
580 heap_free( attr );
583 void free_node( struct node *node )
585 if (!node) return;
586 switch (node_type( node ))
588 case WS_XML_NODE_TYPE_ELEMENT:
590 WS_XML_ELEMENT_NODE *elem = &node->hdr;
591 ULONG i;
593 for (i = 0; i < elem->attributeCount; i++) free_attribute( elem->attributes[i] );
594 heap_free( elem->attributes );
595 heap_free( elem->prefix );
596 heap_free( elem->localName );
597 heap_free( elem->ns );
598 break;
600 case WS_XML_NODE_TYPE_TEXT:
602 WS_XML_TEXT_NODE *text = (WS_XML_TEXT_NODE *)node;
603 heap_free( text->text );
604 break;
606 case WS_XML_NODE_TYPE_COMMENT:
608 WS_XML_COMMENT_NODE *comment = (WS_XML_COMMENT_NODE *)node;
609 heap_free( comment->value.bytes );
610 break;
612 case WS_XML_NODE_TYPE_CDATA:
613 case WS_XML_NODE_TYPE_END_CDATA:
614 case WS_XML_NODE_TYPE_END_ELEMENT:
615 case WS_XML_NODE_TYPE_EOF:
616 case WS_XML_NODE_TYPE_BOF:
617 break;
619 default:
620 ERR( "unhandled type %u\n", node_type( node ) );
621 break;
623 heap_free( node );
626 void destroy_nodes( struct node *node )
628 struct list *ptr;
630 if (!node) return;
631 while ((ptr = list_head( &node->children )))
633 struct node *child = LIST_ENTRY( ptr, struct node, entry );
634 list_remove( &child->entry );
635 destroy_nodes( child );
637 free_node( node );
640 static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
642 WS_XML_ATTRIBUTE *dst;
643 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
644 const WS_XML_STRING *localname = src->localName;
645 const WS_XML_STRING *ns = src->localName;
647 if (!(dst = heap_alloc( sizeof(*dst) ))) return NULL;
648 dst->singleQuote = src->singleQuote;
649 dst->isXmlNs = src->isXmlNs;
650 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
651 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
652 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
653 return dst;
655 error:
656 free_attribute( dst );
657 return NULL;
660 static WS_XML_ATTRIBUTE **dup_attributes( WS_XML_ATTRIBUTE * const *src, ULONG count )
662 WS_XML_ATTRIBUTE **dst;
663 ULONG i;
665 if (!(dst = heap_alloc( sizeof(*dst) * count ))) return NULL;
666 for (i = 0; i < count; i++)
668 if (!(dst[i] = dup_attribute( src[i] )))
670 for (; i > 0; i--) free_attribute( dst[i - 1] );
671 heap_free( dst );
672 return NULL;
675 return dst;
678 static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
680 struct node *node;
681 WS_XML_ELEMENT_NODE *dst;
682 ULONG count = src->attributeCount;
683 WS_XML_ATTRIBUTE **attrs = src->attributes;
684 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
685 const WS_XML_STRING *localname = src->localName;
686 const WS_XML_STRING *ns = src->ns;
688 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
689 dst = &node->hdr;
691 if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
692 dst->attributeCount = count;
694 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
695 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
696 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
697 return node;
699 error:
700 free_node( node );
701 return NULL;
704 static struct node *dup_text_node( const WS_XML_TEXT_NODE *src )
706 struct node *node;
707 WS_XML_TEXT_NODE *dst;
709 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
710 dst = (WS_XML_TEXT_NODE *)node;
712 if (src->text)
714 WS_XML_UTF8_TEXT *utf8;
715 const WS_XML_UTF8_TEXT *utf8_src = (WS_XML_UTF8_TEXT *)src->text;
716 if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length )))
718 free_node( node );
719 return NULL;
721 dst->text = &utf8->text;
723 return node;
726 static struct node *dup_comment_node( const WS_XML_COMMENT_NODE *src )
728 struct node *node;
729 WS_XML_COMMENT_NODE *dst;
731 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return NULL;
732 dst = (WS_XML_COMMENT_NODE *)node;
734 if (src->value.length && !(dst->value.bytes = heap_alloc( src->value.length )))
736 free_node( node );
737 return NULL;
739 memcpy( dst->value.bytes, src->value.bytes, src->value.length );
740 dst->value.length = src->value.length;
741 return node;
744 static struct node *dup_node( const struct node *src )
746 switch (node_type( src ))
748 case WS_XML_NODE_TYPE_ELEMENT:
749 return dup_element_node( &src->hdr );
751 case WS_XML_NODE_TYPE_TEXT:
752 return dup_text_node( (const WS_XML_TEXT_NODE *)src );
754 case WS_XML_NODE_TYPE_COMMENT:
755 return dup_comment_node( (const WS_XML_COMMENT_NODE *)src );
757 case WS_XML_NODE_TYPE_CDATA:
758 case WS_XML_NODE_TYPE_END_CDATA:
759 case WS_XML_NODE_TYPE_END_ELEMENT:
760 case WS_XML_NODE_TYPE_EOF:
761 case WS_XML_NODE_TYPE_BOF:
762 return alloc_node( node_type( src ) );
764 default:
765 ERR( "unhandled type %u\n", node_type( src ) );
766 break;
768 return NULL;
771 static HRESULT dup_tree( struct node **dst, const struct node *src )
773 struct node *parent;
774 const struct node *child;
776 if (!*dst && !(*dst = dup_node( src ))) return E_OUTOFMEMORY;
777 parent = *dst;
779 LIST_FOR_EACH_ENTRY( child, &src->children, struct node, entry )
781 HRESULT hr = E_OUTOFMEMORY;
782 struct node *new_child;
784 if (!(new_child = dup_node( child )) || (hr = dup_tree( &new_child, child )) != S_OK)
786 destroy_nodes( *dst );
787 return hr;
789 new_child->parent = parent;
790 list_add_tail( &parent->children, &new_child->entry );
792 return S_OK;
795 static const struct prop_desc reader_props[] =
797 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_DEPTH */
798 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_FRAGMENT */
799 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
800 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_READ_DECLARATION */
801 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_READER_PROPERTY_CHARSET */
802 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_ROW */
803 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_COLUMN */
804 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_UTF8_TRIM_SIZE */
805 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_BUFFER_SIZE */
806 { sizeof(BOOL), TRUE }, /* WS_XML_READER_PROPERTY_IN_ATTRIBUTE */
807 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_ROOT_MIME_PART_SIZE */
808 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_MIME_HEADERS_SIZE */
809 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_MIME_PARTS */
810 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
811 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_NAMESPACES */
814 enum reader_state
816 READER_STATE_INITIAL,
817 READER_STATE_BOF,
818 READER_STATE_STARTELEMENT,
819 READER_STATE_STARTATTRIBUTE,
820 READER_STATE_STARTCDATA,
821 READER_STATE_CDATA,
822 READER_STATE_TEXT,
823 READER_STATE_ENDELEMENT,
824 READER_STATE_ENDCDATA,
825 READER_STATE_COMMENT,
826 READER_STATE_EOF
829 struct prefix
831 WS_XML_STRING str;
832 WS_XML_STRING ns;
835 struct reader
837 ULONG magic;
838 CRITICAL_SECTION cs;
839 ULONG read_size;
840 ULONG read_pos;
841 const unsigned char *read_bufptr;
842 enum reader_state state;
843 struct node *root;
844 struct node *current;
845 ULONG current_attr;
846 struct node *last;
847 struct prefix *prefixes;
848 ULONG nb_prefixes;
849 ULONG nb_prefixes_allocated;
850 WS_XML_READER_INPUT_TYPE input_type;
851 struct xmlbuf *input_buf;
852 const unsigned char *input_data;
853 ULONG input_size;
854 ULONG text_conv_offset;
855 ULONG prop_count;
856 struct prop prop[sizeof(reader_props)/sizeof(reader_props[0])];
859 #define READER_MAGIC (('R' << 24) | ('E' << 16) | ('A' << 8) | 'D')
861 static struct reader *alloc_reader(void)
863 static const ULONG count = sizeof(reader_props)/sizeof(reader_props[0]);
864 struct reader *ret;
865 ULONG size = sizeof(*ret) + prop_size( reader_props, count );
867 if (!(ret = heap_alloc_zero( size ))) return NULL;
868 if (!(ret->prefixes = heap_alloc_zero( sizeof(*ret->prefixes) )))
870 heap_free( ret );
871 return NULL;
873 ret->nb_prefixes = ret->nb_prefixes_allocated = 1;
875 ret->magic = READER_MAGIC;
876 InitializeCriticalSection( &ret->cs );
877 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
879 prop_init( reader_props, count, ret->prop, &ret[1] );
880 ret->prop_count = count;
881 return ret;
884 static void clear_prefixes( struct prefix *prefixes, ULONG count )
886 ULONG i;
887 for (i = 0; i < count; i++)
889 heap_free( prefixes[i].str.bytes );
890 prefixes[i].str.bytes = NULL;
891 prefixes[i].str.length = 0;
893 heap_free( prefixes[i].ns.bytes );
894 prefixes[i].ns.bytes = NULL;
895 prefixes[i].ns.length = 0;
899 HRESULT copy_node( WS_XML_READER *handle, struct node **node )
901 struct reader *reader = (struct reader *)handle;
902 HRESULT hr;
904 EnterCriticalSection( &reader->cs );
906 if (reader->magic != READER_MAGIC)
908 LeaveCriticalSection( &reader->cs );
909 return E_INVALIDARG;
912 hr = dup_tree( node, reader->current );
914 LeaveCriticalSection( &reader->cs );
915 return hr;
918 static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
920 if (str)
922 heap_free( prefix->str.bytes );
923 if (!(prefix->str.bytes = heap_alloc( str->length ))) return E_OUTOFMEMORY;
924 memcpy( prefix->str.bytes, str->bytes, str->length );
925 prefix->str.length = str->length;
928 heap_free( prefix->ns.bytes );
929 if (!(prefix->ns.bytes = heap_alloc( ns->length ))) return E_OUTOFMEMORY;
930 memcpy( prefix->ns.bytes, ns->bytes, ns->length );
931 prefix->ns.length = ns->length;
933 return S_OK;
936 static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING *ns )
938 ULONG i;
939 HRESULT hr;
941 for (i = 0; i < reader->nb_prefixes; i++)
943 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
944 return set_prefix( &reader->prefixes[i], NULL, ns );
946 if (i >= reader->nb_prefixes_allocated)
948 ULONG new_size = reader->nb_prefixes_allocated * sizeof(*reader->prefixes) * 2;
949 struct prefix *tmp = heap_realloc_zero( reader->prefixes, new_size );
950 if (!tmp) return E_OUTOFMEMORY;
951 reader->prefixes = tmp;
952 reader->nb_prefixes_allocated *= 2;
955 if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr;
956 reader->nb_prefixes++;
957 return S_OK;
960 static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_STRING *prefix )
962 ULONG i;
963 for (i = 0; i < reader->nb_prefixes; i++)
965 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
966 return &reader->prefixes[i].ns;
968 return NULL;
971 static void read_insert_eof( struct reader *reader, struct node *eof )
973 if (!reader->root) reader->root = eof;
974 else
976 eof->parent = reader->root;
977 list_add_tail( &reader->root->children, &eof->entry );
979 reader->current = reader->last = eof;
982 static void read_insert_bof( struct reader *reader, struct node *bof )
984 reader->root->parent = bof;
985 list_add_tail( &bof->children, &reader->root->entry );
986 reader->current = reader->last = reader->root = bof;
989 static void read_insert_node( struct reader *reader, struct node *parent, struct node *node )
991 node->parent = parent;
992 list_add_before( list_tail( &parent->children ), &node->entry );
993 reader->current = reader->last = node;
996 static void free_reader( struct reader *reader )
998 destroy_nodes( reader->root );
999 clear_prefixes( reader->prefixes, reader->nb_prefixes );
1000 heap_free( reader->prefixes );
1001 reader->cs.DebugInfo->Spare[0] = 0;
1002 DeleteCriticalSection( &reader->cs );
1003 heap_free( reader );
1006 static HRESULT init_reader( struct reader *reader )
1008 struct node *node;
1010 reader->state = READER_STATE_INITIAL;
1011 destroy_nodes( reader->root );
1012 reader->root = reader->current = NULL;
1013 reader->current_attr = 0;
1014 clear_prefixes( reader->prefixes, reader->nb_prefixes );
1015 reader->nb_prefixes = 1;
1016 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
1017 read_insert_eof( reader, node );
1018 return S_OK;
1021 /**************************************************************************
1022 * WsCreateReader [webservices.@]
1024 HRESULT WINAPI WsCreateReader( const WS_XML_READER_PROPERTY *properties, ULONG count,
1025 WS_XML_READER **handle, WS_ERROR *error )
1027 struct reader *reader;
1028 ULONG i, max_depth = 32, max_attrs = 128, max_ns = 32;
1029 WS_CHARSET charset = WS_CHARSET_UTF8;
1030 BOOL read_decl = TRUE;
1031 HRESULT hr;
1033 TRACE( "%p %u %p %p\n", properties, count, handle, error );
1034 if (error) FIXME( "ignoring error parameter\n" );
1036 if (!handle) return E_INVALIDARG;
1037 if (!(reader = alloc_reader())) return E_OUTOFMEMORY;
1039 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
1040 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
1041 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_READ_DECLARATION, &read_decl, sizeof(read_decl) );
1042 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset, sizeof(charset) );
1043 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
1045 for (i = 0; i < count; i++)
1047 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
1048 properties[i].valueSize );
1049 if (hr != S_OK)
1051 free_reader( reader );
1052 return hr;
1056 if ((hr = init_reader( reader )) != S_OK)
1058 free_reader( reader );
1059 return hr;
1062 *handle = (WS_XML_READER *)reader;
1063 return S_OK;
1066 /**************************************************************************
1067 * WsFreeReader [webservices.@]
1069 void WINAPI WsFreeReader( WS_XML_READER *handle )
1071 struct reader *reader = (struct reader *)handle;
1073 TRACE( "%p\n", handle );
1075 if (!reader) return;
1077 EnterCriticalSection( &reader->cs );
1079 if (reader->magic != READER_MAGIC)
1081 LeaveCriticalSection( &reader->cs );
1082 return;
1085 reader->magic = 0;
1087 LeaveCriticalSection( &reader->cs );
1088 free_reader( reader );
1091 /**************************************************************************
1092 * WsFillReader [webservices.@]
1094 HRESULT WINAPI WsFillReader( WS_XML_READER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
1095 WS_ERROR *error )
1097 struct reader *reader = (struct reader *)handle;
1099 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
1100 if (error) FIXME( "ignoring error parameter\n" );
1102 if (!reader) return E_INVALIDARG;
1104 EnterCriticalSection( &reader->cs );
1106 if (reader->magic != READER_MAGIC)
1108 LeaveCriticalSection( &reader->cs );
1109 return E_INVALIDARG;
1112 /* FIXME: add support for stream input */
1113 reader->read_size = min( min_size, reader->input_size );
1114 reader->read_pos = 0;
1116 LeaveCriticalSection( &reader->cs );
1117 return S_OK;
1120 /**************************************************************************
1121 * WsGetNamespaceFromPrefix [webservices.@]
1123 HRESULT WINAPI WsGetNamespaceFromPrefix( WS_XML_READER *handle, const WS_XML_STRING *prefix,
1124 BOOL required, const WS_XML_STRING **ns, WS_ERROR *error )
1126 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
1127 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
1128 static const WS_XML_STRING empty_ns = {0, NULL};
1129 static const WS_XML_STRING xml_ns = {36, (BYTE *)"http://www.w3.org/XML/1998/namespace"};
1130 static const WS_XML_STRING xmlns_ns = {29, (BYTE *)"http://www.w3.org/2000/xmlns/"};
1131 struct reader *reader = (struct reader *)handle;
1132 BOOL found = FALSE;
1134 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(prefix), required, ns, error );
1135 if (error) FIXME( "ignoring error parameter\n" );
1137 if (!reader || !prefix || !ns) return E_INVALIDARG;
1139 EnterCriticalSection( &reader->cs );
1141 if (reader->magic != READER_MAGIC)
1143 LeaveCriticalSection( &reader->cs );
1144 return E_INVALIDARG;
1147 if (reader->state != READER_STATE_STARTELEMENT)
1149 LeaveCriticalSection( &reader->cs );
1150 return WS_E_INVALID_OPERATION;
1153 if (!prefix->length)
1155 *ns = &empty_ns;
1156 found = TRUE;
1158 else if (WsXmlStringEquals( prefix, &xml, NULL ) == S_OK)
1160 *ns = &xml_ns;
1161 found = TRUE;
1163 else if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
1165 *ns = &xmlns_ns;
1166 found = TRUE;
1168 else
1170 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
1171 ULONG i;
1173 for (i = 0; i < elem->attributeCount; i++)
1175 if (!elem->attributes[i]->isXmlNs) continue;
1176 if (WsXmlStringEquals( prefix, elem->attributes[i]->prefix, NULL ) == S_OK)
1178 *ns = elem->attributes[i]->ns;
1179 found = TRUE;
1180 break;
1185 if (!found)
1187 if (required) return WS_E_INVALID_FORMAT;
1188 *ns = NULL;
1189 return S_FALSE;
1192 LeaveCriticalSection( &reader->cs );
1193 return S_OK;
1196 /**************************************************************************
1197 * WsGetReaderNode [webservices.@]
1199 HRESULT WINAPI WsGetReaderNode( WS_XML_READER *handle, const WS_XML_NODE **node,
1200 WS_ERROR *error )
1202 struct reader *reader = (struct reader *)handle;
1204 TRACE( "%p %p %p\n", handle, node, error );
1205 if (error) FIXME( "ignoring error parameter\n" );
1207 if (!reader || !node) return E_INVALIDARG;
1209 EnterCriticalSection( &reader->cs );
1211 if (reader->magic != READER_MAGIC)
1213 LeaveCriticalSection( &reader->cs );
1214 return E_INVALIDARG;
1217 *node = &reader->current->hdr.node;
1219 LeaveCriticalSection( &reader->cs );
1220 return S_OK;
1223 /**************************************************************************
1224 * WsGetReaderProperty [webservices.@]
1226 HRESULT WINAPI WsGetReaderProperty( WS_XML_READER *handle, WS_XML_READER_PROPERTY_ID id,
1227 void *buf, ULONG size, WS_ERROR *error )
1229 struct reader *reader = (struct reader *)handle;
1230 HRESULT hr;
1232 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
1233 if (error) FIXME( "ignoring error parameter\n" );
1235 if (!reader) return E_INVALIDARG;
1237 EnterCriticalSection( &reader->cs );
1239 if (reader->magic != READER_MAGIC)
1241 LeaveCriticalSection( &reader->cs );
1242 return E_INVALIDARG;
1245 if (!reader->input_type)
1247 LeaveCriticalSection( &reader->cs );
1248 return WS_E_INVALID_OPERATION;
1251 if (id == WS_XML_READER_PROPERTY_CHARSET)
1253 WS_CHARSET charset;
1254 if ((hr = prop_get( reader->prop, reader->prop_count, id, &charset, size )) != S_OK) goto done;
1255 if (!charset)
1257 hr = WS_E_INVALID_FORMAT;
1258 goto done;
1260 *(WS_CHARSET *)buf = charset;
1261 hr = S_OK;
1263 else hr = prop_get( reader->prop, reader->prop_count, id, buf, size );
1265 done:
1266 LeaveCriticalSection( &reader->cs );
1267 return hr;
1270 /**************************************************************************
1271 * WsGetXmlAttribute [webservices.@]
1273 HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *attr,
1274 WS_HEAP *heap, WCHAR **str, ULONG *len, WS_ERROR *error )
1276 FIXME( "%p %s %p %p %p %p: stub\n", handle, debugstr_xmlstr(attr), heap, str, len, error );
1277 return E_NOTIMPL;
1280 WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len )
1282 WS_XML_STRING *ret;
1284 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
1285 ret->length = len;
1286 ret->bytes = len ? (BYTE *)(ret + 1) : NULL;
1287 ret->dictionary = NULL;
1288 ret->id = 0;
1289 if (data) memcpy( ret->bytes, data, len );
1290 return ret;
1293 WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len )
1295 WS_XML_UTF8_TEXT *ret;
1297 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
1298 ret->text.textType = WS_XML_TEXT_TYPE_UTF8;
1299 ret->value.length = len;
1300 ret->value.bytes = len ? (BYTE *)(ret + 1) : NULL;
1301 ret->value.dictionary = NULL;
1302 ret->value.id = 0;
1303 if (data) memcpy( ret->value.bytes, data, len );
1304 return ret;
1307 static inline BOOL read_end_of_data( struct reader *reader )
1309 return reader->read_pos >= reader->read_size;
1312 static inline const unsigned char *read_current_ptr( struct reader *reader )
1314 return &reader->read_bufptr[reader->read_pos];
1317 /* UTF-8 support based on libs/wine/utf8.c */
1319 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
1320 static const char utf8_length[128] =
1322 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
1323 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
1324 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
1325 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
1326 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
1327 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
1328 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
1329 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
1332 /* first byte mask depending on UTF-8 sequence length */
1333 static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
1335 /* minimum Unicode value depending on UTF-8 sequence length */
1336 static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
1338 static inline unsigned int read_utf8_char( struct reader *reader, unsigned int *skip )
1340 unsigned int len, res;
1341 unsigned char ch = reader->read_bufptr[reader->read_pos];
1342 const unsigned char *end;
1344 if (reader->read_pos >= reader->read_size) return 0;
1346 if (ch < 0x80)
1348 *skip = 1;
1349 return ch;
1351 len = utf8_length[ch - 0x80];
1352 if (reader->read_pos + len >= reader->read_size) return 0;
1353 end = reader->read_bufptr + reader->read_pos + len + 1;
1354 res = ch & utf8_mask[len];
1356 switch (len)
1358 case 3:
1359 if ((ch = end[-3] ^ 0x80) >= 0x40) break;
1360 res = (res << 6) | ch;
1361 case 2:
1362 if ((ch = end[-2] ^ 0x80) >= 0x40) break;
1363 res = (res << 6) | ch;
1364 case 1:
1365 if ((ch = end[-1] ^ 0x80) >= 0x40) break;
1366 res = (res << 6) | ch;
1367 if (res < utf8_minval[len]) break;
1368 *skip = len + 1;
1369 return res;
1372 return 0;
1375 static inline void read_skip( struct reader *reader, unsigned int count )
1377 if (reader->read_pos + count > reader->read_size) return;
1378 reader->read_pos += count;
1381 static inline void read_rewind( struct reader *reader, unsigned int count )
1383 reader->read_pos -= count;
1386 static inline BOOL read_isnamechar( unsigned int ch )
1388 /* FIXME: incomplete */
1389 return (ch >= 'A' && ch <= 'Z') ||
1390 (ch >= 'a' && ch <= 'z') ||
1391 (ch >= '0' && ch <= '9') ||
1392 ch == '_' || ch == '-' || ch == '.' || ch == ':';
1395 static inline BOOL read_isspace( unsigned int ch )
1397 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
1400 static inline void read_skip_whitespace( struct reader *reader )
1402 while (reader->read_pos < reader->read_size && read_isspace( reader->read_bufptr[reader->read_pos] ))
1403 reader->read_pos++;
1406 static inline int read_cmp( struct reader *reader, const char *str, int len )
1408 const unsigned char *ptr = read_current_ptr( reader );
1410 if (len < 0) len = strlen( str );
1411 if (reader->read_pos + len > reader->read_size) return -1;
1412 while (len--)
1414 if (*str != *ptr) return *ptr - *str;
1415 str++; ptr++;
1417 return 0;
1420 static HRESULT read_xmldecl( struct reader *reader )
1422 if (!reader->read_size) return WS_E_INVALID_FORMAT;
1424 if (read_cmp( reader, "<", 1 ) || read_cmp( reader, "<?", 2 ))
1426 reader->state = READER_STATE_BOF;
1427 return S_OK;
1429 if (read_cmp( reader, "<?xml ", 6 )) return WS_E_INVALID_FORMAT;
1430 read_skip( reader, 6 );
1432 /* FIXME: parse attributes */
1433 while (reader->read_pos < reader->read_size && reader->read_bufptr[reader->read_pos] != '?')
1434 reader->read_pos++;
1436 if (read_cmp( reader, "?>", 2 )) return WS_E_INVALID_FORMAT;
1437 read_skip( reader, 2 );
1439 reader->state = READER_STATE_BOF;
1440 return S_OK;
1443 HRESULT append_attribute( WS_XML_ELEMENT_NODE *elem, WS_XML_ATTRIBUTE *attr )
1445 if (elem->attributeCount)
1447 WS_XML_ATTRIBUTE **tmp;
1448 if (!(tmp = heap_realloc( elem->attributes, (elem->attributeCount + 1) * sizeof(attr) )))
1449 return E_OUTOFMEMORY;
1450 elem->attributes = tmp;
1452 else if (!(elem->attributes = heap_alloc( sizeof(attr) ))) return E_OUTOFMEMORY;
1453 elem->attributes[elem->attributeCount++] = attr;
1454 return S_OK;
1457 static HRESULT parse_name( const unsigned char *str, unsigned int len,
1458 WS_XML_STRING **prefix, WS_XML_STRING **localname )
1460 const unsigned char *name_ptr = str, *prefix_ptr = NULL;
1461 unsigned int i, name_len = len, prefix_len = 0;
1463 for (i = 0; i < len; i++)
1465 if (str[i] == ':')
1467 prefix_ptr = str;
1468 prefix_len = i;
1469 name_ptr = &str[i + 1];
1470 name_len -= i + 1;
1471 break;
1474 if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY;
1475 if (!(*localname = alloc_xml_string( name_ptr, name_len )))
1477 heap_free( *prefix );
1478 return E_OUTOFMEMORY;
1480 return S_OK;
1483 static int codepoint_to_utf8( int cp, unsigned char *dst )
1485 if (!cp) return -1;
1486 if (cp < 0x80)
1488 *dst = cp;
1489 return 1;
1491 if (cp < 0x800)
1493 dst[1] = 0x80 | (cp & 0x3f);
1494 cp >>= 6;
1495 dst[0] = 0xc0 | cp;
1496 return 2;
1498 if ((cp >= 0xd800 && cp <= 0xdfff) || cp == 0xfffe || cp == 0xffff) return -1;
1499 if (cp < 0x10000)
1501 dst[2] = 0x80 | (cp & 0x3f);
1502 cp >>= 6;
1503 dst[1] = 0x80 | (cp & 0x3f);
1504 cp >>= 6;
1505 dst[0] = 0xe0 | cp;
1506 return 3;
1508 if (cp >= 0x110000) return -1;
1509 dst[3] = 0x80 | (cp & 0x3f);
1510 cp >>= 6;
1511 dst[2] = 0x80 | (cp & 0x3f);
1512 cp >>= 6;
1513 dst[1] = 0x80 | (cp & 0x3f);
1514 cp >>= 6;
1515 dst[0] = 0xf0 | cp;
1516 return 4;
1519 static HRESULT decode_text( const unsigned char *str, ULONG len, unsigned char *ret, ULONG *ret_len )
1521 const unsigned char *p = str;
1522 unsigned char *q = ret;
1524 *ret_len = 0;
1525 while (len)
1527 if (*p == '&')
1529 p++; len--;
1530 if (!len) return WS_E_INVALID_FORMAT;
1532 if (len >= 3 && !memcmp( p, "lt;", 3 ))
1534 *q++ = '<';
1535 p += 3;
1536 len -= 3;
1538 else if (len >= 3 && !memcmp( p, "gt;", 3 ))
1540 *q++ = '>';
1541 p += 3;
1542 len -= 3;
1544 else if (len >= 5 && !memcmp( p, "quot;", 5 ))
1546 *q++ = '"';
1547 p += 5;
1548 len -= 5;
1550 else if (len >= 4 && !memcmp( p, "amp;", 4 ))
1552 *q++ = '&';
1553 p += 4;
1554 len -= 4;
1556 else if (len >= 5 && !memcmp( p, "apos;", 5 ))
1558 *q++ = '\'';
1559 p += 5;
1560 len -= 5;
1562 else if (*p == '#')
1564 ULONG start, nb_digits, i;
1565 int len_utf8, cp = 0;
1567 p++; len--;
1568 if (!len) return WS_E_INVALID_FORMAT;
1569 if (*p == 'x')
1571 p++; len--;
1573 start = len;
1574 while (len && isxdigit( *p )) { p++; len--; };
1575 if (!len) return WS_E_INVALID_FORMAT;
1577 p -= nb_digits = start - len;
1578 if (!nb_digits || nb_digits > 6 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1579 for (i = 0; i < nb_digits; i++)
1581 cp *= 16;
1582 if (*p >= '0' && *p <= '9') cp += *p - '0';
1583 else if (*p >= 'a' && *p <= 'f') cp += *p - 'a' + 10;
1584 else cp += *p - 'A' + 10;
1585 p++;
1588 else if (isdigit( *p ))
1590 while (len && *p == '0') { p++; len--; };
1591 if (!len) return WS_E_INVALID_FORMAT;
1593 start = len;
1594 while (len && isdigit( *p )) { p++; len--; };
1595 if (!len) return WS_E_INVALID_FORMAT;
1597 p -= nb_digits = start - len;
1598 if (!nb_digits || nb_digits > 7 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1599 for (i = 0; i < nb_digits; i++)
1601 cp *= 10;
1602 cp += *p - '0';
1603 p++;
1606 else return WS_E_INVALID_FORMAT;
1607 p++; len--;
1608 if ((len_utf8 = codepoint_to_utf8( cp, q )) < 0) return WS_E_INVALID_FORMAT;
1609 *ret_len += len_utf8;
1610 q += len_utf8;
1611 continue;
1613 else return WS_E_INVALID_FORMAT;
1615 else
1617 *q++ = *p++;
1618 len--;
1620 *ret_len += 1;
1622 return S_OK;
1625 static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
1627 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
1628 WS_XML_ATTRIBUTE *attr;
1629 WS_XML_UTF8_TEXT *text = NULL;
1630 unsigned int len = 0, ch, skip, quote;
1631 const unsigned char *start;
1632 WS_XML_STRING *prefix, *localname;
1633 HRESULT hr = WS_E_INVALID_FORMAT;
1635 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1637 start = read_current_ptr( reader );
1638 for (;;)
1640 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1641 if (!read_isnamechar( ch )) break;
1642 read_skip( reader, skip );
1643 len += skip;
1645 if (!len) goto error;
1647 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) goto error;
1648 hr = E_OUTOFMEMORY;
1649 if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
1651 heap_free( prefix );
1652 attr->isXmlNs = 1;
1653 if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length )))
1655 heap_free( localname );
1656 goto error;
1658 attr->localName = localname;
1660 else if (!prefix->length && WsXmlStringEquals( localname, &xmlns, NULL ) == S_OK)
1662 attr->isXmlNs = 1;
1663 attr->prefix = prefix;
1664 attr->localName = localname;
1666 else
1668 attr->prefix = prefix;
1669 attr->localName = localname;
1672 hr = WS_E_INVALID_FORMAT;
1673 read_skip_whitespace( reader );
1674 if (read_cmp( reader, "=", 1 )) goto error;
1675 read_skip( reader, 1 );
1677 read_skip_whitespace( reader );
1678 if (read_cmp( reader, "\"", 1 ) && read_cmp( reader, "'", 1 )) goto error;
1679 quote = read_utf8_char( reader, &skip );
1680 read_skip( reader, 1 );
1682 len = 0;
1683 start = read_current_ptr( reader );
1684 for (;;)
1686 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1687 if (ch == quote) break;
1688 read_skip( reader, skip );
1689 len += skip;
1691 read_skip( reader, 1 );
1693 hr = E_OUTOFMEMORY;
1694 if (attr->isXmlNs)
1696 if (!(attr->ns = alloc_xml_string( start, len ))) goto error;
1697 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1698 if (!(text = alloc_utf8_text( NULL, 0 ))) goto error;
1700 else
1702 if (!(text = alloc_utf8_text( NULL, len ))) goto error;
1703 if ((hr = decode_text( start, len, text->value.bytes, &text->value.length )) != S_OK) goto error;
1706 attr->value = &text->text;
1707 attr->singleQuote = (quote == '\'');
1709 *ret = attr;
1710 return S_OK;
1712 error:
1713 heap_free( text );
1714 free_attribute( attr );
1715 return hr;
1718 static struct node *find_parent( struct reader *reader )
1720 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT)
1722 if (is_valid_parent( reader->current->parent->parent )) return reader->current->parent->parent;
1723 return NULL;
1725 else if (is_valid_parent( reader->current )) return reader->current;
1726 else if (is_valid_parent( reader->current->parent )) return reader->current->parent;
1727 return NULL;
1730 static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1732 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
1733 const WS_XML_STRING *ns;
1734 ULONG i;
1736 if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT;
1737 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1738 if (!elem->ns->length) elem->ns->bytes = (BYTE *)(elem->ns + 1); /* quirk */
1740 for (i = 0; i < elem->attributeCount; i++)
1742 WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1743 if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue;
1744 if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT;
1745 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1747 return S_OK;
1750 static HRESULT read_element( struct reader *reader )
1752 unsigned int len = 0, ch, skip;
1753 const unsigned char *start;
1754 struct node *node = NULL, *endnode, *parent;
1755 WS_XML_ELEMENT_NODE *elem;
1756 WS_XML_ATTRIBUTE *attr = NULL;
1757 HRESULT hr = WS_E_INVALID_FORMAT;
1759 if (read_end_of_data( reader ))
1761 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1762 reader->last = reader->current;
1763 reader->state = READER_STATE_EOF;
1764 return S_OK;
1767 if (read_cmp( reader, "<", 1 )) goto error;
1768 read_skip( reader, 1 );
1769 if (!read_isnamechar( read_utf8_char( reader, &skip )))
1771 read_rewind( reader, 1 );
1772 goto error;
1775 start = read_current_ptr( reader );
1776 for (;;)
1778 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1779 if (!read_isnamechar( ch )) break;
1780 read_skip( reader, skip );
1781 len += skip;
1783 if (!len) goto error;
1785 if (!(parent = find_parent( reader ))) goto error;
1787 hr = E_OUTOFMEMORY;
1788 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) goto error;
1789 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) goto error;
1790 list_add_tail( &node->children, &endnode->entry );
1791 endnode->parent = node;
1793 elem = (WS_XML_ELEMENT_NODE *)node;
1794 if ((hr = parse_name( start, len, &elem->prefix, &elem->localName )) != S_OK) goto error;
1796 reader->current_attr = 0;
1797 for (;;)
1799 read_skip_whitespace( reader );
1800 if (!read_cmp( reader, ">", 1 ) || !read_cmp( reader, "/>", 2 )) break;
1801 if ((hr = read_attribute( reader, &attr )) != S_OK) goto error;
1802 if ((hr = append_attribute( elem, attr )) != S_OK)
1804 free_attribute( attr );
1805 goto error;
1807 reader->current_attr++;
1809 if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
1811 read_insert_node( reader, parent, node );
1812 reader->state = READER_STATE_STARTELEMENT;
1813 return S_OK;
1815 error:
1816 destroy_nodes( node );
1817 return hr;
1820 static HRESULT read_text( struct reader *reader )
1822 unsigned int len = 0, ch, skip;
1823 const unsigned char *start;
1824 struct node *node, *parent;
1825 WS_XML_TEXT_NODE *text;
1826 WS_XML_UTF8_TEXT *utf8;
1827 HRESULT hr;
1829 start = read_current_ptr( reader );
1830 for (;;)
1832 if (read_end_of_data( reader )) break;
1833 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1834 if (ch == '<') break;
1835 read_skip( reader, skip );
1836 len += skip;
1839 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1841 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1842 text = (WS_XML_TEXT_NODE *)node;
1843 if (!(utf8 = alloc_utf8_text( NULL, len )))
1845 heap_free( node );
1846 return E_OUTOFMEMORY;
1848 if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK)
1850 heap_free( utf8 );
1851 heap_free( node );
1852 return hr;
1854 text->text = &utf8->text;
1856 read_insert_node( reader, parent, node );
1857 reader->state = READER_STATE_TEXT;
1858 reader->text_conv_offset = 0;
1859 return S_OK;
1862 static HRESULT read_node( struct reader * );
1864 static HRESULT read_startelement( struct reader *reader )
1866 read_skip_whitespace( reader );
1867 if (!read_cmp( reader, "/>", 2 ))
1869 read_skip( reader, 2 );
1870 reader->current = LIST_ENTRY( list_tail( &reader->current->children ), struct node, entry );
1871 reader->last = reader->current;
1872 reader->state = READER_STATE_ENDELEMENT;
1873 return S_OK;
1875 else if (!read_cmp( reader, ">", 1 ))
1877 read_skip( reader, 1 );
1878 return read_node( reader );
1880 return WS_E_INVALID_FORMAT;
1883 static HRESULT read_to_startelement( struct reader *reader, BOOL *found )
1885 HRESULT hr;
1887 switch (reader->state)
1889 case READER_STATE_INITIAL:
1890 if ((hr = read_xmldecl( reader )) != S_OK) return hr;
1891 break;
1893 case READER_STATE_STARTELEMENT:
1894 if (found) *found = TRUE;
1895 return S_OK;
1897 default:
1898 break;
1901 read_skip_whitespace( reader );
1902 if ((hr = read_element( reader )) == S_OK && found)
1904 if (reader->state == READER_STATE_STARTELEMENT)
1905 *found = TRUE;
1906 else
1907 *found = FALSE;
1910 return hr;
1913 static int cmp_name( const unsigned char *name1, ULONG len1, const unsigned char *name2, ULONG len2 )
1915 ULONG i;
1916 if (len1 != len2) return 1;
1917 for (i = 0; i < len1; i++) { if (toupper( name1[i] ) != toupper( name2[i] )) return 1; }
1918 return 0;
1921 static struct node *read_find_startelement( struct reader *reader, const WS_XML_STRING *prefix,
1922 const WS_XML_STRING *localname )
1924 struct node *parent;
1925 const WS_XML_STRING *str;
1927 for (parent = reader->current; parent; parent = parent->parent)
1929 if (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1931 str = parent->hdr.prefix;
1932 if (cmp_name( str->bytes, str->length, prefix->bytes, prefix->length )) continue;
1933 str = parent->hdr.localName;
1934 if (cmp_name( str->bytes, str->length, localname->bytes, localname->length )) continue;
1935 return parent;
1938 return NULL;
1941 static HRESULT read_endelement( struct reader *reader )
1943 struct node *parent;
1944 unsigned int len = 0, ch, skip;
1945 const unsigned char *start;
1946 WS_XML_STRING *prefix, *localname;
1947 HRESULT hr;
1949 if (reader->state == READER_STATE_EOF) return WS_E_INVALID_FORMAT;
1951 if (read_end_of_data( reader ))
1953 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1954 reader->last = reader->current;
1955 reader->state = READER_STATE_EOF;
1956 return S_OK;
1959 if (read_cmp( reader, "</", 2 )) return WS_E_INVALID_FORMAT;
1960 read_skip( reader, 2 );
1962 start = read_current_ptr( reader );
1963 for (;;)
1965 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1966 if (ch == '>')
1968 read_skip( reader, 1 );
1969 break;
1971 if (!read_isnamechar( ch )) return WS_E_INVALID_FORMAT;
1972 read_skip( reader, skip );
1973 len += skip;
1976 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) return hr;
1977 parent = read_find_startelement( reader, prefix, localname );
1978 heap_free( prefix );
1979 heap_free( localname );
1980 if (!parent) return WS_E_INVALID_FORMAT;
1982 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
1983 reader->last = reader->current;
1984 reader->state = READER_STATE_ENDELEMENT;
1985 return S_OK;
1988 static HRESULT read_comment( struct reader *reader )
1990 unsigned int len = 0, ch, skip;
1991 const unsigned char *start;
1992 struct node *node, *parent;
1993 WS_XML_COMMENT_NODE *comment;
1995 if (read_cmp( reader, "<!--", 4 )) return WS_E_INVALID_FORMAT;
1996 read_skip( reader, 4 );
1998 start = read_current_ptr( reader );
1999 for (;;)
2001 if (!read_cmp( reader, "-->", 3 ))
2003 read_skip( reader, 3 );
2004 break;
2006 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
2007 read_skip( reader, skip );
2008 len += skip;
2011 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2013 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
2014 comment = (WS_XML_COMMENT_NODE *)node;
2015 if (!(comment->value.bytes = heap_alloc( len )))
2017 heap_free( node );
2018 return E_OUTOFMEMORY;
2020 memcpy( comment->value.bytes, start, len );
2021 comment->value.length = len;
2023 read_insert_node( reader, parent, node );
2024 reader->state = READER_STATE_COMMENT;
2025 return S_OK;
2028 static HRESULT read_startcdata( struct reader *reader )
2030 struct node *node, *endnode, *parent;
2032 if (read_cmp( reader, "<![CDATA[", 9 )) return WS_E_INVALID_FORMAT;
2033 read_skip( reader, 9 );
2035 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
2037 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
2038 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_CDATA )))
2040 heap_free( node );
2041 return E_OUTOFMEMORY;
2043 list_add_tail( &node->children, &endnode->entry );
2044 endnode->parent = node;
2046 read_insert_node( reader, parent, node );
2047 reader->state = READER_STATE_STARTCDATA;
2048 return S_OK;
2051 static HRESULT read_cdata( struct reader *reader )
2053 unsigned int len = 0, ch, skip;
2054 const unsigned char *start;
2055 struct node *node;
2056 WS_XML_TEXT_NODE *text;
2057 WS_XML_UTF8_TEXT *utf8;
2059 start = read_current_ptr( reader );
2060 for (;;)
2062 if (!read_cmp( reader, "]]>", 3 )) break;
2063 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
2064 read_skip( reader, skip );
2065 len += skip;
2068 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
2069 text = (WS_XML_TEXT_NODE *)node;
2070 if (!(utf8 = alloc_utf8_text( start, len )))
2072 heap_free( node );
2073 return E_OUTOFMEMORY;
2075 text->text = &utf8->text;
2077 read_insert_node( reader, reader->current, node );
2078 reader->state = READER_STATE_CDATA;
2079 return S_OK;
2082 static HRESULT read_endcdata( struct reader *reader )
2084 struct node *parent;
2086 if (read_cmp( reader, "]]>", 3 )) return WS_E_INVALID_FORMAT;
2087 read_skip( reader, 3 );
2089 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT) parent = reader->current->parent;
2090 else parent = reader->current;
2092 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
2093 reader->last = reader->current;
2094 reader->state = READER_STATE_ENDCDATA;
2095 return S_OK;
2098 static HRESULT read_node( struct reader *reader )
2100 HRESULT hr;
2102 for (;;)
2104 if (read_end_of_data( reader ))
2106 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
2107 reader->last = reader->current;
2108 reader->state = READER_STATE_EOF;
2109 return S_OK;
2111 if (reader->state == READER_STATE_STARTCDATA) return read_cdata( reader );
2112 else if (reader->state == READER_STATE_CDATA) return read_endcdata( reader );
2113 else if (!read_cmp( reader, "<?", 2 ))
2115 hr = read_xmldecl( reader );
2116 if (FAILED( hr )) return hr;
2118 else if (!read_cmp( reader, "</", 2 )) return read_endelement( reader );
2119 else if (!read_cmp( reader, "<![CDATA[", 9 )) return read_startcdata( reader );
2120 else if (!read_cmp( reader, "<!--", 4 )) return read_comment( reader );
2121 else if (!read_cmp( reader, "<", 1 )) return read_element( reader );
2122 else if (!read_cmp( reader, "/>", 2 ) || !read_cmp( reader, ">", 1 )) return read_startelement( reader );
2123 else return read_text( reader );
2127 /**************************************************************************
2128 * WsReadEndElement [webservices.@]
2130 HRESULT WINAPI WsReadEndElement( WS_XML_READER *handle, WS_ERROR *error )
2132 struct reader *reader = (struct reader *)handle;
2133 HRESULT hr;
2135 TRACE( "%p %p\n", handle, error );
2136 if (error) FIXME( "ignoring error parameter\n" );
2138 if (!reader) return E_INVALIDARG;
2140 EnterCriticalSection( &reader->cs );
2142 if (reader->magic != READER_MAGIC)
2144 LeaveCriticalSection( &reader->cs );
2145 return E_INVALIDARG;
2148 hr = read_endelement( reader );
2150 LeaveCriticalSection( &reader->cs );
2151 return hr;
2154 /**************************************************************************
2155 * WsReadNode [webservices.@]
2157 HRESULT WINAPI WsReadNode( WS_XML_READER *handle, WS_ERROR *error )
2159 struct reader *reader = (struct reader *)handle;
2160 HRESULT hr;
2162 TRACE( "%p %p\n", handle, error );
2163 if (error) FIXME( "ignoring error parameter\n" );
2165 if (!reader) return E_INVALIDARG;
2167 EnterCriticalSection( &reader->cs );
2169 if (reader->magic != READER_MAGIC)
2171 LeaveCriticalSection( &reader->cs );
2172 return E_INVALIDARG;
2175 hr = read_node( reader );
2177 LeaveCriticalSection( &reader->cs );
2178 return hr;
2181 /**************************************************************************
2182 * WsReadStartElement [webservices.@]
2184 HRESULT WINAPI WsReadStartElement( WS_XML_READER *handle, WS_ERROR *error )
2186 struct reader *reader = (struct reader *)handle;
2187 HRESULT hr;
2189 TRACE( "%p %p\n", handle, error );
2190 if (error) FIXME( "ignoring error parameter\n" );
2192 if (!reader) return E_INVALIDARG;
2194 EnterCriticalSection( &reader->cs );
2196 if (reader->magic != READER_MAGIC)
2198 LeaveCriticalSection( &reader->cs );
2199 return E_INVALIDARG;
2202 hr = read_startelement( reader );
2204 LeaveCriticalSection( &reader->cs );
2205 return hr;
2208 /**************************************************************************
2209 * WsReadToStartElement [webservices.@]
2211 HRESULT WINAPI WsReadToStartElement( WS_XML_READER *handle, const WS_XML_STRING *localname,
2212 const WS_XML_STRING *ns, BOOL *found, WS_ERROR *error )
2214 struct reader *reader = (struct reader *)handle;
2215 HRESULT hr;
2217 TRACE( "%p %s %s %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns), found, error );
2218 if (error) FIXME( "ignoring error parameter\n" );
2220 if (!reader) return E_INVALIDARG;
2221 if (localname || ns) FIXME( "name and/or namespace not verified\n" );
2223 EnterCriticalSection( &reader->cs );
2225 if (reader->magic != READER_MAGIC)
2227 LeaveCriticalSection( &reader->cs );
2228 return E_INVALIDARG;
2231 hr = read_to_startelement( reader, found );
2233 LeaveCriticalSection( &reader->cs );
2234 return hr;
2237 BOOL move_to_root_element( struct node *root, struct node **current )
2239 struct list *ptr;
2240 struct node *node;
2242 if (!(ptr = list_head( &root->children ))) return FALSE;
2243 node = LIST_ENTRY( ptr, struct node, entry );
2244 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT)
2246 *current = node;
2247 return TRUE;
2249 while ((ptr = list_next( &root->children, &node->entry )))
2251 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2252 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2254 *current = next;
2255 return TRUE;
2257 node = next;
2259 return FALSE;
2262 BOOL move_to_next_element( struct node **current )
2264 struct list *ptr;
2265 struct node *node = *current, *parent = (*current)->parent;
2267 if (!parent) return FALSE;
2268 while ((ptr = list_next( &parent->children, &node->entry )))
2270 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2271 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2273 *current = next;
2274 return TRUE;
2276 node = next;
2278 return FALSE;
2281 BOOL move_to_prev_element( struct node **current )
2283 struct list *ptr;
2284 struct node *node = *current, *parent = (*current)->parent;
2286 if (!parent) return FALSE;
2287 while ((ptr = list_prev( &parent->children, &node->entry )))
2289 struct node *prev = LIST_ENTRY( ptr, struct node, entry );
2290 if (node_type( prev ) == WS_XML_NODE_TYPE_ELEMENT)
2292 *current = prev;
2293 return TRUE;
2295 node = prev;
2297 return FALSE;
2300 BOOL move_to_child_element( struct node **current )
2302 struct list *ptr;
2303 struct node *child, *node = *current;
2305 if (!(ptr = list_head( &node->children ))) return FALSE;
2306 child = LIST_ENTRY( ptr, struct node, entry );
2307 if (node_type( child ) == WS_XML_NODE_TYPE_ELEMENT)
2309 *current = child;
2310 return TRUE;
2312 while ((ptr = list_next( &node->children, &child->entry )))
2314 struct node *next = LIST_ENTRY( ptr, struct node, entry );
2315 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
2317 *current = next;
2318 return TRUE;
2320 child = next;
2322 return FALSE;
2325 BOOL move_to_end_element( struct node **current )
2327 struct list *ptr;
2328 struct node *node = *current;
2330 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
2332 if ((ptr = list_tail( &node->children )))
2334 struct node *tail = LIST_ENTRY( ptr, struct node, entry );
2335 if (node_type( tail ) == WS_XML_NODE_TYPE_END_ELEMENT)
2337 *current = tail;
2338 return TRUE;
2341 return FALSE;
2344 BOOL move_to_parent_element( struct node **current )
2346 struct node *parent = (*current)->parent;
2348 if (parent && (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT ||
2349 node_type( parent ) == WS_XML_NODE_TYPE_BOF))
2351 *current = parent;
2352 return TRUE;
2354 return FALSE;
2357 BOOL move_to_first_node( struct node **current )
2359 struct list *ptr;
2360 struct node *node = *current;
2362 if ((ptr = list_head( &node->parent->children )))
2364 *current = LIST_ENTRY( ptr, struct node, entry );
2365 return TRUE;
2367 return FALSE;
2370 BOOL move_to_next_node( struct node **current )
2372 struct list *ptr;
2373 struct node *node = *current;
2375 if ((ptr = list_next( &node->parent->children, &node->entry )))
2377 *current = LIST_ENTRY( ptr, struct node, entry );
2378 return TRUE;
2380 return FALSE;
2383 BOOL move_to_prev_node( struct node **current )
2385 struct list *ptr;
2386 struct node *node = *current;
2388 if ((ptr = list_prev( &node->parent->children, &node->entry )))
2390 *current = LIST_ENTRY( ptr, struct node, entry );
2391 return TRUE;
2393 return FALSE;
2396 BOOL move_to_bof( struct node *root, struct node **current )
2398 *current = root;
2399 return TRUE;
2402 BOOL move_to_eof( struct node *root, struct node **current )
2404 struct list *ptr;
2405 if ((ptr = list_tail( &root->children )))
2407 *current = LIST_ENTRY( ptr, struct node, entry );
2408 return TRUE;
2410 return FALSE;
2413 BOOL move_to_child_node( struct node **current )
2415 struct list *ptr;
2416 struct node *node = *current;
2418 if ((ptr = list_head( &node->children )))
2420 *current = LIST_ENTRY( ptr, struct node, entry );
2421 return TRUE;
2423 return FALSE;
2426 BOOL move_to_parent_node( struct node **current )
2428 struct node *parent = (*current)->parent;
2429 if (!parent) return FALSE;
2430 *current = parent;
2431 return TRUE;
2434 static HRESULT read_move_to( struct reader *reader, WS_MOVE_TO move, BOOL *found )
2436 BOOL success = FALSE;
2437 HRESULT hr = S_OK;
2439 if (!read_end_of_data( reader ))
2441 while (reader->state != READER_STATE_EOF && (hr = read_node( reader )) == S_OK) { /* nothing */ };
2442 if (hr != S_OK) return hr;
2444 switch (move)
2446 case WS_MOVE_TO_ROOT_ELEMENT:
2447 success = move_to_root_element( reader->root, &reader->current );
2448 break;
2450 case WS_MOVE_TO_NEXT_ELEMENT:
2451 success = move_to_next_element( &reader->current );
2452 break;
2454 case WS_MOVE_TO_PREVIOUS_ELEMENT:
2455 success = move_to_prev_element( &reader->current );
2456 break;
2458 case WS_MOVE_TO_CHILD_ELEMENT:
2459 success = move_to_child_element( &reader->current );
2460 break;
2462 case WS_MOVE_TO_END_ELEMENT:
2463 success = move_to_end_element( &reader->current );
2464 break;
2466 case WS_MOVE_TO_PARENT_ELEMENT:
2467 success = move_to_parent_element( &reader->current );
2468 break;
2470 case WS_MOVE_TO_FIRST_NODE:
2471 success = move_to_first_node( &reader->current );
2472 break;
2474 case WS_MOVE_TO_NEXT_NODE:
2475 success = move_to_next_node( &reader->current );
2476 break;
2478 case WS_MOVE_TO_PREVIOUS_NODE:
2479 success = move_to_prev_node( &reader->current );
2480 break;
2482 case WS_MOVE_TO_CHILD_NODE:
2483 success = move_to_child_node( &reader->current );
2484 break;
2486 case WS_MOVE_TO_BOF:
2487 success = move_to_bof( reader->root, &reader->current );
2488 break;
2490 case WS_MOVE_TO_EOF:
2491 success = move_to_eof( reader->root, &reader->current );
2492 break;
2494 default:
2495 FIXME( "unhandled move %u\n", move );
2496 return E_NOTIMPL;
2499 if (found)
2501 *found = success;
2502 return S_OK;
2504 return success ? S_OK : WS_E_INVALID_FORMAT;
2507 /**************************************************************************
2508 * WsMoveReader [webservices.@]
2510 HRESULT WINAPI WsMoveReader( WS_XML_READER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2512 struct reader *reader = (struct reader *)handle;
2513 HRESULT hr;
2515 TRACE( "%p %u %p %p\n", handle, move, found, error );
2516 if (error) FIXME( "ignoring error parameter\n" );
2518 if (!reader) return E_INVALIDARG;
2520 EnterCriticalSection( &reader->cs );
2522 if (reader->magic != READER_MAGIC)
2524 LeaveCriticalSection( &reader->cs );
2525 return E_INVALIDARG;
2528 if (!reader->input_type)
2530 LeaveCriticalSection( &reader->cs );
2531 return WS_E_INVALID_OPERATION;
2534 hr = read_move_to( reader, move, found );
2536 LeaveCriticalSection( &reader->cs );
2537 return hr;
2540 /**************************************************************************
2541 * WsReadStartAttribute [webservices.@]
2543 HRESULT WINAPI WsReadStartAttribute( WS_XML_READER *handle, ULONG index, WS_ERROR *error )
2545 struct reader *reader = (struct reader *)handle;
2546 const WS_XML_ELEMENT_NODE *elem;
2548 TRACE( "%p %u %p\n", handle, index, error );
2549 if (error) FIXME( "ignoring error parameter\n" );
2551 if (!reader) return E_INVALIDARG;
2553 EnterCriticalSection( &reader->cs );
2555 if (reader->magic != READER_MAGIC)
2557 LeaveCriticalSection( &reader->cs );
2558 return E_INVALIDARG;
2561 elem = &reader->current->hdr;
2562 if (reader->state != READER_STATE_STARTELEMENT || index >= elem->attributeCount)
2564 LeaveCriticalSection( &reader->cs );
2565 return WS_E_INVALID_FORMAT;
2568 reader->current_attr = index;
2569 reader->state = READER_STATE_STARTATTRIBUTE;
2571 LeaveCriticalSection( &reader->cs );
2572 return S_OK;
2575 /**************************************************************************
2576 * WsReadEndAttribute [webservices.@]
2578 HRESULT WINAPI WsReadEndAttribute( WS_XML_READER *handle, WS_ERROR *error )
2580 struct reader *reader = (struct reader *)handle;
2582 TRACE( "%p %p\n", handle, error );
2583 if (error) FIXME( "ignoring error parameter\n" );
2585 if (!reader) return E_INVALIDARG;
2587 EnterCriticalSection( &reader->cs );
2589 if (reader->magic != READER_MAGIC)
2591 LeaveCriticalSection( &reader->cs );
2592 return E_INVALIDARG;
2595 if (reader->state != READER_STATE_STARTATTRIBUTE)
2597 LeaveCriticalSection( &reader->cs );
2598 return WS_E_INVALID_FORMAT;
2601 reader->state = READER_STATE_STARTELEMENT;
2603 LeaveCriticalSection( &reader->cs );
2604 return S_OK;
2607 static WCHAR *xmltext_to_widechar( WS_HEAP *heap, const WS_XML_TEXT *text )
2609 WCHAR *ret;
2611 switch (text->textType)
2613 case WS_XML_TEXT_TYPE_UTF8:
2615 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2616 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
2617 if (!(ret = ws_alloc( heap, (len + 1) * sizeof(WCHAR) ))) return NULL;
2618 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, ret, len );
2619 ret[len] = 0;
2620 break;
2622 default:
2623 FIXME( "unhandled type %u\n", text->textType );
2624 return NULL;
2627 return ret;
2630 #define MAX_INT8 0x7f
2631 #define MIN_INT8 (-MAX_INT8 - 1)
2632 #define MAX_INT16 0x7fff
2633 #define MIN_INT16 (-MAX_INT16 - 1)
2634 #define MAX_INT32 0x7fffffff
2635 #define MIN_INT32 (-MAX_INT32 - 1)
2636 #define MAX_INT64 (((INT64)0x7fffffff << 32) | 0xffffffff)
2637 #define MIN_INT64 (-MAX_INT64 - 1)
2638 #define MAX_UINT8 0xff
2639 #define MAX_UINT16 0xffff
2640 #define MAX_UINT32 0xffffffff
2641 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
2643 static HRESULT str_to_int64( const unsigned char *str, ULONG len, INT64 min, INT64 max, INT64 *ret )
2645 BOOL negative = FALSE;
2646 const unsigned char *ptr = str;
2648 *ret = 0;
2649 while (len && read_isspace( *ptr )) { ptr++; len--; }
2650 while (len && read_isspace( ptr[len - 1] )) { len--; }
2651 if (!len) return WS_E_INVALID_FORMAT;
2653 if (*ptr == '-')
2655 negative = TRUE;
2656 ptr++;
2657 len--;
2659 if (!len) return WS_E_INVALID_FORMAT;
2661 while (len--)
2663 int val;
2665 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2666 val = *ptr - '0';
2667 if (negative) val = -val;
2669 if ((!negative && (*ret > max / 10 || *ret * 10 > max - val)) ||
2670 (negative && (*ret < min / 10 || *ret * 10 < min - val)))
2672 return WS_E_NUMERIC_OVERFLOW;
2674 *ret = *ret * 10 + val;
2675 ptr++;
2678 return S_OK;
2681 static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, UINT64 *ret )
2683 const unsigned char *ptr = str;
2685 *ret = 0;
2686 while (len && read_isspace( *ptr )) { ptr++; len--; }
2687 while (len && read_isspace( ptr[len - 1] )) { len--; }
2688 if (!len) return WS_E_INVALID_FORMAT;
2690 while (len--)
2692 unsigned int val;
2694 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2695 val = *ptr - '0';
2697 if ((*ret > max / 10 || *ret * 10 > max - val)) return WS_E_NUMERIC_OVERFLOW;
2698 *ret = *ret * 10 + val;
2699 ptr++;
2702 return S_OK;
2705 BOOL set_fpword( unsigned short new, unsigned short *old )
2707 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2708 unsigned short fpword;
2710 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
2711 *old = fpword;
2712 fpword = new;
2713 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2714 return TRUE;
2715 #else
2716 FIXME( "not implemented\n" );
2717 return FALSE;
2718 #endif
2721 void restore_fpword( unsigned short fpword )
2723 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2724 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2725 #else
2726 FIXME( "not implemented\n" );
2727 #endif
2730 static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret )
2732 static const unsigned __int64 nan = 0xfff8000000000000;
2733 static const unsigned __int64 inf = 0x7ff0000000000000;
2734 static const unsigned __int64 inf_min = 0xfff0000000000000;
2735 HRESULT hr = WS_E_INVALID_FORMAT;
2736 const unsigned char *p = str, *q;
2737 int sign = 1, exp_sign = 1, exp = 0, exp_tmp = 0, neg_exp, i, nb_digits, have_digits;
2738 unsigned __int64 val = 0, tmp;
2739 long double exp_val = 1.0, exp_mul = 10.0;
2740 unsigned short fpword;
2742 while (len && read_isspace( *p )) { p++; len--; }
2743 while (len && read_isspace( p[len - 1] )) { len--; }
2744 if (!len) return WS_E_INVALID_FORMAT;
2746 if (len == 3 && !memcmp( p, "NaN", 3 ))
2748 *(unsigned __int64 *)ret = nan;
2749 return S_OK;
2751 else if (len == 3 && !memcmp( p, "INF", 3 ))
2753 *(unsigned __int64 *)ret = inf;
2754 return S_OK;
2756 else if (len == 4 && !memcmp( p, "-INF", 4 ))
2758 *(unsigned __int64 *)ret = inf_min;
2759 return S_OK;
2762 *ret = 0.0;
2763 if (*p == '-')
2765 sign = -1;
2766 p++; len--;
2768 else if (*p == '+') { p++; len--; };
2769 if (!len) return S_OK;
2771 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
2773 q = p;
2774 while (len && isdigit( *q )) { q++; len--; }
2775 have_digits = nb_digits = q - p;
2776 for (i = 0; i < nb_digits; i++)
2778 tmp = val * 10 + p[i] - '0';
2779 if (val > MAX_UINT64 / 10 || tmp < val)
2781 for (; i < nb_digits; i++) exp++;
2782 break;
2784 val = tmp;
2787 if (len)
2789 if (*q == '.')
2791 p = ++q; len--;
2792 while (len && isdigit( *q )) { q++; len--; };
2793 have_digits |= nb_digits = q - p;
2794 for (i = 0; i < nb_digits; i++)
2796 tmp = val * 10 + p[i] - '0';
2797 if (val > MAX_UINT64 / 10 || tmp < val) break;
2798 val = tmp;
2799 exp--;
2802 if (len > 1 && tolower(*q) == 'e')
2804 if (!have_digits) goto done;
2805 p = ++q; len--;
2806 if (*p == '-')
2808 exp_sign = -1;
2809 p++; len--;
2811 else if (*p == '+') { p++; len--; };
2813 q = p;
2814 while (len && isdigit( *q )) { q++; len--; };
2815 nb_digits = q - p;
2816 if (!nb_digits || len) goto done;
2817 for (i = 0; i < nb_digits; i++)
2819 if (exp_tmp > MAX_INT32 / 10 || (exp_tmp = exp_tmp * 10 + p[i] - '0') < 0)
2820 exp_tmp = MAX_INT32;
2822 exp_tmp *= exp_sign;
2824 if (exp < 0 && exp_tmp < 0 && exp + exp_tmp >= 0) exp = MIN_INT32;
2825 else if (exp > 0 && exp_tmp > 0 && exp + exp_tmp < 0) exp = MAX_INT32;
2826 else exp += exp_tmp;
2829 if (!have_digits || len) goto done;
2831 if ((neg_exp = exp < 0)) exp = -exp;
2832 for (; exp; exp >>= 1)
2834 if (exp & 1) exp_val *= exp_mul;
2835 exp_mul *= exp_mul;
2838 *ret = sign * (neg_exp ? val / exp_val : val * exp_val);
2839 hr = S_OK;
2841 done:
2842 restore_fpword( fpword );
2843 return hr;
2846 static HRESULT str_to_guid( const unsigned char *str, ULONG len, GUID *ret )
2848 static const unsigned char hex[] =
2850 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
2851 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
2852 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
2853 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
2854 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
2855 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
2856 0,10,11,12,13,14,15 /* 0x60 */
2858 const unsigned char *p = str;
2859 ULONG i;
2861 while (len && read_isspace( *p )) { p++; len--; }
2862 while (len && read_isspace( p[len - 1] )) { len--; }
2863 if (len != 36) return WS_E_INVALID_FORMAT;
2865 if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-')
2866 return WS_E_INVALID_FORMAT;
2868 for (i = 0; i < 36; i++)
2870 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
2871 if (p[i] > 'f' || (!hex[p[i]] && p[i] != '0')) return WS_E_INVALID_FORMAT;
2874 ret->Data1 = hex[p[0]] << 28 | hex[p[1]] << 24 | hex[p[2]] << 20 | hex[p[3]] << 16 |
2875 hex[p[4]] << 12 | hex[p[5]] << 8 | hex[p[6]] << 4 | hex[p[7]];
2877 ret->Data2 = hex[p[9]] << 12 | hex[p[10]] << 8 | hex[p[11]] << 4 | hex[p[12]];
2878 ret->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[16]] << 4 | hex[p[17]];
2880 ret->Data4[0] = hex[p[19]] << 4 | hex[p[20]];
2881 ret->Data4[1] = hex[p[21]] << 4 | hex[p[22]];
2882 ret->Data4[2] = hex[p[24]] << 4 | hex[p[25]];
2883 ret->Data4[3] = hex[p[26]] << 4 | hex[p[27]];
2884 ret->Data4[4] = hex[p[28]] << 4 | hex[p[29]];
2885 ret->Data4[5] = hex[p[30]] << 4 | hex[p[31]];
2886 ret->Data4[6] = hex[p[32]] << 4 | hex[p[33]];
2887 ret->Data4[7] = hex[p[34]] << 4 | hex[p[35]];
2889 return S_OK;
2892 static inline unsigned char decode_char( unsigned char c )
2894 if (c >= 'A' && c <= 'Z') return c - 'A';
2895 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2896 if (c >= '0' && c <= '9') return c - '0' + 52;
2897 if (c == '+') return 62;
2898 if (c == '/') return 63;
2899 return 64;
2902 static ULONG decode_base64( const unsigned char *base64, ULONG len, unsigned char *buf )
2904 ULONG i = 0;
2905 unsigned char c0, c1, c2, c3;
2906 const unsigned char *p = base64;
2908 while (len > 4)
2910 if ((c0 = decode_char( p[0] )) > 63) return 0;
2911 if ((c1 = decode_char( p[1] )) > 63) return 0;
2912 if ((c2 = decode_char( p[2] )) > 63) return 0;
2913 if ((c3 = decode_char( p[3] )) > 63) return 0;
2914 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2915 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2916 buf[i + 2] = (c2 << 6) | c3;
2917 len -= 4;
2918 i += 3;
2919 p += 4;
2921 if (p[2] == '=')
2923 if ((c0 = decode_char( p[0] )) > 63) return 0;
2924 if ((c1 = decode_char( p[1] )) > 63) return 0;
2925 buf[i] = (c0 << 2) | (c1 >> 4);
2926 i++;
2928 else if (p[3] == '=')
2930 if ((c0 = decode_char( p[0] )) > 63) return 0;
2931 if ((c1 = decode_char( p[1] )) > 63) return 0;
2932 if ((c2 = decode_char( p[2] )) > 63) return 0;
2933 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2934 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2935 i += 2;
2937 else
2939 if ((c0 = decode_char( p[0] )) > 63) return 0;
2940 if ((c1 = decode_char( p[1] )) > 63) return 0;
2941 if ((c2 = decode_char( p[2] )) > 63) return 0;
2942 if ((c3 = decode_char( p[3] )) > 63) return 0;
2943 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2944 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2945 buf[i + 2] = (c2 << 6) | c3;
2946 i += 3;
2948 return i;
2951 static HRESULT str_to_bytes( const unsigned char *str, ULONG len, WS_HEAP *heap, WS_BYTES *ret )
2953 const unsigned char *p = str;
2955 while (len && read_isspace( *p )) { p++; len--; }
2956 while (len && read_isspace( p[len - 1] )) { len--; }
2958 if (len % 4) return WS_E_INVALID_FORMAT;
2959 if (!(ret->bytes = ws_alloc( heap, len * 3 / 4 ))) return WS_E_QUOTA_EXCEEDED;
2960 ret->length = decode_base64( p, len, ret->bytes );
2961 return S_OK;
2964 static const int month_offsets[2][12] =
2966 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
2967 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
2970 static inline int valid_day( int year, int month, int day )
2972 return day > 0 && day <= month_days[leap_year( year )][month - 1];
2975 static inline int leap_days_before( int year )
2977 return (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
2980 static HRESULT str_to_datetime( const unsigned char *bytes, ULONG len, WS_DATETIME *ret )
2982 const unsigned char *p = bytes, *q;
2983 int year, month, day, hour, min, sec, sec_frac = 0, tz_hour, tz_min, tz_neg;
2985 while (len && read_isspace( *p )) { p++; len--; }
2986 while (len && read_isspace( p[len - 1] )) { len--; }
2988 q = p;
2989 while (len && isdigit( *q )) { q++; len--; };
2990 if (q - p != 4 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2991 year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
2992 if (year < 1) return WS_E_INVALID_FORMAT;
2994 p = ++q; len--;
2995 while (len && isdigit( *q )) { q++; len--; };
2996 if (q - p != 2 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2997 month = (p[0] - '0') * 10 + p[1] - '0';
2998 if (month < 1 || month > 12) return WS_E_INVALID_FORMAT;
3000 p = ++q; len--;
3001 while (len && isdigit( *q )) { q++; len--; };
3002 if (q - p != 2 || !len || *q != 'T') return WS_E_INVALID_FORMAT;
3003 day = (p[0] - '0') * 10 + p[1] - '0';
3004 if (!valid_day( year, month, day )) return WS_E_INVALID_FORMAT;
3006 p = ++q; len--;
3007 while (len && isdigit( *q )) { q++; len--; };
3008 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3009 hour = (p[0] - '0') * 10 + p[1] - '0';
3010 if (hour > 24) return WS_E_INVALID_FORMAT;
3012 p = ++q; len--;
3013 while (len && isdigit( *q )) { q++; len--; };
3014 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3015 min = (p[0] - '0') * 10 + p[1] - '0';
3016 if (min > 59 || (min > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
3018 p = ++q; len--;
3019 while (len && isdigit( *q )) { q++; len--; };
3020 if (q - p != 2 || !len) return WS_E_INVALID_FORMAT;
3021 sec = (p[0] - '0') * 10 + p[1] - '0';
3022 if (sec > 59 || (sec > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
3024 if (*q == '.')
3026 unsigned int i, nb_digits, mul = TICKS_PER_SEC / 10;
3027 p = ++q; len--;
3028 while (len && isdigit( *q )) { q++; len--; };
3029 nb_digits = q - p;
3030 if (nb_digits < 1 || nb_digits > 7) return WS_E_INVALID_FORMAT;
3031 for (i = 0; i < nb_digits; i++)
3033 sec_frac += (p[i] - '0') * mul;
3034 mul /= 10;
3037 if (*q == 'Z')
3039 if (--len) return WS_E_INVALID_FORMAT;
3040 tz_hour = tz_min = tz_neg = 0;
3041 ret->format = WS_DATETIME_FORMAT_UTC;
3043 else if (*q == '+' || *q == '-')
3045 tz_neg = (*q == '-') ? 1 : 0;
3047 p = ++q; len--;
3048 while (len && isdigit( *q )) { q++; len--; };
3049 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
3050 tz_hour = (p[0] - '0') * 10 + p[1] - '0';
3051 if (tz_hour > 14) return WS_E_INVALID_FORMAT;
3053 p = ++q; len--;
3054 while (len && isdigit( *q )) { q++; len--; };
3055 if (q - p != 2 || len) return WS_E_INVALID_FORMAT;
3056 tz_min = (p[0] - '0') * 10 + p[1] - '0';
3057 if (tz_min > 59 || (tz_min > 0 && tz_hour == 14)) return WS_E_INVALID_FORMAT;
3059 ret->format = WS_DATETIME_FORMAT_LOCAL;
3061 else return WS_E_INVALID_FORMAT;
3063 ret->ticks = ((year - 1) * 365 + leap_days_before( year )) * TICKS_PER_DAY;
3064 ret->ticks += month_offsets[leap_year( year )][month - 1] * TICKS_PER_DAY;
3065 ret->ticks += (day - 1) * TICKS_PER_DAY;
3066 ret->ticks += hour * TICKS_PER_HOUR;
3067 ret->ticks += min * TICKS_PER_MIN;
3068 ret->ticks += sec * TICKS_PER_SEC;
3069 ret->ticks += sec_frac;
3071 if (tz_neg)
3073 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN + ret->ticks > TICKS_MAX)
3074 return WS_E_INVALID_FORMAT;
3075 ret->ticks += tz_hour * TICKS_PER_HOUR;
3076 ret->ticks += tz_min * TICKS_PER_MIN;
3078 else
3080 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN > ret->ticks)
3081 return WS_E_INVALID_FORMAT;
3082 ret->ticks -= tz_hour * TICKS_PER_HOUR;
3083 ret->ticks -= tz_min * TICKS_PER_MIN;
3086 return S_OK;
3089 /**************************************************************************
3090 * WsDateTimeToFileTime [webservices.@]
3092 HRESULT WINAPI WsDateTimeToFileTime( const WS_DATETIME *dt, FILETIME *ft, WS_ERROR *error )
3094 unsigned __int64 ticks;
3096 TRACE( "%p %p %p\n", dt, ft, error );
3097 if (error) FIXME( "ignoring error parameter\n" );
3099 if (!dt || !ft) return E_INVALIDARG;
3101 if (dt->ticks < TICKS_1601_01_01) return WS_E_INVALID_FORMAT;
3102 ticks = dt->ticks - TICKS_1601_01_01;
3103 ft->dwHighDateTime = ticks >> 32;
3104 ft->dwLowDateTime = (DWORD)ticks;
3105 return S_OK;
3108 /**************************************************************************
3109 * WsFileTimeToDateTime [webservices.@]
3111 HRESULT WINAPI WsFileTimeToDateTime( const FILETIME *ft, WS_DATETIME *dt, WS_ERROR *error )
3113 unsigned __int64 ticks;
3115 TRACE( "%p %p %p\n", ft, dt, error );
3116 if (error) FIXME( "ignoring error parameter\n" );
3118 if (!dt || !ft) return E_INVALIDARG;
3120 ticks = ((unsigned __int64)ft->dwHighDateTime << 32) | ft->dwLowDateTime;
3121 if (ticks > MAX_UINT64 - TICKS_1601_01_01) return WS_E_NUMERIC_OVERFLOW;
3122 if (ticks + TICKS_1601_01_01 > TICKS_MAX) return WS_E_INVALID_FORMAT;
3123 dt->ticks = ticks + TICKS_1601_01_01;
3124 dt->format = WS_DATETIME_FORMAT_UTC;
3125 return S_OK;
3128 static HRESULT read_get_node_text( struct reader *reader, WS_XML_UTF8_TEXT **ret )
3130 WS_XML_TEXT_NODE *text;
3132 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT)
3133 return WS_E_INVALID_FORMAT;
3135 text = (WS_XML_TEXT_NODE *)&reader->current->hdr.node;
3136 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
3138 FIXME( "text type %u not supported\n", text->text->textType );
3139 return E_NOTIMPL;
3141 *ret = (WS_XML_UTF8_TEXT *)text->text;
3142 return S_OK;
3145 static HRESULT read_get_attribute_text( struct reader *reader, ULONG index, WS_XML_UTF8_TEXT **ret )
3147 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3148 WS_XML_ATTRIBUTE *attr;
3150 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
3151 return WS_E_INVALID_FORMAT;
3153 attr = elem->attributes[index];
3154 if (attr->value->textType != WS_XML_TEXT_TYPE_UTF8)
3156 FIXME( "text type %u not supported\n", attr->value->textType );
3157 return E_NOTIMPL;
3159 *ret = (WS_XML_UTF8_TEXT *)attr->value;
3160 return S_OK;
3163 static BOOL find_attribute( struct reader *reader, const WS_XML_STRING *localname,
3164 const WS_XML_STRING *ns, ULONG *index )
3166 ULONG i;
3167 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3169 if (!localname)
3171 *index = reader->current_attr;
3172 return TRUE;
3174 for (i = 0; i < elem->attributeCount; i++)
3176 const WS_XML_STRING *localname2 = elem->attributes[i]->localName;
3177 const WS_XML_STRING *ns2 = elem->attributes[i]->ns;
3179 if (!cmp_name( localname->bytes, localname->length, localname2->bytes, localname2->length ) &&
3180 !cmp_name( ns->bytes, ns->length, ns2->bytes, ns2->length ))
3182 *index = i;
3183 return TRUE;
3186 return FALSE;
3189 /**************************************************************************
3190 * WsFindAttribute [webservices.@]
3192 HRESULT WINAPI WsFindAttribute( WS_XML_READER *handle, const WS_XML_STRING *localname,
3193 const WS_XML_STRING *ns, BOOL required, ULONG *index,
3194 WS_ERROR *error )
3196 struct reader *reader = (struct reader *)handle;
3197 HRESULT hr = S_OK;
3199 TRACE( "%p %s %s %d %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
3200 required, index, error );
3201 if (error) FIXME( "ignoring error parameter\n" );
3203 if (!reader || !localname || !ns || !index) return E_INVALIDARG;
3205 EnterCriticalSection( &reader->cs );
3207 if (reader->magic != READER_MAGIC)
3209 LeaveCriticalSection( &reader->cs );
3210 return E_INVALIDARG;
3213 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
3215 LeaveCriticalSection( &reader->cs );
3216 return WS_E_INVALID_OPERATION;
3219 if (!find_attribute( reader, localname, ns, index ))
3221 if (required) hr = WS_E_INVALID_FORMAT;
3222 else
3224 *index = ~0u;
3225 hr = S_FALSE;
3229 LeaveCriticalSection( &reader->cs );
3230 return hr;
3233 static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
3234 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3235 WS_XML_UTF8_TEXT **ret, BOOL *found )
3237 switch (mapping)
3239 case WS_ATTRIBUTE_TYPE_MAPPING:
3241 ULONG index;
3242 if (!(*found = find_attribute( reader, localname, ns, &index ))) return S_OK;
3243 return read_get_attribute_text( reader, index, ret );
3245 case WS_ELEMENT_TYPE_MAPPING:
3246 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
3247 case WS_ANY_ELEMENT_TYPE_MAPPING:
3249 HRESULT hr;
3250 *found = TRUE;
3251 if (localname)
3253 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3255 if (WsXmlStringEquals( localname, elem->localName, NULL ) != S_OK ||
3256 WsXmlStringEquals( ns, elem->ns, NULL ) != S_OK)
3258 *found = FALSE;
3259 return S_OK;
3261 if ((hr = read_startelement( reader )) != S_OK) return hr;
3263 return read_get_node_text( reader, ret );
3265 default:
3266 FIXME( "mapping %u not supported\n", mapping );
3267 return E_NOTIMPL;
3271 static HRESULT read_type_bool( struct reader *reader, WS_TYPE_MAPPING mapping,
3272 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3273 const WS_BOOL_DESCRIPTION *desc, WS_READ_OPTION option,
3274 WS_HEAP *heap, void *ret, ULONG size )
3276 WS_XML_UTF8_TEXT *utf8;
3277 HRESULT hr;
3278 BOOL found, val = FALSE;
3280 if (desc)
3282 FIXME( "description not supported\n" );
3283 return E_NOTIMPL;
3285 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3286 if (found)
3288 ULONG len = utf8->value.length;
3289 if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) val = TRUE;
3290 else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) val = TRUE;
3291 else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) val = FALSE;
3292 else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) val = FALSE;
3293 else return WS_E_INVALID_FORMAT;
3296 switch (option)
3298 case WS_READ_REQUIRED_VALUE:
3299 if (!found) return WS_E_INVALID_FORMAT;
3300 /* fall through */
3302 case WS_READ_NILLABLE_VALUE:
3303 if (size != sizeof(BOOL)) return E_INVALIDARG;
3304 *(BOOL *)ret = val;
3305 break;
3307 case WS_READ_REQUIRED_POINTER:
3308 if (!found) return WS_E_INVALID_FORMAT;
3309 /* fall through */
3311 case WS_READ_OPTIONAL_POINTER:
3312 case WS_READ_NILLABLE_POINTER:
3314 BOOL *heap_val = NULL;
3315 if (size != sizeof(heap_val)) return E_INVALIDARG;
3316 if (found)
3318 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3319 *heap_val = val;
3321 *(BOOL **)ret = heap_val;
3322 break;
3324 default:
3325 FIXME( "read option %u not supported\n", option );
3326 return E_NOTIMPL;
3329 return S_OK;
3332 static HRESULT read_type_int8( struct reader *reader, WS_TYPE_MAPPING mapping,
3333 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3334 const WS_INT8_DESCRIPTION *desc, WS_READ_OPTION option,
3335 WS_HEAP *heap, void *ret, ULONG size )
3337 WS_XML_UTF8_TEXT *utf8;
3338 HRESULT hr;
3339 INT64 val = 0;
3340 BOOL found;
3342 if (desc)
3344 FIXME( "description not supported\n" );
3345 return E_NOTIMPL;
3347 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3348 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
3349 return hr;
3351 switch (option)
3353 case WS_READ_REQUIRED_VALUE:
3354 if (!found) return WS_E_INVALID_FORMAT;
3355 /* fall through */
3357 case WS_READ_NILLABLE_VALUE:
3358 if (size != sizeof(INT8)) return E_INVALIDARG;
3359 *(INT8 *)ret = val;
3360 break;
3362 case WS_READ_REQUIRED_POINTER:
3363 if (!found) return WS_E_INVALID_FORMAT;
3364 /* fall through */
3366 case WS_READ_OPTIONAL_POINTER:
3367 case WS_READ_NILLABLE_POINTER:
3369 INT8 *heap_val = NULL;
3370 if (size != sizeof(heap_val)) return E_INVALIDARG;
3371 if (found)
3373 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3374 *heap_val = val;
3376 *(INT8 **)ret = heap_val;
3377 break;
3379 default:
3380 FIXME( "read option %u not supported\n", option );
3381 return E_NOTIMPL;
3384 return S_OK;
3387 static HRESULT read_type_int16( struct reader *reader, WS_TYPE_MAPPING mapping,
3388 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3389 const WS_INT16_DESCRIPTION *desc, WS_READ_OPTION option,
3390 WS_HEAP *heap, void *ret, ULONG size )
3392 WS_XML_UTF8_TEXT *utf8;
3393 HRESULT hr;
3394 INT64 val = 0;
3395 BOOL found;
3397 if (desc)
3399 FIXME( "description not supported\n" );
3400 return E_NOTIMPL;
3402 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3403 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
3404 return hr;
3406 switch (option)
3408 case WS_READ_REQUIRED_VALUE:
3409 if (!found) return WS_E_INVALID_FORMAT;
3410 /* fall through */
3412 case WS_READ_NILLABLE_VALUE:
3413 if (size != sizeof(INT16)) return E_INVALIDARG;
3414 *(INT16 *)ret = val;
3415 break;
3417 case WS_READ_REQUIRED_POINTER:
3418 if (!found) return WS_E_INVALID_FORMAT;
3419 /* fall through */
3421 case WS_READ_OPTIONAL_POINTER:
3422 case WS_READ_NILLABLE_POINTER:
3424 INT16 *heap_val = NULL;
3425 if (size != sizeof(heap_val)) return E_INVALIDARG;
3426 if (found)
3428 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3429 *heap_val = val;
3431 *(INT16 **)ret = heap_val;
3432 break;
3434 default:
3435 FIXME( "read option %u not supported\n", option );
3436 return E_NOTIMPL;
3439 return S_OK;
3442 static HRESULT read_type_int32( struct reader *reader, WS_TYPE_MAPPING mapping,
3443 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3444 const WS_INT32_DESCRIPTION *desc, WS_READ_OPTION option,
3445 WS_HEAP *heap, void *ret, ULONG size )
3447 WS_XML_UTF8_TEXT *utf8;
3448 HRESULT hr;
3449 INT64 val = 0;
3450 BOOL found;
3452 if (desc)
3454 FIXME( "description not supported\n" );
3455 return E_NOTIMPL;
3457 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3458 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
3459 return hr;
3461 switch (option)
3463 case WS_READ_REQUIRED_VALUE:
3464 if (!found) return WS_E_INVALID_FORMAT;
3465 /* fall through */
3467 case WS_READ_NILLABLE_VALUE:
3468 if (size != sizeof(INT32)) return E_INVALIDARG;
3469 *(INT32 *)ret = val;
3470 break;
3472 case WS_READ_REQUIRED_POINTER:
3473 if (!found) return WS_E_INVALID_FORMAT;
3474 /* fall through */
3476 case WS_READ_OPTIONAL_POINTER:
3477 case WS_READ_NILLABLE_POINTER:
3479 INT32 *heap_val = NULL;
3480 if (size != sizeof(heap_val)) return E_INVALIDARG;
3481 if (found)
3483 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3484 *heap_val = val;
3486 *(INT32 **)ret = heap_val;
3487 break;
3489 default:
3490 FIXME( "read option %u not supported\n", option );
3491 return E_NOTIMPL;
3494 return S_OK;
3497 static HRESULT read_type_int64( struct reader *reader, WS_TYPE_MAPPING mapping,
3498 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3499 const WS_INT64_DESCRIPTION *desc, WS_READ_OPTION option,
3500 WS_HEAP *heap, void *ret, ULONG size )
3502 WS_XML_UTF8_TEXT *utf8;
3503 HRESULT hr;
3504 INT64 val = 0;
3505 BOOL found;
3507 if (desc)
3509 FIXME( "description not supported\n" );
3510 return E_NOTIMPL;
3512 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3513 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
3514 return hr;
3516 switch (option)
3518 case WS_READ_REQUIRED_VALUE:
3519 if (!found) return WS_E_INVALID_FORMAT;
3520 /* fall through */
3522 case WS_READ_NILLABLE_VALUE:
3523 if (size != sizeof(INT64)) return E_INVALIDARG;
3524 *(INT64 *)ret = val;
3525 break;
3527 case WS_READ_REQUIRED_POINTER:
3528 if (!found) return WS_E_INVALID_FORMAT;
3529 /* fall through */
3531 case WS_READ_OPTIONAL_POINTER:
3532 case WS_READ_NILLABLE_POINTER:
3534 INT64 *heap_val = NULL;
3535 if (size != sizeof(heap_val)) return E_INVALIDARG;
3536 if (found)
3538 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3539 *heap_val = val;
3541 *(INT64 **)ret = heap_val;
3542 break;
3544 default:
3545 FIXME( "read option %u not supported\n", option );
3546 return E_NOTIMPL;
3549 return S_OK;
3552 static HRESULT read_type_uint8( struct reader *reader, WS_TYPE_MAPPING mapping,
3553 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3554 const WS_UINT8_DESCRIPTION *desc, WS_READ_OPTION option,
3555 WS_HEAP *heap, void *ret, ULONG size )
3557 WS_XML_UTF8_TEXT *utf8;
3558 HRESULT hr;
3559 UINT64 val = 0;
3560 BOOL found;
3562 if (desc)
3564 FIXME( "description not supported\n" );
3565 return E_NOTIMPL;
3567 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3568 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
3569 return hr;
3571 switch (option)
3573 case WS_READ_REQUIRED_VALUE:
3574 if (!found) return WS_E_INVALID_FORMAT;
3575 /* fall through */
3577 case WS_READ_NILLABLE_VALUE:
3578 if (size != sizeof(UINT8)) return E_INVALIDARG;
3579 *(UINT8 *)ret = val;
3580 break;
3582 case WS_READ_REQUIRED_POINTER:
3583 if (!found) return WS_E_INVALID_FORMAT;
3584 /* fall through */
3586 case WS_READ_OPTIONAL_POINTER:
3587 case WS_READ_NILLABLE_POINTER:
3589 UINT8 *heap_val = NULL;
3590 if (size != sizeof(heap_val)) return E_INVALIDARG;
3591 if (found)
3593 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3594 *heap_val = val;
3596 *(UINT8 **)ret = heap_val;
3597 break;
3599 default:
3600 FIXME( "read option %u not supported\n", option );
3601 return E_NOTIMPL;
3604 return S_OK;
3607 static HRESULT read_type_uint16( struct reader *reader, WS_TYPE_MAPPING mapping,
3608 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3609 const WS_UINT16_DESCRIPTION *desc, WS_READ_OPTION option,
3610 WS_HEAP *heap, void *ret, ULONG size )
3612 WS_XML_UTF8_TEXT *utf8;
3613 HRESULT hr;
3614 UINT64 val = 0;
3615 BOOL found;
3617 if (desc)
3619 FIXME( "description not supported\n" );
3620 return E_NOTIMPL;
3622 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3623 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
3624 return hr;
3626 switch (option)
3628 case WS_READ_REQUIRED_VALUE:
3629 if (!found) return WS_E_INVALID_FORMAT;
3630 /* fall through */
3632 case WS_READ_NILLABLE_VALUE:
3633 if (size != sizeof(UINT16)) return E_INVALIDARG;
3634 *(UINT16 *)ret = val;
3635 break;
3637 case WS_READ_REQUIRED_POINTER:
3638 if (!found) return WS_E_INVALID_FORMAT;
3639 /* fall through */
3641 case WS_READ_OPTIONAL_POINTER:
3642 case WS_READ_NILLABLE_POINTER:
3644 UINT16 *heap_val = NULL;
3645 if (size != sizeof(heap_val)) return E_INVALIDARG;
3646 if (found)
3648 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3649 *heap_val = val;
3651 *(UINT16 **)ret = heap_val;
3652 break;
3654 default:
3655 FIXME( "read option %u not supported\n", option );
3656 return E_NOTIMPL;
3659 return S_OK;
3662 static HRESULT read_type_uint32( struct reader *reader, WS_TYPE_MAPPING mapping,
3663 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3664 const WS_UINT32_DESCRIPTION *desc, WS_READ_OPTION option,
3665 WS_HEAP *heap, void *ret, ULONG size )
3667 WS_XML_UTF8_TEXT *utf8;
3668 HRESULT hr;
3669 UINT64 val = 0;
3670 BOOL found;
3672 if (desc)
3674 FIXME( "description not supported\n" );
3675 return E_NOTIMPL;
3677 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3678 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
3679 return hr;
3681 switch (option)
3683 case WS_READ_REQUIRED_VALUE:
3684 if (!found) return WS_E_INVALID_FORMAT;
3685 /* fall through */
3687 case WS_READ_NILLABLE_VALUE:
3688 if (size != sizeof(UINT32)) return E_INVALIDARG;
3689 *(UINT32 *)ret = val;
3690 break;
3692 case WS_READ_REQUIRED_POINTER:
3693 if (!found) return WS_E_INVALID_FORMAT;
3694 /* fall through */
3696 case WS_READ_OPTIONAL_POINTER:
3697 case WS_READ_NILLABLE_POINTER:
3699 UINT32 *heap_val = NULL;
3700 if (size != sizeof(heap_val)) return E_INVALIDARG;
3701 if (found)
3703 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3704 *heap_val = val;
3706 *(UINT32 **)ret = heap_val;
3707 break;
3709 default:
3710 FIXME( "read option %u not supported\n", option );
3711 return E_NOTIMPL;
3714 return S_OK;
3717 static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
3718 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3719 const WS_UINT64_DESCRIPTION *desc, WS_READ_OPTION option,
3720 WS_HEAP *heap, void *ret, ULONG size )
3722 WS_XML_UTF8_TEXT *utf8;
3723 HRESULT hr;
3724 UINT64 val = 0;
3725 BOOL found;
3727 if (desc)
3729 FIXME( "description not supported\n" );
3730 return E_NOTIMPL;
3732 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3733 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
3734 return hr;
3736 switch (option)
3738 case WS_READ_REQUIRED_VALUE:
3739 if (!found) return WS_E_INVALID_FORMAT;
3740 /* fall through */
3742 case WS_READ_NILLABLE_VALUE:
3743 if (size != sizeof(UINT64)) return E_INVALIDARG;
3744 *(UINT64 *)ret = val;
3745 break;
3747 case WS_READ_REQUIRED_POINTER:
3748 if (!found) return WS_E_INVALID_FORMAT;
3749 /* fall through */
3751 case WS_READ_OPTIONAL_POINTER:
3752 case WS_READ_NILLABLE_POINTER:
3754 UINT64 *heap_val = NULL;
3755 if (size != sizeof(heap_val)) return E_INVALIDARG;
3756 if (found)
3758 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3759 *heap_val = val;
3761 *(UINT64 **)ret = heap_val;
3762 break;
3764 default:
3765 FIXME( "read option %u not supported\n", option );
3766 return E_NOTIMPL;
3769 return S_OK;
3772 static HRESULT read_type_double( struct reader *reader, WS_TYPE_MAPPING mapping,
3773 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3774 const WS_DOUBLE_DESCRIPTION *desc, WS_READ_OPTION option,
3775 WS_HEAP *heap, void *ret, ULONG size )
3777 WS_XML_UTF8_TEXT *utf8;
3778 HRESULT hr;
3779 double val = 0.0;
3780 BOOL found;
3782 if (desc) FIXME( "ignoring description\n" );
3784 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3785 if (found && (hr = str_to_double( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3787 switch (option)
3789 case WS_READ_REQUIRED_VALUE:
3790 if (!found) return WS_E_INVALID_FORMAT;
3791 /* fall through */
3793 case WS_READ_NILLABLE_VALUE:
3794 if (size != sizeof(double)) return E_INVALIDARG;
3795 *(double *)ret = val;
3796 break;
3798 case WS_READ_REQUIRED_POINTER:
3799 if (!found) return WS_E_INVALID_FORMAT;
3800 /* fall through */
3802 case WS_READ_OPTIONAL_POINTER:
3803 case WS_READ_NILLABLE_POINTER:
3805 double *heap_val = NULL;
3806 if (size != sizeof(heap_val)) return E_INVALIDARG;
3807 if (found)
3809 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3810 *heap_val = val;
3812 *(double **)ret = heap_val;
3813 break;
3815 default:
3816 FIXME( "read option %u not supported\n", option );
3817 return E_NOTIMPL;
3820 return S_OK;
3823 static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
3824 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3825 const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
3826 WS_HEAP *heap, WCHAR **ret, ULONG size )
3828 WS_XML_UTF8_TEXT *utf8;
3829 HRESULT hr;
3830 WCHAR *str = NULL;
3831 BOOL found;
3833 if (desc)
3835 FIXME( "description not supported\n" );
3836 return E_NOTIMPL;
3838 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3839 if (found && !(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
3841 switch (option)
3843 case WS_READ_REQUIRED_POINTER:
3844 if (!found) return WS_E_INVALID_FORMAT;
3845 /* fall through */
3847 case WS_READ_OPTIONAL_POINTER:
3848 case WS_READ_NILLABLE_POINTER:
3849 if (size != sizeof(str)) return E_INVALIDARG;
3850 *ret = str;
3851 break;
3853 default:
3854 FIXME( "read option %u not supported\n", option );
3855 return E_NOTIMPL;
3858 return S_OK;
3861 static HRESULT get_enum_value( const WS_XML_UTF8_TEXT *text, const WS_ENUM_DESCRIPTION *desc, int *ret )
3863 ULONG i;
3864 for (i = 0; i < desc->valueCount; i++)
3866 if (WsXmlStringEquals( &text->value, desc->values[i].name, NULL ) == S_OK)
3868 *ret = desc->values[i].value;
3869 return S_OK;
3872 return WS_E_INVALID_FORMAT;
3875 static HRESULT read_type_enum( struct reader *reader, WS_TYPE_MAPPING mapping,
3876 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3877 const WS_ENUM_DESCRIPTION *desc, WS_READ_OPTION option,
3878 WS_HEAP *heap, void *ret, ULONG size )
3880 WS_XML_UTF8_TEXT *utf8;
3881 HRESULT hr;
3882 int val = 0;
3883 BOOL found;
3885 if (!desc) return E_INVALIDARG;
3887 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3888 if (found && (hr = get_enum_value( utf8, desc, &val )) != S_OK) return hr;
3890 switch (option)
3892 case WS_READ_REQUIRED_VALUE:
3893 if (!found) return WS_E_INVALID_FORMAT;
3894 /* fall through */
3896 case WS_READ_NILLABLE_VALUE:
3897 if (size != sizeof(int)) return E_INVALIDARG;
3898 *(int *)ret = val;
3899 break;
3901 case WS_READ_REQUIRED_POINTER:
3902 if (!found) return WS_E_INVALID_FORMAT;
3903 /* fall through */
3905 case WS_READ_OPTIONAL_POINTER:
3906 case WS_READ_NILLABLE_POINTER:
3908 int *heap_val = NULL;
3909 if (size != sizeof(heap_val)) return E_INVALIDARG;
3910 if (found)
3912 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3913 *heap_val = val;
3915 *(int **)ret = heap_val;
3916 break;
3918 default:
3919 FIXME( "read option %u not supported\n", option );
3920 return E_NOTIMPL;
3923 return S_OK;
3926 static HRESULT read_type_datetime( struct reader *reader, WS_TYPE_MAPPING mapping,
3927 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3928 const WS_DATETIME_DESCRIPTION *desc, WS_READ_OPTION option,
3929 WS_HEAP *heap, void *ret, ULONG size )
3931 WS_XML_UTF8_TEXT *utf8;
3932 HRESULT hr;
3933 WS_DATETIME val = {0, WS_DATETIME_FORMAT_UTC};
3934 BOOL found;
3936 if (desc) FIXME( "ignoring description\n" );
3938 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3939 if (found && (hr = str_to_datetime( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3941 switch (option)
3943 case WS_READ_REQUIRED_VALUE:
3944 if (!found) return WS_E_INVALID_FORMAT;
3945 /* fall through */
3947 case WS_READ_NILLABLE_VALUE:
3948 if (size != sizeof(WS_DATETIME)) return E_INVALIDARG;
3949 *(WS_DATETIME *)ret = val;
3950 break;
3952 case WS_READ_REQUIRED_POINTER:
3953 if (!found) return WS_E_INVALID_FORMAT;
3954 /* fall through */
3956 case WS_READ_OPTIONAL_POINTER:
3957 case WS_READ_NILLABLE_POINTER:
3959 WS_DATETIME *heap_val = NULL;
3960 if (size != sizeof(heap_val)) return E_INVALIDARG;
3961 if (found)
3963 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3964 *heap_val = val;
3966 *(WS_DATETIME **)ret = heap_val;
3967 break;
3969 default:
3970 FIXME( "read option %u not supported\n", option );
3971 return E_NOTIMPL;
3974 return S_OK;
3977 static HRESULT read_type_guid( struct reader *reader, WS_TYPE_MAPPING mapping,
3978 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3979 const WS_GUID_DESCRIPTION *desc, WS_READ_OPTION option,
3980 WS_HEAP *heap, void *ret, ULONG size )
3982 WS_XML_UTF8_TEXT *utf8;
3983 GUID val = {0};
3984 HRESULT hr;
3985 BOOL found;
3987 if (desc) FIXME( "ignoring description\n" );
3989 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3990 if (found && (hr = str_to_guid( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3992 switch (option)
3994 case WS_READ_REQUIRED_VALUE:
3995 if (!found) return WS_E_INVALID_FORMAT;
3996 /* fall through */
3998 case WS_READ_NILLABLE_VALUE:
3999 if (size != sizeof(GUID)) return E_INVALIDARG;
4000 *(GUID *)ret = val;
4001 break;
4003 case WS_READ_REQUIRED_POINTER:
4004 if (!found) return WS_E_INVALID_FORMAT;
4005 /* fall through */
4007 case WS_READ_OPTIONAL_POINTER:
4008 case WS_READ_NILLABLE_POINTER:
4010 GUID *heap_val = NULL;
4011 if (size != sizeof(heap_val)) return E_INVALIDARG;
4012 if (found)
4014 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4015 *heap_val = val;
4017 *(GUID **)ret = heap_val;
4018 break;
4020 default:
4021 FIXME( "read option %u not supported\n", option );
4022 return E_NOTIMPL;
4025 return S_OK;
4028 static HRESULT read_type_bytes( struct reader *reader, WS_TYPE_MAPPING mapping,
4029 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4030 const WS_BYTES_DESCRIPTION *desc, WS_READ_OPTION option,
4031 WS_HEAP *heap, void *ret, ULONG size )
4033 WS_XML_UTF8_TEXT *utf8;
4034 WS_BYTES val = {0};
4035 HRESULT hr;
4036 BOOL found;
4038 if (desc) FIXME( "ignoring description\n" );
4040 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
4041 if (found && (hr = str_to_bytes( utf8->value.bytes, utf8->value.length, heap, &val )) != S_OK)
4042 return hr;
4044 switch (option)
4046 case WS_READ_REQUIRED_VALUE:
4047 if (!found) return WS_E_INVALID_FORMAT;
4048 /* fall through */
4050 case WS_READ_NILLABLE_VALUE:
4051 if (size != sizeof(WS_BYTES)) return E_INVALIDARG;
4052 *(WS_BYTES *)ret = val;
4053 break;
4055 case WS_READ_REQUIRED_POINTER:
4056 if (!found) return WS_E_INVALID_FORMAT;
4057 /* fall through */
4059 case WS_READ_OPTIONAL_POINTER:
4060 case WS_READ_NILLABLE_POINTER:
4062 WS_BYTES *heap_val = NULL;
4063 if (size != sizeof(heap_val)) return E_INVALIDARG;
4064 if (found)
4066 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
4067 *heap_val = val;
4069 *(WS_BYTES **)ret = heap_val;
4070 break;
4072 default:
4073 FIXME( "read option %u not supported\n", option );
4074 return E_NOTIMPL;
4077 return S_OK;
4080 static BOOL is_empty_text_node( const struct node *node )
4082 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
4083 const WS_XML_UTF8_TEXT *utf8;
4084 ULONG i;
4086 if (node_type( node ) != WS_XML_NODE_TYPE_TEXT) return FALSE;
4087 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
4089 ERR( "unhandled text type %u\n", text->text->textType );
4090 return FALSE;
4092 utf8 = (const WS_XML_UTF8_TEXT *)text->text;
4093 for (i = 0; i < utf8->value.length; i++) if (!read_isspace( utf8->value.bytes[i] )) return FALSE;
4094 return TRUE;
4097 static HRESULT read_next_node( struct reader *reader )
4099 if (reader->current == reader->last) return read_node( reader );
4100 if (move_to_child_node( &reader->current )) return S_OK;
4101 if (move_to_next_node( &reader->current )) return S_OK;
4102 if (!move_to_parent_node( &reader->current )) return WS_E_INVALID_FORMAT;
4103 if (move_to_next_node( &reader->current )) return S_OK;
4104 return WS_E_INVALID_FORMAT;
4107 /* skips comment and empty text nodes */
4108 static HRESULT read_type_next_node( struct reader *reader )
4110 for (;;)
4112 HRESULT hr;
4113 WS_XML_NODE_TYPE type;
4115 if ((hr = read_next_node( reader )) != S_OK) return hr;
4116 type = node_type( reader->current );
4117 if (type == WS_XML_NODE_TYPE_COMMENT ||
4118 (type == WS_XML_NODE_TYPE_TEXT && is_empty_text_node( reader->current ))) continue;
4119 return S_OK;
4123 static BOOL match_current_element( struct reader *reader, const WS_XML_STRING *localname,
4124 const WS_XML_STRING *ns )
4126 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
4127 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
4128 return WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK &&
4129 WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK;
4132 static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname,
4133 const WS_XML_STRING *ns )
4135 struct node *node;
4136 ULONG attr;
4137 HRESULT hr;
4139 if (!localname) return S_OK; /* assume reader is already correctly positioned */
4140 if (reader->current == reader->last)
4142 BOOL found;
4143 if ((hr = read_to_startelement( reader, &found )) != S_OK) return hr;
4144 if (!found) return WS_E_INVALID_FORMAT;
4146 if (match_current_element( reader, localname, ns )) return S_OK;
4148 node = reader->current;
4149 attr = reader->current_attr;
4151 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
4152 if (match_current_element( reader, localname, ns )) return S_OK;
4154 reader->current = node;
4155 reader->current_attr = attr;
4157 return WS_E_INVALID_FORMAT;
4160 ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
4162 switch (type)
4164 case WS_INT8_TYPE:
4165 case WS_UINT8_TYPE:
4166 return sizeof(INT8);
4168 case WS_INT16_TYPE:
4169 case WS_UINT16_TYPE:
4170 return sizeof(INT16);
4172 case WS_BOOL_TYPE:
4173 case WS_INT32_TYPE:
4174 case WS_UINT32_TYPE:
4175 case WS_ENUM_TYPE:
4176 return sizeof(INT32);
4178 case WS_INT64_TYPE:
4179 case WS_UINT64_TYPE:
4180 return sizeof(INT64);
4182 case WS_DOUBLE_TYPE:
4183 return sizeof(double);
4185 case WS_DATETIME_TYPE:
4186 return sizeof(WS_DATETIME);
4188 case WS_GUID_TYPE:
4189 return sizeof(GUID);
4191 case WS_STRING_TYPE:
4192 return sizeof(WS_STRING);
4194 case WS_WSZ_TYPE:
4195 return sizeof(WCHAR *);
4197 case WS_BYTES_TYPE:
4198 return sizeof(WS_BYTES);
4200 case WS_XML_STRING_TYPE:
4201 return sizeof(WS_XML_STRING);
4203 case WS_STRUCT_TYPE:
4204 return desc->size;
4206 case WS_DESCRIPTION_TYPE:
4207 return sizeof(WS_STRUCT_DESCRIPTION *);
4209 default:
4210 ERR( "unhandled type %u\n", type );
4211 return 0;
4215 static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options )
4217 if (options & WS_FIELD_POINTER)
4219 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
4220 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
4221 return WS_READ_REQUIRED_POINTER;
4224 switch (type)
4226 case WS_BOOL_TYPE:
4227 case WS_INT8_TYPE:
4228 case WS_INT16_TYPE:
4229 case WS_INT32_TYPE:
4230 case WS_INT64_TYPE:
4231 case WS_UINT8_TYPE:
4232 case WS_UINT16_TYPE:
4233 case WS_UINT32_TYPE:
4234 case WS_UINT64_TYPE:
4235 case WS_DOUBLE_TYPE:
4236 case WS_DATETIME_TYPE:
4237 case WS_GUID_TYPE:
4238 case WS_STRING_TYPE:
4239 case WS_BYTES_TYPE:
4240 case WS_XML_STRING_TYPE:
4241 case WS_STRUCT_TYPE:
4242 case WS_ENUM_TYPE:
4243 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_READ_NILLABLE_VALUE;
4244 return WS_READ_REQUIRED_VALUE;
4246 case WS_WSZ_TYPE:
4247 case WS_DESCRIPTION_TYPE:
4248 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
4249 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
4250 return WS_READ_REQUIRED_POINTER;
4252 default:
4253 FIXME( "unhandled type %u\n", type );
4254 return 0;
4258 static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
4259 const WS_XML_STRING *, const void *, WS_READ_OPTION, WS_HEAP *,
4260 void *, ULONG );
4262 static HRESULT read_type_repeating_element( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4263 WS_HEAP *heap, void **ret, ULONG *count )
4265 HRESULT hr;
4266 ULONG item_size, nb_items = 0, nb_allocated = 1, offset = 0;
4267 WS_READ_OPTION option;
4268 char *buf;
4270 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
4272 /* wrapper element */
4273 if (desc->localName && ((hr = read_type_next_element_node( reader, desc->localName, desc->ns )) != S_OK))
4274 return hr;
4276 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
4277 item_size = get_type_size( desc->type, desc->typeDescription );
4278 else
4279 item_size = sizeof(void *);
4281 if (!(buf = ws_alloc_zero( heap, item_size ))) return WS_E_QUOTA_EXCEEDED;
4282 for (;;)
4284 if (nb_items >= nb_allocated)
4286 SIZE_T old_size = nb_allocated * item_size, new_size = old_size * 2;
4287 if (!(buf = ws_realloc_zero( heap, buf, old_size, new_size )))
4288 return WS_E_QUOTA_EXCEEDED;
4289 nb_allocated *= 2;
4291 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs,
4292 desc->typeDescription, option, heap, buf + offset, item_size );
4293 if (hr == WS_E_INVALID_FORMAT) break;
4294 if (hr != S_OK)
4296 ws_free( heap, buf, nb_allocated * item_size );
4297 return hr;
4299 offset += item_size;
4300 nb_items++;
4303 if (desc->localName && ((hr = read_type_next_node( reader )) != S_OK)) return hr;
4305 if (desc->itemRange && (nb_items < desc->itemRange->minItemCount || nb_items > desc->itemRange->maxItemCount))
4307 TRACE( "number of items %u out of range (%u-%u)\n", nb_items, desc->itemRange->minItemCount,
4308 desc->itemRange->maxItemCount );
4309 ws_free( heap, buf, nb_allocated * item_size );
4310 return WS_E_INVALID_FORMAT;
4313 *count = nb_items;
4314 *ret = buf;
4316 return S_OK;
4319 static HRESULT read_type_text( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4320 WS_READ_OPTION option, WS_HEAP *heap, void *ret, ULONG size )
4322 HRESULT hr;
4323 if (reader->current == reader->last)
4325 BOOL found;
4326 if ((hr = read_to_startelement( reader, &found )) != S_OK) return S_OK;
4327 if (!found) return WS_E_INVALID_FORMAT;
4329 if ((hr = read_next_node( reader )) != S_OK) return hr;
4330 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT) return WS_E_INVALID_FORMAT;
4332 return read_type( reader, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, NULL, NULL,
4333 desc->typeDescription, option, heap, ret, size );
4336 static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
4337 WS_HEAP *heap, char *buf, ULONG offset )
4339 char *ptr;
4340 WS_READ_OPTION option;
4341 ULONG size;
4342 HRESULT hr;
4344 if (!desc) return E_INVALIDARG;
4345 if (desc->options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
4347 FIXME( "options %08x not supported\n", desc->options );
4348 return E_NOTIMPL;
4350 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
4352 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
4353 size = get_type_size( desc->type, desc->typeDescription );
4354 else
4355 size = sizeof(void *);
4357 ptr = buf + offset;
4358 switch (desc->mapping)
4360 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
4361 FIXME( "WS_TYPE_ATTRIBUTE_FIELD_MAPPING not supported\n" );
4362 return S_OK;
4364 case WS_ATTRIBUTE_FIELD_MAPPING:
4365 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4366 desc->typeDescription, option, heap, ptr, size );
4367 break;
4369 case WS_ELEMENT_FIELD_MAPPING:
4370 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4371 desc->typeDescription, option, heap, ptr, size );
4372 break;
4374 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
4376 ULONG count;
4377 hr = read_type_repeating_element( reader, desc, heap, (void **)ptr, &count );
4378 if (hr == S_OK) *(ULONG *)(buf + desc->countOffset) = count;
4379 break;
4381 case WS_TEXT_FIELD_MAPPING:
4382 hr = read_type_text( reader, desc, option, heap, ptr, size );
4383 break;
4385 default:
4386 FIXME( "unhandled field mapping %u\n", desc->mapping );
4387 return E_NOTIMPL;
4390 if (hr == WS_E_INVALID_FORMAT)
4392 switch (option)
4394 case WS_READ_REQUIRED_VALUE:
4395 case WS_READ_REQUIRED_POINTER:
4396 return WS_E_INVALID_FORMAT;
4398 case WS_READ_NILLABLE_VALUE:
4399 if (desc->defaultValue) memcpy( ptr, desc->defaultValue->value, desc->defaultValue->valueSize );
4400 return S_OK;
4402 case WS_READ_OPTIONAL_POINTER:
4403 case WS_READ_NILLABLE_POINTER:
4404 *(void **)ptr = NULL;
4405 return S_OK;
4407 default:
4408 ERR( "unhandled option %u\n", option );
4409 return E_NOTIMPL;
4413 return hr;
4416 static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
4417 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4418 const WS_STRUCT_DESCRIPTION *desc, WS_READ_OPTION option,
4419 WS_HEAP *heap, void *ret, ULONG size )
4421 ULONG i, offset;
4422 HRESULT hr;
4423 char *buf;
4425 if (!desc) return E_INVALIDARG;
4426 if (desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4428 FIXME( "struct options %08x not supported\n",
4429 desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT );
4432 switch (option)
4434 case WS_READ_REQUIRED_POINTER:
4435 case WS_READ_OPTIONAL_POINTER:
4436 case WS_READ_NILLABLE_POINTER:
4437 if (size != sizeof(void *)) return E_INVALIDARG;
4438 if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
4439 break;
4441 case WS_READ_REQUIRED_VALUE:
4442 case WS_READ_NILLABLE_VALUE:
4443 if (size != desc->size) return E_INVALIDARG;
4444 buf = ret;
4445 break;
4447 default:
4448 FIXME( "unhandled read option %u\n", option );
4449 return E_NOTIMPL;
4452 for (i = 0; i < desc->fieldCount; i++)
4454 offset = desc->fields[i]->offset;
4455 if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, offset )) != S_OK)
4456 break;
4459 switch (option)
4461 case WS_READ_REQUIRED_POINTER:
4462 if (hr != S_OK)
4464 ws_free( heap, buf, desc->size );
4465 return hr;
4467 *(char **)ret = buf;
4468 break;
4470 case WS_READ_OPTIONAL_POINTER:
4471 case WS_READ_NILLABLE_POINTER:
4472 if (is_nil_value( buf, desc->size ))
4474 ws_free( heap, buf, desc->size );
4475 buf = NULL;
4477 *(char **)ret = buf;
4478 break;
4480 case WS_READ_REQUIRED_VALUE:
4481 case WS_READ_NILLABLE_VALUE:
4482 if (hr != S_OK) return hr;
4483 break;
4485 default:
4486 ERR( "unhandled read option %u\n", option );
4487 return E_NOTIMPL;
4490 if (desc->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4492 struct node *parent = find_parent( reader );
4493 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
4495 return S_OK;
4498 static HRESULT start_mapping( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname,
4499 const WS_XML_STRING *ns )
4501 switch (mapping)
4503 case WS_ELEMENT_TYPE_MAPPING:
4504 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4505 return read_type_next_element_node( reader, localname, ns );
4507 case WS_ANY_ELEMENT_TYPE_MAPPING:
4508 case WS_ATTRIBUTE_TYPE_MAPPING:
4509 return S_OK;
4511 default:
4512 FIXME( "unhandled mapping %u\n", mapping );
4513 return E_NOTIMPL;
4517 static HRESULT read_type_endelement_node( struct reader *reader )
4519 const struct node *parent = find_parent( reader );
4520 HRESULT hr;
4522 for (;;)
4524 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
4525 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT && reader->current->parent == parent)
4527 return S_OK;
4529 if (read_end_of_data( reader ) || !(parent->flags & NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT)) break;
4532 return WS_E_INVALID_FORMAT;
4535 static HRESULT end_mapping( struct reader *reader, WS_TYPE_MAPPING mapping )
4537 switch (mapping)
4539 case WS_ELEMENT_TYPE_MAPPING:
4540 return read_type_endelement_node( reader );
4542 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4543 return read_type_next_node( reader );
4545 case WS_ATTRIBUTE_TYPE_MAPPING:
4546 default:
4547 return S_OK;
4551 static HRESULT is_nil_element( const WS_XML_ELEMENT_NODE *elem )
4553 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
4554 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
4555 ULONG i;
4557 for (i = 0; i < elem->attributeCount; i++)
4559 const WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)elem->attributes[i]->value;
4561 if (elem->attributes[i]->isXmlNs) continue;
4562 if (WsXmlStringEquals( elem->attributes[i]->localName, &localname, NULL ) == S_OK &&
4563 WsXmlStringEquals( elem->attributes[i]->ns, &ns, NULL ) == S_OK &&
4564 text->value.length == 4 && !memcmp( text->value.bytes, "true", 4 )) return TRUE;
4566 return FALSE;
4569 static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYPE type,
4570 const WS_XML_STRING *localname, const WS_XML_STRING *ns, const void *desc,
4571 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
4573 HRESULT hr;
4575 if ((hr = start_mapping( reader, mapping, localname, ns )) != S_OK) return hr;
4577 if (mapping == WS_ELEMENT_TYPE_MAPPING && is_nil_element( &reader->current->hdr ))
4579 if (option != WS_READ_NILLABLE_POINTER && option != WS_READ_NILLABLE_VALUE) return WS_E_INVALID_FORMAT;
4580 return end_mapping( reader, mapping );
4583 switch (type)
4585 case WS_BOOL_TYPE:
4586 if ((hr = read_type_bool( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4587 return hr;
4588 break;
4590 case WS_INT8_TYPE:
4591 if ((hr = read_type_int8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4592 return hr;
4593 break;
4595 case WS_INT16_TYPE:
4596 if ((hr = read_type_int16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4597 return hr;
4598 break;
4600 case WS_INT32_TYPE:
4601 if ((hr = read_type_int32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4602 return hr;
4603 break;
4605 case WS_INT64_TYPE:
4606 if ((hr = read_type_int64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4607 return hr;
4608 break;
4610 case WS_UINT8_TYPE:
4611 if ((hr = read_type_uint8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4612 return hr;
4613 break;
4615 case WS_UINT16_TYPE:
4616 if ((hr = read_type_uint16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4617 return hr;
4618 break;
4620 case WS_UINT32_TYPE:
4621 if ((hr = read_type_uint32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4622 return hr;
4623 break;
4625 case WS_UINT64_TYPE:
4626 if ((hr = read_type_uint64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4627 return hr;
4628 break;
4630 case WS_DOUBLE_TYPE:
4631 if ((hr = read_type_double( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4632 return hr;
4633 break;
4635 case WS_DATETIME_TYPE:
4636 if ((hr = read_type_datetime( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4637 return hr;
4638 break;
4640 case WS_GUID_TYPE:
4641 if ((hr = read_type_guid( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4642 return hr;
4643 break;
4645 case WS_WSZ_TYPE:
4646 if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4647 return hr;
4648 break;
4650 case WS_BYTES_TYPE:
4651 if ((hr = read_type_bytes( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4652 return hr;
4653 break;
4655 case WS_STRUCT_TYPE:
4656 if ((hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4657 return hr;
4658 break;
4660 case WS_ENUM_TYPE:
4661 if ((hr = read_type_enum( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4662 return hr;
4663 break;
4665 default:
4666 FIXME( "type %u not supported\n", type );
4667 return E_NOTIMPL;
4670 return end_mapping( reader, mapping );
4673 /**************************************************************************
4674 * WsReadType [webservices.@]
4676 HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4677 const void *desc, WS_READ_OPTION option, WS_HEAP *heap, void *value,
4678 ULONG size, WS_ERROR *error )
4680 struct reader *reader = (struct reader *)handle;
4681 HRESULT hr;
4683 TRACE( "%p %u %u %p %u %p %p %u %p\n", handle, mapping, type, desc, option, heap, value,
4684 size, error );
4685 if (error) FIXME( "ignoring error parameter\n" );
4687 if (!reader || !value) return E_INVALIDARG;
4689 EnterCriticalSection( &reader->cs );
4691 if (reader->magic != READER_MAGIC)
4693 LeaveCriticalSection( &reader->cs );
4694 return E_INVALIDARG;
4697 if ((hr = read_type( reader, mapping, type, NULL, NULL, desc, option, heap, value, size )) != S_OK)
4699 LeaveCriticalSection( &reader->cs );
4700 return hr;
4703 switch (mapping)
4705 case WS_ELEMENT_TYPE_MAPPING:
4706 hr = read_node( reader );
4707 break;
4709 default:
4710 break;
4713 if (hr == S_OK && !read_end_of_data( reader )) hr = WS_E_INVALID_FORMAT;
4715 LeaveCriticalSection( &reader->cs );
4716 return hr;
4719 /**************************************************************************
4720 * WsReadElement [webservices.@]
4722 HRESULT WINAPI WsReadElement( WS_XML_READER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4723 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
4724 WS_ERROR *error )
4726 struct reader *reader = (struct reader *)handle;
4727 HRESULT hr;
4729 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
4730 if (error) FIXME( "ignoring error parameter\n" );
4732 if (!reader || !desc || !value) return E_INVALIDARG;
4734 EnterCriticalSection( &reader->cs );
4736 if (reader->magic != READER_MAGIC)
4738 LeaveCriticalSection( &reader->cs );
4739 return E_INVALIDARG;
4742 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->elementLocalName,
4743 desc->elementNs, desc->typeDescription, option, heap, value, size );
4745 LeaveCriticalSection( &reader->cs );
4746 return hr;
4749 /**************************************************************************
4750 * WsReadValue [webservices.@]
4752 HRESULT WINAPI WsReadValue( WS_XML_READER *handle, WS_VALUE_TYPE value_type, void *value, ULONG size,
4753 WS_ERROR *error )
4755 struct reader *reader = (struct reader *)handle;
4756 WS_TYPE type = map_value_type( value_type );
4757 HRESULT hr;
4759 TRACE( "%p %u %p %u %p\n", handle, type, value, size, error );
4760 if (error) FIXME( "ignoring error parameter\n" );
4762 if (!reader || !value || type == ~0u) return E_INVALIDARG;
4764 EnterCriticalSection( &reader->cs );
4766 if (reader->magic != READER_MAGIC)
4768 LeaveCriticalSection( &reader->cs );
4769 return E_INVALIDARG;
4772 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, type, NULL, NULL, NULL, WS_READ_REQUIRED_VALUE,
4773 NULL, value, size );
4775 LeaveCriticalSection( &reader->cs );
4776 return hr;
4779 static inline BOOL is_utf8( const unsigned char *data, ULONG size, ULONG *offset )
4781 static const char bom[] = {0xef,0xbb,0xbf};
4782 const unsigned char *p = data;
4784 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4785 (size > 2 && !(*offset = 0));
4788 static inline BOOL is_utf16le( const unsigned char *data, ULONG size, ULONG *offset )
4790 static const char bom[] = {0xff,0xfe};
4791 const unsigned char *p = data;
4793 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4794 (size >= 4 && p[0] == '<' && !p[1] && !(*offset = 0));
4797 static WS_CHARSET detect_charset( const unsigned char *data, ULONG size, ULONG *offset )
4799 WS_CHARSET ret = 0;
4801 /* FIXME: parse xml declaration */
4803 if (is_utf16le( data, size, offset )) ret = WS_CHARSET_UTF16LE;
4804 else if (is_utf8( data, size, offset )) ret = WS_CHARSET_UTF8;
4805 else
4807 FIXME( "charset not recognized\n" );
4808 return 0;
4811 TRACE( "detected charset %u\n", ret );
4812 return ret;
4815 static void set_input_buffer( struct reader *reader, struct xmlbuf *buf, const unsigned char *data, ULONG size )
4817 reader->input_type = WS_XML_READER_INPUT_TYPE_BUFFER;
4818 reader->input_buf = buf;
4819 reader->input_data = data;
4820 reader->input_size = size;
4822 reader->read_size = reader->input_size;
4823 reader->read_pos = 0;
4824 reader->read_bufptr = reader->input_data;
4826 reader->text_conv_offset = 0;
4829 /**************************************************************************
4830 * WsSetInput [webservices.@]
4832 HRESULT WINAPI WsSetInput( WS_XML_READER *handle, const WS_XML_READER_ENCODING *encoding,
4833 const WS_XML_READER_INPUT *input, const WS_XML_READER_PROPERTY *properties,
4834 ULONG count, WS_ERROR *error )
4836 struct reader *reader = (struct reader *)handle;
4837 struct node *node;
4838 ULONG i, offset = 0;
4839 HRESULT hr;
4841 TRACE( "%p %p %p %p %u %p\n", handle, encoding, input, properties, count, error );
4842 if (error) FIXME( "ignoring error parameter\n" );
4844 if (!reader) return E_INVALIDARG;
4846 EnterCriticalSection( &reader->cs );
4848 if (reader->magic != READER_MAGIC)
4850 LeaveCriticalSection( &reader->cs );
4851 return E_INVALIDARG;
4854 for (i = 0; i < count; i++)
4856 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4857 properties[i].valueSize );
4858 if (hr != S_OK) goto done;
4861 if ((hr = init_reader( reader )) != S_OK) goto done;
4863 switch (encoding->encodingType)
4865 case WS_XML_READER_ENCODING_TYPE_TEXT:
4867 WS_XML_READER_TEXT_ENCODING *text = (WS_XML_READER_TEXT_ENCODING *)encoding;
4868 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4869 WS_CHARSET charset = text->charSet;
4871 if (input->inputType != WS_XML_READER_INPUT_TYPE_BUFFER)
4873 FIXME( "charset detection on input type %u not supported\n", input->inputType );
4874 hr = E_NOTIMPL;
4875 goto done;
4878 if (charset == WS_CHARSET_AUTO)
4879 charset = detect_charset( buf->encodedData, buf->encodedDataSize, &offset );
4881 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET,
4882 &charset, sizeof(charset) );
4883 if (hr != S_OK) goto done;
4884 break;
4886 default:
4887 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4888 hr = E_NOTIMPL;
4889 goto done;
4892 switch (input->inputType)
4894 case WS_XML_READER_INPUT_TYPE_BUFFER:
4896 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4897 set_input_buffer( reader, NULL, (const unsigned char *)buf->encodedData + offset,
4898 buf->encodedDataSize - offset );
4899 break;
4901 default:
4902 FIXME( "input type %u not supported\n", input->inputType );
4903 hr = E_NOTIMPL;
4904 goto done;
4907 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
4908 else read_insert_bof( reader, node );
4910 done:
4911 LeaveCriticalSection( &reader->cs );
4912 return hr;
4915 /**************************************************************************
4916 * WsSetInputToBuffer [webservices.@]
4918 HRESULT WINAPI WsSetInputToBuffer( WS_XML_READER *handle, WS_XML_BUFFER *buffer,
4919 const WS_XML_READER_PROPERTY *properties, ULONG count,
4920 WS_ERROR *error )
4922 struct reader *reader = (struct reader *)handle;
4923 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4924 WS_CHARSET charset;
4925 struct node *node;
4926 ULONG i, offset = 0;
4927 HRESULT hr;
4929 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
4930 if (error) FIXME( "ignoring error parameter\n" );
4932 if (!reader || !xmlbuf) return E_INVALIDARG;
4934 EnterCriticalSection( &reader->cs );
4936 if (reader->magic != READER_MAGIC)
4938 LeaveCriticalSection( &reader->cs );
4939 return E_INVALIDARG;
4942 for (i = 0; i < count; i++)
4944 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4945 properties[i].valueSize );
4946 if (hr != S_OK) goto done;
4949 if ((hr = init_reader( reader )) != S_OK) goto done;
4951 charset = detect_charset( xmlbuf->ptr, xmlbuf->size, &offset );
4952 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset,
4953 sizeof(charset) );
4954 if (hr != S_OK) goto done;
4956 set_input_buffer( reader, xmlbuf, (const unsigned char *)xmlbuf->ptr + offset, xmlbuf->size - offset );
4957 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
4958 else read_insert_bof( reader, node );
4960 done:
4961 LeaveCriticalSection( &reader->cs );
4962 return hr;
4965 /**************************************************************************
4966 * WsXmlStringEquals [webservices.@]
4968 HRESULT WINAPI WsXmlStringEquals( const WS_XML_STRING *str1, const WS_XML_STRING *str2, WS_ERROR *error )
4970 TRACE( "%s %s %p\n", debugstr_xmlstr(str1), debugstr_xmlstr(str2), error );
4971 if (error) FIXME( "ignoring error parameter\n" );
4973 if (!str1 || !str2) return E_INVALIDARG;
4975 if (str1->length != str2->length) return S_FALSE;
4976 if (!memcmp( str1->bytes, str2->bytes, str1->length )) return S_OK;
4977 return S_FALSE;
4980 /**************************************************************************
4981 * WsGetReaderPosition [webservices.@]
4983 HRESULT WINAPI WsGetReaderPosition( WS_XML_READER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4985 struct reader *reader = (struct reader *)handle;
4987 TRACE( "%p %p %p\n", handle, pos, error );
4988 if (error) FIXME( "ignoring error parameter\n" );
4990 if (!reader || !pos) return E_INVALIDARG;
4992 EnterCriticalSection( &reader->cs );
4994 if (reader->magic != READER_MAGIC)
4996 LeaveCriticalSection( &reader->cs );
4997 return E_INVALIDARG;
5000 if (!reader->input_buf)
5002 LeaveCriticalSection( &reader->cs );
5003 return WS_E_INVALID_OPERATION;
5006 pos->buffer = (WS_XML_BUFFER *)reader->input_buf;
5007 pos->node = reader->current;
5009 LeaveCriticalSection( &reader->cs );
5010 return S_OK;
5013 /**************************************************************************
5014 * WsSetReaderPosition [webservices.@]
5016 HRESULT WINAPI WsSetReaderPosition( WS_XML_READER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
5018 struct reader *reader = (struct reader *)handle;
5020 TRACE( "%p %p %p\n", handle, pos, error );
5021 if (error) FIXME( "ignoring error parameter\n" );
5023 if (!reader || !pos) return E_INVALIDARG;
5025 EnterCriticalSection( &reader->cs );
5027 if (reader->magic != READER_MAGIC || (struct xmlbuf *)pos->buffer != reader->input_buf)
5029 LeaveCriticalSection( &reader->cs );
5030 return E_INVALIDARG;
5033 if (!reader->input_buf)
5035 LeaveCriticalSection( &reader->cs );
5036 return WS_E_INVALID_OPERATION;
5039 reader->current = pos->node;
5041 LeaveCriticalSection( &reader->cs );
5042 return S_OK;
5045 static HRESULT utf8_to_base64( const WS_XML_UTF8_TEXT *utf8, WS_XML_BASE64_TEXT *base64 )
5047 if (utf8->value.length % 4) return WS_E_INVALID_FORMAT;
5048 if (!(base64->bytes = heap_alloc( utf8->value.length * 3 / 4 ))) return E_OUTOFMEMORY;
5049 base64->length = decode_base64( utf8->value.bytes, utf8->value.length, base64->bytes );
5050 return S_OK;
5053 /**************************************************************************
5054 * WsReadBytes [webservices.@]
5056 HRESULT WINAPI WsReadBytes( WS_XML_READER *handle, void *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
5058 struct reader *reader = (struct reader *)handle;
5059 HRESULT hr;
5061 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
5062 if (error) FIXME( "ignoring error parameter\n" );
5064 if (!reader) return E_INVALIDARG;
5066 EnterCriticalSection( &reader->cs );
5068 if (reader->magic != READER_MAGIC)
5070 LeaveCriticalSection( &reader->cs );
5071 return E_INVALIDARG;
5074 if (!reader->input_type)
5076 LeaveCriticalSection( &reader->cs );
5077 return WS_E_INVALID_OPERATION;
5080 if (!count)
5082 LeaveCriticalSection( &reader->cs );
5083 return E_INVALIDARG;
5086 *count = 0;
5087 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
5089 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5090 WS_XML_BASE64_TEXT base64;
5092 if ((hr = utf8_to_base64( (const WS_XML_UTF8_TEXT *)text->text, &base64 )) != S_OK)
5094 LeaveCriticalSection( &reader->cs );
5095 return hr;
5097 if (reader->text_conv_offset == base64.length)
5099 heap_free( base64.bytes );
5100 hr = read_node( reader );
5101 LeaveCriticalSection( &reader->cs );
5102 return hr;
5104 *count = min( base64.length - reader->text_conv_offset, max_count );
5105 memcpy( bytes, base64.bytes + reader->text_conv_offset, *count );
5106 reader->text_conv_offset += *count;
5107 heap_free( base64.bytes );
5110 LeaveCriticalSection( &reader->cs );
5111 return S_OK;
5114 static HRESULT utf8_to_utf16( const WS_XML_UTF8_TEXT *utf8, WS_XML_UTF16_TEXT *utf16 )
5116 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
5117 if (!(utf16->bytes = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
5118 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, (WCHAR *)utf16->bytes, len );
5119 utf16->byteCount = len * sizeof(WCHAR);
5120 return S_OK;
5123 /**************************************************************************
5124 * WsReadChars [webservices.@]
5126 HRESULT WINAPI WsReadChars( WS_XML_READER *handle, WCHAR *chars, ULONG max_count, ULONG *count, WS_ERROR *error )
5128 struct reader *reader = (struct reader *)handle;
5130 TRACE( "%p %p %u %p %p\n", handle, chars, max_count, count, error );
5131 if (error) FIXME( "ignoring error parameter\n" );
5133 if (!reader) return E_INVALIDARG;
5135 EnterCriticalSection( &reader->cs );
5137 if (reader->magic != READER_MAGIC)
5139 LeaveCriticalSection( &reader->cs );
5140 return E_INVALIDARG;
5143 if (!reader->input_type)
5145 LeaveCriticalSection( &reader->cs );
5146 return WS_E_INVALID_OPERATION;
5149 if (!count)
5151 LeaveCriticalSection( &reader->cs );
5152 return E_INVALIDARG;
5155 *count = 0;
5156 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && chars)
5158 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5159 WS_XML_UTF16_TEXT utf16;
5160 HRESULT hr;
5162 if ((hr = utf8_to_utf16( (const WS_XML_UTF8_TEXT *)text->text, &utf16 )) != S_OK)
5164 LeaveCriticalSection( &reader->cs );
5165 return hr;
5167 if (reader->text_conv_offset == utf16.byteCount / sizeof(WCHAR))
5169 heap_free( utf16.bytes );
5170 hr = read_node( reader );
5171 LeaveCriticalSection( &reader->cs );
5172 return hr;
5174 *count = min( utf16.byteCount / sizeof(WCHAR) - reader->text_conv_offset, max_count );
5175 memcpy( chars, utf16.bytes + reader->text_conv_offset * sizeof(WCHAR), *count * sizeof(WCHAR) );
5176 reader->text_conv_offset += *count;
5177 heap_free( utf16.bytes );
5180 LeaveCriticalSection( &reader->cs );
5181 return S_OK;
5184 /**************************************************************************
5185 * WsReadCharsUtf8 [webservices.@]
5187 HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
5189 struct reader *reader = (struct reader *)handle;
5190 HRESULT hr;
5192 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
5193 if (error) FIXME( "ignoring error parameter\n" );
5195 if (!reader) return E_INVALIDARG;
5197 EnterCriticalSection( &reader->cs );
5199 if (reader->magic != READER_MAGIC)
5201 LeaveCriticalSection( &reader->cs );
5202 return E_INVALIDARG;
5205 if (!reader->input_type)
5207 LeaveCriticalSection( &reader->cs );
5208 return WS_E_INVALID_OPERATION;
5211 if (!count)
5213 LeaveCriticalSection( &reader->cs );
5214 return E_INVALIDARG;
5217 *count = 0;
5218 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
5220 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
5221 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
5223 if (reader->text_conv_offset == utf8->value.length)
5225 hr = read_node( reader );
5226 LeaveCriticalSection( &reader->cs );
5227 return hr;
5229 *count = min( utf8->value.length - reader->text_conv_offset, max_count );
5230 memcpy( bytes, utf8->value.bytes + reader->text_conv_offset, *count );
5231 reader->text_conv_offset += *count;
5234 LeaveCriticalSection( &reader->cs );
5235 return S_OK;
5238 HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *desc, USHORT index, const WS_FIELD_DESCRIPTION **ret )
5240 if (index >= desc->fieldCount) return E_INVALIDARG;
5241 *ret = desc->fields[index];
5242 return S_OK;
5245 static ULONG get_field_size( const WS_FIELD_DESCRIPTION *desc )
5247 WS_READ_OPTION option;
5248 ULONG size;
5250 switch ((option = get_field_read_option( desc->type, desc->options )))
5252 case WS_READ_REQUIRED_POINTER:
5253 case WS_READ_OPTIONAL_POINTER:
5254 case WS_READ_NILLABLE_POINTER:
5255 size = sizeof(void *);
5256 break;
5258 case WS_READ_REQUIRED_VALUE:
5259 case WS_READ_NILLABLE_VALUE:
5260 size = get_type_size( desc->type, desc->typeDescription );
5261 break;
5263 default:
5264 WARN( "unhandled option %u\n", option );
5265 return 0;
5268 return size;
5271 static HRESULT read_param( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, void *ret )
5273 if (!ret && !(ret = ws_alloc_zero( heap, get_field_size(desc) ))) return WS_E_QUOTA_EXCEEDED;
5274 return read_type_struct_field( reader, desc, heap, ret, 0 );
5277 static HRESULT read_param_array( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap,
5278 void **ret, ULONG *count )
5280 if (!ret && !(ret = ws_alloc_zero( heap, sizeof(void **) ))) return WS_E_QUOTA_EXCEEDED;
5281 return read_type_repeating_element( reader, desc, heap, ret, count );
5284 static void set_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, ULONG len,
5285 const void **args )
5287 ULONG i, *ptr;
5288 for (i = 0; i < count; i++)
5290 if (params[i].outputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
5291 continue;
5292 if ((ptr = *(ULONG **)args[i])) *ptr = len;
5293 break;
5297 HRESULT read_output_params( WS_XML_READER *handle, WS_HEAP *heap, const WS_ELEMENT_DESCRIPTION *desc,
5298 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
5300 struct reader *reader = (struct reader *)handle;
5301 const WS_STRUCT_DESCRIPTION *desc_struct;
5302 const WS_FIELD_DESCRIPTION *desc_field;
5303 ULONG i, len;
5304 HRESULT hr;
5306 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
5308 EnterCriticalSection( &reader->cs );
5310 if (reader->magic != READER_MAGIC)
5312 LeaveCriticalSection( &reader->cs );
5313 return E_INVALIDARG;
5316 if ((hr = start_mapping( reader, WS_ELEMENT_TYPE_MAPPING, desc->elementLocalName, desc->elementNs )) != S_OK)
5317 goto done;
5319 for (i = 0; i < count; i++)
5321 if (params[i].outputMessageIndex == INVALID_PARAMETER_INDEX) continue;
5322 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
5324 FIXME( "messages type not supported\n" );
5325 hr = E_NOTIMPL;
5326 goto done;
5328 if ((hr = get_param_desc( desc_struct, params[i].outputMessageIndex, &desc_field )) != S_OK) goto done;
5329 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
5331 void *ptr = *(void **)args[i];
5332 if ((hr = read_param( reader, desc_field, heap, ptr )) != S_OK) goto done;
5334 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
5336 void **ptr = *(void ***)args[i];
5337 if ((hr = read_param_array( reader, desc_field, heap, ptr, &len )) != S_OK) goto done;
5338 set_array_len( params, count, params[i].outputMessageIndex, len, args );
5342 if (desc_struct->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
5344 struct node *parent = find_parent( reader );
5345 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
5348 hr = end_mapping( reader, WS_ELEMENT_TYPE_MAPPING );
5350 done:
5351 LeaveCriticalSection( &reader->cs );
5352 return hr;