From: Shaun Ren sren@codeweavers.com
Signed-off-by: Shaun Ren sren@codeweavers.com --- dlls/webservices/error.c | 142 ++++++++++++++++++++++++++++-- dlls/webservices/tests/reader.c | 81 ++++++++++++++++- dlls/webservices/webservices.spec | 2 +- include/webservices.h | 1 + 4 files changed, 216 insertions(+), 10 deletions(-)
diff --git a/dlls/webservices/error.c b/dlls/webservices/error.c index d5364e42bff..d188b229ff4 100644 --- a/dlls/webservices/error.c +++ b/dlls/webservices/error.c @@ -41,8 +41,12 @@ struct error { ULONG magic; CRITICAL_SECTION cs; + WS_HEAP *heap; ULONG prop_count; struct prop prop[ARRAY_SIZE( error_props )]; + ULONG strs_count; + ULONG strs_size; /* Maximum length of the strs array */ + WS_STRING *strs; };
#define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O') @@ -54,6 +58,11 @@ static struct error *alloc_error(void) ULONG size = sizeof(*ret) + prop_size( error_props, count );
if (!(ret = calloc( 1, size ))) return NULL; + if (WsCreateHeap( 1 << 20, 0, NULL, 0, &ret->heap, NULL ) != S_OK) + { + free( ret ); + return NULL; + }
ret->magic = ERROR_MAGIC; InitializeCriticalSection( &ret->cs ); @@ -61,16 +70,51 @@ static struct error *alloc_error(void)
prop_init( error_props, count, ret->prop, &ret[1] ); ret->prop_count = count; + + ret->strs = NULL; + ret->strs_count = ret->strs_size = 0; + return ret; }
static void free_error( struct error *error ) { + WsFreeHeap( error->heap ); error->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &error->cs ); free( error ); }
+/* Grow the strs array to fit an extra element. */ +static HRESULT grow_strs_array( struct error *error ) +{ + WS_STRING *new_ptr; + ULONG new_size; + + if (error->strs_count < error->strs_size) + return S_OK; + + new_size = error->strs_size > 0 ? 2 * error->strs_size : 1; + if (error->strs_size > 0) + { + new_size = 2 * error->strs_size; + new_ptr = ws_realloc_zero( error->heap, error->strs, + error->strs_size * sizeof(WS_STRING), + new_size * sizeof(WS_STRING) ); + } + else + { + new_size = 1; + new_ptr = ws_alloc_zero( error->heap, sizeof(WS_STRING) ); + } + if (!new_ptr) + return E_OUTOFMEMORY; + + error->strs = new_ptr; + error->strs_size = new_size; + return S_OK; +} + /************************************************************************** * WsCreateError [webservices.@] */ @@ -111,8 +155,12 @@ HRESULT WINAPI WsCreateError( const WS_ERROR_PROPERTY *properties, ULONG count, static void reset_error( struct error *error ) { ULONG code = 0; - /* FIXME: release strings added with WsAddErrorString when it's implemented, reset string count */ + prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE, &code, sizeof(code) ); + + error->strs = NULL; + error->strs_count = error->strs_size = 0; + WsResetHeap( error->heap, NULL ); }
/************************************************************************** @@ -175,22 +223,31 @@ HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, vo ULONG size ) { struct error *error = (struct error *)handle; - HRESULT hr; + HRESULT hr = S_OK;
TRACE( "%p %u %p %lu\n", handle, id, buf, size );
- if (!error) return E_INVALIDARG; + if (!error || !buf) return E_INVALIDARG;
EnterCriticalSection( &error->cs );
if (error->magic != ERROR_MAGIC) { - LeaveCriticalSection( &error->cs ); - return E_INVALIDARG; + hr = E_INVALIDARG; + goto done; }
- hr = prop_get( error->prop, error->prop_count, id, buf, size ); + if (id == WS_ERROR_PROPERTY_STRING_COUNT) + { + if (size == sizeof(ULONG)) + *(ULONG *)buf = error->strs_count; + else + hr = E_INVALIDARG; + } + else + hr = prop_get( error->prop, error->prop_count, id, buf, size );
+done: LeaveCriticalSection( &error->cs ); TRACE( "returning %#lx\n", hr ); return hr; @@ -201,8 +258,33 @@ HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, vo */ HRESULT WINAPI WsGetErrorString( WS_ERROR *handle, ULONG index, WS_STRING *str ) { - FIXME( "%p %lu %p: stub\n", handle, index, str ); - return E_NOTIMPL; + struct error *error = (struct error *)handle; + HRESULT hr = S_OK; + + TRACE( "%p %lu %p\n", handle, index, str ); + + if (!error || !str) return E_INVALIDARG; + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + if (index >= error->strs_count) + { + hr = E_INVALIDARG; + goto done; + } + + /* The strings are indexed from most recently added to least recently added. */ + memcpy( str, &error->strs[error->strs_count - 1 - index], sizeof(WS_STRING) ); + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; }
/************************************************************************** @@ -233,3 +315,47 @@ HRESULT WINAPI WsSetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, co TRACE( "returning %#lx\n", hr ); return hr; } + +/************************************************************************** + * WsAddErrorString [webservices.@] + */ +HRESULT WINAPI WsAddErrorString( WS_ERROR *handle, const WS_STRING *str ) +{ + struct error *error = (struct error *)handle; + WCHAR *chars; + HRESULT hr; + + TRACE( "%p %p\n", handle, str ); + + if (!error || !str) return E_INVALIDARG; + + EnterCriticalSection( &error->cs ); + + if (error->magic != ERROR_MAGIC) + { + hr = E_INVALIDARG; + goto done; + } + if (!(chars = ws_alloc( error->heap, str->length * sizeof(*chars) ))) + { + hr = E_OUTOFMEMORY; + goto done; + } + + if ( (hr = grow_strs_array( error )) != S_OK ) + { + ws_free( error->heap, chars, str->length * sizeof(*chars) ); + goto done; + } + + memcpy( chars, str->chars, str->length * sizeof(*chars) ); + + error->strs[error->strs_count].chars = chars; + error->strs[error->strs_count].length = str->length; + error->strs_count++; + +done: + LeaveCriticalSection( &error->cs ); + TRACE( "returning %#lx\n", hr ); + return hr; +} diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index f62697b9662..84a8660d6f1 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -3890,9 +3890,10 @@ static void test_WsReadValue(void) static void test_WsResetError(void) { WS_ERROR_PROPERTY prop; - ULONG size, code; + ULONG size, code, count; WS_ERROR *error; LANGID langid; + WS_STRING str; HRESULT hr;
hr = WsResetError( NULL ); @@ -3942,6 +3943,34 @@ static void test_WsResetError(void) ok( langid == MAKELANGID( LANG_DUTCH, SUBLANG_DEFAULT ), "got %u\n", langid );
WsFreeError( error ); + + str.chars = (WCHAR *) L"str"; + str.length = 3; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsAddErrorString(error, &str ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + size = sizeof(count); + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, size ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 2, "got %lu\n", count ); + + hr = WsResetError( error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + size = sizeof(count); + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, size ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 0, "got %lu\n", count ); + + WsFreeError( error ); }
static void test_WsGetReaderPosition(void) @@ -7044,6 +7073,55 @@ static void test_description_type(void) WsFreeHeap( heap ); }
+static void test_WsAddErrorString(void) +{ + ULONG count; + WS_ERROR *error; + WS_STRING emptystr = { 0 }; + WS_STRING str1 = { 4, (WCHAR *) L"str1" }; + WS_STRING str2 = { 4, (WCHAR *) L"str2" }; + WS_STRING out; + HRESULT hr; + + hr = WsCreateError( NULL, 0, &error ); + ok( hr == S_OK, "got %#lx\n", hr ); + + hr = WsAddErrorString( NULL, NULL ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + hr = WsAddErrorString( NULL, &str1 ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + hr = WsAddErrorString( error, NULL ); + ok( hr == E_INVALIDARG, "got %#lx\n", hr ); + + hr = WsAddErrorString( error, &emptystr ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str2 ); + ok( hr == S_OK, "got %#lx\n", hr ); + hr = WsAddErrorString(error, &str1 ); + ok( hr == S_OK, "got %#lx\n", hr ); + + count = 0xdeadbeef; + hr = WsGetErrorProperty( error, WS_ERROR_PROPERTY_STRING_COUNT, &count, sizeof(count) ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + + hr = WsGetErrorString( error, 0, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == str1.length, "got %lu\n", out.length ); + ok( !memcmp( out.chars, str1.chars, str1.length ), "wrong error string\n" ); + + hr = WsGetErrorString( error, 1, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == str2.length, "got %lu\n", out.length ); + ok( !memcmp( out.chars, str2.chars, str2.length ), "wrong error string\n" ); + + hr = WsGetErrorString( error, 2, &out ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( out.length == 0, "got %lu\n", out.length ); + ok( out.chars != NULL, "out.chars == NULL\n" ); + + WsFreeError( error ); +} START_TEST(reader) { test_WsCreateError(); @@ -7095,4 +7173,5 @@ START_TEST(reader) test_empty_text_field(); test_stream_input(); test_description_type(); + test_WsAddErrorString(); } diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index 3fe1f4d4275..679d294ec1c 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -6,7 +6,7 @@ @ stdcall WsAbortServiceProxy(ptr ptr) @ stdcall WsAcceptChannel(ptr ptr ptr ptr) @ stdcall WsAddCustomHeader(ptr ptr long ptr long long ptr) -@ stub WsAddErrorString +@ stdcall WsAddErrorString(ptr ptr) @ stdcall WsAddMappedHeader(ptr ptr long long ptr long ptr) @ stdcall WsAddressMessage(ptr ptr ptr) @ stdcall WsAlloc(ptr long ptr ptr) diff --git a/include/webservices.h b/include/webservices.h index a6018d5d258..9395ad6f0e3 100644 --- a/include/webservices.h +++ b/include/webservices.h @@ -1588,6 +1588,7 @@ HRESULT WINAPI WsAbortServiceProxy(WS_SERVICE_PROXY*, WS_ERROR*); HRESULT WINAPI WsAcceptChannel(WS_LISTENER*, WS_CHANNEL*, const WS_ASYNC_CONTEXT*, WS_ERROR*); HRESULT WINAPI WsAddCustomHeader(WS_MESSAGE*, const WS_ELEMENT_DESCRIPTION*, WS_WRITE_OPTION, const void*, ULONG, ULONG, WS_ERROR*); +HRESULT WINAPI WsAddErrorString(WS_ERROR*, const WS_STRING*); HRESULT WINAPI WsAddMappedHeader(WS_MESSAGE*, const WS_XML_STRING*, WS_TYPE, WS_WRITE_OPTION, const void*, ULONG, WS_ERROR*); HRESULT WINAPI WsAddressMessage(WS_MESSAGE*, const WS_ENDPOINT_ADDRESS*, WS_ERROR*);