[8/9] webservices: Implement WsCopyNode.

Hans Leidekker hans at codeweavers.com
Mon Jul 4 04:35:44 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c              | 163 ++++++++++++++++++++++++++++++++-
 dlls/webservices/tests/writer.c        |  83 +++++++++++++++++
 dlls/webservices/webservices.spec      |   2 +-
 dlls/webservices/webservices_private.h |   2 +
 dlls/webservices/writer.c              | 114 +++++++++++++++++++++++
 5 files changed, 362 insertions(+), 2 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index ed59404..9e33000 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -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;
diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index 32b6858..bd99b85 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -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();
 }
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index d235f31..a848e4c 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -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)
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 74ee5a4..bad2dfb 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -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
 {
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 5070c7d..86789c7 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -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;
+}
-- 
2.8.1




More information about the wine-patches mailing list