webservices: Implement WsCopyNode.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2016-07-04 11:35:44 +02:00 committed by Alexandre Julliard
parent e74502b837
commit 46821e27ab
5 changed files with 362 additions and 2 deletions

View File

@ -378,6 +378,161 @@ void destroy_nodes( struct node *node )
free_node( node );
}
static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
{
WS_XML_ATTRIBUTE *dst;
const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
const WS_XML_STRING *localname = src->localName;
const WS_XML_STRING *ns = src->localName;
if (!(dst = heap_alloc( sizeof(*dst) ))) return NULL;
dst->singleQuote = src->singleQuote;
dst->isXmlNs = src->isXmlNs;
if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
return dst;
error:
free_attribute( dst );
return NULL;
}
static WS_XML_ATTRIBUTE **dup_attributes( WS_XML_ATTRIBUTE * const *src, ULONG count )
{
WS_XML_ATTRIBUTE **dst;
ULONG i;
if (!(dst = heap_alloc( sizeof(*dst) * count ))) return NULL;
for (i = 0; i < count; i++)
{
if (!(dst[i] = dup_attribute( src[i] )))
{
for (; i > 0; i--) free_attribute( dst[i - 1] );
heap_free( dst );
return NULL;
}
}
return dst;
}
static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
{
struct node *node;
WS_XML_ELEMENT_NODE *dst;
ULONG count = src->attributeCount;
WS_XML_ATTRIBUTE **attrs = src->attributes;
const WS_XML_STRING *prefix = (src->prefix && src->prefix->length) ? src->prefix : NULL;
const WS_XML_STRING *localname = src->localName;
const WS_XML_STRING *ns = src->ns;
if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return NULL;
dst = &node->hdr;
if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
dst->attributeCount = count;
if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
return node;
error:
free_node( node );
return NULL;
}
static struct node *dup_text_node( const WS_XML_TEXT_NODE *src )
{
struct node *node;
WS_XML_TEXT_NODE *dst;
if (!(node = alloc_node( WS_XML_NODE_TYPE_TEXT ))) return NULL;
dst = (WS_XML_TEXT_NODE *)node;
if (src->text)
{
WS_XML_UTF8_TEXT *utf8;
const WS_XML_UTF8_TEXT *utf8_src = (WS_XML_UTF8_TEXT *)src->text;
if (!(utf8 = alloc_utf8_text( utf8_src->value.bytes, utf8_src->value.length )))
{
free_node( node );
return NULL;
}
dst->text = &utf8->text;
}
return node;
}
static struct node *dup_comment_node( const WS_XML_COMMENT_NODE *src )
{
struct node *node;
WS_XML_COMMENT_NODE *dst;
if (!(node = alloc_node( WS_XML_NODE_TYPE_COMMENT ))) return NULL;
dst = (WS_XML_COMMENT_NODE *)node;
if (src->value.length && !(dst->value.bytes = heap_alloc( src->value.length )))
{
free_node( node );
return NULL;
}
memcpy( dst->value.bytes, src->value.bytes, src->value.length );
dst->value.length = src->value.length;
return node;
}
static struct node *dup_node( const struct node *src )
{
switch (node_type( src ))
{
case WS_XML_NODE_TYPE_ELEMENT:
return dup_element_node( &src->hdr );
case WS_XML_NODE_TYPE_TEXT:
return dup_text_node( (const WS_XML_TEXT_NODE *)src );
case WS_XML_NODE_TYPE_COMMENT:
return dup_comment_node( (const WS_XML_COMMENT_NODE *)src );
case WS_XML_NODE_TYPE_CDATA:
case WS_XML_NODE_TYPE_END_CDATA:
case WS_XML_NODE_TYPE_END_ELEMENT:
case WS_XML_NODE_TYPE_EOF:
case WS_XML_NODE_TYPE_BOF:
return alloc_node( node_type( src ) );
default:
ERR( "unhandled type %u\n", node_type( src ) );
break;
}
return NULL;
}
static HRESULT dup_tree( struct node **dst, const struct node *src )
{
struct node *parent;
const struct node *child;
if (!*dst && !(*dst = dup_node( src ))) return E_OUTOFMEMORY;
parent = *dst;
LIST_FOR_EACH_ENTRY( child, &src->children, struct node, entry )
{
HRESULT hr = E_OUTOFMEMORY;
struct node *new_child;
if (!(new_child = dup_node( child )) || (hr = dup_tree( &new_child, child )) != S_OK)
{
destroy_nodes( *dst );
return hr;
}
new_child->parent = parent;
list_add_tail( &parent->children, &new_child->entry );
}
return S_OK;
}
static const struct prop_desc reader_props[] =
{
{ sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_DEPTH */
@ -482,6 +637,12 @@ static void free_reader( struct reader *reader )
heap_free( reader );
}
HRESULT copy_node( WS_XML_READER *handle, struct node **node )
{
struct reader *reader = (struct reader *)handle;
return dup_tree( node, reader->current );
}
static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
{
if (str)
@ -1871,7 +2032,7 @@ BOOL move_to_child_node( struct node **current )
return FALSE;
}
static BOOL move_to_parent_node( struct node **current )
BOOL move_to_parent_node( struct node **current )
{
struct node *parent = (*current)->parent;
if (!parent) return FALSE;

View File

@ -1733,6 +1733,88 @@ static void test_WsWriteNode(void)
WsFreeHeap( heap );
}
static HRESULT set_input( WS_XML_READER *reader, const char *data, ULONG size )
{
WS_XML_READER_TEXT_ENCODING enc;
WS_XML_READER_BUFFER_INPUT input;
enc.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT;
enc.charSet = WS_CHARSET_AUTO;
input.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
input.encodedData = (void *)data;
input.encodedDataSize = size;
return WsSetInput( reader, &enc.encoding, &input.input, NULL, 0, NULL );
}
static void test_WsCopyNode(void)
{
WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {1, (BYTE *)"u"}, ns = {0, NULL};
WS_XML_NODE_POSITION pos, pos2;
WS_XML_WRITER *writer;
WS_XML_READER *reader;
WS_XML_BUFFER *buffer;
WS_HEAP *heap;
HRESULT hr;
hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsCreateWriter( NULL, 0, &writer, NULL ) ;
ok( hr == S_OK, "got %08x\n", hr );
hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteStartElement( writer, NULL, &localname2, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsGetWriterPosition( writer, &pos, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
check_output_buffer( buffer, "<t><u/></t>", __LINE__ );
hr = WsCreateReader( NULL, 0, &reader, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = set_input( reader, "<v/>", sizeof("<v/>") - 1 );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsFillReader( reader, sizeof("<v/>") - 1, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsSetWriterPosition( writer, &pos, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsCopyNode( writer, reader, NULL );
ok( hr == S_OK, "got %08x\n", hr );
check_output_buffer( buffer, "<t><u/><v/></t>", __LINE__ );
hr = WsGetWriterPosition( writer, &pos2, NULL );
ok( hr == S_OK, "got %08x\n", hr );
ok( pos2.buffer == pos.buffer, "wrong buffer\n" );
ok( pos2.node == pos.node, "wrong node\n" );
WsFreeReader( reader );
WsFreeWriter( writer );
WsFreeHeap( heap );
}
START_TEST(writer)
{
test_WsCreateWriter();
@ -1756,4 +1838,5 @@ START_TEST(writer)
test_WsSetWriterPosition();
test_WsWriteXmlBuffer();
test_WsWriteNode();
test_WsCopyNode();
}

View File

@ -19,7 +19,7 @@
@ stdcall WsCloseServiceProxy(ptr ptr ptr)
@ stub WsCombineUrl
@ stub WsCopyError
@ stub WsCopyNode
@ stdcall WsCopyNode(ptr ptr ptr)
@ stdcall WsCreateChannel(long long ptr long ptr ptr ptr)
@ stub WsCreateChannelForListener
@ stdcall WsCreateError(ptr long ptr)

View File

@ -46,6 +46,7 @@ struct node *alloc_node( WS_XML_NODE_TYPE ) DECLSPEC_HIDDEN;
void free_node( struct node * ) DECLSPEC_HIDDEN;
void destroy_nodes( struct node * ) DECLSPEC_HIDDEN;
struct node *find_parent( struct node * ) DECLSPEC_HIDDEN;
HRESULT copy_node( WS_XML_READER *, struct node ** ) DECLSPEC_HIDDEN;
static inline WS_XML_NODE_TYPE node_type( const struct node *node )
{
@ -64,6 +65,7 @@ BOOL move_to_prev_node( struct node ** ) DECLSPEC_HIDDEN;
BOOL move_to_bof( struct node *, struct node ** ) DECLSPEC_HIDDEN;
BOOL move_to_eof( struct node *, struct node ** ) DECLSPEC_HIDDEN;
BOOL move_to_child_node( struct node ** ) DECLSPEC_HIDDEN;
BOOL move_to_parent_node( struct node ** ) DECLSPEC_HIDDEN;
struct prop_desc
{

View File

@ -1988,3 +1988,117 @@ HRESULT WINAPI WsWriteNode( WS_XML_WRITER *handle, const WS_XML_NODE *node, WS_E
return write_node( writer, node );
}
static HRESULT write_tree_node( struct writer *writer )
{
HRESULT hr;
switch (node_type( writer->current ))
{
case WS_XML_NODE_TYPE_ELEMENT:
if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
return hr;
if ((hr = write_startelement( writer )) != S_OK) return hr;
writer->state = WRITER_STATE_STARTELEMENT;
return S_OK;
case WS_XML_NODE_TYPE_TEXT:
if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
return hr;
if ((hr = write_text( writer )) != S_OK) return hr;
writer->state = WRITER_STATE_TEXT;
return S_OK;
case WS_XML_NODE_TYPE_END_ELEMENT:
if ((hr = write_close_element( writer, writer->current->parent )) != S_OK) return hr;
writer->state = WRITER_STATE_ENDELEMENT;
return S_OK;
case WS_XML_NODE_TYPE_COMMENT:
if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
return hr;
if ((hr = write_comment( writer )) != S_OK) return hr;
writer->state = WRITER_STATE_COMMENT;
return S_OK;
case WS_XML_NODE_TYPE_CDATA:
if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
return hr;
if ((hr = write_cdata( writer )) != S_OK) return hr;
writer->state = WRITER_STATE_STARTCDATA;
return S_OK;
case WS_XML_NODE_TYPE_END_CDATA:
if ((hr = write_endcdata( writer )) != S_OK) return hr;
writer->state = WRITER_STATE_ENDCDATA;
return S_OK;
case WS_XML_NODE_TYPE_EOF:
case WS_XML_NODE_TYPE_BOF:
return S_OK;
default:
ERR( "unknown node type %u\n", node_type(writer->current) );
return E_INVALIDARG;
}
}
static HRESULT write_tree( struct writer *writer )
{
HRESULT hr;
if ((hr = write_tree_node( writer )) != S_OK) return hr;
for (;;)
{
if (node_type( writer->current ) == WS_XML_NODE_TYPE_EOF) break;
if (move_to_child_node( &writer->current ))
{
if ((hr = write_tree_node( writer )) != S_OK) return hr;
continue;
}
if (move_to_next_node( &writer->current ))
{
if ((hr = write_tree_node( writer )) != S_OK) return hr;
continue;
}
if (!move_to_parent_node( &writer->current ) || !move_to_next_node( &writer->current ))
{
ERR( "invalid tree\n" );
return WS_E_INVALID_FORMAT;
}
if ((hr = write_tree_node( writer )) != S_OK) return hr;
}
return S_OK;
}
static void write_rewind( struct writer *writer )
{
writer->write_pos = 0;
writer->current = writer->root;
writer->state = WRITER_STATE_INITIAL;
}
/**************************************************************************
* WsCopyNode [webservices.@]
*/
HRESULT WINAPI WsCopyNode( WS_XML_WRITER *handle, WS_XML_READER *reader, WS_ERROR *error )
{
struct writer *writer = (struct writer *)handle;
struct node *parent, *current = writer->current, *node = NULL;
HRESULT hr;
TRACE( "%p %p %p\n", handle, reader, error );
if (error) FIXME( "ignoring error parameter\n" );
if (!writer) return E_INVALIDARG;
if (!(parent = find_parent( writer->current ))) return WS_E_INVALID_FORMAT;
if ((hr = copy_node( reader, &node )) != S_OK) return hr;
write_insert_node( writer, parent, node );
write_rewind( writer );
if ((hr = write_tree( writer )) != S_OK) return hr;
writer->current = current;
return S_OK;
}