[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