webservices: Properly restore the reader position when the next element doesn't match.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2018-04-18 12:53:33 +02:00 committed by Alexandre Julliard
parent 731f22835e
commit 079f84d918

View File

@ -4346,6 +4346,24 @@ static HRESULT read_next_node( struct reader *reader )
return WS_E_INVALID_FORMAT; return WS_E_INVALID_FORMAT;
} }
struct reader_pos
{
struct node *node;
ULONG attr;
};
static void save_reader_position( const struct reader *reader, struct reader_pos *pos )
{
pos->node = reader->current;
pos->attr = reader->current_attr;
}
static void restore_reader_position( struct reader *reader, const struct reader_pos *pos )
{
reader->current = pos->node;
reader->current_attr = pos->attr;
}
static HRESULT get_text( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname, static HRESULT get_text( struct reader *reader, WS_TYPE_MAPPING mapping, const WS_XML_STRING *localname,
const WS_XML_STRING *ns, const WS_XML_TEXT **ret, BOOL *found ) const WS_XML_STRING *ns, const WS_XML_TEXT **ret, BOOL *found )
{ {
@ -4364,16 +4382,19 @@ static HRESULT get_text( struct reader *reader, WS_TYPE_MAPPING mapping, const W
*found = TRUE; *found = TRUE;
if (localname) if (localname)
{ {
struct reader_pos pos;
HRESULT hr; HRESULT hr;
if (!match_element( reader->current, localname, ns )) if (!match_element( reader->current, localname, ns ))
{ {
*found = FALSE; *found = FALSE;
return S_OK; return S_OK;
} }
save_reader_position( reader, &pos );
if ((hr = read_next_node( reader )) != S_OK) return hr; if ((hr = read_next_node( reader )) != S_OK) return hr;
if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT) if (node_type( reader->current ) != WS_XML_NODE_TYPE_TEXT)
{ {
if (!move_to_parent_element( &reader->current )) return WS_E_INVALID_FORMAT; restore_reader_position( reader, &pos );
*found = FALSE; *found = FALSE;
return S_OK; return S_OK;
} }
@ -6021,8 +6042,7 @@ static HRESULT read_type_next_node( struct reader *reader )
static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname, static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_STRING *localname,
const WS_XML_STRING *ns ) const WS_XML_STRING *ns )
{ {
struct node *node; struct reader_pos pos;
ULONG attr;
HRESULT hr; HRESULT hr;
if (!localname) return S_OK; /* assume reader is already correctly positioned */ if (!localname) return S_OK; /* assume reader is already correctly positioned */
@ -6034,14 +6054,10 @@ static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_
} }
if (match_element( reader->current, localname, ns )) return S_OK; if (match_element( reader->current, localname, ns )) return S_OK;
node = reader->current; save_reader_position( reader, &pos );
attr = reader->current_attr;
if ((hr = read_type_next_node( reader )) != S_OK) return hr; if ((hr = read_type_next_node( reader )) != S_OK) return hr;
if (match_element( reader->current, localname, ns )) return S_OK; if (match_element( reader->current, localname, ns )) return S_OK;
restore_reader_position( reader, &pos );
reader->current = node;
reader->current_attr = attr;
return WS_E_INVALID_FORMAT; return WS_E_INVALID_FORMAT;
} }
@ -6166,55 +6182,37 @@ static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options )
static HRESULT read_type_field( struct reader *, const WS_FIELD_DESCRIPTION *, WS_HEAP *, char *, ULONG ); static HRESULT read_type_field( struct reader *, const WS_FIELD_DESCRIPTION *, WS_HEAP *, char *, ULONG );
static HRESULT read_type_union( struct reader *reader, const WS_UNION_DESCRIPTION *desc, WS_READ_OPTION option, static HRESULT read_type_union( struct reader *reader, const WS_UNION_DESCRIPTION *desc, WS_HEAP *heap, void *ret,
WS_HEAP *heap, void *ret, ULONG size ) ULONG size, BOOL *found )
{ {
BOOL found = FALSE; struct reader_pos pos;
HRESULT hr; HRESULT hr;
ULONG i; ULONG i;
switch (option)
{
case WS_READ_REQUIRED_VALUE:
case WS_READ_NILLABLE_VALUE:
if (size != desc->size) return E_INVALIDARG; if (size != desc->size) return E_INVALIDARG;
break;
default:
return E_INVALIDARG;
}
save_reader_position( reader, &pos );
if ((hr = read_type_next_node( reader )) != S_OK) return hr; if ((hr = read_type_next_node( reader )) != S_OK) return hr;
if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return WS_E_INVALID_FORMAT;
for (i = 0; i < desc->fieldCount; i++) for (i = 0; i < desc->fieldCount; i++)
{ {
if ((found = match_element( reader->current, desc->fields[i]->field.localName, desc->fields[i]->field.ns ))) if ((*found = match_element( reader->current, desc->fields[i]->field.localName, desc->fields[i]->field.ns )))
break; break;
} }
if (!found) *(int *)((char *)ret + desc->enumOffset) = desc->noneEnumValue; if (!*found)
{
*(int *)((char *)ret + desc->enumOffset) = desc->noneEnumValue;
restore_reader_position( reader, &pos );
}
else else
{ {
ULONG offset = desc->fields[i]->field.offset; ULONG offset = desc->fields[i]->field.offset;
if ((hr = read_type_field( reader, &desc->fields[i]->field, heap, ret, offset )) == S_OK) if ((hr = read_type_field( reader, &desc->fields[i]->field, heap, ret, offset )) != S_OK) return hr;
*(int *)((char *)ret + desc->enumOffset) = desc->fields[i]->value; *(int *)((char *)ret + desc->enumOffset) = desc->fields[i]->value;
} }
switch (option) return S_OK;
{
case WS_READ_NILLABLE_VALUE:
if (!found) move_to_parent_element( &reader->current );
break;
case WS_READ_REQUIRED_VALUE:
if (!found) hr = WS_E_INVALID_FORMAT;
break;
default:
return E_INVALIDARG;
}
return hr;
} }
static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *, static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
@ -6251,17 +6249,28 @@ static HRESULT read_type_array( struct reader *reader, const WS_FIELD_DESCRIPTIO
} }
if (desc->type == WS_UNION_TYPE) if (desc->type == WS_UNION_TYPE)
hr = read_type_union( reader, desc->typeDescription, option, heap, buf + offset, item_size ); {
BOOL found;
hr = read_type_union( reader, desc->typeDescription, heap, buf + offset, item_size, &found );
if (hr != S_OK)
{
ws_free( heap, buf, nb_allocated * item_size );
return hr;
}
if (!found) break;
}
else else
{
hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs, hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->itemLocalName, desc->itemNs,
desc->typeDescription, option, heap, buf + offset, item_size ); desc->typeDescription, option, heap, buf + offset, item_size );
if (hr == WS_E_INVALID_FORMAT) break; if (hr == WS_E_INVALID_FORMAT) break;
if (hr != S_OK) if (hr != S_OK)
{ {
ws_free( heap, buf, nb_allocated * item_size ); ws_free( heap, buf, nb_allocated * item_size );
return hr; return hr;
} }
}
offset += item_size; offset += item_size;
nb_items++; nb_items++;
} }
@ -6338,11 +6347,13 @@ static HRESULT read_type_field( struct reader *reader, const WS_FIELD_DESCRIPTIO
break; break;
case WS_ELEMENT_CHOICE_FIELD_MAPPING: case WS_ELEMENT_CHOICE_FIELD_MAPPING:
{
BOOL found;
if (desc->type != WS_UNION_TYPE || !desc->typeDescription || if (desc->type != WS_UNION_TYPE || !desc->typeDescription ||
(desc->options & (WS_FIELD_POINTER|WS_FIELD_NILLABLE))) return E_INVALIDARG; (desc->options & (WS_FIELD_POINTER|WS_FIELD_NILLABLE))) return E_INVALIDARG;
hr = read_type_union( reader, desc->typeDescription, option, heap, ptr, size ); hr = read_type_union( reader, desc->typeDescription, heap, ptr, size, &found );
break; break;
}
case WS_REPEATING_ELEMENT_FIELD_MAPPING: case WS_REPEATING_ELEMENT_FIELD_MAPPING:
case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING: case WS_REPEATING_ELEMENT_CHOICE_FIELD_MAPPING:
{ {