From 1e3b84a75e1c10215dd90de01bbb65a8144ba71b Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 10 Nov 2015 10:46:40 +0100 Subject: [PATCH] webservices: Implement WsWriteStartElement. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/reader.c | 24 ++- dlls/webservices/webservices.spec | 2 +- dlls/webservices/webservices_private.h | 15 ++ dlls/webservices/writer.c | 209 +++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 14 deletions(-) diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 3e5a107876f..a0d0792b4b8 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -29,7 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(webservices); -static const char *debugstr_xmlstr( const WS_XML_STRING *str ) +const char *debugstr_xmlstr( const WS_XML_STRING *str ) { if (!str) return "(null)"; return debugstr_an( (const char *)str->bytes, str->length ); @@ -164,6 +164,12 @@ void *ws_alloc( WS_HEAP *handle, SIZE_T size ) return HeapAlloc( heap->handle, 0, size ); } +void *ws_realloc( WS_HEAP *handle, void *ptr, SIZE_T size ) +{ + struct heap *heap = (struct heap *)handle; + return HeapReAlloc( heap->handle, 0, ptr, size ); +} + void ws_free( WS_HEAP *handle, void *ptr ) { struct heap *heap = (struct heap *)handle; @@ -267,15 +273,7 @@ void WINAPI WsFreeHeap( WS_HEAP *handle ) heap_free( heap ); } -struct node -{ - WS_XML_ELEMENT_NODE hdr; - struct list entry; - struct node *parent; - struct list children; -}; - -static struct node *alloc_node( WS_XML_NODE_TYPE type ) +struct node *alloc_node( WS_XML_NODE_TYPE type ) { struct node *ret; @@ -296,7 +294,7 @@ static void free_attribute( WS_XML_ATTRIBUTE *attr ) heap_free( attr ); } -static void free_node( struct node *node ) +void free_node( struct node *node ) { if (!node) return; switch (node->hdr.node.nodeType) @@ -336,7 +334,7 @@ static void free_node( struct node *node ) heap_free( node ); } -static void destroy_nodes( struct node *node ) +void destroy_nodes( struct node *node ) { struct list *ptr; @@ -648,7 +646,7 @@ HRESULT WINAPI WsGetXmlAttribute( WS_XML_READER *handle, const WS_XML_STRING *at return E_NOTIMPL; } -static WS_XML_STRING *alloc_xml_string( const char *data, ULONG len ) +WS_XML_STRING *alloc_xml_string( const char *data, ULONG len ) { WS_XML_STRING *ret; diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index 9fb96fbffd9..f0516d1d304 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -183,7 +183,7 @@ @ stub WsWriteQualifiedName @ stub WsWriteStartAttribute @ stub WsWriteStartCData -@ stub WsWriteStartElement +@ stdcall WsWriteStartElement(ptr ptr ptr ptr ptr) @ stub WsWriteText @ stub WsWriteType @ stub WsWriteValue diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index 369ccbbbba9..cac9b87a2da 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -25,7 +25,22 @@ struct xmlbuf }; void *ws_alloc( WS_HEAP *, SIZE_T ) DECLSPEC_HIDDEN; +void *ws_realloc( WS_HEAP *, void *, SIZE_T ) DECLSPEC_HIDDEN; void ws_free( WS_HEAP *, void * ) DECLSPEC_HIDDEN; +const char *debugstr_xmlstr( const WS_XML_STRING * ) DECLSPEC_HIDDEN; +WS_XML_STRING *alloc_xml_string( const char *, ULONG ) DECLSPEC_HIDDEN; + +struct node +{ + WS_XML_ELEMENT_NODE hdr; + struct list entry; + struct node *parent; + struct list children; +}; + +struct node *alloc_node( WS_XML_NODE_TYPE ) DECLSPEC_HIDDEN; +void free_node( struct node * ) DECLSPEC_HIDDEN; +void destroy_nodes( struct node * ) DECLSPEC_HIDDEN; static inline void *heap_alloc( SIZE_T size ) { diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 5523926d8e3..fc83d3d2bc9 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -23,6 +23,7 @@ #include "webservices.h" #include "wine/debug.h" +#include "wine/list.h" #include "webservices_private.h" WINE_DEFAULT_DEBUG_CHANNEL(webservices); @@ -55,10 +56,23 @@ writer_props[] = { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */ }; +enum writer_state +{ + WRITER_STATE_INITIAL, + WRITER_STATE_STARTELEMENT, + WRITER_STATE_STARTENDELEMENT, + WRITER_STATE_STARTATTRIBUTE, + WRITER_STATE_ENDSTARTELEMENT, + WRITER_STATE_ENDELEMENT +}; + struct writer { ULONG write_pos; char *write_bufptr; + enum writer_state state; + struct node *root; + struct node *current; WS_XML_WRITER_OUTPUT_TYPE output_type; struct xmlbuf *output_buf; WS_HEAP *output_heap; @@ -108,10 +122,46 @@ static HRESULT get_writer_prop( struct writer *writer, WS_XML_WRITER_PROPERTY_ID static void free_writer( struct writer *writer ) { + destroy_nodes( writer->root ); WsFreeHeap( writer->output_heap ); heap_free( writer ); } +static void write_insert_eof( struct writer *writer, struct node *eof ) +{ + if (!writer->root) writer->root = eof; + else + { + eof->parent = writer->root; + list_add_tail( &writer->root->children, &eof->entry ); + } + writer->current = eof; +} + +static void write_insert_node( struct writer *writer, struct node *node ) +{ + node->parent = writer->current; + if (writer->current == writer->root) + { + struct list *eof = list_tail( &writer->root->children ); + list_add_before( eof, &node->entry ); + } + else list_add_tail( &writer->current->children, &node->entry ); + writer->current = node; +} + +static HRESULT write_init_state( struct writer *writer ) +{ + struct node *node; + + destroy_nodes( writer->root ); + writer->root = NULL; + if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY; + write_insert_eof( writer, node ); + writer->state = WRITER_STATE_INITIAL; + return S_OK; +} + /************************************************************************** * WsCreateWriter [webservices.@] */ @@ -161,6 +211,13 @@ HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG c return hr; } + hr = write_init_state( writer ); + if (hr != S_OK) + { + free_writer( writer ); + return hr; + } + *handle = (WS_XML_WRITER *)writer; return S_OK; } @@ -327,3 +384,155 @@ HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer set_output_buffer( writer, xmlbuf ); return S_OK; } + +static HRESULT write_grow_buffer( struct writer *writer, ULONG size ) +{ + struct xmlbuf *buf = writer->output_buf; + SIZE_T new_size; + void *tmp; + + if (buf->size_allocated >= writer->write_pos + size) + { + buf->size = writer->write_pos + size; + return S_OK; + } + new_size = max( buf->size_allocated * 2, writer->write_pos + size ); + if (!(tmp = ws_realloc( buf->heap, buf->ptr, new_size ))) return E_OUTOFMEMORY; + writer->write_bufptr = buf->ptr = tmp; + buf->size_allocated = new_size; + buf->size = writer->write_pos + size; + return S_OK; +} + +static inline void write_char( struct writer *writer, char ch ) +{ + writer->write_bufptr[writer->write_pos++] = ch; +} + +static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len ) +{ + memcpy( writer->write_bufptr + writer->write_pos, bytes, len ); + writer->write_pos += len; +} + +static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr ) +{ + WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value; + ULONG size; + HRESULT hr; + + /* ' prefix:attr="value"' */ + + size = attr->localName->length + 4 /* ' =""' */; + if (attr->prefix) size += attr->prefix->length + 1 /* ':' */; + if (text) size += text->value.length; + if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr; + + write_char( writer, ' ' ); + if (attr->prefix) + { + write_bytes( writer, attr->prefix->bytes, attr->prefix->length ); + write_char( writer, ':' ); + } + write_bytes( writer, attr->localName->bytes, attr->localName->length ); + write_char( writer, '=' ); + if (attr->singleQuote) write_char( writer, '\'' ); + else write_char( writer, '"' ); + if (text) write_bytes( writer, text->value.bytes, text->value.length ); + if (attr->singleQuote) write_char( writer, '\'' ); + else write_char( writer, '"' ); + + /* FIXME: ignoring namespace */ + return S_OK; +} + +static HRESULT write_startelement( struct writer *writer ) +{ + WS_XML_ELEMENT_NODE *elem = (WS_XML_ELEMENT_NODE *)writer->current; + ULONG size, i; + HRESULT hr; + + /* 'localName->length + 1 /* '<' */; + if (elem->prefix) size += elem->prefix->length + 1 /* ':' */; + if (elem->ns->length) + { + size += strlen(" xmlns") + elem->ns->length + 3 /* '=""' */; + if (elem->prefix) size += elem->prefix->length + 1 /* ':' */; + } + if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr; + + write_char( writer, '<' ); + if (elem->prefix) + { + write_bytes( writer, elem->prefix->bytes, elem->prefix->length ); + write_char( writer, ':' ); + } + write_bytes( writer, elem->localName->bytes, elem->localName->length ); + for (i = 0; i < elem->attributeCount; i++) + { + if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr; + } + if (elem->ns->length) + { + write_bytes( writer, (const BYTE *)" xmlns", 6 ); + if (elem->prefix) + { + write_char( writer, ':' ); + write_bytes( writer, elem->prefix->bytes, elem->prefix->length ); + } + write_char( writer, '=' ); + write_char( writer, '"' ); + write_bytes( writer, elem->ns->bytes, elem->ns->length ); + write_char( writer, '"' ); + } + return S_OK; +} + +/************************************************************************** + * WsWriteStartElement [webservices.@] + */ +HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix, + const WS_XML_STRING *localname, const WS_XML_STRING *ns, + WS_ERROR *error ) +{ + struct writer *writer = (struct writer *)handle; + struct node *node; + WS_XML_ELEMENT_NODE *elem; + HRESULT hr = E_OUTOFMEMORY; + + TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname), + debugstr_xmlstr(ns), error ); + if (error) FIXME( "ignoring error parameter\n" ); + + if (!writer || !localname || !ns) return E_INVALIDARG; + + /* flush current start element */ + if (writer->state == WRITER_STATE_STARTELEMENT) + { + if ((hr = write_startelement( writer )) != S_OK) return hr; + if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr; + write_char( writer, '>' ); + } + + if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY; + elem = (WS_XML_ELEMENT_NODE *)node; + + if (prefix && !(elem->prefix = alloc_xml_string( (const char *)prefix->bytes, prefix->length ))) + goto error; + + if (!(elem->localName = alloc_xml_string( (const char *)localname->bytes, localname->length ))) + goto error; + + if (!(elem->ns = alloc_xml_string( (const char *)ns->bytes, ns->length ))) + goto error; + + write_insert_node( writer, node ); + writer->state = WRITER_STATE_STARTELEMENT; + return S_OK; + +error: + free_node( node ); + return hr; +}