2 * Copyright 2015, 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "webservices.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
29 #include "webservices_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
33 static const struct prop_desc error_props
[] =
35 { sizeof(ULONG
), TRUE
}, /* WS_ERROR_PROPERTY_STRING_COUNT */
36 { sizeof(ULONG
), FALSE
}, /* WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE */
37 { sizeof(LANGID
), FALSE
} /* WS_ERROR_PROPERTY_LANGID */
46 struct prop prop
[ARRAY_SIZE( error_props
)];
48 ULONG strs_size
; /* Maximum length of the strs array */
51 WS_XML_STRING fault_action
;
54 #define ERROR_MAGIC (('E' << 24) | ('R' << 16) | ('R' << 8) | 'O')
56 static struct error
*alloc_error(void)
58 static const ULONG count
= ARRAY_SIZE( error_props
);
60 ULONG size
= sizeof(*ret
) + prop_size( error_props
, count
);
62 if (!(ret
= calloc( 1, size
))) return NULL
;
63 if (WsCreateHeap( 1 << 20, 0, NULL
, 0, &ret
->heap
, NULL
) != S_OK
)
69 ret
->magic
= ERROR_MAGIC
;
70 InitializeCriticalSection( &ret
->cs
);
71 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": error.cs");
73 prop_init( error_props
, count
, ret
->prop
, &ret
[1] );
74 ret
->prop_count
= count
;
77 ret
->strs_count
= ret
->strs_size
= 0;
82 static void free_error( struct error
*error
)
84 WsFreeHeap( error
->heap
);
85 error
->cs
.DebugInfo
->Spare
[0] = 0;
86 DeleteCriticalSection( &error
->cs
);
90 void free_fault_fields( WS_HEAP
*heap
, WS_FAULT
*fault
)
92 WS_FAULT_CODE
*code
, *prev_code
;
98 ws_free( heap
, code
->value
.localName
.bytes
, code
->value
.localName
.length
);
99 ws_free( heap
, code
->value
.ns
.bytes
, code
->value
.ns
.length
);
101 code
= code
->subCode
;
102 ws_free( heap
, prev_code
, sizeof(*prev_code
) );
105 for (i
= 0; i
< fault
->reasonCount
; i
++)
107 ws_free( heap
, fault
->reasons
[i
].text
.chars
, fault
->reasons
[i
].text
.length
* sizeof(WCHAR
) );
108 ws_free( heap
, fault
->reasons
[i
].lang
.chars
, fault
->reasons
[i
].lang
.length
* sizeof(WCHAR
) );
110 ws_free( heap
, fault
->reasons
, fault
->reasonCount
* sizeof(*fault
->reasons
) );
112 ws_free( heap
, fault
->actor
.chars
, fault
->actor
.length
* sizeof(WCHAR
) );
113 ws_free( heap
, fault
->node
.chars
, fault
->node
.length
* sizeof(WCHAR
) );
114 free_xmlbuf((struct xmlbuf
*)fault
->detail
);
117 static void free_fault( WS_HEAP
*heap
, WS_FAULT
*fault
)
120 free_fault_fields( heap
, fault
);
121 ws_free( heap
, fault
, sizeof(*fault
) );
124 static BOOL
copy_xml_string( WS_HEAP
*heap
, const WS_XML_STRING
*src
, WS_XML_STRING
*dst
)
126 if (!src
->length
) return TRUE
;
127 if (!(dst
->bytes
= ws_alloc( heap
, src
->length
))) return FALSE
;
128 memcpy( dst
->bytes
, src
->bytes
, src
->length
);
129 dst
->length
= src
->length
;
133 static BOOL
copy_string( WS_HEAP
*heap
, const WS_STRING
*src
, WS_STRING
*dst
)
136 if (!src
->length
) return TRUE
;
137 size
= src
->length
* sizeof(WCHAR
);
138 if (!(dst
->chars
= ws_alloc( heap
, size
))) return FALSE
;
139 memcpy( dst
->chars
, src
->chars
, size
);
140 dst
->length
= src
->length
;
144 /* Grow the strs array to fit an extra element. */
145 static HRESULT
grow_strs_array( struct error
*error
)
150 if (error
->strs_count
< error
->strs_size
)
153 new_size
= error
->strs_size
> 0 ? 2 * error
->strs_size
: 1;
154 if (error
->strs_size
> 0)
156 new_size
= 2 * error
->strs_size
;
157 new_ptr
= ws_realloc_zero( error
->heap
, error
->strs
,
158 error
->strs_size
* sizeof(WS_STRING
),
159 new_size
* sizeof(WS_STRING
) );
164 new_ptr
= ws_alloc_zero( error
->heap
, sizeof(WS_STRING
) );
167 return E_OUTOFMEMORY
;
169 error
->strs
= new_ptr
;
170 error
->strs_size
= new_size
;
174 static WS_FAULT
*dup_fault( WS_HEAP
*heap
, const WS_FAULT
*src
)
177 WS_FAULT_CODE
*code
, *prev_code
, *new_code
;
178 struct xmlbuf
*buf
, *new_buf
;
180 BOOL success
= FALSE
;
182 if (!(new_fault
= ws_alloc_zero( heap
, sizeof(*new_fault
) )))
189 if (!(new_code
= ws_alloc_zero( heap
, sizeof(*new_code
) )) ||
190 !copy_xml_string( heap
, &code
->value
.localName
, &new_code
->value
.localName
) ||
191 !copy_xml_string( heap
, &code
->value
.ns
, &new_code
->value
.ns
))
195 prev_code
->subCode
= new_code
;
197 new_fault
->code
= new_code
;
198 prev_code
= new_code
;
199 code
= code
->subCode
;
202 if (src
->reasonCount
> 0)
204 if (!(new_fault
->reasons
= ws_alloc_zero( heap
, sizeof(*new_fault
->reasons
) * src
->reasonCount
)))
206 new_fault
->reasonCount
= src
->reasonCount
;
207 for (i
= 0; i
< src
->reasonCount
; i
++)
209 if (!copy_string( heap
, &src
->reasons
[i
].text
, &new_fault
->reasons
[i
].text
) ||
210 !copy_string( heap
, &src
->reasons
[i
].lang
, &new_fault
->reasons
[i
].lang
))
215 if (!copy_string( heap
, &src
->actor
, &new_fault
->actor
) ||
216 !copy_string( heap
, &src
->node
, &new_fault
->node
))
219 buf
= (struct xmlbuf
*)src
->detail
;
223 if (!(new_buf
= alloc_xmlbuf( heap
, buf
->bytes
.length
, buf
->encoding
,
224 buf
->charset
, buf
->dict_static
, buf
->dict
)))
226 memcpy( new_buf
->bytes
.bytes
, buf
->bytes
.bytes
, buf
->bytes
.length
);
227 new_buf
->bytes
.length
= buf
->bytes
.length
;
229 new_fault
->detail
= (WS_XML_BUFFER
*)new_buf
;
235 free_fault( heap
, new_fault
);
241 static HRESULT
set_fault( struct error
*error
, const WS_FAULT
*value
)
243 static const WCHAR prefix
[] = L
"The fault reason was: '";
244 static const WCHAR postfix
[] = L
"'.";
245 static const ULONG prefix_len
= ARRAY_SIZE(prefix
) - 1, postfix_len
= ARRAY_SIZE(postfix
) - 1;
252 if (!(fault
= dup_fault( error
->heap
, value
)))
253 return E_OUTOFMEMORY
;
255 /* FIXME: check if reason lang matches error property langid */
256 if (fault
->reasonCount
> 0)
258 if ((hr
= grow_strs_array( error
)) != S_OK
) goto done
;
260 str
= &error
->strs
[error
->strs_count
];
261 len
= prefix_len
+ fault
->reasons
[0].text
.length
+ postfix_len
;
262 if (!(str
->chars
= ws_alloc( error
->heap
, len
* sizeof(WCHAR
) )))
269 memcpy( dst
, prefix
, prefix_len
* sizeof(WCHAR
) );
271 memcpy( dst
, fault
->reasons
[0].text
.chars
, fault
->reasons
[0].text
.length
* sizeof(WCHAR
) );
272 dst
+= fault
->reasons
[0].text
.length
;
273 memcpy( dst
, postfix
, postfix_len
* sizeof(WCHAR
) );
279 free_fault( error
->heap
, error
->fault
);
280 error
->fault
= fault
;
284 free_fault( error
->heap
, fault
);
288 static HRESULT
set_action( struct error
*error
, const WS_XML_STRING
*value
)
292 if (value
->length
== 0)
294 ws_free( error
->heap
, error
->fault_action
.bytes
, error
->fault_action
.length
);
295 memset( &error
->fault_action
, 0, sizeof(error
->fault_action
) );
299 if (!(buf
= ws_alloc( error
->heap
, value
->length
)))
300 return E_OUTOFMEMORY
;
302 memcpy( buf
, value
->bytes
, value
->length
);
303 ws_free( error
->heap
, error
->fault_action
.bytes
, error
->fault_action
.length
);
304 error
->fault_action
.bytes
= buf
;
305 error
->fault_action
.length
= value
->length
;
310 /**************************************************************************
311 * WsCreateError [webservices.@]
313 HRESULT WINAPI
WsCreateError( const WS_ERROR_PROPERTY
*properties
, ULONG count
, WS_ERROR
**handle
)
316 LANGID langid
= GetUserDefaultUILanguage();
320 TRACE( "%p %lu %p\n", properties
, count
, handle
);
322 if (!handle
) return E_INVALIDARG
;
323 if (!(error
= alloc_error())) return E_OUTOFMEMORY
;
325 prop_set( error
->prop
, error
->prop_count
, WS_ERROR_PROPERTY_LANGID
, &langid
, sizeof(langid
) );
326 for (i
= 0; i
< count
; i
++)
328 if (properties
[i
].id
== WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE
)
333 hr
= prop_set( error
->prop
, error
->prop_count
, properties
[i
].id
, properties
[i
].value
,
334 properties
[i
].valueSize
);
342 TRACE( "created %p\n", error
);
343 *handle
= (WS_ERROR
*)error
;
347 static void reset_error( struct error
*error
)
351 prop_set( error
->prop
, error
->prop_count
, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE
, &code
, sizeof(code
) );
354 error
->strs_count
= error
->strs_size
= 0;
356 memset( &error
->fault_action
, 0, sizeof(error
->fault_action
) );
358 WsResetHeap( error
->heap
, NULL
);
361 /**************************************************************************
362 * WsFreeError [webservices.@]
364 void WINAPI
WsFreeError( WS_ERROR
*handle
)
366 struct error
*error
= (struct error
*)handle
;
368 TRACE( "%p\n", handle
);
372 EnterCriticalSection( &error
->cs
);
374 if (error
->magic
!= ERROR_MAGIC
)
376 LeaveCriticalSection( &error
->cs
);
380 reset_error( error
);
383 LeaveCriticalSection( &error
->cs
);
387 /**************************************************************************
388 * WsResetError [webservices.@]
390 HRESULT WINAPI
WsResetError( WS_ERROR
*handle
)
392 struct error
*error
= (struct error
*)handle
;
395 TRACE( "%p\n", handle
);
397 if (!error
) return E_INVALIDARG
;
399 EnterCriticalSection( &error
->cs
);
401 if (error
->magic
!= ERROR_MAGIC
)
403 LeaveCriticalSection( &error
->cs
);
407 reset_error( error
);
409 LeaveCriticalSection( &error
->cs
);
410 TRACE( "returning %#lx\n", hr
);
414 /**************************************************************************
415 * WsGetErrorProperty [webservices.@]
417 HRESULT WINAPI
WsGetErrorProperty( WS_ERROR
*handle
, WS_ERROR_PROPERTY_ID id
, void *buf
,
420 struct error
*error
= (struct error
*)handle
;
423 TRACE( "%p %u %p %lu\n", handle
, id
, buf
, size
);
425 if (!error
|| !buf
) return E_INVALIDARG
;
427 EnterCriticalSection( &error
->cs
);
429 if (error
->magic
!= ERROR_MAGIC
)
435 if (id
== WS_ERROR_PROPERTY_STRING_COUNT
)
437 if (size
== sizeof(ULONG
))
438 *(ULONG
*)buf
= error
->strs_count
;
443 hr
= prop_get( error
->prop
, error
->prop_count
, id
, buf
, size
);
446 LeaveCriticalSection( &error
->cs
);
447 TRACE( "returning %#lx\n", hr
);
451 /**************************************************************************
452 * WsGetErrorString [webservices.@]
454 HRESULT WINAPI
WsGetErrorString( WS_ERROR
*handle
, ULONG index
, WS_STRING
*str
)
456 struct error
*error
= (struct error
*)handle
;
459 TRACE( "%p %lu %p\n", handle
, index
, str
);
461 if (!error
|| !str
) return E_INVALIDARG
;
463 EnterCriticalSection( &error
->cs
);
465 if (error
->magic
!= ERROR_MAGIC
)
470 if (index
>= error
->strs_count
)
476 /* The strings are indexed from most recently added to least recently added. */
477 memcpy( str
, &error
->strs
[error
->strs_count
- 1 - index
], sizeof(WS_STRING
) );
480 LeaveCriticalSection( &error
->cs
);
481 TRACE( "returning %#lx\n", hr
);
485 /**************************************************************************
486 * WsSetErrorProperty [webservices.@]
488 HRESULT WINAPI
WsSetErrorProperty( WS_ERROR
*handle
, WS_ERROR_PROPERTY_ID id
, const void *value
,
491 struct error
*error
= (struct error
*)handle
;
494 TRACE( "%p %u %p %lu\n", handle
, id
, value
, size
);
496 if (!error
) return E_INVALIDARG
;
498 EnterCriticalSection( &error
->cs
);
500 if (error
->magic
!= ERROR_MAGIC
)
502 LeaveCriticalSection( &error
->cs
);
506 if (id
== WS_ERROR_PROPERTY_LANGID
) hr
= WS_E_INVALID_OPERATION
;
507 else hr
= prop_set( error
->prop
, error
->prop_count
, id
, value
, size
);
509 LeaveCriticalSection( &error
->cs
);
510 TRACE( "returning %#lx\n", hr
);
514 /**************************************************************************
515 * WsAddErrorString [webservices.@]
517 HRESULT WINAPI
WsAddErrorString( WS_ERROR
*handle
, const WS_STRING
*str
)
519 struct error
*error
= (struct error
*)handle
;
523 TRACE( "%p %p\n", handle
, str
);
525 if (!error
|| !str
) return E_INVALIDARG
;
527 EnterCriticalSection( &error
->cs
);
529 if (error
->magic
!= ERROR_MAGIC
)
534 if (!(chars
= ws_alloc( error
->heap
, str
->length
* sizeof(*chars
) )))
540 if ( (hr
= grow_strs_array( error
)) != S_OK
)
542 ws_free( error
->heap
, chars
, str
->length
* sizeof(*chars
) );
546 memcpy( chars
, str
->chars
, str
->length
* sizeof(*chars
) );
548 error
->strs
[error
->strs_count
].chars
= chars
;
549 error
->strs
[error
->strs_count
].length
= str
->length
;
553 LeaveCriticalSection( &error
->cs
);
554 TRACE( "returning %#lx\n", hr
);
558 /**************************************************************************
559 * WsGetFaultErrorDetail [webservices.@]
561 HRESULT WINAPI
WsGetFaultErrorDetail( WS_ERROR
*handle
, const WS_FAULT_DETAIL_DESCRIPTION
*desc
,
562 WS_READ_OPTION option
, WS_HEAP
*heap
, void *value
, ULONG size
)
564 static const WS_XML_STRING detail
= {6, (BYTE
*)"detail"};
565 struct error
*error
= (struct error
*)handle
;
566 WS_XML_READER
*reader
= NULL
;
567 const WS_XML_NODE
*node
;
568 const WS_XML_ELEMENT_NODE
*elem
;
572 TRACE( "%p %p %u %p %p %lu\n", handle
, desc
, option
, heap
, value
, size
);
574 if (!error
|| !desc
|| !value
) return E_INVALIDARG
;
575 if ((option
== WS_READ_REQUIRED_POINTER
||
576 option
== WS_READ_OPTIONAL_POINTER
||
577 option
== WS_READ_NILLABLE_POINTER
) && size
!= sizeof(void *))
580 EnterCriticalSection( &error
->cs
);
582 if (error
->magic
!= ERROR_MAGIC
)
588 if (!error
->fault
|| !error
->fault
->detail
)
593 if ((hr
= WsCreateReader( NULL
, 0, &reader
, NULL
)) != S_OK
) goto done
;
594 if ((hr
= WsSetInputToBuffer( reader
, error
->fault
->detail
, NULL
, 0, NULL
)) != S_OK
) goto done
;
596 if ((hr
= WsReadNode( reader
, NULL
)) != S_OK
) goto done
;
597 if ((hr
= WsGetReaderNode( reader
, &node
, NULL
)) != S_OK
) goto done
;
598 elem
= (const WS_XML_ELEMENT_NODE
*)node
;
599 if (!(node
->nodeType
== WS_XML_NODE_TYPE_ELEMENT
&&
600 WsXmlStringEquals( elem
->localName
, &detail
, NULL
) == S_OK
))
602 hr
= WS_E_INVALID_FORMAT
;
606 if (desc
->action
&& error
->fault_action
.length
&&
607 WsXmlStringEquals( desc
->action
, &error
->fault_action
, NULL
) != S_OK
)
613 if ((hr
= WsReadNode( reader
, NULL
)) != S_OK
) goto done
;
614 if ((hr
= WsReadElement( reader
, desc
->detailElementDescription
,
615 option
, heap
, value
, size
, handle
)) != S_OK
)
619 LeaveCriticalSection( &error
->cs
);
620 WsFreeReader( reader
);
622 if ((hr
!= S_OK
|| nil
) && (option
== WS_READ_OPTIONAL_POINTER
|| option
== WS_READ_NILLABLE_POINTER
))
623 *(void **)value
= NULL
;
624 if (nil
&& !(option
== WS_READ_OPTIONAL_POINTER
|| option
== WS_READ_NILLABLE_POINTER
))
625 hr
= WS_E_INVALID_FORMAT
;
627 TRACE( "returning %#lx\n", hr
);
631 /**************************************************************************
632 * WsGetFaultErrorProperty [webservices.@]
634 HRESULT WINAPI
WsGetFaultErrorProperty( WS_ERROR
*handle
, WS_FAULT_ERROR_PROPERTY_ID id
,
635 void *buf
, ULONG size
)
637 struct error
*error
= (struct error
*)handle
;
640 TRACE( "%p %u %p %lu\n", handle
, id
, buf
, size
);
642 if (!error
|| !buf
) return E_INVALIDARG
;
643 if (id
> WS_FAULT_ERROR_PROPERTY_HEADER
) return E_INVALIDARG
;
644 else if (id
== WS_FAULT_ERROR_PROPERTY_HEADER
)
646 FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" );
650 EnterCriticalSection( &error
->cs
);
652 if (error
->magic
!= ERROR_MAGIC
)
658 if (id
== WS_FAULT_ERROR_PROPERTY_FAULT
&& size
== sizeof(WS_FAULT
*))
659 *(WS_FAULT
**)buf
= error
->fault
;
660 else if (id
== WS_FAULT_ERROR_PROPERTY_ACTION
&& size
== sizeof(WS_XML_STRING
))
661 memcpy( buf
, &error
->fault_action
, sizeof(WS_XML_STRING
) );
666 LeaveCriticalSection( &error
->cs
);
667 TRACE( "returning %#lx\n", hr
);
671 /**************************************************************************
672 * WsSetFaultErrorProperty [webservices.@]
674 HRESULT WINAPI
WsSetFaultErrorProperty( WS_ERROR
*handle
, WS_FAULT_ERROR_PROPERTY_ID id
,
675 const void *value
, ULONG size
)
677 struct error
*error
= (struct error
*)handle
;
680 TRACE( "%p %u %p %lu\n", handle
, id
, value
, size
);
682 if (!error
|| !value
) return E_INVALIDARG
;
683 if (id
> WS_FAULT_ERROR_PROPERTY_HEADER
) return E_INVALIDARG
;
684 else if (id
== WS_FAULT_ERROR_PROPERTY_HEADER
)
686 FIXME( "WS_FAULT_ERROR_PROPERTY_HEADER not supported\n" );
690 EnterCriticalSection( &error
->cs
);
692 if (error
->magic
!= ERROR_MAGIC
)
698 if (id
== WS_FAULT_ERROR_PROPERTY_FAULT
&& size
== sizeof(WS_FAULT
))
699 hr
= set_fault( error
, value
);
700 else if (id
== WS_FAULT_ERROR_PROPERTY_ACTION
&& size
== sizeof(WS_XML_STRING
))
701 hr
= set_action( error
, value
);
706 LeaveCriticalSection( &error
->cs
);
707 TRACE( "returning %#lx\n", hr
);