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:
parent
29ab520445
commit
3e326c9a19
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "winhttp.h"
|
||||
|
||||
#define STREAM_BUFSIZE 4096
|
||||
|
||||
struct xmlbuf
|
||||
{
|
||||
WS_HEAP *heap;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*);
|
||||
|
|
Loading…
Reference in New Issue