[PATCH 3/7] webservices: Add support for stream output.

Hans Leidekker hans at codeweavers.com
Tue Dec 4 06:57:28 CST 2018


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c              |  1 -
 dlls/webservices/tests/writer.c        | 71 ++++++++++++++++++++++++
 dlls/webservices/webservices.spec      |  2 +-
 dlls/webservices/webservices_private.h |  2 +
 dlls/webservices/writer.c              | 98 ++++++++++++++++++++++++++++++----
 include/webservices.h                  | 14 +++--
 6 files changed, 172 insertions(+), 16 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 9a9d491730..270aecc220 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -6921,7 +6921,6 @@ static void set_input_buffer( struct reader *reader, const unsigned char *data,
     reader->text_conv_offset = 0;
 }
 
-#define STREAM_BUFSIZE 4096
 static void set_input_stream( struct reader *reader, WS_READ_CALLBACK callback, void *state )
 {
     reader->input_type     = WS_XML_READER_INPUT_TYPE_STREAM;
diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index a55da605e8..8d189fd9e4 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -4685,6 +4685,76 @@ static void test_repeating_element_choice(void)
     WsFreeWriter( writer );
 }
 
+static const struct stream_test
+{
+    ULONG min_size;
+    ULONG ret_size;
+}
+stream_tests[] =
+{
+    { 0, 4 },
+    { 1, 4 },
+    { 4, 4 },
+    { 5, 4 },
+};
+
+static CALLBACK HRESULT write_callback( void *state, const WS_BYTES *buf, ULONG count,
+                                        const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
+{
+    ULONG i = *(ULONG *)state;
+    ok( buf->length == stream_tests[i].ret_size, "%u: got %u\n", i, buf->length );
+    ok( !memcmp( buf->bytes, "<t/>", stream_tests[i].ret_size ), "%u: wrong data\n", i );
+    ok( count == 1, "%u: got %u\n", i, count );
+    return S_OK;
+}
+
+static void test_stream_output(void)
+{
+    static WS_XML_STRING str_ns = {0, NULL}, str_t = {1, (BYTE *)"t"};
+    WS_XML_WRITER_TEXT_ENCODING text = {{WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
+    WS_XML_WRITER_STREAM_OUTPUT stream;
+    WS_XML_WRITER *writer;
+    HRESULT hr;
+    ULONG i = 0;
+
+    hr = WsCreateWriter( NULL, 0, &writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsFlushWriter( writer, 0, NULL, NULL );
+    ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
+
+    stream.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
+    stream.writeCallback      = write_callback;
+    stream.writeCallbackState = &i;
+    hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsFlushWriter( writer, 0, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    for (i = 0; i < ARRAY_SIZE(stream_tests); i++)
+    {
+        stream.writeCallbackState = &i;
+        hr = WsSetOutput( writer, &text.encoding, &stream.output, NULL, 0, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteEndElement( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsFlushWriter( writer, stream_tests[i].min_size, NULL, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+    }
+
+    WsFreeWriter( writer );
+}
+
 START_TEST(writer)
 {
     test_WsCreateWriter();
@@ -4728,4 +4798,5 @@ START_TEST(writer)
     test_union_type();
     test_text_types_binary();
     test_repeating_element_choice();
+    test_stream_output();
 }
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index adad68dbdd..bd152b1ac3 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -47,7 +47,7 @@
 @ stdcall WsFillReader(ptr long ptr ptr)
 @ stdcall WsFindAttribute(ptr ptr ptr long ptr ptr)
 @ stub WsFlushBody
-@ stub WsFlushWriter
+@ stdcall WsFlushWriter(ptr long ptr ptr)
 @ stdcall WsFreeChannel(ptr)
 @ stdcall WsFreeError(ptr)
 @ stdcall WsFreeHeap(ptr)
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index b482b5ba20..6a6f65dbec 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -18,6 +18,8 @@
 
 #include "winhttp.h"
 
+#define STREAM_BUFSIZE 4096
+
 struct xmlbuf
 {
     WS_HEAP                     *heap;
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 0a28d9dc84..4f6cb60195 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -84,9 +84,12 @@ struct writer
     WS_XML_WRITER_ENCODING_TYPE  output_enc;
     WS_CHARSET                   output_charset;
     WS_XML_WRITER_OUTPUT_TYPE    output_type;
+    WS_WRITE_CALLBACK            output_cb;
+    void                        *output_cb_state;
     struct xmlbuf               *output_buf;
     BOOL                         output_buf_user;
     WS_HEAP                     *output_heap;
+    unsigned char               *stream_buf;
     const WS_XML_DICTIONARY     *dict;
     BOOL                         dict_do_lookup;
     WS_DYNAMIC_STRING_CALLBACK   dict_cb;
@@ -121,6 +124,7 @@ static void free_writer( struct writer *writer )
     destroy_nodes( writer->root );
     free_xml_string( writer->current_ns );
     WsFreeHeap( writer->output_heap );
+    heap_free( writer->stream_buf );
 
 #ifndef __MINGW32__
     writer->cs.DebugInfo->Spare[0] = 0;
@@ -294,7 +298,7 @@ HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERT
         return E_INVALIDARG;
     }
 
-    if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
+    if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
     else
     {
         switch (id)
@@ -346,6 +350,15 @@ static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
     writer->write_pos    = 0;
 }
 
+static void set_output_stream( struct writer *writer, WS_WRITE_CALLBACK callback, void *state )
+{
+    writer->output_type     = WS_XML_WRITER_OUTPUT_TYPE_STREAM;
+    writer->output_cb       = callback;
+    writer->output_cb_state = state;
+    writer->write_bufptr    = writer->stream_buf;
+    writer->write_pos       = 0;
+}
+
 /**************************************************************************
  *          WsSetOutput		[webservices.@]
  */
@@ -384,7 +397,7 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING
     {
     case WS_XML_WRITER_ENCODING_TYPE_TEXT:
     {
-        WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
+        const WS_XML_WRITER_TEXT_ENCODING *text = (const WS_XML_WRITER_TEXT_ENCODING *)encoding;
         if (text->charSet != WS_CHARSET_UTF8)
         {
             FIXME( "charset %u not supported\n", text->charSet );
@@ -397,7 +410,7 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING
     }
     case WS_XML_WRITER_ENCODING_TYPE_BINARY:
     {
-        WS_XML_WRITER_BINARY_ENCODING *bin = (WS_XML_WRITER_BINARY_ENCODING *)encoding;
+        const WS_XML_WRITER_BINARY_ENCODING *bin = (const WS_XML_WRITER_BINARY_ENCODING *)encoding;
         writer->output_enc     = WS_XML_WRITER_ENCODING_TYPE_BINARY;
         writer->output_charset = 0;
         writer->dict           = bin->staticDictionary;
@@ -426,6 +439,18 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING
         writer->output_buf_user = FALSE;
         break;
     }
+    case WS_XML_WRITER_OUTPUT_TYPE_STREAM:
+    {
+        const WS_XML_WRITER_STREAM_OUTPUT *stream = (const WS_XML_WRITER_STREAM_OUTPUT *)output;
+        if (!writer->stream_buf && !(writer->stream_buf = heap_alloc( STREAM_BUFSIZE )))
+        {
+            hr = E_OUTOFMEMORY;
+            goto done;
+        }
+        set_output_stream( writer, stream->writeCallback, stream->writeCallbackState );
+        break;
+
+    }
     default:
         FIXME( "output type %u not supported\n", output->outputType );
         hr = E_NOTIMPL;
@@ -489,12 +514,63 @@ done:
     return hr;
 }
 
+static HRESULT flush_writer( struct writer *writer, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
+                             WS_ERROR *error )
+{
+    WS_BYTES buf;
+
+    if (writer->write_pos < min_size) return S_OK;
+
+    buf.bytes  = writer->write_bufptr;
+    buf.length = writer->write_pos;
+    writer->output_cb( writer->output_cb_state, &buf, 1, ctx, error );
+    writer->write_pos = 0;
+    return S_OK;
+}
+
+/**************************************************************************
+ *          WsFlushWriter		[webservices.@]
+ */
+HRESULT WINAPI WsFlushWriter( WS_XML_WRITER *handle, ULONG min_size, const WS_ASYNC_CONTEXT *ctx,
+                              WS_ERROR *error )
+{
+    struct writer *writer = (struct writer *)handle;
+    HRESULT hr;
+
+    TRACE( "%p %u %p %p\n", handle, min_size, ctx, error );
+    if (error) FIXME( "ignoring error parameter\n" );
+    if (ctx) FIXME( "ignoring ctx parameter\n" );
+
+    if (!writer) return E_INVALIDARG;
+
+    EnterCriticalSection( &writer->cs );
+
+    if (writer->magic != WRITER_MAGIC)
+    {
+        LeaveCriticalSection( &writer->cs );
+        return E_INVALIDARG;
+    }
+
+    if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_STREAM) hr = WS_E_INVALID_OPERATION;
+    else hr = flush_writer( writer, min_size, ctx, error );
+
+    LeaveCriticalSection( &writer->cs );
+    TRACE( "returning %08x\n", hr );
+    return hr;
+}
+
 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
 {
     struct xmlbuf *buf = writer->output_buf;
     SIZE_T new_size;
     void *tmp;
 
+    if (writer->output_type == WS_XML_WRITER_OUTPUT_TYPE_STREAM)
+    {
+        if (size > STREAM_BUFSIZE) return WS_E_QUOTA_EXCEEDED;
+        return flush_writer( writer, STREAM_BUFSIZE - size, NULL, NULL );
+    }
+
     if (buf->size >= writer->write_pos + size)
     {
         buf->bytes.length = writer->write_pos + size;
@@ -2047,7 +2123,7 @@ HRESULT WINAPI WsWriteStartAttribute( WS_XML_WRITER *handle, const WS_XML_STRING
 }
 
 /* flush current start element if necessary */
-static HRESULT write_flush( struct writer *writer )
+static HRESULT write_commit( struct writer *writer )
 {
     if (writer->state == WRITER_STATE_STARTELEMENT)
     {
@@ -2089,7 +2165,7 @@ static HRESULT write_cdata( struct writer *writer )
 static HRESULT write_cdata_node( struct writer *writer )
 {
     HRESULT hr;
-    if ((hr = write_flush( writer )) != S_OK) return hr;
+    if ((hr = write_commit( writer )) != S_OK) return hr;
     if ((hr = write_add_cdata_node( writer )) != S_OK) return hr;
     if ((hr = write_add_endcdata_node( writer )) != S_OK) return hr;
     if ((hr = write_cdata( writer )) != S_OK) return hr;
@@ -2220,7 +2296,7 @@ static HRESULT write_element_node( struct writer *writer, const WS_XML_STRING *p
                                    const WS_XML_STRING *localname, const WS_XML_STRING *ns )
 {
     HRESULT hr;
-    if ((hr = write_flush( writer )) != S_OK) return hr;
+    if ((hr = write_commit( writer )) != S_OK) return hr;
     if ((hr = write_add_element_node( writer, prefix, localname, ns )) != S_OK) return hr;
     if ((hr = write_add_endelement_node( writer, writer->current )) != S_OK) return hr;
     writer->state = WRITER_STATE_STARTELEMENT;
@@ -2826,7 +2902,7 @@ static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
     ULONG offset = 0;
     HRESULT hr;
 
-    if ((hr = write_flush( writer )) != S_OK) return hr;
+    if ((hr = write_commit( writer )) != S_OK) return hr;
     if (node_type( writer->current ) != WS_XML_NODE_TYPE_TEXT)
     {
         if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
@@ -4158,7 +4234,7 @@ HRESULT WINAPI WsWriteXmlBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer, W
         goto done;
     }
 
-    if ((hr = write_flush( writer )) != S_OK) goto done;
+    if ((hr = write_commit( writer )) != S_OK) goto done;
     if ((hr = write_grow_buffer( writer, xmlbuf->bytes.length )) != S_OK) goto done;
     write_bytes( writer, xmlbuf->bytes.bytes, xmlbuf->bytes.length );
 
@@ -4261,7 +4337,7 @@ static HRESULT write_qualified_name( struct writer *writer, const WS_XML_STRING
     WS_XML_QNAME_TEXT qname = {{WS_XML_TEXT_TYPE_QNAME}};
     HRESULT hr;
 
-    if ((hr = write_flush( writer )) != S_OK) return hr;
+    if ((hr = write_commit( writer )) != S_OK) return hr;
     if (!prefix && ((hr = find_prefix( writer, ns, &prefix )) != S_OK)) return hr;
 
     qname.prefix    = (WS_XML_STRING *)prefix;
@@ -4398,7 +4474,7 @@ HRESULT WINAPI WsMoveWriter( WS_XML_WRITER *handle, WS_MOVE_TO move, BOOL *found
         return E_INVALIDARG;
     }
 
-    if (!writer->output_type) hr = WS_E_INVALID_OPERATION;
+    if (writer->output_type != WS_XML_WRITER_OUTPUT_TYPE_BUFFER) hr = WS_E_INVALID_OPERATION;
     else hr = write_move_to( writer, move, found );
 
     LeaveCriticalSection( &writer->cs );
@@ -4526,7 +4602,7 @@ static HRESULT write_comment( struct writer *writer )
 static HRESULT write_comment_node( struct writer *writer, const WS_XML_STRING *value )
 {
     HRESULT hr;
-    if ((hr = write_flush( writer )) != S_OK) return hr;
+    if ((hr = write_commit( writer )) != S_OK) return hr;
     if ((hr = write_add_comment_node( writer, value )) != S_OK) return hr;
     if ((hr = write_comment( writer )) != S_OK) return hr;
     writer->state = WRITER_STATE_COMMENT;
diff --git a/include/webservices.h b/include/webservices.h
index 69e3c8a276..a6018d5d25 100644
--- a/include/webservices.h
+++ b/include/webservices.h
@@ -296,15 +296,21 @@ typedef struct _WS_ASYNC_CONTEXT {
 typedef HRESULT (CALLBACK *WS_READ_CALLBACK)
     (void*, void*, ULONG, ULONG*, const WS_ASYNC_CONTEXT*, WS_ERROR*);
 
-typedef HRESULT (CALLBACK *WS_WRITE_CALLBACK)
-    (void*, const WS_BYTES*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
-
 typedef struct _WS_XML_READER_STREAM_INPUT {
     WS_XML_READER_INPUT input;
     WS_READ_CALLBACK readCallback;
     void *readCallbackState;
 } WS_XML_READER_STREAM_INPUT;
 
+typedef HRESULT (CALLBACK *WS_WRITE_CALLBACK)
+    (void*, const WS_BYTES*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
+
+typedef struct _WS_XML_WRITER_STREAM_OUTPUT {
+    WS_XML_WRITER_OUTPUT output;
+    WS_WRITE_CALLBACK writeCallback;
+    void *writeCallbackState;
+} WS_XML_WRITER_STREAM_OUTPUT;
+
 typedef enum {
     WS_ELEMENT_TYPE_MAPPING         = 1,
     WS_ATTRIBUTE_TYPE_MAPPING       = 2,
@@ -1626,6 +1632,8 @@ HRESULT WINAPI WsFillBody(WS_MESSAGE*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*
 HRESULT WINAPI WsFillReader(WS_XML_READER*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
 HRESULT WINAPI WsFindAttribute(WS_XML_READER*, const WS_XML_STRING*, const WS_XML_STRING*, BOOL,
                                ULONG*, WS_ERROR*);
+HRESULT WINAPI WsFlushBody(WS_MESSAGE*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
+HRESULT WINAPI WsFlushWriter(WS_XML_WRITER*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
 void WINAPI WsFreeChannel(WS_CHANNEL*);
 void WINAPI WsFreeError(WS_ERROR*);
 void WINAPI WsFreeHeap(WS_HEAP*);
-- 
2.11.0




More information about the wine-devel mailing list