webservices: Implement WsReadAttribute.
[wine.git] / dlls / webservices / reader.c
blob0cfc844275cb8a181520f6ee81d8f31790b738d8
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 struct node *alloc_node( WS_XML_NODE_TYPE type )
75 struct node *ret;
77 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
78 ret->hdr.node.nodeType = type;
79 list_init( &ret->entry );
80 list_init( &ret->children );
81 return ret;
84 void free_attribute( WS_XML_ATTRIBUTE *attr )
86 if (!attr) return;
87 heap_free( attr->prefix );
88 heap_free( attr->localName );
89 heap_free( attr->ns );
90 heap_free( attr->value );
91 heap_free( attr );
94 void free_node( struct node *node )
96 if (!node) return;
97 switch (node_type( node ))
99 case WS_XML_NODE_TYPE_ELEMENT:
101 WS_XML_ELEMENT_NODE *elem = &node->hdr;
102 ULONG i;
104 for (i = 0; i < elem->attributeCount; i++) free_attribute( elem->attributes[i] );
105 heap_free( elem->attributes );
106 heap_free( elem->prefix );
107 heap_free( elem->localName );
108 heap_free( elem->ns );
109 break;
111 case WS_XML_NODE_TYPE_TEXT:
113 WS_XML_TEXT_NODE *text = (WS_XML_TEXT_NODE *)node;
114 heap_free( text->text );
115 break;
117 case WS_XML_NODE_TYPE_COMMENT:
119 WS_XML_COMMENT_NODE *comment = (WS_XML_COMMENT_NODE *)node;
120 heap_free( comment->value.bytes );
121 break;
123 case WS_XML_NODE_TYPE_CDATA:
124 case WS_XML_NODE_TYPE_END_CDATA:
125 case WS_XML_NODE_TYPE_END_ELEMENT:
126 case WS_XML_NODE_TYPE_EOF:
127 case WS_XML_NODE_TYPE_BOF:
128 break;
130 default:
131 ERR( "unhandled type %u\n", node_type( node ) );
132 break;
134 heap_free( node );
137 void destroy_nodes( struct node *node )
139 struct list *ptr;
141 if (!node) return;
142 while ((ptr = list_head( &node->children )))
144 struct node *child = LIST_ENTRY( ptr, struct node, entry );
145 list_remove( &child->entry );
146 destroy_nodes( child );
148 free_node( node );
151 static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
153 WS_XML_ATTRIBUTE *dst;
154 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
155 const WS_XML_STRING *localname = src->localName;
156 const WS_XML_STRING *ns = src->localName;
158 if (!(dst = heap_alloc( sizeof(*dst) ))) return NULL;
159 dst->singleQuote = src->singleQuote;
160 dst->isXmlNs = src->isXmlNs;
161 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
162 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
163 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
164 return dst;
166 error:
167 free_attribute( dst );
168 return NULL;
171 static WS_XML_ATTRIBUTE **dup_attributes( WS_XML_ATTRIBUTE * const *src, ULONG count )
173 WS_XML_ATTRIBUTE **dst;
174 ULONG i;
176 if (!(dst = heap_alloc( sizeof(*dst) * count ))) return NULL;
177 for (i = 0; i < count; i++)
179 if (!(dst[i] = dup_attribute( src[i] )))
181 for (; i > 0; i--) free_attribute( dst[i - 1] );
182 heap_free( dst );
183 return NULL;
186 return dst;
189 static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
191 struct node *node;
192 WS_XML_ELEMENT_NODE *dst;
193 ULONG count = src->attributeCount;
194 WS_XML_ATTRIBUTE **attrs = src->attributes;
195 const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
196 const WS_XML_STRING *localname = src->localName;
197 const WS_XML_STRING *ns = src->ns;
199 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
200 dst = &node->hdr;
202 if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
203 dst->attributeCount = count;
205 if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
206 if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
207 if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
208 return node;
210 error:
211 free_node( node );
212 return NULL;
215 static struct node *dup_text_node( const WS_XML_TEXT_NODE *src )
217 struct node *node;
218 WS_XML_TEXT_NODE *dst;
220 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
221 dst = (WS_XML_TEXT_NODE *)node;
223 if (src->text)
225 WS_XML_UTF8_TEXT *utf8;
226 const WS_XML_UTF8_TEXT *utf8_src = (WS_XML_UTF8_TEXT *)src->text;
227 if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length )))
229 free_node( node );
230 return NULL;
232 dst->text = &utf8->text;
234 return node;
237 static struct node *dup_comment_node( const WS_XML_COMMENT_NODE *src )
239 struct node *node;
240 WS_XML_COMMENT_NODE *dst;
242 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return NULL;
243 dst = (WS_XML_COMMENT_NODE *)node;
245 if (src->value.length && !(dst->value.bytes = heap_alloc( src->value.length )))
247 free_node( node );
248 return NULL;
250 memcpy( dst->value.bytes, src->value.bytes, src->value.length );
251 dst->value.length = src->value.length;
252 return node;
255 static struct node *dup_node( const struct node *src )
257 switch (node_type( src ))
259 case WS_XML_NODE_TYPE_ELEMENT:
260 return dup_element_node( &src->hdr );
262 case WS_XML_NODE_TYPE_TEXT:
263 return dup_text_node( (const WS_XML_TEXT_NODE *)src );
265 case WS_XML_NODE_TYPE_COMMENT:
266 return dup_comment_node( (const WS_XML_COMMENT_NODE *)src );
268 case WS_XML_NODE_TYPE_CDATA:
269 case WS_XML_NODE_TYPE_END_CDATA:
270 case WS_XML_NODE_TYPE_END_ELEMENT:
271 case WS_XML_NODE_TYPE_EOF:
272 case WS_XML_NODE_TYPE_BOF:
273 return alloc_node( node_type( src ) );
275 default:
276 ERR( "unhandled type %u\n", node_type( src ) );
277 break;
279 return NULL;
282 static HRESULT dup_tree( struct node **dst, const struct node *src )
284 struct node *parent;
285 const struct node *child;
287 if (!*dst && !(*dst = dup_node( src ))) return E_OUTOFMEMORY;
288 parent = *dst;
290 LIST_FOR_EACH_ENTRY( child, &src->children, struct node, entry )
292 HRESULT hr = E_OUTOFMEMORY;
293 struct node *new_child;
295 if (!(new_child = dup_node( child )) || (hr = dup_tree( &new_child, child )) != S_OK)
297 destroy_nodes( *dst );
298 return hr;
300 new_child->parent = parent;
301 list_add_tail( &parent->children, &new_child->entry );
303 return S_OK;
306 static const struct prop_desc reader_props[] =
308 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_DEPTH */
309 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_FRAGMENT */
310 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
311 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_READ_DECLARATION */
312 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_READER_PROPERTY_CHARSET */
313 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_ROW */
314 { sizeof(ULONGLONG), TRUE }, /* WS_XML_READER_PROPERTY_COLUMN */
315 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_UTF8_TRIM_SIZE */
316 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_BUFFER_SIZE */
317 { sizeof(BOOL), TRUE }, /* WS_XML_READER_PROPERTY_IN_ATTRIBUTE */
318 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_ROOT_MIME_PART_SIZE */
319 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_STREAM_MAX_MIME_HEADERS_SIZE */
320 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_MIME_PARTS */
321 { sizeof(BOOL), FALSE }, /* WS_XML_READER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
322 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_NAMESPACES */
325 enum reader_state
327 READER_STATE_INITIAL,
328 READER_STATE_BOF,
329 READER_STATE_STARTELEMENT,
330 READER_STATE_STARTATTRIBUTE,
331 READER_STATE_STARTCDATA,
332 READER_STATE_CDATA,
333 READER_STATE_TEXT,
334 READER_STATE_ENDELEMENT,
335 READER_STATE_ENDCDATA,
336 READER_STATE_COMMENT,
337 READER_STATE_EOF
340 struct prefix
342 WS_XML_STRING str;
343 WS_XML_STRING ns;
346 struct reader
348 ULONG magic;
349 CRITICAL_SECTION cs;
350 ULONG read_size;
351 ULONG read_pos;
352 const unsigned char *read_bufptr;
353 enum reader_state state;
354 struct node *root;
355 struct node *current;
356 ULONG current_attr;
357 struct node *last;
358 struct prefix *prefixes;
359 ULONG nb_prefixes;
360 ULONG nb_prefixes_allocated;
361 WS_XML_READER_INPUT_TYPE input_type;
362 struct xmlbuf *input_buf;
363 const unsigned char *input_data;
364 ULONG input_size;
365 ULONG text_conv_offset;
366 ULONG prop_count;
367 struct prop prop[sizeof(reader_props)/sizeof(reader_props[0])];
370 #define READER_MAGIC (('R' << 24) | ('E' << 16) | ('A' << 8) | 'D')
372 static struct reader *alloc_reader(void)
374 static const ULONG count = sizeof(reader_props)/sizeof(reader_props[0]);
375 struct reader *ret;
376 ULONG size = sizeof(*ret) + prop_size( reader_props, count );
378 if (!(ret = heap_alloc_zero( size ))) return NULL;
379 if (!(ret->prefixes = heap_alloc_zero( sizeof(*ret->prefixes) )))
381 heap_free( ret );
382 return NULL;
384 ret->nb_prefixes = ret->nb_prefixes_allocated = 1;
386 ret->magic = READER_MAGIC;
387 InitializeCriticalSection( &ret->cs );
388 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
390 prop_init( reader_props, count, ret->prop, &ret[1] );
391 ret->prop_count = count;
392 return ret;
395 static void clear_prefixes( struct prefix *prefixes, ULONG count )
397 ULONG i;
398 for (i = 0; i < count; i++)
400 heap_free( prefixes[i].str.bytes );
401 prefixes[i].str.bytes = NULL;
402 prefixes[i].str.length = 0;
404 heap_free( prefixes[i].ns.bytes );
405 prefixes[i].ns.bytes = NULL;
406 prefixes[i].ns.length = 0;
410 HRESULT copy_node( WS_XML_READER *handle, struct node **node )
412 struct reader *reader = (struct reader *)handle;
413 HRESULT hr;
415 EnterCriticalSection( &reader->cs );
417 if (reader->magic != READER_MAGIC)
419 LeaveCriticalSection( &reader->cs );
420 return E_INVALIDARG;
423 hr = dup_tree( node, reader->current );
425 LeaveCriticalSection( &reader->cs );
426 return hr;
429 static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
431 if (str)
433 heap_free( prefix->str.bytes );
434 if (!(prefix->str.bytes = heap_alloc( str->length ))) return E_OUTOFMEMORY;
435 memcpy( prefix->str.bytes, str->bytes, str->length );
436 prefix->str.length = str->length;
439 heap_free( prefix->ns.bytes );
440 if (!(prefix->ns.bytes = heap_alloc( ns->length ))) return E_OUTOFMEMORY;
441 memcpy( prefix->ns.bytes, ns->bytes, ns->length );
442 prefix->ns.length = ns->length;
444 return S_OK;
447 static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING *ns )
449 ULONG i;
450 HRESULT hr;
452 for (i = 0; i < reader->nb_prefixes; i++)
454 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
455 return set_prefix( &reader->prefixes[i], NULL, ns );
457 if (i >= reader->nb_prefixes_allocated)
459 ULONG new_size = reader->nb_prefixes_allocated * sizeof(*reader->prefixes) * 2;
460 struct prefix *tmp = heap_realloc_zero( reader->prefixes, new_size );
461 if (!tmp) return E_OUTOFMEMORY;
462 reader->prefixes = tmp;
463 reader->nb_prefixes_allocated *= 2;
466 if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr;
467 reader->nb_prefixes++;
468 return S_OK;
471 static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_STRING *prefix )
473 ULONG i;
474 for (i = 0; i < reader->nb_prefixes; i++)
476 if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
477 return &reader->prefixes[i].ns;
479 return NULL;
482 static void read_insert_eof( struct reader *reader, struct node *eof )
484 if (!reader->root) reader->root = eof;
485 else
487 eof->parent = reader->root;
488 list_add_tail( &reader->root->children, &eof->entry );
490 reader->current = reader->last = eof;
493 static void read_insert_bof( struct reader *reader, struct node *bof )
495 reader->root->parent = bof;
496 list_add_tail( &bof->children, &reader->root->entry );
497 reader->current = reader->last = reader->root = bof;
500 static void read_insert_node( struct reader *reader, struct node *parent, struct node *node )
502 node->parent = parent;
503 list_add_before( list_tail( &parent->children ), &node->entry );
504 reader->current = reader->last = node;
507 static void free_reader( struct reader *reader )
509 destroy_nodes( reader->root );
510 clear_prefixes( reader->prefixes, reader->nb_prefixes );
511 heap_free( reader->prefixes );
512 reader->cs.DebugInfo->Spare[0] = 0;
513 DeleteCriticalSection( &reader->cs );
514 heap_free( reader );
517 static HRESULT init_reader( struct reader *reader )
519 struct node *node;
521 reader->state = READER_STATE_INITIAL;
522 destroy_nodes( reader->root );
523 reader->root = reader->current = NULL;
524 reader->current_attr = 0;
525 clear_prefixes( reader->prefixes, reader->nb_prefixes );
526 reader->nb_prefixes = 1;
527 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
528 read_insert_eof( reader, node );
529 return S_OK;
532 /**************************************************************************
533 * WsCreateReader [webservices.@]
535 HRESULT WINAPI WsCreateReader( const WS_XML_READER_PROPERTY *properties, ULONG count,
536 WS_XML_READER **handle, WS_ERROR *error )
538 struct reader *reader;
539 ULONG i, max_depth = 32, max_attrs = 128, max_ns = 32;
540 WS_CHARSET charset = WS_CHARSET_UTF8;
541 BOOL read_decl = TRUE;
542 HRESULT hr;
544 TRACE( "%p %u %p %p\n", properties, count, handle, error );
545 if (error) FIXME( "ignoring error parameter\n" );
547 if (!handle) return E_INVALIDARG;
548 if (!(reader = alloc_reader())) return E_OUTOFMEMORY;
550 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
551 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
552 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_READ_DECLARATION, &read_decl, sizeof(read_decl) );
553 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset, sizeof(charset) );
554 prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
556 for (i = 0; i < count; i++)
558 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
559 properties[i].valueSize );
560 if (hr != S_OK)
562 free_reader( reader );
563 return hr;
567 if ((hr = init_reader( reader )) != S_OK)
569 free_reader( reader );
570 return hr;
573 *handle = (WS_XML_READER *)reader;
574 return S_OK;
577 /**************************************************************************
578 * WsFreeReader [webservices.@]
580 void WINAPI WsFreeReader( WS_XML_READER *handle )
582 struct reader *reader = (struct reader *)handle;
584 TRACE( "%p\n", handle );
586 if (!reader) return;
588 EnterCriticalSection( &reader->cs );
590 if (reader->magic != READER_MAGIC)
592 LeaveCriticalSection( &reader->cs );
593 return;
596 reader->magic = 0;
598 LeaveCriticalSection( &reader->cs );
599 free_reader( reader );
602 /**************************************************************************
603 * WsFillReader [webservices.@]
605 HRESULT WINAPI WsFillReader( WS_XML_READER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
606 WS_ERROR *error )
608 struct reader *reader = (struct reader *)handle;
610 TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
611 if (error) FIXME( "ignoring error parameter\n" );
613 if (!reader) return E_INVALIDARG;
615 EnterCriticalSection( &reader->cs );
617 if (reader->magic != READER_MAGIC)
619 LeaveCriticalSection( &reader->cs );
620 return E_INVALIDARG;
623 /* FIXME: add support for stream input */
624 reader->read_size = min( min_size, reader->input_size );
625 reader->read_pos = 0;
627 LeaveCriticalSection( &reader->cs );
628 return S_OK;
631 /**************************************************************************
632 * WsGetNamespaceFromPrefix [webservices.@]
634 HRESULT WINAPI WsGetNamespaceFromPrefix( WS_XML_READER *handle, const WS_XML_STRING *prefix,
635 BOOL required, const WS_XML_STRING **ns, WS_ERROR *error )
637 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
638 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
639 static const WS_XML_STRING empty_ns = {0, NULL};
640 static const WS_XML_STRING xml_ns = {36, (BYTE *)"http://www.w3.org/XML/1998/namespace"};
641 static const WS_XML_STRING xmlns_ns = {29, (BYTE *)"http://www.w3.org/2000/xmlns/"};
642 struct reader *reader = (struct reader *)handle;
643 BOOL found = FALSE;
645 TRACE( "%p %s %d %p %p\n", handle, debugstr_xmlstr(prefix), required, ns, error );
646 if (error) FIXME( "ignoring error parameter\n" );
648 if (!reader || !prefix || !ns) return E_INVALIDARG;
650 EnterCriticalSection( &reader->cs );
652 if (reader->magic != READER_MAGIC)
654 LeaveCriticalSection( &reader->cs );
655 return E_INVALIDARG;
658 if (reader->state != READER_STATE_STARTELEMENT)
660 LeaveCriticalSection( &reader->cs );
661 return WS_E_INVALID_OPERATION;
664 if (!prefix->length)
666 *ns = &empty_ns;
667 found = TRUE;
669 else if (WsXmlStringEquals( prefix, &xml, NULL ) == S_OK)
671 *ns = &xml_ns;
672 found = TRUE;
674 else if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
676 *ns = &xmlns_ns;
677 found = TRUE;
679 else
681 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
682 ULONG i;
684 for (i = 0; i < elem->attributeCount; i++)
686 if (!elem->attributes[i]->isXmlNs) continue;
687 if (WsXmlStringEquals( prefix, elem->attributes[i]->prefix, NULL ) == S_OK)
689 *ns = elem->attributes[i]->ns;
690 found = TRUE;
691 break;
696 LeaveCriticalSection( &reader->cs );
698 if (!found)
700 if (required) return WS_E_INVALID_FORMAT;
701 *ns = NULL;
702 return S_FALSE;
705 return S_OK;
708 /**************************************************************************
709 * WsGetReaderNode [webservices.@]
711 HRESULT WINAPI WsGetReaderNode( WS_XML_READER *handle, const WS_XML_NODE **node,
712 WS_ERROR *error )
714 struct reader *reader = (struct reader *)handle;
716 TRACE( "%p %p %p\n", handle, node, error );
717 if (error) FIXME( "ignoring error parameter\n" );
719 if (!reader || !node) return E_INVALIDARG;
721 EnterCriticalSection( &reader->cs );
723 if (reader->magic != READER_MAGIC)
725 LeaveCriticalSection( &reader->cs );
726 return E_INVALIDARG;
729 *node = &reader->current->hdr.node;
731 LeaveCriticalSection( &reader->cs );
732 return S_OK;
735 /**************************************************************************
736 * WsGetReaderProperty [webservices.@]
738 HRESULT WINAPI WsGetReaderProperty( WS_XML_READER *handle, WS_XML_READER_PROPERTY_ID id,
739 void *buf, ULONG size, WS_ERROR *error )
741 struct reader *reader = (struct reader *)handle;
742 HRESULT hr;
744 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
745 if (error) FIXME( "ignoring error parameter\n" );
747 if (!reader) return E_INVALIDARG;
749 EnterCriticalSection( &reader->cs );
751 if (reader->magic != READER_MAGIC)
753 LeaveCriticalSection( &reader->cs );
754 return E_INVALIDARG;
757 if (!reader->input_type)
759 LeaveCriticalSection( &reader->cs );
760 return WS_E_INVALID_OPERATION;
763 if (id == WS_XML_READER_PROPERTY_CHARSET)
765 WS_CHARSET charset;
766 if ((hr = prop_get( reader->prop, reader->prop_count, id, &charset, size )) != S_OK) goto done;
767 if (!charset)
769 hr = WS_E_INVALID_FORMAT;
770 goto done;
772 *(WS_CHARSET *)buf = charset;
773 hr = S_OK;
775 else hr = prop_get( reader->prop, reader->prop_count, id, buf, size );
777 done:
778 LeaveCriticalSection( &reader->cs );
779 return hr;
782 /**************************************************************************
783 * WsGetXmlAttribute [webservices.@]
785 HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *attr,
786 WS_HEAP *heap, WCHAR **str, ULONG *len, WS_ERROR *error )
788 FIXME( "%p %s %p %p %p %p: stub\n", handle, debugstr_xmlstr(attr), heap, str, len, error );
789 return E_NOTIMPL;
792 WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len )
794 WS_XML_STRING *ret;
796 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
797 ret->length = len;
798 ret->bytes = len ? (BYTE *)(ret + 1) : NULL;
799 ret->dictionary = NULL;
800 ret->id = 0;
801 if (data) memcpy( ret->bytes, data, len );
802 return ret;
805 WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len )
807 WS_XML_UTF8_TEXT *ret;
809 if (!(ret = heap_alloc( sizeof(*ret) + len ))) return NULL;
810 ret->text.textType = WS_XML_TEXT_TYPE_UTF8;
811 ret->value.length = len;
812 ret->value.bytes = len ? (BYTE *)(ret + 1) : NULL;
813 ret->value.dictionary = NULL;
814 ret->value.id = 0;
815 if (data) memcpy( ret->value.bytes, data, len );
816 return ret;
819 static inline BOOL read_end_of_data( struct reader *reader )
821 return reader->read_pos >= reader->read_size;
824 static inline const unsigned char *read_current_ptr( struct reader *reader )
826 return &reader->read_bufptr[reader->read_pos];
829 /* UTF-8 support based on libs/wine/utf8.c */
831 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
832 static const char utf8_length[128] =
834 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
835 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
836 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
837 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
838 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
839 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
840 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
841 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
844 /* first byte mask depending on UTF-8 sequence length */
845 static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
847 /* minimum Unicode value depending on UTF-8 sequence length */
848 static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
850 static inline unsigned int read_utf8_char( struct reader *reader, unsigned int *skip )
852 unsigned int len, res;
853 unsigned char ch = reader->read_bufptr[reader->read_pos];
854 const unsigned char *end;
856 if (reader->read_pos >= reader->read_size) return 0;
858 if (ch < 0x80)
860 *skip = 1;
861 return ch;
863 len = utf8_length[ch - 0x80];
864 if (reader->read_pos + len >= reader->read_size) return 0;
865 end = reader->read_bufptr + reader->read_pos + len + 1;
866 res = ch & utf8_mask[len];
868 switch (len)
870 case 3:
871 if ((ch = end[-3] ^ 0x80) >= 0x40) break;
872 res = (res << 6) | ch;
873 case 2:
874 if ((ch = end[-2] ^ 0x80) >= 0x40) break;
875 res = (res << 6) | ch;
876 case 1:
877 if ((ch = end[-1] ^ 0x80) >= 0x40) break;
878 res = (res << 6) | ch;
879 if (res < utf8_minval[len]) break;
880 *skip = len + 1;
881 return res;
884 return 0;
887 static inline void read_skip( struct reader *reader, unsigned int count )
889 if (reader->read_pos + count > reader->read_size) return;
890 reader->read_pos += count;
893 static inline void read_rewind( struct reader *reader, unsigned int count )
895 reader->read_pos -= count;
898 static inline BOOL read_isnamechar( unsigned int ch )
900 /* FIXME: incomplete */
901 return (ch >= 'A' && ch <= 'Z') ||
902 (ch >= 'a' && ch <= 'z') ||
903 (ch >= '0' && ch <= '9') ||
904 ch == '_' || ch == '-' || ch == '.' || ch == ':';
907 static inline BOOL read_isspace( unsigned int ch )
909 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
912 static inline void read_skip_whitespace( struct reader *reader )
914 while (reader->read_pos < reader->read_size && read_isspace( reader->read_bufptr[reader->read_pos] ))
915 reader->read_pos++;
918 static inline int read_cmp( struct reader *reader, const char *str, int len )
920 const unsigned char *ptr = read_current_ptr( reader );
922 if (len < 0) len = strlen( str );
923 if (reader->read_pos + len > reader->read_size) return -1;
924 while (len--)
926 if (*str != *ptr) return *ptr - *str;
927 str++; ptr++;
929 return 0;
932 static HRESULT read_xmldecl( struct reader *reader )
934 if (!reader->read_size) return WS_E_INVALID_FORMAT;
936 if (read_cmp( reader, "<", 1 ) || read_cmp( reader, "<?", 2 ))
938 reader->state = READER_STATE_BOF;
939 return S_OK;
941 if (read_cmp( reader, "<?xml ", 6 )) return WS_E_INVALID_FORMAT;
942 read_skip( reader, 6 );
944 /* FIXME: parse attributes */
945 while (reader->read_pos < reader->read_size && reader->read_bufptr[reader->read_pos] != '?')
946 reader->read_pos++;
948 if (read_cmp( reader, "?>", 2 )) return WS_E_INVALID_FORMAT;
949 read_skip( reader, 2 );
951 reader->state = READER_STATE_BOF;
952 return S_OK;
955 HRESULT append_attribute( WS_XML_ELEMENT_NODE *elem, WS_XML_ATTRIBUTE *attr )
957 if (elem->attributeCount)
959 WS_XML_ATTRIBUTE **tmp;
960 if (!(tmp = heap_realloc( elem->attributes, (elem->attributeCount + 1) * sizeof(attr) )))
961 return E_OUTOFMEMORY;
962 elem->attributes = tmp;
964 else if (!(elem->attributes = heap_alloc( sizeof(attr) ))) return E_OUTOFMEMORY;
965 elem->attributes[elem->attributeCount++] = attr;
966 return S_OK;
969 static HRESULT split_name( const unsigned char *str, ULONG len, const unsigned char **prefix,
970 ULONG *prefix_len, const unsigned char **localname, ULONG *localname_len )
972 const unsigned char *ptr = str;
974 *prefix = NULL;
975 *prefix_len = 0;
977 *localname = str;
978 *localname_len = len;
980 while (len--)
982 if (*ptr == ':')
984 if (ptr == str) return WS_E_INVALID_FORMAT;
985 *prefix = str;
986 *prefix_len = ptr - str;
987 *localname = ptr + 1;
988 *localname_len = len;
989 break;
991 ptr++;
993 return S_OK;
996 static HRESULT parse_name( const unsigned char *str, ULONG len, WS_XML_STRING **prefix, WS_XML_STRING **localname )
998 const unsigned char *localname_ptr, *prefix_ptr;
999 ULONG localname_len, prefix_len;
1000 HRESULT hr;
1002 if ((hr = split_name( str, len, &prefix_ptr, &prefix_len, &localname_ptr, &localname_len )) != S_OK) return hr;
1003 if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY;
1004 if (!(*localname = alloc_xml_string( localname_ptr, localname_len )))
1006 heap_free( *prefix );
1007 *prefix = NULL;
1008 return E_OUTOFMEMORY;
1010 return S_OK;
1013 static int codepoint_to_utf8( int cp, unsigned char *dst )
1015 if (!cp) return -1;
1016 if (cp < 0x80)
1018 *dst = cp;
1019 return 1;
1021 if (cp < 0x800)
1023 dst[1] = 0x80 | (cp & 0x3f);
1024 cp >>= 6;
1025 dst[0] = 0xc0 | cp;
1026 return 2;
1028 if ((cp >= 0xd800 && cp <= 0xdfff) || cp == 0xfffe || cp == 0xffff) return -1;
1029 if (cp < 0x10000)
1031 dst[2] = 0x80 | (cp & 0x3f);
1032 cp >>= 6;
1033 dst[1] = 0x80 | (cp & 0x3f);
1034 cp >>= 6;
1035 dst[0] = 0xe0 | cp;
1036 return 3;
1038 if (cp >= 0x110000) return -1;
1039 dst[3] = 0x80 | (cp & 0x3f);
1040 cp >>= 6;
1041 dst[2] = 0x80 | (cp & 0x3f);
1042 cp >>= 6;
1043 dst[1] = 0x80 | (cp & 0x3f);
1044 cp >>= 6;
1045 dst[0] = 0xf0 | cp;
1046 return 4;
1049 static HRESULT decode_text( const unsigned char *str, ULONG len, unsigned char *ret, ULONG *ret_len )
1051 const unsigned char *p = str;
1052 unsigned char *q = ret;
1054 *ret_len = 0;
1055 while (len)
1057 if (*p == '&')
1059 p++; len--;
1060 if (!len) return WS_E_INVALID_FORMAT;
1062 if (len >= 3 && !memcmp( p, "lt;", 3 ))
1064 *q++ = '<';
1065 p += 3;
1066 len -= 3;
1068 else if (len >= 3 && !memcmp( p, "gt;", 3 ))
1070 *q++ = '>';
1071 p += 3;
1072 len -= 3;
1074 else if (len >= 5 && !memcmp( p, "quot;", 5 ))
1076 *q++ = '"';
1077 p += 5;
1078 len -= 5;
1080 else if (len >= 4 && !memcmp( p, "amp;", 4 ))
1082 *q++ = '&';
1083 p += 4;
1084 len -= 4;
1086 else if (len >= 5 && !memcmp( p, "apos;", 5 ))
1088 *q++ = '\'';
1089 p += 5;
1090 len -= 5;
1092 else if (*p == '#')
1094 ULONG start, nb_digits, i;
1095 int len_utf8, cp = 0;
1097 p++; len--;
1098 if (!len) return WS_E_INVALID_FORMAT;
1099 if (*p == 'x')
1101 p++; len--;
1103 start = len;
1104 while (len && isxdigit( *p )) { p++; len--; };
1105 if (!len) return WS_E_INVALID_FORMAT;
1107 p -= nb_digits = start - len;
1108 if (!nb_digits || nb_digits > 6 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1109 for (i = 0; i < nb_digits; i++)
1111 cp *= 16;
1112 if (*p >= '0' && *p <= '9') cp += *p - '0';
1113 else if (*p >= 'a' && *p <= 'f') cp += *p - 'a' + 10;
1114 else cp += *p - 'A' + 10;
1115 p++;
1118 else if (isdigit( *p ))
1120 while (len && *p == '0') { p++; len--; };
1121 if (!len) return WS_E_INVALID_FORMAT;
1123 start = len;
1124 while (len && isdigit( *p )) { p++; len--; };
1125 if (!len) return WS_E_INVALID_FORMAT;
1127 p -= nb_digits = start - len;
1128 if (!nb_digits || nb_digits > 7 || p[nb_digits] != ';') return WS_E_INVALID_FORMAT;
1129 for (i = 0; i < nb_digits; i++)
1131 cp *= 10;
1132 cp += *p - '0';
1133 p++;
1136 else return WS_E_INVALID_FORMAT;
1137 p++; len--;
1138 if ((len_utf8 = codepoint_to_utf8( cp, q )) < 0) return WS_E_INVALID_FORMAT;
1139 *ret_len += len_utf8;
1140 q += len_utf8;
1141 continue;
1143 else return WS_E_INVALID_FORMAT;
1145 else
1147 *q++ = *p++;
1148 len--;
1150 *ret_len += 1;
1152 return S_OK;
1155 static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
1157 static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"};
1158 WS_XML_ATTRIBUTE *attr;
1159 WS_XML_UTF8_TEXT *text = NULL;
1160 unsigned int len = 0, ch, skip, quote;
1161 const unsigned char *start;
1162 WS_XML_STRING *prefix, *localname;
1163 HRESULT hr = WS_E_INVALID_FORMAT;
1165 if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
1167 start = read_current_ptr( reader );
1168 for (;;)
1170 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1171 if (!read_isnamechar( ch )) break;
1172 read_skip( reader, skip );
1173 len += skip;
1175 if (!len) goto error;
1177 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) goto error;
1178 hr = E_OUTOFMEMORY;
1179 if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
1181 heap_free( prefix );
1182 attr->isXmlNs = 1;
1183 if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length )))
1185 heap_free( localname );
1186 goto error;
1188 attr->localName = localname;
1190 else if (!prefix->length && WsXmlStringEquals( localname, &xmlns, NULL ) == S_OK)
1192 attr->isXmlNs = 1;
1193 attr->prefix = prefix;
1194 attr->localName = localname;
1196 else
1198 attr->prefix = prefix;
1199 attr->localName = localname;
1202 hr = WS_E_INVALID_FORMAT;
1203 read_skip_whitespace( reader );
1204 if (read_cmp( reader, "=", 1 )) goto error;
1205 read_skip( reader, 1 );
1207 read_skip_whitespace( reader );
1208 if (read_cmp( reader, "\"", 1 ) && read_cmp( reader, "'", 1 )) goto error;
1209 quote = read_utf8_char( reader, &skip );
1210 read_skip( reader, 1 );
1212 len = 0;
1213 start = read_current_ptr( reader );
1214 for (;;)
1216 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1217 if (ch == quote) break;
1218 read_skip( reader, skip );
1219 len += skip;
1221 read_skip( reader, 1 );
1223 hr = E_OUTOFMEMORY;
1224 if (attr->isXmlNs)
1226 if (!(attr->ns = alloc_xml_string( start, len ))) goto error;
1227 if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
1228 if (!(text = alloc_utf8_text( NULL, 0 ))) goto error;
1230 else
1232 if (!(text = alloc_utf8_text( NULL, len ))) goto error;
1233 if ((hr = decode_text( start, len, text->value.bytes, &text->value.length )) != S_OK) goto error;
1236 attr->value = &text->text;
1237 attr->singleQuote = (quote == '\'');
1239 *ret = attr;
1240 return S_OK;
1242 error:
1243 heap_free( text );
1244 free_attribute( attr );
1245 return hr;
1248 static struct node *find_parent( struct reader *reader )
1250 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT)
1252 if (is_valid_parent( reader->current->parent->parent )) return reader->current->parent->parent;
1253 return NULL;
1255 else if (is_valid_parent( reader->current )) return reader->current;
1256 else if (is_valid_parent( reader->current->parent )) return reader->current->parent;
1257 return NULL;
1260 static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
1262 static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
1263 const WS_XML_STRING *ns;
1264 ULONG i;
1266 if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT;
1267 if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1268 if (!elem->ns->length) elem->ns->bytes = (BYTE *)(elem->ns + 1); /* quirk */
1270 for (i = 0; i < elem->attributeCount; i++)
1272 WS_XML_ATTRIBUTE *attr = elem->attributes[i];
1273 if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue;
1274 if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT;
1275 if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
1277 return S_OK;
1280 static HRESULT read_element( struct reader *reader )
1282 unsigned int len = 0, ch, skip;
1283 const unsigned char *start;
1284 struct node *node = NULL, *endnode, *parent;
1285 WS_XML_ELEMENT_NODE *elem;
1286 WS_XML_ATTRIBUTE *attr = NULL;
1287 HRESULT hr = WS_E_INVALID_FORMAT;
1289 if (read_end_of_data( reader ))
1291 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1292 reader->last = reader->current;
1293 reader->state = READER_STATE_EOF;
1294 return S_OK;
1297 if (read_cmp( reader, "<", 1 )) goto error;
1298 read_skip( reader, 1 );
1299 if (!read_isnamechar( read_utf8_char( reader, &skip )))
1301 read_rewind( reader, 1 );
1302 goto error;
1305 start = read_current_ptr( reader );
1306 for (;;)
1308 if (!(ch = read_utf8_char( reader, &skip ))) goto error;
1309 if (!read_isnamechar( ch )) break;
1310 read_skip( reader, skip );
1311 len += skip;
1313 if (!len) goto error;
1315 if (!(parent = find_parent( reader ))) goto error;
1317 hr = E_OUTOFMEMORY;
1318 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) goto error;
1319 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_ELEMENT ))) goto error;
1320 list_add_tail( &node->children, &endnode->entry );
1321 endnode->parent = node;
1323 elem = (WS_XML_ELEMENT_NODE *)node;
1324 if ((hr = parse_name( start, len, &elem->prefix, &elem->localName )) != S_OK) goto error;
1326 reader->current_attr = 0;
1327 for (;;)
1329 read_skip_whitespace( reader );
1330 if (!read_cmp( reader, ">", 1 ) || !read_cmp( reader, "/>", 2 )) break;
1331 if ((hr = read_attribute( reader, &attr )) != S_OK) goto error;
1332 if ((hr = append_attribute( elem, attr )) != S_OK)
1334 free_attribute( attr );
1335 goto error;
1337 reader->current_attr++;
1339 if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
1341 read_insert_node( reader, parent, node );
1342 reader->state = READER_STATE_STARTELEMENT;
1343 return S_OK;
1345 error:
1346 destroy_nodes( node );
1347 return hr;
1350 static HRESULT read_text( struct reader *reader )
1352 unsigned int len = 0, ch, skip;
1353 const unsigned char *start;
1354 struct node *node, *parent;
1355 WS_XML_TEXT_NODE *text;
1356 WS_XML_UTF8_TEXT *utf8;
1357 HRESULT hr;
1359 start = read_current_ptr( reader );
1360 for (;;)
1362 if (read_end_of_data( reader )) break;
1363 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1364 if (ch == '<') break;
1365 read_skip( reader, skip );
1366 len += skip;
1369 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1371 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1372 text = (WS_XML_TEXT_NODE *)node;
1373 if (!(utf8 = alloc_utf8_text( NULL, len )))
1375 heap_free( node );
1376 return E_OUTOFMEMORY;
1378 if ((hr = decode_text( start, len, utf8->value.bytes, &utf8->value.length )) != S_OK)
1380 heap_free( utf8 );
1381 heap_free( node );
1382 return hr;
1384 text->text = &utf8->text;
1386 read_insert_node( reader, parent, node );
1387 reader->state = READER_STATE_TEXT;
1388 reader->text_conv_offset = 0;
1389 return S_OK;
1392 static HRESULT read_node( struct reader * );
1394 static HRESULT read_startelement( struct reader *reader )
1396 read_skip_whitespace( reader );
1397 if (!read_cmp( reader, "/>", 2 ))
1399 read_skip( reader, 2 );
1400 reader->current = LIST_ENTRY( list_tail( &reader->current->children ), struct node, entry );
1401 reader->last = reader->current;
1402 reader->state = READER_STATE_ENDELEMENT;
1403 return S_OK;
1405 else if (!read_cmp( reader, ">", 1 ))
1407 read_skip( reader, 1 );
1408 return read_node( reader );
1410 return WS_E_INVALID_FORMAT;
1413 static HRESULT read_to_startelement( struct reader *reader, BOOL *found )
1415 HRESULT hr;
1417 switch (reader->state)
1419 case READER_STATE_INITIAL:
1420 if ((hr = read_xmldecl( reader )) != S_OK) return hr;
1421 break;
1423 case READER_STATE_STARTELEMENT:
1424 if (found) *found = TRUE;
1425 return S_OK;
1427 default:
1428 break;
1431 read_skip_whitespace( reader );
1432 if ((hr = read_element( reader )) == S_OK && found)
1434 if (reader->state == READER_STATE_STARTELEMENT)
1435 *found = TRUE;
1436 else
1437 *found = FALSE;
1440 return hr;
1443 static int cmp_name( const unsigned char *name1, ULONG len1, const unsigned char *name2, ULONG len2 )
1445 ULONG i;
1446 if (len1 != len2) return 1;
1447 for (i = 0; i < len1; i++) { if (toupper( name1[i] ) != toupper( name2[i] )) return 1; }
1448 return 0;
1451 static struct node *read_find_startelement( struct reader *reader, const WS_XML_STRING *prefix,
1452 const WS_XML_STRING *localname )
1454 struct node *parent;
1455 const WS_XML_STRING *str;
1457 for (parent = reader->current; parent; parent = parent->parent)
1459 if (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT)
1461 str = parent->hdr.prefix;
1462 if (cmp_name( str->bytes, str->length, prefix->bytes, prefix->length )) continue;
1463 str = parent->hdr.localName;
1464 if (cmp_name( str->bytes, str->length, localname->bytes, localname->length )) continue;
1465 return parent;
1468 return NULL;
1471 static HRESULT read_endelement( struct reader *reader )
1473 struct node *parent;
1474 unsigned int len = 0, ch, skip;
1475 const unsigned char *start;
1476 WS_XML_STRING *prefix, *localname;
1477 HRESULT hr;
1479 if (reader->state == READER_STATE_EOF) return WS_E_INVALID_FORMAT;
1481 if (read_end_of_data( reader ))
1483 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1484 reader->last = reader->current;
1485 reader->state = READER_STATE_EOF;
1486 return S_OK;
1489 if (read_cmp( reader, "</", 2 )) return WS_E_INVALID_FORMAT;
1490 read_skip( reader, 2 );
1492 start = read_current_ptr( reader );
1493 for (;;)
1495 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1496 if (ch == '>')
1498 read_skip( reader, 1 );
1499 break;
1501 if (!read_isnamechar( ch )) return WS_E_INVALID_FORMAT;
1502 read_skip( reader, skip );
1503 len += skip;
1506 if ((hr = parse_name( start, len, &prefix, &localname )) != S_OK) return hr;
1507 parent = read_find_startelement( reader, prefix, localname );
1508 heap_free( prefix );
1509 heap_free( localname );
1510 if (!parent) return WS_E_INVALID_FORMAT;
1512 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
1513 reader->last = reader->current;
1514 reader->state = READER_STATE_ENDELEMENT;
1515 return S_OK;
1518 static HRESULT read_comment( struct reader *reader )
1520 unsigned int len = 0, ch, skip;
1521 const unsigned char *start;
1522 struct node *node, *parent;
1523 WS_XML_COMMENT_NODE *comment;
1525 if (read_cmp( reader, "<!--", 4 )) return WS_E_INVALID_FORMAT;
1526 read_skip( reader, 4 );
1528 start = read_current_ptr( reader );
1529 for (;;)
1531 if (!read_cmp( reader, "-->", 3 ))
1533 read_skip( reader, 3 );
1534 break;
1536 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1537 read_skip( reader, skip );
1538 len += skip;
1541 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1543 if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return E_OUTOFMEMORY;
1544 comment = (WS_XML_COMMENT_NODE *)node;
1545 if (!(comment->value.bytes = heap_alloc( len )))
1547 heap_free( node );
1548 return E_OUTOFMEMORY;
1550 memcpy( comment->value.bytes, start, len );
1551 comment->value.length = len;
1553 read_insert_node( reader, parent, node );
1554 reader->state = READER_STATE_COMMENT;
1555 return S_OK;
1558 static HRESULT read_startcdata( struct reader *reader )
1560 struct node *node, *endnode, *parent;
1562 if (read_cmp( reader, "<![CDATA[", 9 )) return WS_E_INVALID_FORMAT;
1563 read_skip( reader, 9 );
1565 if (!(parent = find_parent( reader ))) return WS_E_INVALID_FORMAT;
1567 if (!(node = alloc_node( WS_XML_NODE_TYPE_CDATA ))) return E_OUTOFMEMORY;
1568 if (!(endnode = alloc_node( WS_XML_NODE_TYPE_END_CDATA )))
1570 heap_free( node );
1571 return E_OUTOFMEMORY;
1573 list_add_tail( &node->children, &endnode->entry );
1574 endnode->parent = node;
1576 read_insert_node( reader, parent, node );
1577 reader->state = READER_STATE_STARTCDATA;
1578 return S_OK;
1581 static HRESULT read_cdata( struct reader *reader )
1583 unsigned int len = 0, ch, skip;
1584 const unsigned char *start;
1585 struct node *node;
1586 WS_XML_TEXT_NODE *text;
1587 WS_XML_UTF8_TEXT *utf8;
1589 start = read_current_ptr( reader );
1590 for (;;)
1592 if (!read_cmp( reader, "]]>", 3 )) break;
1593 if (!(ch = read_utf8_char( reader, &skip ))) return WS_E_INVALID_FORMAT;
1594 read_skip( reader, skip );
1595 len += skip;
1598 if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return E_OUTOFMEMORY;
1599 text = (WS_XML_TEXT_NODE *)node;
1600 if (!(utf8 = alloc_utf8_text( start, len )))
1602 heap_free( node );
1603 return E_OUTOFMEMORY;
1605 text->text = &utf8->text;
1607 read_insert_node( reader, reader->current, node );
1608 reader->state = READER_STATE_CDATA;
1609 return S_OK;
1612 static HRESULT read_endcdata( struct reader *reader )
1614 struct node *parent;
1616 if (read_cmp( reader, "]]>", 3 )) return WS_E_INVALID_FORMAT;
1617 read_skip( reader, 3 );
1619 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT) parent = reader->current->parent;
1620 else parent = reader->current;
1622 reader->current = LIST_ENTRY( list_tail( &parent->children ), struct node, entry );
1623 reader->last = reader->current;
1624 reader->state = READER_STATE_ENDCDATA;
1625 return S_OK;
1628 static HRESULT read_node( struct reader *reader )
1630 HRESULT hr;
1632 for (;;)
1634 if (read_end_of_data( reader ))
1636 reader->current = LIST_ENTRY( list_tail( &reader->root->children ), struct node, entry );
1637 reader->last = reader->current;
1638 reader->state = READER_STATE_EOF;
1639 return S_OK;
1641 if (reader->state == READER_STATE_STARTCDATA) return read_cdata( reader );
1642 else if (reader->state == READER_STATE_CDATA) return read_endcdata( reader );
1643 else if (!read_cmp( reader, "<?", 2 ))
1645 hr = read_xmldecl( reader );
1646 if (FAILED( hr )) return hr;
1648 else if (!read_cmp( reader, "</", 2 )) return read_endelement( reader );
1649 else if (!read_cmp( reader, "<![CDATA[", 9 )) return read_startcdata( reader );
1650 else if (!read_cmp( reader, "<!--", 4 )) return read_comment( reader );
1651 else if (!read_cmp( reader, "<", 1 )) return read_element( reader );
1652 else if (!read_cmp( reader, "/>", 2 ) || !read_cmp( reader, ">", 1 )) return read_startelement( reader );
1653 else return read_text( reader );
1657 /**************************************************************************
1658 * WsReadEndElement [webservices.@]
1660 HRESULT WINAPI WsReadEndElement( WS_XML_READER *handle, WS_ERROR *error )
1662 struct reader *reader = (struct reader *)handle;
1663 HRESULT hr;
1665 TRACE( "%p %p\n", handle, error );
1666 if (error) FIXME( "ignoring error parameter\n" );
1668 if (!reader) return E_INVALIDARG;
1670 EnterCriticalSection( &reader->cs );
1672 if (reader->magic != READER_MAGIC)
1674 LeaveCriticalSection( &reader->cs );
1675 return E_INVALIDARG;
1678 hr = read_endelement( reader );
1680 LeaveCriticalSection( &reader->cs );
1681 return hr;
1684 /**************************************************************************
1685 * WsReadNode [webservices.@]
1687 HRESULT WINAPI WsReadNode( WS_XML_READER *handle, WS_ERROR *error )
1689 struct reader *reader = (struct reader *)handle;
1690 HRESULT hr;
1692 TRACE( "%p %p\n", handle, error );
1693 if (error) FIXME( "ignoring error parameter\n" );
1695 if (!reader) return E_INVALIDARG;
1697 EnterCriticalSection( &reader->cs );
1699 if (reader->magic != READER_MAGIC)
1701 LeaveCriticalSection( &reader->cs );
1702 return E_INVALIDARG;
1705 hr = read_node( reader );
1707 LeaveCriticalSection( &reader->cs );
1708 return hr;
1711 /**************************************************************************
1712 * WsReadStartElement [webservices.@]
1714 HRESULT WINAPI WsReadStartElement( WS_XML_READER *handle, WS_ERROR *error )
1716 struct reader *reader = (struct reader *)handle;
1717 HRESULT hr;
1719 TRACE( "%p %p\n", handle, error );
1720 if (error) FIXME( "ignoring error parameter\n" );
1722 if (!reader) return E_INVALIDARG;
1724 EnterCriticalSection( &reader->cs );
1726 if (reader->magic != READER_MAGIC)
1728 LeaveCriticalSection( &reader->cs );
1729 return E_INVALIDARG;
1732 hr = read_startelement( reader );
1734 LeaveCriticalSection( &reader->cs );
1735 return hr;
1738 /**************************************************************************
1739 * WsReadToStartElement [webservices.@]
1741 HRESULT WINAPI WsReadToStartElement( WS_XML_READER *handle, const WS_XML_STRING *localname,
1742 const WS_XML_STRING *ns, BOOL *found, WS_ERROR *error )
1744 struct reader *reader = (struct reader *)handle;
1745 HRESULT hr;
1747 TRACE( "%p %s %s %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns), found, error );
1748 if (error) FIXME( "ignoring error parameter\n" );
1750 if (!reader) return E_INVALIDARG;
1751 if (localname || ns) FIXME( "name and/or namespace not verified\n" );
1753 EnterCriticalSection( &reader->cs );
1755 if (reader->magic != READER_MAGIC)
1757 LeaveCriticalSection( &reader->cs );
1758 return E_INVALIDARG;
1761 hr = read_to_startelement( reader, found );
1763 LeaveCriticalSection( &reader->cs );
1764 return hr;
1767 BOOL move_to_root_element( struct node *root, struct node **current )
1769 struct list *ptr;
1770 struct node *node;
1772 if (!(ptr = list_head( &root->children ))) return FALSE;
1773 node = LIST_ENTRY( ptr, struct node, entry );
1774 if (node_type( node ) == WS_XML_NODE_TYPE_ELEMENT)
1776 *current = node;
1777 return TRUE;
1779 while ((ptr = list_next( &root->children, &node->entry )))
1781 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1782 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1784 *current = next;
1785 return TRUE;
1787 node = next;
1789 return FALSE;
1792 BOOL move_to_next_element( struct node **current )
1794 struct list *ptr;
1795 struct node *node = *current, *parent = (*current)->parent;
1797 if (!parent) return FALSE;
1798 while ((ptr = list_next( &parent->children, &node->entry )))
1800 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1801 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1803 *current = next;
1804 return TRUE;
1806 node = next;
1808 return FALSE;
1811 BOOL move_to_prev_element( struct node **current )
1813 struct list *ptr;
1814 struct node *node = *current, *parent = (*current)->parent;
1816 if (!parent) return FALSE;
1817 while ((ptr = list_prev( &parent->children, &node->entry )))
1819 struct node *prev = LIST_ENTRY( ptr, struct node, entry );
1820 if (node_type( prev ) == WS_XML_NODE_TYPE_ELEMENT)
1822 *current = prev;
1823 return TRUE;
1825 node = prev;
1827 return FALSE;
1830 BOOL move_to_child_element( struct node **current )
1832 struct list *ptr;
1833 struct node *child, *node = *current;
1835 if (!(ptr = list_head( &node->children ))) return FALSE;
1836 child = LIST_ENTRY( ptr, struct node, entry );
1837 if (node_type( child ) == WS_XML_NODE_TYPE_ELEMENT)
1839 *current = child;
1840 return TRUE;
1842 while ((ptr = list_next( &node->children, &child->entry )))
1844 struct node *next = LIST_ENTRY( ptr, struct node, entry );
1845 if (node_type( next ) == WS_XML_NODE_TYPE_ELEMENT)
1847 *current = next;
1848 return TRUE;
1850 child = next;
1852 return FALSE;
1855 BOOL move_to_end_element( struct node **current )
1857 struct list *ptr;
1858 struct node *node = *current;
1860 if (node_type( node ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
1862 if ((ptr = list_tail( &node->children )))
1864 struct node *tail = LIST_ENTRY( ptr, struct node, entry );
1865 if (node_type( tail ) == WS_XML_NODE_TYPE_END_ELEMENT)
1867 *current = tail;
1868 return TRUE;
1871 return FALSE;
1874 BOOL move_to_parent_element( struct node **current )
1876 struct node *parent = (*current)->parent;
1878 if (parent && (node_type( parent ) == WS_XML_NODE_TYPE_ELEMENT ||
1879 node_type( parent ) == WS_XML_NODE_TYPE_BOF))
1881 *current = parent;
1882 return TRUE;
1884 return FALSE;
1887 BOOL move_to_first_node( struct node **current )
1889 struct list *ptr;
1890 struct node *node = *current;
1892 if ((ptr = list_head( &node->parent->children )))
1894 *current = LIST_ENTRY( ptr, struct node, entry );
1895 return TRUE;
1897 return FALSE;
1900 BOOL move_to_next_node( struct node **current )
1902 struct list *ptr;
1903 struct node *node = *current;
1905 if ((ptr = list_next( &node->parent->children, &node->entry )))
1907 *current = LIST_ENTRY( ptr, struct node, entry );
1908 return TRUE;
1910 return FALSE;
1913 BOOL move_to_prev_node( struct node **current )
1915 struct list *ptr;
1916 struct node *node = *current;
1918 if ((ptr = list_prev( &node->parent->children, &node->entry )))
1920 *current = LIST_ENTRY( ptr, struct node, entry );
1921 return TRUE;
1923 return FALSE;
1926 BOOL move_to_bof( struct node *root, struct node **current )
1928 *current = root;
1929 return TRUE;
1932 BOOL move_to_eof( struct node *root, struct node **current )
1934 struct list *ptr;
1935 if ((ptr = list_tail( &root->children )))
1937 *current = LIST_ENTRY( ptr, struct node, entry );
1938 return TRUE;
1940 return FALSE;
1943 BOOL move_to_child_node( struct node **current )
1945 struct list *ptr;
1946 struct node *node = *current;
1948 if ((ptr = list_head( &node->children )))
1950 *current = LIST_ENTRY( ptr, struct node, entry );
1951 return TRUE;
1953 return FALSE;
1956 BOOL move_to_parent_node( struct node **current )
1958 struct node *parent = (*current)->parent;
1959 if (!parent) return FALSE;
1960 *current = parent;
1961 return TRUE;
1964 static HRESULT read_move_to( struct reader *reader, WS_MOVE_TO move, BOOL *found )
1966 BOOL success = FALSE;
1967 HRESULT hr = S_OK;
1969 if (!read_end_of_data( reader ))
1971 while (reader->state != READER_STATE_EOF && (hr = read_node( reader )) == S_OK) { /* nothing */ };
1972 if (hr != S_OK) return hr;
1974 switch (move)
1976 case WS_MOVE_TO_ROOT_ELEMENT:
1977 success = move_to_root_element( reader->root, &reader->current );
1978 break;
1980 case WS_MOVE_TO_NEXT_ELEMENT:
1981 success = move_to_next_element( &reader->current );
1982 break;
1984 case WS_MOVE_TO_PREVIOUS_ELEMENT:
1985 success = move_to_prev_element( &reader->current );
1986 break;
1988 case WS_MOVE_TO_CHILD_ELEMENT:
1989 success = move_to_child_element( &reader->current );
1990 break;
1992 case WS_MOVE_TO_END_ELEMENT:
1993 success = move_to_end_element( &reader->current );
1994 break;
1996 case WS_MOVE_TO_PARENT_ELEMENT:
1997 success = move_to_parent_element( &reader->current );
1998 break;
2000 case WS_MOVE_TO_FIRST_NODE:
2001 success = move_to_first_node( &reader->current );
2002 break;
2004 case WS_MOVE_TO_NEXT_NODE:
2005 success = move_to_next_node( &reader->current );
2006 break;
2008 case WS_MOVE_TO_PREVIOUS_NODE:
2009 success = move_to_prev_node( &reader->current );
2010 break;
2012 case WS_MOVE_TO_CHILD_NODE:
2013 success = move_to_child_node( &reader->current );
2014 break;
2016 case WS_MOVE_TO_BOF:
2017 success = move_to_bof( reader->root, &reader->current );
2018 break;
2020 case WS_MOVE_TO_EOF:
2021 success = move_to_eof( reader->root, &reader->current );
2022 break;
2024 default:
2025 FIXME( "unhandled move %u\n", move );
2026 return E_NOTIMPL;
2029 if (found)
2031 *found = success;
2032 return S_OK;
2034 return success ? S_OK : WS_E_INVALID_FORMAT;
2037 /**************************************************************************
2038 * WsMoveReader [webservices.@]
2040 HRESULT WINAPI WsMoveReader( WS_XML_READER *handle, WS_MOVE_TO move, BOOL *found, WS_ERROR *error )
2042 struct reader *reader = (struct reader *)handle;
2043 HRESULT hr;
2045 TRACE( "%p %u %p %p\n", handle, move, found, error );
2046 if (error) FIXME( "ignoring error parameter\n" );
2048 if (!reader) return E_INVALIDARG;
2050 EnterCriticalSection( &reader->cs );
2052 if (reader->magic != READER_MAGIC)
2054 LeaveCriticalSection( &reader->cs );
2055 return E_INVALIDARG;
2058 if (!reader->input_type)
2060 LeaveCriticalSection( &reader->cs );
2061 return WS_E_INVALID_OPERATION;
2064 hr = read_move_to( reader, move, found );
2066 LeaveCriticalSection( &reader->cs );
2067 return hr;
2070 /**************************************************************************
2071 * WsReadStartAttribute [webservices.@]
2073 HRESULT WINAPI WsReadStartAttribute( WS_XML_READER *handle, ULONG index, WS_ERROR *error )
2075 struct reader *reader = (struct reader *)handle;
2076 const WS_XML_ELEMENT_NODE *elem;
2078 TRACE( "%p %u %p\n", handle, index, error );
2079 if (error) FIXME( "ignoring error parameter\n" );
2081 if (!reader) return E_INVALIDARG;
2083 EnterCriticalSection( &reader->cs );
2085 if (reader->magic != READER_MAGIC)
2087 LeaveCriticalSection( &reader->cs );
2088 return E_INVALIDARG;
2091 elem = &reader->current->hdr;
2092 if (reader->state != READER_STATE_STARTELEMENT || index >= elem->attributeCount)
2094 LeaveCriticalSection( &reader->cs );
2095 return WS_E_INVALID_FORMAT;
2098 reader->current_attr = index;
2099 reader->state = READER_STATE_STARTATTRIBUTE;
2101 LeaveCriticalSection( &reader->cs );
2102 return S_OK;
2105 /**************************************************************************
2106 * WsReadEndAttribute [webservices.@]
2108 HRESULT WINAPI WsReadEndAttribute( WS_XML_READER *handle, WS_ERROR *error )
2110 struct reader *reader = (struct reader *)handle;
2112 TRACE( "%p %p\n", handle, error );
2113 if (error) FIXME( "ignoring error parameter\n" );
2115 if (!reader) return E_INVALIDARG;
2117 EnterCriticalSection( &reader->cs );
2119 if (reader->magic != READER_MAGIC)
2121 LeaveCriticalSection( &reader->cs );
2122 return E_INVALIDARG;
2125 if (reader->state != READER_STATE_STARTATTRIBUTE)
2127 LeaveCriticalSection( &reader->cs );
2128 return WS_E_INVALID_FORMAT;
2131 reader->state = READER_STATE_STARTELEMENT;
2133 LeaveCriticalSection( &reader->cs );
2134 return S_OK;
2137 static HRESULT find_namespace( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING **ns )
2139 const struct node *node;
2140 for (node = reader->current->parent; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
2142 const WS_XML_ELEMENT_NODE *elem = &node->hdr;
2143 ULONG i;
2144 for (i = 0; i < elem->attributeCount; i++)
2146 if (!elem->attributes[i]->isXmlNs) continue;
2147 if (WsXmlStringEquals( elem->attributes[i]->prefix, prefix, NULL ) != S_OK) continue;
2148 *ns = elem->attributes[i]->ns;
2149 return S_OK;
2152 return WS_E_INVALID_FORMAT;
2155 static HRESULT read_qualified_name( struct reader *reader, WS_HEAP *heap, WS_XML_STRING *prefix_ret,
2156 WS_XML_STRING *localname_ret, WS_XML_STRING *ns_ret )
2158 const WS_XML_TEXT_NODE *node = (const WS_XML_TEXT_NODE *)reader->current;
2159 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)node->text;
2160 unsigned char *prefix_bytes, *localname_bytes, *ns_bytes;
2161 const unsigned char *ptr = utf8->value.bytes;
2162 WS_XML_STRING prefix, localname, empty = {0, NULL};
2163 const WS_XML_STRING *ns = &empty;
2164 ULONG len = utf8->value.length;
2165 HRESULT hr;
2167 while (len && read_isspace( *ptr )) { ptr++; len--; }
2168 while (len && read_isspace( ptr[len - 1] )) { len--; }
2169 if (!len) return WS_E_INVALID_FORMAT;
2171 if ((hr = split_name( ptr, len, (const unsigned char **)&prefix.bytes, &prefix.length,
2172 (const unsigned char **)&localname.bytes, &localname.length )) != S_OK) return hr;
2174 if (!localname.length) return WS_E_INVALID_FORMAT;
2175 if (prefix.length && (hr = find_namespace( reader, &prefix, &ns )) != S_OK) return hr;
2177 if (!(prefix_bytes = ws_alloc( heap, prefix.length ))) return WS_E_QUOTA_EXCEEDED;
2178 memcpy( prefix_bytes, prefix.bytes, prefix.length );
2180 if (!(localname_bytes = ws_alloc( heap, localname.length )))
2182 ws_free( heap, prefix_bytes, prefix.length );
2183 return WS_E_QUOTA_EXCEEDED;
2185 memcpy( localname_bytes, localname.bytes, localname.length );
2187 if (!(ns_bytes = ws_alloc( heap, ns->length )))
2189 ws_free( heap, prefix_bytes, prefix.length );
2190 ws_free( heap, localname_bytes, localname.length );
2191 return WS_E_QUOTA_EXCEEDED;
2193 memcpy( ns_bytes, ns->bytes, ns->length );
2195 prefix_ret->bytes = prefix_bytes;
2196 prefix_ret->length = prefix.length;
2198 localname_ret->bytes = localname_bytes;
2199 localname_ret->length = localname.length;
2201 ns_ret->bytes = ns_bytes;
2202 ns_ret->length = ns->length;
2204 return S_OK;
2207 /**************************************************************************
2208 * WsReadQualifiedName [webservices.@]
2210 HRESULT WINAPI WsReadQualifiedName( WS_XML_READER *handle, WS_HEAP *heap, WS_XML_STRING *prefix,
2211 WS_XML_STRING *localname, WS_XML_STRING *ns,
2212 WS_ERROR *error )
2214 struct reader *reader = (struct reader *)handle;
2215 HRESULT hr;
2217 TRACE( "%p %p %p %p %p %p\n", handle, heap, prefix, localname, ns, error );
2218 if (error) FIXME( "ignoring error parameter\n" );
2220 if (!reader || !heap) return E_INVALIDARG;
2222 EnterCriticalSection( &reader->cs );
2224 if (reader->magic != READER_MAGIC)
2226 LeaveCriticalSection( &reader->cs );
2227 return E_INVALIDARG;
2230 if (!reader->input_type)
2232 LeaveCriticalSection( &reader->cs );
2233 return WS_E_INVALID_OPERATION;
2236 if (!localname)
2238 LeaveCriticalSection( &reader->cs );
2239 return E_INVALIDARG;
2242 if (reader->state != READER_STATE_TEXT)
2244 LeaveCriticalSection( &reader->cs );
2245 return WS_E_INVALID_FORMAT;
2248 hr = read_qualified_name( reader, heap, prefix, localname, ns );
2250 LeaveCriticalSection( &reader->cs );
2251 return hr;
2254 static WCHAR *xmltext_to_widechar( WS_HEAP *heap, const WS_XML_TEXT *text )
2256 WCHAR *ret;
2258 switch (text->textType)
2260 case WS_XML_TEXT_TYPE_UTF8:
2262 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
2263 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
2264 if (!(ret = ws_alloc( heap, (len + 1) * sizeof(WCHAR) ))) return NULL;
2265 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, ret, len );
2266 ret[len] = 0;
2267 break;
2269 default:
2270 FIXME( "unhandled type %u\n", text->textType );
2271 return NULL;
2274 return ret;
2277 #define MAX_INT8 0x7f
2278 #define MIN_INT8 (-MAX_INT8 - 1)
2279 #define MAX_INT16 0x7fff
2280 #define MIN_INT16 (-MAX_INT16 - 1)
2281 #define MAX_INT32 0x7fffffff
2282 #define MIN_INT32 (-MAX_INT32 - 1)
2283 #define MAX_INT64 (((INT64)0x7fffffff << 32) | 0xffffffff)
2284 #define MIN_INT64 (-MAX_INT64 - 1)
2285 #define MAX_UINT8 0xff
2286 #define MAX_UINT16 0xffff
2287 #define MAX_UINT32 0xffffffff
2288 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
2290 static HRESULT str_to_int64( const unsigned char *str, ULONG len, INT64 min, INT64 max, INT64 *ret )
2292 BOOL negative = FALSE;
2293 const unsigned char *ptr = str;
2295 *ret = 0;
2296 while (len && read_isspace( *ptr )) { ptr++; len--; }
2297 while (len && read_isspace( ptr[len - 1] )) { len--; }
2298 if (!len) return WS_E_INVALID_FORMAT;
2300 if (*ptr == '-')
2302 negative = TRUE;
2303 ptr++;
2304 len--;
2306 if (!len) return WS_E_INVALID_FORMAT;
2308 while (len--)
2310 int val;
2312 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2313 val = *ptr - '0';
2314 if (negative) val = -val;
2316 if ((!negative && (*ret > max / 10 || *ret * 10 > max - val)) ||
2317 (negative && (*ret < min / 10 || *ret * 10 < min - val)))
2319 return WS_E_NUMERIC_OVERFLOW;
2321 *ret = *ret * 10 + val;
2322 ptr++;
2325 return S_OK;
2328 static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, UINT64 *ret )
2330 const unsigned char *ptr = str;
2332 *ret = 0;
2333 while (len && read_isspace( *ptr )) { ptr++; len--; }
2334 while (len && read_isspace( ptr[len - 1] )) { len--; }
2335 if (!len) return WS_E_INVALID_FORMAT;
2337 while (len--)
2339 unsigned int val;
2341 if (!isdigit( *ptr )) return WS_E_INVALID_FORMAT;
2342 val = *ptr - '0';
2344 if ((*ret > max / 10 || *ret * 10 > max - val)) return WS_E_NUMERIC_OVERFLOW;
2345 *ret = *ret * 10 + val;
2346 ptr++;
2349 return S_OK;
2352 BOOL set_fpword( unsigned short new, unsigned short *old )
2354 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2355 unsigned short fpword;
2357 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
2358 *old = fpword;
2359 fpword = new;
2360 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2361 return TRUE;
2362 #else
2363 FIXME( "not implemented\n" );
2364 return FALSE;
2365 #endif
2368 void restore_fpword( unsigned short fpword )
2370 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2371 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
2372 #else
2373 FIXME( "not implemented\n" );
2374 #endif
2377 static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret )
2379 static const unsigned __int64 nan = 0xfff8000000000000;
2380 static const unsigned __int64 inf = 0x7ff0000000000000;
2381 static const unsigned __int64 inf_min = 0xfff0000000000000;
2382 HRESULT hr = WS_E_INVALID_FORMAT;
2383 const unsigned char *p = str, *q;
2384 int sign = 1, exp_sign = 1, exp = 0, exp_tmp = 0, neg_exp, i, nb_digits, have_digits;
2385 unsigned __int64 val = 0, tmp;
2386 long double exp_val = 1.0, exp_mul = 10.0;
2387 unsigned short fpword;
2389 while (len && read_isspace( *p )) { p++; len--; }
2390 while (len && read_isspace( p[len - 1] )) { len--; }
2391 if (!len) return WS_E_INVALID_FORMAT;
2393 if (len == 3 && !memcmp( p, "NaN", 3 ))
2395 *(unsigned __int64 *)ret = nan;
2396 return S_OK;
2398 else if (len == 3 && !memcmp( p, "INF", 3 ))
2400 *(unsigned __int64 *)ret = inf;
2401 return S_OK;
2403 else if (len == 4 && !memcmp( p, "-INF", 4 ))
2405 *(unsigned __int64 *)ret = inf_min;
2406 return S_OK;
2409 *ret = 0.0;
2410 if (*p == '-')
2412 sign = -1;
2413 p++; len--;
2415 else if (*p == '+') { p++; len--; };
2416 if (!len) return S_OK;
2418 if (!set_fpword( 0x37f, &fpword )) return E_NOTIMPL;
2420 q = p;
2421 while (len && isdigit( *q )) { q++; len--; }
2422 have_digits = nb_digits = q - p;
2423 for (i = 0; i < nb_digits; i++)
2425 tmp = val * 10 + p[i] - '0';
2426 if (val > MAX_UINT64 / 10 || tmp < val)
2428 for (; i < nb_digits; i++) exp++;
2429 break;
2431 val = tmp;
2434 if (len)
2436 if (*q == '.')
2438 p = ++q; len--;
2439 while (len && isdigit( *q )) { q++; len--; };
2440 have_digits |= nb_digits = q - p;
2441 for (i = 0; i < nb_digits; i++)
2443 tmp = val * 10 + p[i] - '0';
2444 if (val > MAX_UINT64 / 10 || tmp < val) break;
2445 val = tmp;
2446 exp--;
2449 if (len > 1 && tolower(*q) == 'e')
2451 if (!have_digits) goto done;
2452 p = ++q; len--;
2453 if (*p == '-')
2455 exp_sign = -1;
2456 p++; len--;
2458 else if (*p == '+') { p++; len--; };
2460 q = p;
2461 while (len && isdigit( *q )) { q++; len--; };
2462 nb_digits = q - p;
2463 if (!nb_digits || len) goto done;
2464 for (i = 0; i < nb_digits; i++)
2466 if (exp_tmp > MAX_INT32 / 10 || (exp_tmp = exp_tmp * 10 + p[i] - '0') < 0)
2467 exp_tmp = MAX_INT32;
2469 exp_tmp *= exp_sign;
2471 if (exp < 0 && exp_tmp < 0 && exp + exp_tmp >= 0) exp = MIN_INT32;
2472 else if (exp > 0 && exp_tmp > 0 && exp + exp_tmp < 0) exp = MAX_INT32;
2473 else exp += exp_tmp;
2476 if (!have_digits || len) goto done;
2478 if ((neg_exp = exp < 0)) exp = -exp;
2479 for (; exp; exp >>= 1)
2481 if (exp & 1) exp_val *= exp_mul;
2482 exp_mul *= exp_mul;
2485 *ret = sign * (neg_exp ? val / exp_val : val * exp_val);
2486 hr = S_OK;
2488 done:
2489 restore_fpword( fpword );
2490 return hr;
2493 static HRESULT str_to_guid( const unsigned char *str, ULONG len, GUID *ret )
2495 static const unsigned char hex[] =
2497 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
2498 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
2499 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
2500 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
2501 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
2502 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
2503 0,10,11,12,13,14,15 /* 0x60 */
2505 const unsigned char *p = str;
2506 ULONG i;
2508 while (len && read_isspace( *p )) { p++; len--; }
2509 while (len && read_isspace( p[len - 1] )) { len--; }
2510 if (len != 36) return WS_E_INVALID_FORMAT;
2512 if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-')
2513 return WS_E_INVALID_FORMAT;
2515 for (i = 0; i < 36; i++)
2517 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
2518 if (p[i] > 'f' || (!hex[p[i]] && p[i] != '0')) return WS_E_INVALID_FORMAT;
2521 ret->Data1 = hex[p[0]] << 28 | hex[p[1]] << 24 | hex[p[2]] << 20 | hex[p[3]] << 16 |
2522 hex[p[4]] << 12 | hex[p[5]] << 8 | hex[p[6]] << 4 | hex[p[7]];
2524 ret->Data2 = hex[p[9]] << 12 | hex[p[10]] << 8 | hex[p[11]] << 4 | hex[p[12]];
2525 ret->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[16]] << 4 | hex[p[17]];
2527 ret->Data4[0] = hex[p[19]] << 4 | hex[p[20]];
2528 ret->Data4[1] = hex[p[21]] << 4 | hex[p[22]];
2529 ret->Data4[2] = hex[p[24]] << 4 | hex[p[25]];
2530 ret->Data4[3] = hex[p[26]] << 4 | hex[p[27]];
2531 ret->Data4[4] = hex[p[28]] << 4 | hex[p[29]];
2532 ret->Data4[5] = hex[p[30]] << 4 | hex[p[31]];
2533 ret->Data4[6] = hex[p[32]] << 4 | hex[p[33]];
2534 ret->Data4[7] = hex[p[34]] << 4 | hex[p[35]];
2536 return S_OK;
2539 static inline unsigned char decode_char( unsigned char c )
2541 if (c >= 'A' && c <= 'Z') return c - 'A';
2542 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2543 if (c >= '0' && c <= '9') return c - '0' + 52;
2544 if (c == '+') return 62;
2545 if (c == '/') return 63;
2546 return 64;
2549 static ULONG decode_base64( const unsigned char *base64, ULONG len, unsigned char *buf )
2551 ULONG i = 0;
2552 unsigned char c0, c1, c2, c3;
2553 const unsigned char *p = base64;
2555 while (len > 4)
2557 if ((c0 = decode_char( p[0] )) > 63) return 0;
2558 if ((c1 = decode_char( p[1] )) > 63) return 0;
2559 if ((c2 = decode_char( p[2] )) > 63) return 0;
2560 if ((c3 = decode_char( p[3] )) > 63) return 0;
2561 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2562 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2563 buf[i + 2] = (c2 << 6) | c3;
2564 len -= 4;
2565 i += 3;
2566 p += 4;
2568 if (p[2] == '=')
2570 if ((c0 = decode_char( p[0] )) > 63) return 0;
2571 if ((c1 = decode_char( p[1] )) > 63) return 0;
2572 buf[i] = (c0 << 2) | (c1 >> 4);
2573 i++;
2575 else if (p[3] == '=')
2577 if ((c0 = decode_char( p[0] )) > 63) return 0;
2578 if ((c1 = decode_char( p[1] )) > 63) return 0;
2579 if ((c2 = decode_char( p[2] )) > 63) return 0;
2580 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2581 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2582 i += 2;
2584 else
2586 if ((c0 = decode_char( p[0] )) > 63) return 0;
2587 if ((c1 = decode_char( p[1] )) > 63) return 0;
2588 if ((c2 = decode_char( p[2] )) > 63) return 0;
2589 if ((c3 = decode_char( p[3] )) > 63) return 0;
2590 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2591 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2592 buf[i + 2] = (c2 << 6) | c3;
2593 i += 3;
2595 return i;
2598 static HRESULT str_to_bytes( const unsigned char *str, ULONG len, WS_HEAP *heap, WS_BYTES *ret )
2600 const unsigned char *p = str;
2602 while (len && read_isspace( *p )) { p++; len--; }
2603 while (len && read_isspace( p[len - 1] )) { len--; }
2605 if (len % 4) return WS_E_INVALID_FORMAT;
2606 if (!(ret->bytes = ws_alloc( heap, len * 3 / 4 ))) return WS_E_QUOTA_EXCEEDED;
2607 ret->length = decode_base64( p, len, ret->bytes );
2608 return S_OK;
2611 static const int month_offsets[2][12] =
2613 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
2614 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
2617 static inline int valid_day( int year, int month, int day )
2619 return day > 0 && day <= month_days[leap_year( year )][month - 1];
2622 static inline int leap_days_before( int year )
2624 return (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
2627 static HRESULT str_to_datetime( const unsigned char *bytes, ULONG len, WS_DATETIME *ret )
2629 const unsigned char *p = bytes, *q;
2630 int year, month, day, hour, min, sec, sec_frac = 0, tz_hour, tz_min, tz_neg;
2632 while (len && read_isspace( *p )) { p++; len--; }
2633 while (len && read_isspace( p[len - 1] )) { len--; }
2635 q = p;
2636 while (len && isdigit( *q )) { q++; len--; };
2637 if (q - p != 4 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2638 year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
2639 if (year < 1) return WS_E_INVALID_FORMAT;
2641 p = ++q; len--;
2642 while (len && isdigit( *q )) { q++; len--; };
2643 if (q - p != 2 || !len || *q != '-') return WS_E_INVALID_FORMAT;
2644 month = (p[0] - '0') * 10 + p[1] - '0';
2645 if (month < 1 || month > 12) return WS_E_INVALID_FORMAT;
2647 p = ++q; len--;
2648 while (len && isdigit( *q )) { q++; len--; };
2649 if (q - p != 2 || !len || *q != 'T') return WS_E_INVALID_FORMAT;
2650 day = (p[0] - '0') * 10 + p[1] - '0';
2651 if (!valid_day( year, month, day )) return WS_E_INVALID_FORMAT;
2653 p = ++q; len--;
2654 while (len && isdigit( *q )) { q++; len--; };
2655 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2656 hour = (p[0] - '0') * 10 + p[1] - '0';
2657 if (hour > 24) return WS_E_INVALID_FORMAT;
2659 p = ++q; len--;
2660 while (len && isdigit( *q )) { q++; len--; };
2661 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2662 min = (p[0] - '0') * 10 + p[1] - '0';
2663 if (min > 59 || (min > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
2665 p = ++q; len--;
2666 while (len && isdigit( *q )) { q++; len--; };
2667 if (q - p != 2 || !len) return WS_E_INVALID_FORMAT;
2668 sec = (p[0] - '0') * 10 + p[1] - '0';
2669 if (sec > 59 || (sec > 0 && hour == 24)) return WS_E_INVALID_FORMAT;
2671 if (*q == '.')
2673 unsigned int i, nb_digits, mul = TICKS_PER_SEC / 10;
2674 p = ++q; len--;
2675 while (len && isdigit( *q )) { q++; len--; };
2676 nb_digits = q - p;
2677 if (nb_digits < 1 || nb_digits > 7) return WS_E_INVALID_FORMAT;
2678 for (i = 0; i < nb_digits; i++)
2680 sec_frac += (p[i] - '0') * mul;
2681 mul /= 10;
2684 if (*q == 'Z')
2686 if (--len) return WS_E_INVALID_FORMAT;
2687 tz_hour = tz_min = tz_neg = 0;
2688 ret->format = WS_DATETIME_FORMAT_UTC;
2690 else if (*q == '+' || *q == '-')
2692 tz_neg = (*q == '-') ? 1 : 0;
2694 p = ++q; len--;
2695 while (len && isdigit( *q )) { q++; len--; };
2696 if (q - p != 2 || !len || *q != ':') return WS_E_INVALID_FORMAT;
2697 tz_hour = (p[0] - '0') * 10 + p[1] - '0';
2698 if (tz_hour > 14) return WS_E_INVALID_FORMAT;
2700 p = ++q; len--;
2701 while (len && isdigit( *q )) { q++; len--; };
2702 if (q - p != 2 || len) return WS_E_INVALID_FORMAT;
2703 tz_min = (p[0] - '0') * 10 + p[1] - '0';
2704 if (tz_min > 59 || (tz_min > 0 && tz_hour == 14)) return WS_E_INVALID_FORMAT;
2706 ret->format = WS_DATETIME_FORMAT_LOCAL;
2708 else return WS_E_INVALID_FORMAT;
2710 ret->ticks = ((year - 1) * 365 + leap_days_before( year )) * TICKS_PER_DAY;
2711 ret->ticks += month_offsets[leap_year( year )][month - 1] * TICKS_PER_DAY;
2712 ret->ticks += (day - 1) * TICKS_PER_DAY;
2713 ret->ticks += hour * TICKS_PER_HOUR;
2714 ret->ticks += min * TICKS_PER_MIN;
2715 ret->ticks += sec * TICKS_PER_SEC;
2716 ret->ticks += sec_frac;
2718 if (tz_neg)
2720 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN + ret->ticks > TICKS_MAX)
2721 return WS_E_INVALID_FORMAT;
2722 ret->ticks += tz_hour * TICKS_PER_HOUR;
2723 ret->ticks += tz_min * TICKS_PER_MIN;
2725 else
2727 if (tz_hour * TICKS_PER_HOUR + tz_min * TICKS_PER_MIN > ret->ticks)
2728 return WS_E_INVALID_FORMAT;
2729 ret->ticks -= tz_hour * TICKS_PER_HOUR;
2730 ret->ticks -= tz_min * TICKS_PER_MIN;
2733 return S_OK;
2736 /**************************************************************************
2737 * WsDateTimeToFileTime [webservices.@]
2739 HRESULT WINAPI WsDateTimeToFileTime( const WS_DATETIME *dt, FILETIME *ft, WS_ERROR *error )
2741 unsigned __int64 ticks;
2743 TRACE( "%p %p %p\n", dt, ft, error );
2744 if (error) FIXME( "ignoring error parameter\n" );
2746 if (!dt || !ft) return E_INVALIDARG;
2748 if (dt->ticks < TICKS_1601_01_01) return WS_E_INVALID_FORMAT;
2749 ticks = dt->ticks - TICKS_1601_01_01;
2750 ft->dwHighDateTime = ticks >> 32;
2751 ft->dwLowDateTime = (DWORD)ticks;
2752 return S_OK;
2755 /**************************************************************************
2756 * WsFileTimeToDateTime [webservices.@]
2758 HRESULT WINAPI WsFileTimeToDateTime( const FILETIME *ft, WS_DATETIME *dt, WS_ERROR *error )
2760 unsigned __int64 ticks;
2762 TRACE( "%p %p %p\n", ft, dt, error );
2763 if (error) FIXME( "ignoring error parameter\n" );
2765 if (!dt || !ft) return E_INVALIDARG;
2767 ticks = ((unsigned __int64)ft->dwHighDateTime << 32) | ft->dwLowDateTime;
2768 if (ticks > MAX_UINT64 - TICKS_1601_01_01) return WS_E_NUMERIC_OVERFLOW;
2769 if (ticks + TICKS_1601_01_01 > TICKS_MAX) return WS_E_INVALID_FORMAT;
2770 dt->ticks = ticks + TICKS_1601_01_01;
2771 dt->format = WS_DATETIME_FORMAT_UTC;
2772 return S_OK;
2775 static HRESULT read_get_node_text( struct reader *reader, WS_XML_UTF8_TEXT **ret )
2777 WS_XML_TEXT_NODE *text;
2779 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT)
2780 return WS_E_INVALID_FORMAT;
2782 text = (WS_XML_TEXT_NODE *)&reader->current->hdr.node;
2783 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
2785 FIXME( "text type %u not supported\n", text->text->textType );
2786 return E_NOTIMPL;
2788 *ret = (WS_XML_UTF8_TEXT *)text->text;
2789 return S_OK;
2792 static HRESULT read_get_attribute_text( struct reader *reader, ULONG index, WS_XML_UTF8_TEXT **ret )
2794 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2795 WS_XML_ATTRIBUTE *attr;
2797 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
2798 return WS_E_INVALID_FORMAT;
2800 attr = elem->attributes[index];
2801 if (attr->value->textType != WS_XML_TEXT_TYPE_UTF8)
2803 FIXME( "text type %u not supported\n", attr->value->textType );
2804 return E_NOTIMPL;
2806 *ret = (WS_XML_UTF8_TEXT *)attr->value;
2807 return S_OK;
2810 static BOOL find_attribute( struct reader *reader, const WS_XML_STRING *localname,
2811 const WS_XML_STRING *ns, ULONG *index )
2813 ULONG i;
2814 WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2816 if (!localname)
2818 *index = reader->current_attr;
2819 return TRUE;
2821 for (i = 0; i < elem->attributeCount; i++)
2823 const WS_XML_STRING *localname2 = elem->attributes[i]->localName;
2824 const WS_XML_STRING *ns2 = elem->attributes[i]->ns;
2826 if (!cmp_name( localname->bytes, localname->length, localname2->bytes, localname2->length ) &&
2827 !cmp_name( ns->bytes, ns->length, ns2->bytes, ns2->length ))
2829 *index = i;
2830 return TRUE;
2833 return FALSE;
2836 /**************************************************************************
2837 * WsFindAttribute [webservices.@]
2839 HRESULT WINAPI WsFindAttribute( WS_XML_READER *handle, const WS_XML_STRING *localname,
2840 const WS_XML_STRING *ns, BOOL required, ULONG *index,
2841 WS_ERROR *error )
2843 struct reader *reader = (struct reader *)handle;
2844 HRESULT hr = S_OK;
2846 TRACE( "%p %s %s %d %p %p\n", handle, debugstr_xmlstr(localname), debugstr_xmlstr(ns),
2847 required, index, error );
2848 if (error) FIXME( "ignoring error parameter\n" );
2850 if (!reader || !localname || !ns || !index) return E_INVALIDARG;
2852 EnterCriticalSection( &reader->cs );
2854 if (reader->magic != READER_MAGIC)
2856 LeaveCriticalSection( &reader->cs );
2857 return E_INVALIDARG;
2860 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT)
2862 LeaveCriticalSection( &reader->cs );
2863 return WS_E_INVALID_OPERATION;
2866 if (!find_attribute( reader, localname, ns, index ))
2868 if (required) hr = WS_E_INVALID_FORMAT;
2869 else
2871 *index = ~0u;
2872 hr = S_FALSE;
2876 LeaveCriticalSection( &reader->cs );
2877 return hr;
2880 static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
2881 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2882 WS_XML_UTF8_TEXT **ret, BOOL *found )
2884 switch (mapping)
2886 case WS_ATTRIBUTE_TYPE_MAPPING:
2888 ULONG index;
2889 if (!(*found = find_attribute( reader, localname, ns, &index ))) return S_OK;
2890 return read_get_attribute_text( reader, index, ret );
2892 case WS_ELEMENT_TYPE_MAPPING:
2893 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
2894 case WS_ANY_ELEMENT_TYPE_MAPPING:
2896 HRESULT hr;
2897 *found = TRUE;
2898 if (localname)
2900 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
2902 if (WsXmlStringEquals( localname, elem->localName, NULL ) != S_OK ||
2903 WsXmlStringEquals( ns, elem->ns, NULL ) != S_OK)
2905 *found = FALSE;
2906 return S_OK;
2908 if ((hr = read_startelement( reader )) != S_OK) return hr;
2910 return read_get_node_text( reader, ret );
2912 default:
2913 FIXME( "mapping %u not supported\n", mapping );
2914 return E_NOTIMPL;
2918 static HRESULT read_type_bool( struct reader *reader, WS_TYPE_MAPPING mapping,
2919 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2920 const WS_BOOL_DESCRIPTION *desc, WS_READ_OPTION option,
2921 WS_HEAP *heap, void *ret, ULONG size )
2923 WS_XML_UTF8_TEXT *utf8;
2924 HRESULT hr;
2925 BOOL found, val = FALSE;
2927 if (desc)
2929 FIXME( "description not supported\n" );
2930 return E_NOTIMPL;
2932 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
2933 if (found)
2935 ULONG len = utf8->value.length;
2936 if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) val = TRUE;
2937 else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) val = TRUE;
2938 else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) val = FALSE;
2939 else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) val = FALSE;
2940 else return WS_E_INVALID_FORMAT;
2943 switch (option)
2945 case WS_READ_REQUIRED_VALUE:
2946 if (!found) return WS_E_INVALID_FORMAT;
2947 /* fall through */
2949 case WS_READ_NILLABLE_VALUE:
2950 if (size != sizeof(BOOL)) return E_INVALIDARG;
2951 *(BOOL *)ret = val;
2952 break;
2954 case WS_READ_REQUIRED_POINTER:
2955 if (!found) return WS_E_INVALID_FORMAT;
2956 /* fall through */
2958 case WS_READ_OPTIONAL_POINTER:
2959 case WS_READ_NILLABLE_POINTER:
2961 BOOL *heap_val = NULL;
2962 if (size != sizeof(heap_val)) return E_INVALIDARG;
2963 if (found)
2965 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
2966 *heap_val = val;
2968 *(BOOL **)ret = heap_val;
2969 break;
2971 default:
2972 FIXME( "read option %u not supported\n", option );
2973 return E_NOTIMPL;
2976 return S_OK;
2979 static HRESULT read_type_int8( struct reader *reader, WS_TYPE_MAPPING mapping,
2980 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
2981 const WS_INT8_DESCRIPTION *desc, WS_READ_OPTION option,
2982 WS_HEAP *heap, void *ret, ULONG size )
2984 WS_XML_UTF8_TEXT *utf8;
2985 HRESULT hr;
2986 INT64 val = 0;
2987 BOOL found;
2989 if (desc)
2991 FIXME( "description not supported\n" );
2992 return E_NOTIMPL;
2994 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
2995 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
2996 return hr;
2998 switch (option)
3000 case WS_READ_REQUIRED_VALUE:
3001 if (!found) return WS_E_INVALID_FORMAT;
3002 /* fall through */
3004 case WS_READ_NILLABLE_VALUE:
3005 if (size != sizeof(INT8)) return E_INVALIDARG;
3006 *(INT8 *)ret = val;
3007 break;
3009 case WS_READ_REQUIRED_POINTER:
3010 if (!found) return WS_E_INVALID_FORMAT;
3011 /* fall through */
3013 case WS_READ_OPTIONAL_POINTER:
3014 case WS_READ_NILLABLE_POINTER:
3016 INT8 *heap_val = NULL;
3017 if (size != sizeof(heap_val)) return E_INVALIDARG;
3018 if (found)
3020 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3021 *heap_val = val;
3023 *(INT8 **)ret = heap_val;
3024 break;
3026 default:
3027 FIXME( "read option %u not supported\n", option );
3028 return E_NOTIMPL;
3031 return S_OK;
3034 static HRESULT read_type_int16( struct reader *reader, WS_TYPE_MAPPING mapping,
3035 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3036 const WS_INT16_DESCRIPTION *desc, WS_READ_OPTION option,
3037 WS_HEAP *heap, void *ret, ULONG size )
3039 WS_XML_UTF8_TEXT *utf8;
3040 HRESULT hr;
3041 INT64 val = 0;
3042 BOOL found;
3044 if (desc)
3046 FIXME( "description not supported\n" );
3047 return E_NOTIMPL;
3049 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3050 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
3051 return hr;
3053 switch (option)
3055 case WS_READ_REQUIRED_VALUE:
3056 if (!found) return WS_E_INVALID_FORMAT;
3057 /* fall through */
3059 case WS_READ_NILLABLE_VALUE:
3060 if (size != sizeof(INT16)) return E_INVALIDARG;
3061 *(INT16 *)ret = val;
3062 break;
3064 case WS_READ_REQUIRED_POINTER:
3065 if (!found) return WS_E_INVALID_FORMAT;
3066 /* fall through */
3068 case WS_READ_OPTIONAL_POINTER:
3069 case WS_READ_NILLABLE_POINTER:
3071 INT16 *heap_val = NULL;
3072 if (size != sizeof(heap_val)) return E_INVALIDARG;
3073 if (found)
3075 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3076 *heap_val = val;
3078 *(INT16 **)ret = heap_val;
3079 break;
3081 default:
3082 FIXME( "read option %u not supported\n", option );
3083 return E_NOTIMPL;
3086 return S_OK;
3089 static HRESULT read_type_int32( struct reader *reader, WS_TYPE_MAPPING mapping,
3090 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3091 const WS_INT32_DESCRIPTION *desc, WS_READ_OPTION option,
3092 WS_HEAP *heap, void *ret, ULONG size )
3094 WS_XML_UTF8_TEXT *utf8;
3095 HRESULT hr;
3096 INT64 val = 0;
3097 BOOL found;
3099 if (desc)
3101 FIXME( "description not supported\n" );
3102 return E_NOTIMPL;
3104 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3105 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
3106 return hr;
3108 switch (option)
3110 case WS_READ_REQUIRED_VALUE:
3111 if (!found) return WS_E_INVALID_FORMAT;
3112 /* fall through */
3114 case WS_READ_NILLABLE_VALUE:
3115 if (size != sizeof(INT32)) return E_INVALIDARG;
3116 *(INT32 *)ret = val;
3117 break;
3119 case WS_READ_REQUIRED_POINTER:
3120 if (!found) return WS_E_INVALID_FORMAT;
3121 /* fall through */
3123 case WS_READ_OPTIONAL_POINTER:
3124 case WS_READ_NILLABLE_POINTER:
3126 INT32 *heap_val = NULL;
3127 if (size != sizeof(heap_val)) return E_INVALIDARG;
3128 if (found)
3130 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3131 *heap_val = val;
3133 *(INT32 **)ret = heap_val;
3134 break;
3136 default:
3137 FIXME( "read option %u not supported\n", option );
3138 return E_NOTIMPL;
3141 return S_OK;
3144 static HRESULT read_type_int64( struct reader *reader, WS_TYPE_MAPPING mapping,
3145 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3146 const WS_INT64_DESCRIPTION *desc, WS_READ_OPTION option,
3147 WS_HEAP *heap, void *ret, ULONG size )
3149 WS_XML_UTF8_TEXT *utf8;
3150 HRESULT hr;
3151 INT64 val = 0;
3152 BOOL found;
3154 if (desc)
3156 FIXME( "description not supported\n" );
3157 return E_NOTIMPL;
3159 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3160 if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
3161 return hr;
3163 switch (option)
3165 case WS_READ_REQUIRED_VALUE:
3166 if (!found) return WS_E_INVALID_FORMAT;
3167 /* fall through */
3169 case WS_READ_NILLABLE_VALUE:
3170 if (size != sizeof(INT64)) return E_INVALIDARG;
3171 *(INT64 *)ret = val;
3172 break;
3174 case WS_READ_REQUIRED_POINTER:
3175 if (!found) return WS_E_INVALID_FORMAT;
3176 /* fall through */
3178 case WS_READ_OPTIONAL_POINTER:
3179 case WS_READ_NILLABLE_POINTER:
3181 INT64 *heap_val = NULL;
3182 if (size != sizeof(heap_val)) return E_INVALIDARG;
3183 if (found)
3185 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3186 *heap_val = val;
3188 *(INT64 **)ret = heap_val;
3189 break;
3191 default:
3192 FIXME( "read option %u not supported\n", option );
3193 return E_NOTIMPL;
3196 return S_OK;
3199 static HRESULT read_type_uint8( struct reader *reader, WS_TYPE_MAPPING mapping,
3200 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3201 const WS_UINT8_DESCRIPTION *desc, WS_READ_OPTION option,
3202 WS_HEAP *heap, void *ret, ULONG size )
3204 WS_XML_UTF8_TEXT *utf8;
3205 HRESULT hr;
3206 UINT64 val = 0;
3207 BOOL found;
3209 if (desc)
3211 FIXME( "description not supported\n" );
3212 return E_NOTIMPL;
3214 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3215 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
3216 return hr;
3218 switch (option)
3220 case WS_READ_REQUIRED_VALUE:
3221 if (!found) return WS_E_INVALID_FORMAT;
3222 /* fall through */
3224 case WS_READ_NILLABLE_VALUE:
3225 if (size != sizeof(UINT8)) return E_INVALIDARG;
3226 *(UINT8 *)ret = val;
3227 break;
3229 case WS_READ_REQUIRED_POINTER:
3230 if (!found) return WS_E_INVALID_FORMAT;
3231 /* fall through */
3233 case WS_READ_OPTIONAL_POINTER:
3234 case WS_READ_NILLABLE_POINTER:
3236 UINT8 *heap_val = NULL;
3237 if (size != sizeof(heap_val)) return E_INVALIDARG;
3238 if (found)
3240 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3241 *heap_val = val;
3243 *(UINT8 **)ret = heap_val;
3244 break;
3246 default:
3247 FIXME( "read option %u not supported\n", option );
3248 return E_NOTIMPL;
3251 return S_OK;
3254 static HRESULT read_type_uint16( struct reader *reader, WS_TYPE_MAPPING mapping,
3255 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3256 const WS_UINT16_DESCRIPTION *desc, WS_READ_OPTION option,
3257 WS_HEAP *heap, void *ret, ULONG size )
3259 WS_XML_UTF8_TEXT *utf8;
3260 HRESULT hr;
3261 UINT64 val = 0;
3262 BOOL found;
3264 if (desc)
3266 FIXME( "description not supported\n" );
3267 return E_NOTIMPL;
3269 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3270 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
3271 return hr;
3273 switch (option)
3275 case WS_READ_REQUIRED_VALUE:
3276 if (!found) return WS_E_INVALID_FORMAT;
3277 /* fall through */
3279 case WS_READ_NILLABLE_VALUE:
3280 if (size != sizeof(UINT16)) return E_INVALIDARG;
3281 *(UINT16 *)ret = val;
3282 break;
3284 case WS_READ_REQUIRED_POINTER:
3285 if (!found) return WS_E_INVALID_FORMAT;
3286 /* fall through */
3288 case WS_READ_OPTIONAL_POINTER:
3289 case WS_READ_NILLABLE_POINTER:
3291 UINT16 *heap_val = NULL;
3292 if (size != sizeof(heap_val)) return E_INVALIDARG;
3293 if (found)
3295 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3296 *heap_val = val;
3298 *(UINT16 **)ret = heap_val;
3299 break;
3301 default:
3302 FIXME( "read option %u not supported\n", option );
3303 return E_NOTIMPL;
3306 return S_OK;
3309 static HRESULT read_type_uint32( struct reader *reader, WS_TYPE_MAPPING mapping,
3310 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3311 const WS_UINT32_DESCRIPTION *desc, WS_READ_OPTION option,
3312 WS_HEAP *heap, void *ret, ULONG size )
3314 WS_XML_UTF8_TEXT *utf8;
3315 HRESULT hr;
3316 UINT64 val = 0;
3317 BOOL found;
3319 if (desc)
3321 FIXME( "description not supported\n" );
3322 return E_NOTIMPL;
3324 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3325 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
3326 return hr;
3328 switch (option)
3330 case WS_READ_REQUIRED_VALUE:
3331 if (!found) return WS_E_INVALID_FORMAT;
3332 /* fall through */
3334 case WS_READ_NILLABLE_VALUE:
3335 if (size != sizeof(UINT32)) return E_INVALIDARG;
3336 *(UINT32 *)ret = val;
3337 break;
3339 case WS_READ_REQUIRED_POINTER:
3340 if (!found) return WS_E_INVALID_FORMAT;
3341 /* fall through */
3343 case WS_READ_OPTIONAL_POINTER:
3344 case WS_READ_NILLABLE_POINTER:
3346 UINT32 *heap_val = NULL;
3347 if (size != sizeof(heap_val)) return E_INVALIDARG;
3348 if (found)
3350 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3351 *heap_val = val;
3353 *(UINT32 **)ret = heap_val;
3354 break;
3356 default:
3357 FIXME( "read option %u not supported\n", option );
3358 return E_NOTIMPL;
3361 return S_OK;
3364 static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
3365 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3366 const WS_UINT64_DESCRIPTION *desc, WS_READ_OPTION option,
3367 WS_HEAP *heap, void *ret, ULONG size )
3369 WS_XML_UTF8_TEXT *utf8;
3370 HRESULT hr;
3371 UINT64 val = 0;
3372 BOOL found;
3374 if (desc)
3376 FIXME( "description not supported\n" );
3377 return E_NOTIMPL;
3379 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3380 if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
3381 return hr;
3383 switch (option)
3385 case WS_READ_REQUIRED_VALUE:
3386 if (!found) return WS_E_INVALID_FORMAT;
3387 /* fall through */
3389 case WS_READ_NILLABLE_VALUE:
3390 if (size != sizeof(UINT64)) return E_INVALIDARG;
3391 *(UINT64 *)ret = val;
3392 break;
3394 case WS_READ_REQUIRED_POINTER:
3395 if (!found) return WS_E_INVALID_FORMAT;
3396 /* fall through */
3398 case WS_READ_OPTIONAL_POINTER:
3399 case WS_READ_NILLABLE_POINTER:
3401 UINT64 *heap_val = NULL;
3402 if (size != sizeof(heap_val)) return E_INVALIDARG;
3403 if (found)
3405 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3406 *heap_val = val;
3408 *(UINT64 **)ret = heap_val;
3409 break;
3411 default:
3412 FIXME( "read option %u not supported\n", option );
3413 return E_NOTIMPL;
3416 return S_OK;
3419 static HRESULT read_type_double( struct reader *reader, WS_TYPE_MAPPING mapping,
3420 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3421 const WS_DOUBLE_DESCRIPTION *desc, WS_READ_OPTION option,
3422 WS_HEAP *heap, void *ret, ULONG size )
3424 WS_XML_UTF8_TEXT *utf8;
3425 HRESULT hr;
3426 double val = 0.0;
3427 BOOL found;
3429 if (desc) FIXME( "ignoring description\n" );
3431 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3432 if (found && (hr = str_to_double( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3434 switch (option)
3436 case WS_READ_REQUIRED_VALUE:
3437 if (!found) return WS_E_INVALID_FORMAT;
3438 /* fall through */
3440 case WS_READ_NILLABLE_VALUE:
3441 if (size != sizeof(double)) return E_INVALIDARG;
3442 *(double *)ret = val;
3443 break;
3445 case WS_READ_REQUIRED_POINTER:
3446 if (!found) return WS_E_INVALID_FORMAT;
3447 /* fall through */
3449 case WS_READ_OPTIONAL_POINTER:
3450 case WS_READ_NILLABLE_POINTER:
3452 double *heap_val = NULL;
3453 if (size != sizeof(heap_val)) return E_INVALIDARG;
3454 if (found)
3456 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3457 *heap_val = val;
3459 *(double **)ret = heap_val;
3460 break;
3462 default:
3463 FIXME( "read option %u not supported\n", option );
3464 return E_NOTIMPL;
3467 return S_OK;
3470 static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
3471 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3472 const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
3473 WS_HEAP *heap, WCHAR **ret, ULONG size )
3475 WS_XML_UTF8_TEXT *utf8;
3476 HRESULT hr;
3477 WCHAR *str = NULL;
3478 BOOL found;
3480 if (desc)
3482 FIXME( "description not supported\n" );
3483 return E_NOTIMPL;
3485 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3486 if (found && !(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
3488 switch (option)
3490 case WS_READ_REQUIRED_POINTER:
3491 if (!found) return WS_E_INVALID_FORMAT;
3492 /* fall through */
3494 case WS_READ_OPTIONAL_POINTER:
3495 case WS_READ_NILLABLE_POINTER:
3496 if (size != sizeof(str)) return E_INVALIDARG;
3497 *ret = str;
3498 break;
3500 default:
3501 FIXME( "read option %u not supported\n", option );
3502 return E_NOTIMPL;
3505 return S_OK;
3508 static HRESULT get_enum_value( const WS_XML_UTF8_TEXT *text, const WS_ENUM_DESCRIPTION *desc, int *ret )
3510 ULONG i;
3511 for (i = 0; i < desc->valueCount; i++)
3513 if (WsXmlStringEquals( &text->value, desc->values[i].name, NULL ) == S_OK)
3515 *ret = desc->values[i].value;
3516 return S_OK;
3519 return WS_E_INVALID_FORMAT;
3522 static HRESULT read_type_enum( struct reader *reader, WS_TYPE_MAPPING mapping,
3523 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3524 const WS_ENUM_DESCRIPTION *desc, WS_READ_OPTION option,
3525 WS_HEAP *heap, void *ret, ULONG size )
3527 WS_XML_UTF8_TEXT *utf8;
3528 HRESULT hr;
3529 int val = 0;
3530 BOOL found;
3532 if (!desc) return E_INVALIDARG;
3534 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3535 if (found && (hr = get_enum_value( utf8, desc, &val )) != S_OK) return hr;
3537 switch (option)
3539 case WS_READ_REQUIRED_VALUE:
3540 if (!found) return WS_E_INVALID_FORMAT;
3541 /* fall through */
3543 case WS_READ_NILLABLE_VALUE:
3544 if (size != sizeof(int)) return E_INVALIDARG;
3545 *(int *)ret = val;
3546 break;
3548 case WS_READ_REQUIRED_POINTER:
3549 if (!found) return WS_E_INVALID_FORMAT;
3550 /* fall through */
3552 case WS_READ_OPTIONAL_POINTER:
3553 case WS_READ_NILLABLE_POINTER:
3555 int *heap_val = NULL;
3556 if (size != sizeof(heap_val)) return E_INVALIDARG;
3557 if (found)
3559 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3560 *heap_val = val;
3562 *(int **)ret = heap_val;
3563 break;
3565 default:
3566 FIXME( "read option %u not supported\n", option );
3567 return E_NOTIMPL;
3570 return S_OK;
3573 static HRESULT read_type_datetime( struct reader *reader, WS_TYPE_MAPPING mapping,
3574 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3575 const WS_DATETIME_DESCRIPTION *desc, WS_READ_OPTION option,
3576 WS_HEAP *heap, void *ret, ULONG size )
3578 WS_XML_UTF8_TEXT *utf8;
3579 HRESULT hr;
3580 WS_DATETIME val = {0, WS_DATETIME_FORMAT_UTC};
3581 BOOL found;
3583 if (desc) FIXME( "ignoring description\n" );
3585 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3586 if (found && (hr = str_to_datetime( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3588 switch (option)
3590 case WS_READ_REQUIRED_VALUE:
3591 if (!found) return WS_E_INVALID_FORMAT;
3592 /* fall through */
3594 case WS_READ_NILLABLE_VALUE:
3595 if (size != sizeof(WS_DATETIME)) return E_INVALIDARG;
3596 *(WS_DATETIME *)ret = val;
3597 break;
3599 case WS_READ_REQUIRED_POINTER:
3600 if (!found) return WS_E_INVALID_FORMAT;
3601 /* fall through */
3603 case WS_READ_OPTIONAL_POINTER:
3604 case WS_READ_NILLABLE_POINTER:
3606 WS_DATETIME *heap_val = NULL;
3607 if (size != sizeof(heap_val)) return E_INVALIDARG;
3608 if (found)
3610 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3611 *heap_val = val;
3613 *(WS_DATETIME **)ret = heap_val;
3614 break;
3616 default:
3617 FIXME( "read option %u not supported\n", option );
3618 return E_NOTIMPL;
3621 return S_OK;
3624 static HRESULT read_type_guid( struct reader *reader, WS_TYPE_MAPPING mapping,
3625 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3626 const WS_GUID_DESCRIPTION *desc, WS_READ_OPTION option,
3627 WS_HEAP *heap, void *ret, ULONG size )
3629 WS_XML_UTF8_TEXT *utf8;
3630 GUID val = {0};
3631 HRESULT hr;
3632 BOOL found;
3634 if (desc) FIXME( "ignoring description\n" );
3636 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3637 if (found && (hr = str_to_guid( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
3639 switch (option)
3641 case WS_READ_REQUIRED_VALUE:
3642 if (!found) return WS_E_INVALID_FORMAT;
3643 /* fall through */
3645 case WS_READ_NILLABLE_VALUE:
3646 if (size != sizeof(GUID)) return E_INVALIDARG;
3647 *(GUID *)ret = val;
3648 break;
3650 case WS_READ_REQUIRED_POINTER:
3651 if (!found) return WS_E_INVALID_FORMAT;
3652 /* fall through */
3654 case WS_READ_OPTIONAL_POINTER:
3655 case WS_READ_NILLABLE_POINTER:
3657 GUID *heap_val = NULL;
3658 if (size != sizeof(heap_val)) return E_INVALIDARG;
3659 if (found)
3661 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3662 *heap_val = val;
3664 *(GUID **)ret = heap_val;
3665 break;
3667 default:
3668 FIXME( "read option %u not supported\n", option );
3669 return E_NOTIMPL;
3672 return S_OK;
3675 static HRESULT read_type_bytes( struct reader *reader, WS_TYPE_MAPPING mapping,
3676 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
3677 const WS_BYTES_DESCRIPTION *desc, WS_READ_OPTION option,
3678 WS_HEAP *heap, void *ret, ULONG size )
3680 WS_XML_UTF8_TEXT *utf8;
3681 WS_BYTES val = {0};
3682 HRESULT hr;
3683 BOOL found;
3685 if (desc) FIXME( "ignoring description\n" );
3687 if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
3688 if (found && (hr = str_to_bytes( utf8->value.bytes, utf8->value.length, heap, &val )) != S_OK)
3689 return hr;
3691 switch (option)
3693 case WS_READ_REQUIRED_VALUE:
3694 if (!found) return WS_E_INVALID_FORMAT;
3695 /* fall through */
3697 case WS_READ_NILLABLE_VALUE:
3698 if (size != sizeof(WS_BYTES)) return E_INVALIDARG;
3699 *(WS_BYTES *)ret = val;
3700 break;
3702 case WS_READ_REQUIRED_POINTER:
3703 if (!found) return WS_E_INVALID_FORMAT;
3704 /* fall through */
3706 case WS_READ_OPTIONAL_POINTER:
3707 case WS_READ_NILLABLE_POINTER:
3709 WS_BYTES *heap_val = NULL;
3710 if (size != sizeof(heap_val)) return E_INVALIDARG;
3711 if (found)
3713 if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
3714 *heap_val = val;
3716 *(WS_BYTES **)ret = heap_val;
3717 break;
3719 default:
3720 FIXME( "read option %u not supported\n", option );
3721 return E_NOTIMPL;
3724 return S_OK;
3727 static BOOL is_empty_text_node( const struct node *node )
3729 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
3730 const WS_XML_UTF8_TEXT *utf8;
3731 ULONG i;
3733 if (node_type( node ) != WS_XML_NODE_TYPE_TEXT) return FALSE;
3734 if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
3736 ERR( "unhandled text type %u\n", text->text->textType );
3737 return FALSE;
3739 utf8 = (const WS_XML_UTF8_TEXT *)text->text;
3740 for (i = 0; i < utf8->value.length; i++) if (!read_isspace( utf8->value.bytes[i] )) return FALSE;
3741 return TRUE;
3744 static HRESULT read_next_node( struct reader *reader )
3746 if (reader->current == reader->last) return read_node( reader );
3747 if (move_to_child_node( &reader->current )) return S_OK;
3748 if (move_to_next_node( &reader->current )) return S_OK;
3749 if (!move_to_parent_node( &reader->current )) return WS_E_INVALID_FORMAT;
3750 if (move_to_next_node( &reader->current )) return S_OK;
3751 return WS_E_INVALID_FORMAT;
3754 /* skips comment and empty text nodes */
3755 static HRESULT read_type_next_node( struct reader *reader )
3757 for (;;)
3759 HRESULT hr;
3760 WS_XML_NODE_TYPE type;
3762 if ((hr = read_next_node( reader )) != S_OK) return hr;
3763 type = node_type( reader->current );
3764 if (type == WS_XML_NODE_TYPE_COMMENT ||
3765 (type == WS_XML_NODE_TYPE_TEXT && is_empty_text_node( reader->current ))) continue;
3766 return S_OK;
3770 static BOOL match_current_element( struct reader *reader, const WS_XML_STRING *localname,
3771 const WS_XML_STRING *ns )
3773 const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
3774 if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return FALSE;
3775 return WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK &&
3776 WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK;
3779 static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname,
3780 const WS_XML_STRING *ns )
3782 struct node *node;
3783 ULONG attr;
3784 HRESULT hr;
3786 if (!localname) return S_OK; /* assume reader is already correctly positioned */
3787 if (reader->current == reader->last)
3789 BOOL found;
3790 if ((hr = read_to_startelement( reader, &found )) != S_OK) return hr;
3791 if (!found) return WS_E_INVALID_FORMAT;
3793 if (match_current_element( reader, localname, ns )) return S_OK;
3795 node = reader->current;
3796 attr = reader->current_attr;
3798 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
3799 if (match_current_element( reader, localname, ns )) return S_OK;
3801 reader->current = node;
3802 reader->current_attr = attr;
3804 return WS_E_INVALID_FORMAT;
3807 ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
3809 switch (type)
3811 case WS_INT8_TYPE:
3812 case WS_UINT8_TYPE:
3813 return sizeof(INT8);
3815 case WS_INT16_TYPE:
3816 case WS_UINT16_TYPE:
3817 return sizeof(INT16);
3819 case WS_BOOL_TYPE:
3820 case WS_INT32_TYPE:
3821 case WS_UINT32_TYPE:
3822 case WS_ENUM_TYPE:
3823 return sizeof(INT32);
3825 case WS_INT64_TYPE:
3826 case WS_UINT64_TYPE:
3827 return sizeof(INT64);
3829 case WS_DOUBLE_TYPE:
3830 return sizeof(double);
3832 case WS_DATETIME_TYPE:
3833 return sizeof(WS_DATETIME);
3835 case WS_GUID_TYPE:
3836 return sizeof(GUID);
3838 case WS_STRING_TYPE:
3839 return sizeof(WS_STRING);
3841 case WS_WSZ_TYPE:
3842 return sizeof(WCHAR *);
3844 case WS_BYTES_TYPE:
3845 return sizeof(WS_BYTES);
3847 case WS_XML_STRING_TYPE:
3848 return sizeof(WS_XML_STRING);
3850 case WS_STRUCT_TYPE:
3851 return desc->size;
3853 case WS_DESCRIPTION_TYPE:
3854 return sizeof(WS_STRUCT_DESCRIPTION *);
3856 default:
3857 ERR( "unhandled type %u\n", type );
3858 return 0;
3862 static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options )
3864 if (options & WS_FIELD_POINTER)
3866 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
3867 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
3868 return WS_READ_REQUIRED_POINTER;
3871 switch (type)
3873 case WS_BOOL_TYPE:
3874 case WS_INT8_TYPE:
3875 case WS_INT16_TYPE:
3876 case WS_INT32_TYPE:
3877 case WS_INT64_TYPE:
3878 case WS_UINT8_TYPE:
3879 case WS_UINT16_TYPE:
3880 case WS_UINT32_TYPE:
3881 case WS_UINT64_TYPE:
3882 case WS_DOUBLE_TYPE:
3883 case WS_DATETIME_TYPE:
3884 case WS_GUID_TYPE:
3885 case WS_STRING_TYPE:
3886 case WS_BYTES_TYPE:
3887 case WS_XML_STRING_TYPE:
3888 case WS_STRUCT_TYPE:
3889 case WS_ENUM_TYPE:
3890 if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_READ_NILLABLE_VALUE;
3891 return WS_READ_REQUIRED_VALUE;
3893 case WS_WSZ_TYPE:
3894 case WS_DESCRIPTION_TYPE:
3895 if (options & WS_FIELD_NILLABLE) return WS_READ_NILLABLE_POINTER;
3896 if (options & WS_FIELD_OPTIONAL) return WS_READ_OPTIONAL_POINTER;
3897 return WS_READ_REQUIRED_POINTER;
3899 default:
3900 FIXME( "unhandled type %u\n", type );
3901 return 0;
3905 static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
3906 const WS_XML_STRING *, const void *, WS_READ_OPTION, WS_HEAP *,
3907 void *, ULONG );
3909 static HRESULT read_type_repeating_element( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3910 WS_HEAP *heap, void **ret, ULONG *count )
3912 HRESULT hr;
3913 ULONG item_size, nb_items = 0, nb_allocated = 1, offset = 0;
3914 WS_READ_OPTION option;
3915 char *buf;
3917 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
3919 /* wrapper element */
3920 if (desc->localName && ((hr = read_type_next_element_node( reader, desc->localName, desc->ns )) != S_OK))
3921 return hr;
3923 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
3924 item_size = get_type_size( desc->type, desc->typeDescription );
3925 else
3926 item_size = sizeof(void *);
3928 if (!(buf = ws_alloc_zero( heap, item_size ))) return WS_E_QUOTA_EXCEEDED;
3929 for (;;)
3931 if (nb_items >= nb_allocated)
3933 SIZE_T old_size = nb_allocated * item_size, new_size = old_size * 2;
3934 if (!(buf = ws_realloc_zero( heap, buf, old_size, new_size )))
3935 return WS_E_QUOTA_EXCEEDED;
3936 nb_allocated *= 2;
3938 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs,
3939 desc->typeDescription, option, heap, buf + offset, item_size );
3940 if (hr == WS_E_INVALID_FORMAT) break;
3941 if (hr != S_OK)
3943 ws_free( heap, buf, nb_allocated * item_size );
3944 return hr;
3946 offset += item_size;
3947 nb_items++;
3950 if (desc->localName && ((hr = read_type_next_node( reader )) != S_OK)) return hr;
3952 if (desc->itemRange && (nb_items < desc->itemRange->minItemCount || nb_items > desc->itemRange->maxItemCount))
3954 TRACE( "number of items %u out of range (%u-%u)\n", nb_items, desc->itemRange->minItemCount,
3955 desc->itemRange->maxItemCount );
3956 ws_free( heap, buf, nb_allocated * item_size );
3957 return WS_E_INVALID_FORMAT;
3960 *count = nb_items;
3961 *ret = buf;
3963 return S_OK;
3966 static HRESULT read_type_text( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3967 WS_READ_OPTION option, WS_HEAP *heap, void *ret, ULONG size )
3969 HRESULT hr;
3970 if (reader->current == reader->last)
3972 BOOL found;
3973 if ((hr = read_to_startelement( reader, &found )) != S_OK) return S_OK;
3974 if (!found) return WS_E_INVALID_FORMAT;
3976 if ((hr = read_next_node( reader )) != S_OK) return hr;
3977 if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT) return WS_E_INVALID_FORMAT;
3979 return read_type( reader, WS_ANY_ELEMENT_TYPE_MAPPING, desc->type, NULL, NULL,
3980 desc->typeDescription, option, heap, ret, size );
3983 static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
3984 WS_HEAP *heap, char *buf, ULONG offset )
3986 char *ptr;
3987 WS_READ_OPTION option;
3988 ULONG size;
3989 HRESULT hr;
3991 if (!desc) return E_INVALIDARG;
3992 if (desc->options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE|WS_FIELD_NILLABLE_ITEM))
3994 FIXME( "options %08x not supported\n", desc->options );
3995 return E_NOTIMPL;
3997 if (!(option = get_field_read_option( desc->type, desc->options ))) return E_INVALIDARG;
3999 if (option == WS_READ_REQUIRED_VALUE || option == WS_READ_NILLABLE_VALUE)
4000 size = get_type_size( desc->type, desc->typeDescription );
4001 else
4002 size = sizeof(void *);
4004 ptr = buf + offset;
4005 switch (desc->mapping)
4007 case WS_TYPE_ATTRIBUTE_FIELD_MAPPING:
4008 FIXME( "WS_TYPE_ATTRIBUTE_FIELD_MAPPING not supported\n" );
4009 return S_OK;
4011 case WS_ATTRIBUTE_FIELD_MAPPING:
4012 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4013 desc->typeDescription, option, heap, ptr, size );
4014 break;
4016 case WS_ELEMENT_FIELD_MAPPING:
4017 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
4018 desc->typeDescription, option, heap, ptr, size );
4019 break;
4021 case WS_REPEATING_ELEMENT_FIELD_MAPPING:
4023 ULONG count;
4024 hr = read_type_repeating_element( reader, desc, heap, (void **)ptr, &count );
4025 if (hr == S_OK) *(ULONG *)(buf + desc->countOffset) = count;
4026 break;
4028 case WS_TEXT_FIELD_MAPPING:
4029 hr = read_type_text( reader, desc, option, heap, ptr, size );
4030 break;
4032 default:
4033 FIXME( "unhandled field mapping %u\n", desc->mapping );
4034 return E_NOTIMPL;
4037 if (hr == WS_E_INVALID_FORMAT)
4039 switch (option)
4041 case WS_READ_REQUIRED_VALUE:
4042 case WS_READ_REQUIRED_POINTER:
4043 return WS_E_INVALID_FORMAT;
4045 case WS_READ_NILLABLE_VALUE:
4046 if (desc->defaultValue) memcpy( ptr, desc->defaultValue->value, desc->defaultValue->valueSize );
4047 return S_OK;
4049 case WS_READ_OPTIONAL_POINTER:
4050 case WS_READ_NILLABLE_POINTER:
4051 *(void **)ptr = NULL;
4052 return S_OK;
4054 default:
4055 ERR( "unhandled option %u\n", option );
4056 return E_NOTIMPL;
4060 return hr;
4063 static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
4064 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
4065 const WS_STRUCT_DESCRIPTION *desc, WS_READ_OPTION option,
4066 WS_HEAP *heap, void *ret, ULONG size )
4068 ULONG i, offset;
4069 HRESULT hr;
4070 char *buf;
4072 if (!desc) return E_INVALIDARG;
4073 if (desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4075 FIXME( "struct options %08x not supported\n",
4076 desc->structOptions & ~WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT );
4079 switch (option)
4081 case WS_READ_REQUIRED_POINTER:
4082 case WS_READ_OPTIONAL_POINTER:
4083 case WS_READ_NILLABLE_POINTER:
4084 if (size != sizeof(void *)) return E_INVALIDARG;
4085 if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
4086 break;
4088 case WS_READ_REQUIRED_VALUE:
4089 case WS_READ_NILLABLE_VALUE:
4090 if (size != desc->size) return E_INVALIDARG;
4091 buf = ret;
4092 break;
4094 default:
4095 FIXME( "unhandled read option %u\n", option );
4096 return E_NOTIMPL;
4099 for (i = 0; i < desc->fieldCount; i++)
4101 offset = desc->fields[i]->offset;
4102 if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, offset )) != S_OK)
4103 break;
4106 switch (option)
4108 case WS_READ_REQUIRED_POINTER:
4109 if (hr != S_OK)
4111 ws_free( heap, buf, desc->size );
4112 return hr;
4114 *(char **)ret = buf;
4115 break;
4117 case WS_READ_OPTIONAL_POINTER:
4118 case WS_READ_NILLABLE_POINTER:
4119 if (is_nil_value( buf, desc->size ))
4121 ws_free( heap, buf, desc->size );
4122 buf = NULL;
4124 *(char **)ret = buf;
4125 break;
4127 case WS_READ_REQUIRED_VALUE:
4128 case WS_READ_NILLABLE_VALUE:
4129 if (hr != S_OK) return hr;
4130 break;
4132 default:
4133 ERR( "unhandled read option %u\n", option );
4134 return E_NOTIMPL;
4137 if (desc->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
4139 struct node *parent = find_parent( reader );
4140 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
4142 return S_OK;
4145 static HRESULT start_mapping( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname,
4146 const WS_XML_STRING *ns )
4148 switch (mapping)
4150 case WS_ELEMENT_TYPE_MAPPING:
4151 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4152 return read_type_next_element_node( reader, localname, ns );
4154 case WS_ANY_ELEMENT_TYPE_MAPPING:
4155 case WS_ATTRIBUTE_TYPE_MAPPING:
4156 return S_OK;
4158 default:
4159 FIXME( "unhandled mapping %u\n", mapping );
4160 return E_NOTIMPL;
4164 static HRESULT read_type_endelement_node( struct reader *reader )
4166 const struct node *parent = find_parent( reader );
4167 HRESULT hr;
4169 for (;;)
4171 if ((hr = read_type_next_node( reader )) != S_OK) return hr;
4172 if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT && reader->current->parent == parent)
4174 return S_OK;
4176 if (read_end_of_data( reader ) || !(parent->flags & NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT)) break;
4179 return WS_E_INVALID_FORMAT;
4182 static HRESULT end_mapping( struct reader *reader, WS_TYPE_MAPPING mapping )
4184 switch (mapping)
4186 case WS_ELEMENT_TYPE_MAPPING:
4187 return read_type_endelement_node( reader );
4189 case WS_ELEMENT_CONTENT_TYPE_MAPPING:
4190 return read_type_next_node( reader );
4192 case WS_ATTRIBUTE_TYPE_MAPPING:
4193 default:
4194 return S_OK;
4198 static HRESULT is_nil_element( const WS_XML_ELEMENT_NODE *elem )
4200 static const WS_XML_STRING localname = {3, (BYTE *)"nil"};
4201 static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"};
4202 ULONG i;
4204 for (i = 0; i < elem->attributeCount; i++)
4206 const WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)elem->attributes[i]->value;
4208 if (elem->attributes[i]->isXmlNs) continue;
4209 if (WsXmlStringEquals( elem->attributes[i]->localName, &localname, NULL ) == S_OK &&
4210 WsXmlStringEquals( elem->attributes[i]->ns, &ns, NULL ) == S_OK &&
4211 text->value.length == 4 && !memcmp( text->value.bytes, "true", 4 )) return TRUE;
4213 return FALSE;
4216 static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYPE type,
4217 const WS_XML_STRING *localname, const WS_XML_STRING *ns, const void *desc,
4218 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size )
4220 HRESULT hr;
4222 if ((hr = start_mapping( reader, mapping, localname, ns )) != S_OK) return hr;
4224 if (mapping == WS_ELEMENT_TYPE_MAPPING && is_nil_element( &reader->current->hdr ))
4226 if (option != WS_READ_NILLABLE_POINTER && option != WS_READ_NILLABLE_VALUE) return WS_E_INVALID_FORMAT;
4227 return end_mapping( reader, mapping );
4230 switch (type)
4232 case WS_BOOL_TYPE:
4233 if ((hr = read_type_bool( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4234 return hr;
4235 break;
4237 case WS_INT8_TYPE:
4238 if ((hr = read_type_int8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4239 return hr;
4240 break;
4242 case WS_INT16_TYPE:
4243 if ((hr = read_type_int16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4244 return hr;
4245 break;
4247 case WS_INT32_TYPE:
4248 if ((hr = read_type_int32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4249 return hr;
4250 break;
4252 case WS_INT64_TYPE:
4253 if ((hr = read_type_int64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4254 return hr;
4255 break;
4257 case WS_UINT8_TYPE:
4258 if ((hr = read_type_uint8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4259 return hr;
4260 break;
4262 case WS_UINT16_TYPE:
4263 if ((hr = read_type_uint16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4264 return hr;
4265 break;
4267 case WS_UINT32_TYPE:
4268 if ((hr = read_type_uint32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4269 return hr;
4270 break;
4272 case WS_UINT64_TYPE:
4273 if ((hr = read_type_uint64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4274 return hr;
4275 break;
4277 case WS_DOUBLE_TYPE:
4278 if ((hr = read_type_double( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4279 return hr;
4280 break;
4282 case WS_DATETIME_TYPE:
4283 if ((hr = read_type_datetime( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4284 return hr;
4285 break;
4287 case WS_GUID_TYPE:
4288 if ((hr = read_type_guid( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4289 return hr;
4290 break;
4292 case WS_WSZ_TYPE:
4293 if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4294 return hr;
4295 break;
4297 case WS_BYTES_TYPE:
4298 if ((hr = read_type_bytes( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4299 return hr;
4300 break;
4302 case WS_STRUCT_TYPE:
4303 if ((hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4304 return hr;
4305 break;
4307 case WS_ENUM_TYPE:
4308 if ((hr = read_type_enum( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
4309 return hr;
4310 break;
4312 default:
4313 FIXME( "type %u not supported\n", type );
4314 return E_NOTIMPL;
4317 return end_mapping( reader, mapping );
4320 /**************************************************************************
4321 * WsReadType [webservices.@]
4323 HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TYPE type,
4324 const void *desc, WS_READ_OPTION option, WS_HEAP *heap, void *value,
4325 ULONG size, WS_ERROR *error )
4327 struct reader *reader = (struct reader *)handle;
4328 HRESULT hr;
4330 TRACE( "%p %u %u %p %u %p %p %u %p\n", handle, mapping, type, desc, option, heap, value,
4331 size, error );
4332 if (error) FIXME( "ignoring error parameter\n" );
4334 if (!reader || !value) return E_INVALIDARG;
4336 EnterCriticalSection( &reader->cs );
4338 if (reader->magic != READER_MAGIC)
4340 LeaveCriticalSection( &reader->cs );
4341 return E_INVALIDARG;
4344 if ((hr = read_type( reader, mapping, type, NULL, NULL, desc, option, heap, value, size )) != S_OK)
4346 LeaveCriticalSection( &reader->cs );
4347 return hr;
4350 switch (mapping)
4352 case WS_ELEMENT_TYPE_MAPPING:
4353 hr = read_node( reader );
4354 break;
4356 default:
4357 break;
4360 if (hr == S_OK && !read_end_of_data( reader )) hr = WS_E_INVALID_FORMAT;
4362 LeaveCriticalSection( &reader->cs );
4363 return hr;
4366 /**************************************************************************
4367 * WsReadElement [webservices.@]
4369 HRESULT WINAPI WsReadElement( WS_XML_READER *handle, const WS_ELEMENT_DESCRIPTION *desc,
4370 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
4371 WS_ERROR *error )
4373 struct reader *reader = (struct reader *)handle;
4374 HRESULT hr;
4376 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
4377 if (error) FIXME( "ignoring error parameter\n" );
4379 if (!reader || !desc || !value) return E_INVALIDARG;
4381 EnterCriticalSection( &reader->cs );
4383 if (reader->magic != READER_MAGIC)
4385 LeaveCriticalSection( &reader->cs );
4386 return E_INVALIDARG;
4389 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->elementLocalName,
4390 desc->elementNs, desc->typeDescription, option, heap, value, size );
4392 LeaveCriticalSection( &reader->cs );
4393 return hr;
4396 /**************************************************************************
4397 * WsReadValue [webservices.@]
4399 HRESULT WINAPI WsReadValue( WS_XML_READER *handle, WS_VALUE_TYPE value_type, void *value, ULONG size,
4400 WS_ERROR *error )
4402 struct reader *reader = (struct reader *)handle;
4403 WS_TYPE type = map_value_type( value_type );
4404 HRESULT hr;
4406 TRACE( "%p %u %p %u %p\n", handle, type, value, size, error );
4407 if (error) FIXME( "ignoring error parameter\n" );
4409 if (!reader || !value || type == ~0u) return E_INVALIDARG;
4411 EnterCriticalSection( &reader->cs );
4413 if (reader->magic != READER_MAGIC)
4415 LeaveCriticalSection( &reader->cs );
4416 return E_INVALIDARG;
4419 hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, type, NULL, NULL, NULL, WS_READ_REQUIRED_VALUE,
4420 NULL, value, size );
4422 LeaveCriticalSection( &reader->cs );
4423 return hr;
4426 /**************************************************************************
4427 * WsReadAttribute [webservices.@]
4429 HRESULT WINAPI WsReadAttribute( WS_XML_READER *handle, const WS_ATTRIBUTE_DESCRIPTION *desc,
4430 WS_READ_OPTION option, WS_HEAP *heap, void *value, ULONG size,
4431 WS_ERROR *error )
4433 struct reader *reader = (struct reader *)handle;
4434 HRESULT hr;
4436 TRACE( "%p %p %u %p %p %u %p\n", handle, desc, option, heap, value, size, error );
4437 if (error) FIXME( "ignoring error parameter\n" );
4439 if (!reader || !desc || !value) return E_INVALIDARG;
4441 EnterCriticalSection( &reader->cs );
4443 if (reader->magic != READER_MAGIC)
4445 LeaveCriticalSection( &reader->cs );
4446 return E_INVALIDARG;
4449 if (!reader->input_type)
4451 LeaveCriticalSection( &reader->cs );
4452 return WS_E_INVALID_OPERATION;
4455 hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->attributeLocalName,
4456 desc->attributeNs, desc->typeDescription, option, heap, value, size );
4458 LeaveCriticalSection( &reader->cs );
4459 return hr;
4462 static inline BOOL is_utf8( const unsigned char *data, ULONG size, ULONG *offset )
4464 static const char bom[] = {0xef,0xbb,0xbf};
4465 const unsigned char *p = data;
4467 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4468 (size > 2 && !(*offset = 0));
4471 static inline BOOL is_utf16le( const unsigned char *data, ULONG size, ULONG *offset )
4473 static const char bom[] = {0xff,0xfe};
4474 const unsigned char *p = data;
4476 return (size >= sizeof(bom) && !memcmp( p, bom, sizeof(bom) ) && (*offset = sizeof(bom))) ||
4477 (size >= 4 && p[0] == '<' && !p[1] && !(*offset = 0));
4480 static WS_CHARSET detect_charset( const unsigned char *data, ULONG size, ULONG *offset )
4482 WS_CHARSET ret = 0;
4484 /* FIXME: parse xml declaration */
4486 if (is_utf16le( data, size, offset )) ret = WS_CHARSET_UTF16LE;
4487 else if (is_utf8( data, size, offset )) ret = WS_CHARSET_UTF8;
4488 else
4490 FIXME( "charset not recognized\n" );
4491 return 0;
4494 TRACE( "detected charset %u\n", ret );
4495 return ret;
4498 static void set_input_buffer( struct reader *reader, struct xmlbuf *buf, const unsigned char *data, ULONG size )
4500 reader->input_type = WS_XML_READER_INPUT_TYPE_BUFFER;
4501 reader->input_buf = buf;
4502 reader->input_data = data;
4503 reader->input_size = size;
4505 reader->read_size = reader->input_size;
4506 reader->read_pos = 0;
4507 reader->read_bufptr = reader->input_data;
4509 reader->text_conv_offset = 0;
4512 /**************************************************************************
4513 * WsSetInput [webservices.@]
4515 HRESULT WINAPI WsSetInput( WS_XML_READER *handle, const WS_XML_READER_ENCODING *encoding,
4516 const WS_XML_READER_INPUT *input, const WS_XML_READER_PROPERTY *properties,
4517 ULONG count, WS_ERROR *error )
4519 struct reader *reader = (struct reader *)handle;
4520 struct node *node;
4521 ULONG i, offset = 0;
4522 HRESULT hr;
4524 TRACE( "%p %p %p %p %u %p\n", handle, encoding, input, properties, count, error );
4525 if (error) FIXME( "ignoring error parameter\n" );
4527 if (!reader) return E_INVALIDARG;
4529 EnterCriticalSection( &reader->cs );
4531 if (reader->magic != READER_MAGIC)
4533 LeaveCriticalSection( &reader->cs );
4534 return E_INVALIDARG;
4537 for (i = 0; i < count; i++)
4539 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4540 properties[i].valueSize );
4541 if (hr != S_OK) goto done;
4544 if ((hr = init_reader( reader )) != S_OK) goto done;
4546 switch (encoding->encodingType)
4548 case WS_XML_READER_ENCODING_TYPE_TEXT:
4550 WS_XML_READER_TEXT_ENCODING *text = (WS_XML_READER_TEXT_ENCODING *)encoding;
4551 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4552 WS_CHARSET charset = text->charSet;
4554 if (input->inputType != WS_XML_READER_INPUT_TYPE_BUFFER)
4556 FIXME( "charset detection on input type %u not supported\n", input->inputType );
4557 hr = E_NOTIMPL;
4558 goto done;
4561 if (charset == WS_CHARSET_AUTO)
4562 charset = detect_charset( buf->encodedData, buf->encodedDataSize, &offset );
4564 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET,
4565 &charset, sizeof(charset) );
4566 if (hr != S_OK) goto done;
4567 break;
4569 default:
4570 FIXME( "encoding type %u not supported\n", encoding->encodingType );
4571 hr = E_NOTIMPL;
4572 goto done;
4575 switch (input->inputType)
4577 case WS_XML_READER_INPUT_TYPE_BUFFER:
4579 WS_XML_READER_BUFFER_INPUT *buf = (WS_XML_READER_BUFFER_INPUT *)input;
4580 set_input_buffer( reader, NULL, (const unsigned char *)buf->encodedData + offset,
4581 buf->encodedDataSize - offset );
4582 break;
4584 default:
4585 FIXME( "input type %u not supported\n", input->inputType );
4586 hr = E_NOTIMPL;
4587 goto done;
4590 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
4591 else read_insert_bof( reader, node );
4593 done:
4594 LeaveCriticalSection( &reader->cs );
4595 return hr;
4598 /**************************************************************************
4599 * WsSetInputToBuffer [webservices.@]
4601 HRESULT WINAPI WsSetInputToBuffer( WS_XML_READER *handle, WS_XML_BUFFER *buffer,
4602 const WS_XML_READER_PROPERTY *properties, ULONG count,
4603 WS_ERROR *error )
4605 struct reader *reader = (struct reader *)handle;
4606 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
4607 WS_CHARSET charset;
4608 struct node *node;
4609 ULONG i, offset = 0;
4610 HRESULT hr;
4612 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
4613 if (error) FIXME( "ignoring error parameter\n" );
4615 if (!reader || !xmlbuf) return E_INVALIDARG;
4617 EnterCriticalSection( &reader->cs );
4619 if (reader->magic != READER_MAGIC)
4621 LeaveCriticalSection( &reader->cs );
4622 return E_INVALIDARG;
4625 for (i = 0; i < count; i++)
4627 hr = prop_set( reader->prop, reader->prop_count, properties[i].id, properties[i].value,
4628 properties[i].valueSize );
4629 if (hr != S_OK) goto done;
4632 if ((hr = init_reader( reader )) != S_OK) goto done;
4634 charset = detect_charset( xmlbuf->ptr, xmlbuf->size, &offset );
4635 hr = prop_set( reader->prop, reader->prop_count, WS_XML_READER_PROPERTY_CHARSET, &charset,
4636 sizeof(charset) );
4637 if (hr != S_OK) goto done;
4639 set_input_buffer( reader, xmlbuf, (const unsigned char *)xmlbuf->ptr + offset, xmlbuf->size - offset );
4640 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) hr = E_OUTOFMEMORY;
4641 else read_insert_bof( reader, node );
4643 done:
4644 LeaveCriticalSection( &reader->cs );
4645 return hr;
4648 /**************************************************************************
4649 * WsXmlStringEquals [webservices.@]
4651 HRESULT WINAPI WsXmlStringEquals( const WS_XML_STRING *str1, const WS_XML_STRING *str2, WS_ERROR *error )
4653 TRACE( "%s %s %p\n", debugstr_xmlstr(str1), debugstr_xmlstr(str2), error );
4654 if (error) FIXME( "ignoring error parameter\n" );
4656 if (!str1 || !str2) return E_INVALIDARG;
4658 if (str1->length != str2->length) return S_FALSE;
4659 if (!memcmp( str1->bytes, str2->bytes, str1->length )) return S_OK;
4660 return S_FALSE;
4663 /**************************************************************************
4664 * WsGetReaderPosition [webservices.@]
4666 HRESULT WINAPI WsGetReaderPosition( WS_XML_READER *handle, WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4668 struct reader *reader = (struct reader *)handle;
4670 TRACE( "%p %p %p\n", handle, pos, error );
4671 if (error) FIXME( "ignoring error parameter\n" );
4673 if (!reader || !pos) return E_INVALIDARG;
4675 EnterCriticalSection( &reader->cs );
4677 if (reader->magic != READER_MAGIC)
4679 LeaveCriticalSection( &reader->cs );
4680 return E_INVALIDARG;
4683 if (!reader->input_buf)
4685 LeaveCriticalSection( &reader->cs );
4686 return WS_E_INVALID_OPERATION;
4689 pos->buffer = (WS_XML_BUFFER *)reader->input_buf;
4690 pos->node = reader->current;
4692 LeaveCriticalSection( &reader->cs );
4693 return S_OK;
4696 /**************************************************************************
4697 * WsSetReaderPosition [webservices.@]
4699 HRESULT WINAPI WsSetReaderPosition( WS_XML_READER *handle, const WS_XML_NODE_POSITION *pos, WS_ERROR *error )
4701 struct reader *reader = (struct reader *)handle;
4703 TRACE( "%p %p %p\n", handle, pos, error );
4704 if (error) FIXME( "ignoring error parameter\n" );
4706 if (!reader || !pos) return E_INVALIDARG;
4708 EnterCriticalSection( &reader->cs );
4710 if (reader->magic != READER_MAGIC || (struct xmlbuf *)pos->buffer != reader->input_buf)
4712 LeaveCriticalSection( &reader->cs );
4713 return E_INVALIDARG;
4716 if (!reader->input_buf)
4718 LeaveCriticalSection( &reader->cs );
4719 return WS_E_INVALID_OPERATION;
4722 reader->current = pos->node;
4724 LeaveCriticalSection( &reader->cs );
4725 return S_OK;
4728 static HRESULT utf8_to_base64( const WS_XML_UTF8_TEXT *utf8, WS_XML_BASE64_TEXT *base64 )
4730 if (utf8->value.length % 4) return WS_E_INVALID_FORMAT;
4731 if (!(base64->bytes = heap_alloc( utf8->value.length * 3 / 4 ))) return E_OUTOFMEMORY;
4732 base64->length = decode_base64( utf8->value.bytes, utf8->value.length, base64->bytes );
4733 return S_OK;
4736 /**************************************************************************
4737 * WsReadBytes [webservices.@]
4739 HRESULT WINAPI WsReadBytes( WS_XML_READER *handle, void *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
4741 struct reader *reader = (struct reader *)handle;
4742 HRESULT hr;
4744 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
4745 if (error) FIXME( "ignoring error parameter\n" );
4747 if (!reader) return E_INVALIDARG;
4749 EnterCriticalSection( &reader->cs );
4751 if (reader->magic != READER_MAGIC)
4753 LeaveCriticalSection( &reader->cs );
4754 return E_INVALIDARG;
4757 if (!reader->input_type)
4759 LeaveCriticalSection( &reader->cs );
4760 return WS_E_INVALID_OPERATION;
4763 if (!count)
4765 LeaveCriticalSection( &reader->cs );
4766 return E_INVALIDARG;
4769 *count = 0;
4770 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
4772 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4773 WS_XML_BASE64_TEXT base64;
4775 if ((hr = utf8_to_base64( (const WS_XML_UTF8_TEXT *)text->text, &base64 )) != S_OK)
4777 LeaveCriticalSection( &reader->cs );
4778 return hr;
4780 if (reader->text_conv_offset == base64.length)
4782 heap_free( base64.bytes );
4783 hr = read_node( reader );
4784 LeaveCriticalSection( &reader->cs );
4785 return hr;
4787 *count = min( base64.length - reader->text_conv_offset, max_count );
4788 memcpy( bytes, base64.bytes + reader->text_conv_offset, *count );
4789 reader->text_conv_offset += *count;
4790 heap_free( base64.bytes );
4793 LeaveCriticalSection( &reader->cs );
4794 return S_OK;
4797 static HRESULT utf8_to_utf16( const WS_XML_UTF8_TEXT *utf8, WS_XML_UTF16_TEXT *utf16 )
4799 int len = MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, NULL, 0 );
4800 if (!(utf16->bytes = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
4801 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8->value.bytes, utf8->value.length, (WCHAR *)utf16->bytes, len );
4802 utf16->byteCount = len * sizeof(WCHAR);
4803 return S_OK;
4806 /**************************************************************************
4807 * WsReadChars [webservices.@]
4809 HRESULT WINAPI WsReadChars( WS_XML_READER *handle, WCHAR *chars, ULONG max_count, ULONG *count, WS_ERROR *error )
4811 struct reader *reader = (struct reader *)handle;
4813 TRACE( "%p %p %u %p %p\n", handle, chars, max_count, count, error );
4814 if (error) FIXME( "ignoring error parameter\n" );
4816 if (!reader) return E_INVALIDARG;
4818 EnterCriticalSection( &reader->cs );
4820 if (reader->magic != READER_MAGIC)
4822 LeaveCriticalSection( &reader->cs );
4823 return E_INVALIDARG;
4826 if (!reader->input_type)
4828 LeaveCriticalSection( &reader->cs );
4829 return WS_E_INVALID_OPERATION;
4832 if (!count)
4834 LeaveCriticalSection( &reader->cs );
4835 return E_INVALIDARG;
4838 *count = 0;
4839 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && chars)
4841 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4842 WS_XML_UTF16_TEXT utf16;
4843 HRESULT hr;
4845 if ((hr = utf8_to_utf16( (const WS_XML_UTF8_TEXT *)text->text, &utf16 )) != S_OK)
4847 LeaveCriticalSection( &reader->cs );
4848 return hr;
4850 if (reader->text_conv_offset == utf16.byteCount / sizeof(WCHAR))
4852 heap_free( utf16.bytes );
4853 hr = read_node( reader );
4854 LeaveCriticalSection( &reader->cs );
4855 return hr;
4857 *count = min( utf16.byteCount / sizeof(WCHAR) - reader->text_conv_offset, max_count );
4858 memcpy( chars, utf16.bytes + reader->text_conv_offset * sizeof(WCHAR), *count * sizeof(WCHAR) );
4859 reader->text_conv_offset += *count;
4860 heap_free( utf16.bytes );
4863 LeaveCriticalSection( &reader->cs );
4864 return S_OK;
4867 /**************************************************************************
4868 * WsReadCharsUtf8 [webservices.@]
4870 HRESULT WINAPI WsReadCharsUtf8( WS_XML_READER *handle, BYTE *bytes, ULONG max_count, ULONG *count, WS_ERROR *error )
4872 struct reader *reader = (struct reader *)handle;
4873 HRESULT hr;
4875 TRACE( "%p %p %u %p %p\n", handle, bytes, max_count, count, error );
4876 if (error) FIXME( "ignoring error parameter\n" );
4878 if (!reader) return E_INVALIDARG;
4880 EnterCriticalSection( &reader->cs );
4882 if (reader->magic != READER_MAGIC)
4884 LeaveCriticalSection( &reader->cs );
4885 return E_INVALIDARG;
4888 if (!reader->input_type)
4890 LeaveCriticalSection( &reader->cs );
4891 return WS_E_INVALID_OPERATION;
4894 if (!count)
4896 LeaveCriticalSection( &reader->cs );
4897 return E_INVALIDARG;
4900 *count = 0;
4901 if (node_type( reader->current ) == WS_XML_NODE_TYPE_TEXT && bytes)
4903 const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)reader->current;
4904 const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
4906 if (reader->text_conv_offset == utf8->value.length)
4908 hr = read_node( reader );
4909 LeaveCriticalSection( &reader->cs );
4910 return hr;
4912 *count = min( utf8->value.length - reader->text_conv_offset, max_count );
4913 memcpy( bytes, utf8->value.bytes + reader->text_conv_offset, *count );
4914 reader->text_conv_offset += *count;
4917 LeaveCriticalSection( &reader->cs );
4918 return S_OK;
4921 HRESULT get_param_desc( const WS_STRUCT_DESCRIPTION *desc, USHORT index, const WS_FIELD_DESCRIPTION **ret )
4923 if (index >= desc->fieldCount) return E_INVALIDARG;
4924 *ret = desc->fields[index];
4925 return S_OK;
4928 static ULONG get_field_size( const WS_FIELD_DESCRIPTION *desc )
4930 WS_READ_OPTION option;
4931 ULONG size;
4933 switch ((option = get_field_read_option( desc->type, desc->options )))
4935 case WS_READ_REQUIRED_POINTER:
4936 case WS_READ_OPTIONAL_POINTER:
4937 case WS_READ_NILLABLE_POINTER:
4938 size = sizeof(void *);
4939 break;
4941 case WS_READ_REQUIRED_VALUE:
4942 case WS_READ_NILLABLE_VALUE:
4943 size = get_type_size( desc->type, desc->typeDescription );
4944 break;
4946 default:
4947 WARN( "unhandled option %u\n", option );
4948 return 0;
4951 return size;
4954 static HRESULT read_param( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, void *ret )
4956 if (!ret && !(ret = ws_alloc_zero( heap, get_field_size(desc) ))) return WS_E_QUOTA_EXCEEDED;
4957 return read_type_struct_field( reader, desc, heap, ret, 0 );
4960 static HRESULT read_param_array( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap,
4961 void **ret, ULONG *count )
4963 if (!ret && !(ret = ws_alloc_zero( heap, sizeof(void **) ))) return WS_E_QUOTA_EXCEEDED;
4964 return read_type_repeating_element( reader, desc, heap, ret, count );
4967 static void set_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, ULONG len,
4968 const void **args )
4970 ULONG i, *ptr;
4971 for (i = 0; i < count; i++)
4973 if (params[i].outputMessageIndex != index || params[i].parameterType != WS_PARAMETER_TYPE_ARRAY_COUNT)
4974 continue;
4975 if ((ptr = *(ULONG **)args[i])) *ptr = len;
4976 break;
4980 HRESULT read_output_params( WS_XML_READER *handle, WS_HEAP *heap, const WS_ELEMENT_DESCRIPTION *desc,
4981 const WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
4983 struct reader *reader = (struct reader *)handle;
4984 const WS_STRUCT_DESCRIPTION *desc_struct;
4985 const WS_FIELD_DESCRIPTION *desc_field;
4986 ULONG i, len;
4987 HRESULT hr;
4989 if (desc->type != WS_STRUCT_TYPE || !(desc_struct = desc->typeDescription)) return E_INVALIDARG;
4991 EnterCriticalSection( &reader->cs );
4993 if (reader->magic != READER_MAGIC)
4995 LeaveCriticalSection( &reader->cs );
4996 return E_INVALIDARG;
4999 if ((hr = start_mapping( reader, WS_ELEMENT_TYPE_MAPPING, desc->elementLocalName, desc->elementNs )) != S_OK)
5000 goto done;
5002 for (i = 0; i < count; i++)
5004 if (params[i].outputMessageIndex == INVALID_PARAMETER_INDEX) continue;
5005 if (params[i].parameterType == WS_PARAMETER_TYPE_MESSAGES)
5007 FIXME( "messages type not supported\n" );
5008 hr = E_NOTIMPL;
5009 goto done;
5011 if ((hr = get_param_desc( desc_struct, params[i].outputMessageIndex, &desc_field )) != S_OK) goto done;
5012 if (params[i].parameterType == WS_PARAMETER_TYPE_NORMAL)
5014 void *ptr = *(void **)args[i];
5015 if ((hr = read_param( reader, desc_field, heap, ptr )) != S_OK) goto done;
5017 else if (params[i].parameterType == WS_PARAMETER_TYPE_ARRAY)
5019 void **ptr = *(void ***)args[i];
5020 if ((hr = read_param_array( reader, desc_field, heap, ptr, &len )) != S_OK) goto done;
5021 set_array_len( params, count, params[i].outputMessageIndex, len, args );
5025 if (desc_struct->structOptions & WS_STRUCT_IGNORE_TRAILING_ELEMENT_CONTENT)
5027 struct node *parent = find_parent( reader );
5028 parent->flags |= NODE_FLAG_IGNORE_TRAILING_ELEMENT_CONTENT;
5031 hr = end_mapping( reader, WS_ELEMENT_TYPE_MAPPING );
5033 done:
5034 LeaveCriticalSection( &reader->cs );
5035 return hr;