[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