webservices: Implement WsCopyNode.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e74502b837
commit
46821e27ab
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue