webservices: Add support for stream output.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2018-12-04 13:57:28 +01:00 committed by Alexandre Julliard
parent 29ab520445
commit 3e326c9a19
6 changed files with 172 additions and 16 deletions

View File

@ -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;

View File

@ -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();
}

View File

@ -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)

View File

@ -18,6 +18,8 @@
#include "winhttp.h"
#define STREAM_BUFSIZE 4096
struct xmlbuf
{
WS_HEAP *heap;

View File

@ -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;

View File

@ -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*);