cmd: DIR command outputs free space for the path.
[wine.git] / dlls / webservices / error.c
blobaa1a9744f34ad118b71009a9396cf49fcb3e2516
1 /*
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
19 #include <stdarg.h>
20 #include <stdlib.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
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 */
40 struct error
42 ULONG magic;
43 CRITICAL_SECTION cs;
44 WS_HEAP *heap;
45 ULONG prop_count;
46 struct prop prop[ARRAY_SIZE( error_props )];
47 ULONG strs_count;
48 ULONG strs_size; /* Maximum length of the strs array */
49 WS_STRING *strs;
50 WS_FAULT *fault;
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 );
59 struct error *ret;
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)
65 free( ret );
66 return NULL;
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;
76 ret->strs = NULL;
77 ret->strs_count = ret->strs_size = 0;
79 return ret;
82 static void free_error( struct error *error )
84 WsFreeHeap( error->heap );
85 error->cs.DebugInfo->Spare[0] = 0;
86 DeleteCriticalSection( &error->cs );
87 free( error );
90 void free_fault_fields( WS_HEAP *heap, WS_FAULT *fault )
92 WS_FAULT_CODE *code, *prev_code;
93 ULONG i;
95 code = fault->code;
96 while ( 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 );
100 prev_code = code;
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 )
119 if (!fault) return;
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;
130 return TRUE;
133 static BOOL copy_string( WS_HEAP *heap, const WS_STRING *src, WS_STRING *dst )
135 ULONG size;
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;
141 return TRUE;
144 /* Grow the strs array to fit an extra element. */
145 static HRESULT grow_strs_array( struct error *error )
147 WS_STRING *new_ptr;
148 ULONG new_size;
150 if (error->strs_count < error->strs_size)
151 return S_OK;
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) );
161 else
163 new_size = 1;
164 new_ptr = ws_alloc_zero( error->heap, sizeof(WS_STRING) );
166 if (!new_ptr)
167 return E_OUTOFMEMORY;
169 error->strs = new_ptr;
170 error->strs_size = new_size;
171 return S_OK;
174 static WS_FAULT *dup_fault( WS_HEAP *heap, const WS_FAULT *src )
176 WS_FAULT *new_fault;
177 WS_FAULT_CODE *code, *prev_code, *new_code;
178 struct xmlbuf *buf, *new_buf;
179 ULONG i;
180 BOOL success = FALSE;
182 if (!(new_fault = ws_alloc_zero( heap, sizeof(*new_fault) )))
183 return NULL;
185 prev_code = NULL;
186 code = src->code;
187 while ( code )
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 ))
192 goto done;
194 if (prev_code)
195 prev_code->subCode = new_code;
196 else
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 )))
205 goto done;
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 ))
211 goto done;
215 if (!copy_string( heap, &src->actor, &new_fault->actor ) ||
216 !copy_string( heap, &src->node, &new_fault->node ))
217 goto done;
219 buf = (struct xmlbuf *)src->detail;
220 new_buf = NULL;
221 if (buf)
223 if (!(new_buf = alloc_xmlbuf( heap, buf->bytes.length, buf->encoding,
224 buf->charset, buf->dict_static, buf->dict )))
225 goto done;
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;
231 success = TRUE;
232 done:
233 if (!success)
235 free_fault( heap, new_fault );
236 return NULL;
238 return 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;
246 WS_FAULT *fault;
247 WS_STRING *str;
248 WCHAR *dst;
249 ULONG len;
250 HRESULT hr = S_OK;
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) )))
264 hr = E_OUTOFMEMORY;
265 goto done;
268 dst = str->chars;
269 memcpy( dst, prefix, prefix_len * sizeof(WCHAR) );
270 dst += prefix_len;
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) );
275 str->length = len;
276 error->strs_count++;
279 free_fault( error->heap, error->fault );
280 error->fault = fault;
282 done:
283 if (hr != S_OK)
284 free_fault( error->heap, fault );
285 return hr;
288 static HRESULT set_action( struct error *error, const WS_XML_STRING *value )
290 BYTE *buf;
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) );
296 return S_OK;
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;
307 return S_OK;
310 /**************************************************************************
311 * WsCreateError [webservices.@]
313 HRESULT WINAPI WsCreateError( const WS_ERROR_PROPERTY *properties, ULONG count, WS_ERROR **handle )
315 struct error *error;
316 LANGID langid = GetUserDefaultUILanguage();
317 HRESULT hr;
318 ULONG i;
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)
330 free_error( error );
331 return E_INVALIDARG;
333 hr = prop_set( error->prop, error->prop_count, properties[i].id, properties[i].value,
334 properties[i].valueSize );
335 if (hr != S_OK)
337 free_error( error );
338 return hr;
342 TRACE( "created %p\n", error );
343 *handle = (WS_ERROR *)error;
344 return S_OK;
347 static void reset_error( struct error *error )
349 ULONG code = 0;
351 prop_set( error->prop, error->prop_count, WS_ERROR_PROPERTY_ORIGINAL_ERROR_CODE, &code, sizeof(code) );
353 error->strs = NULL;
354 error->strs_count = error->strs_size = 0;
355 error->fault = NULL;
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 );
370 if (!error) return;
372 EnterCriticalSection( &error->cs );
374 if (error->magic != ERROR_MAGIC)
376 LeaveCriticalSection( &error->cs );
377 return;
380 reset_error( error );
381 error->magic = 0;
383 LeaveCriticalSection( &error->cs );
384 free_error( error );
387 /**************************************************************************
388 * WsResetError [webservices.@]
390 HRESULT WINAPI WsResetError( WS_ERROR *handle )
392 struct error *error = (struct error *)handle;
393 HRESULT hr = S_OK;
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 );
404 return E_INVALIDARG;
407 reset_error( error );
409 LeaveCriticalSection( &error->cs );
410 TRACE( "returning %#lx\n", hr );
411 return hr;
414 /**************************************************************************
415 * WsGetErrorProperty [webservices.@]
417 HRESULT WINAPI WsGetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, void *buf,
418 ULONG size )
420 struct error *error = (struct error *)handle;
421 HRESULT hr = S_OK;
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)
431 hr = E_INVALIDARG;
432 goto done;
435 if (id == WS_ERROR_PROPERTY_STRING_COUNT)
437 if (size == sizeof(ULONG))
438 *(ULONG *)buf = error->strs_count;
439 else
440 hr = E_INVALIDARG;
442 else
443 hr = prop_get( error->prop, error->prop_count, id, buf, size );
445 done:
446 LeaveCriticalSection( &error->cs );
447 TRACE( "returning %#lx\n", hr );
448 return hr;
451 /**************************************************************************
452 * WsGetErrorString [webservices.@]
454 HRESULT WINAPI WsGetErrorString( WS_ERROR *handle, ULONG index, WS_STRING *str )
456 struct error *error = (struct error *)handle;
457 HRESULT hr = S_OK;
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)
467 hr = E_INVALIDARG;
468 goto done;
470 if (index >= error->strs_count)
472 hr = E_INVALIDARG;
473 goto done;
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) );
479 done:
480 LeaveCriticalSection( &error->cs );
481 TRACE( "returning %#lx\n", hr );
482 return hr;
485 /**************************************************************************
486 * WsSetErrorProperty [webservices.@]
488 HRESULT WINAPI WsSetErrorProperty( WS_ERROR *handle, WS_ERROR_PROPERTY_ID id, const void *value,
489 ULONG size )
491 struct error *error = (struct error *)handle;
492 HRESULT hr;
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 );
503 return E_INVALIDARG;
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 );
511 return hr;
514 /**************************************************************************
515 * WsAddErrorString [webservices.@]
517 HRESULT WINAPI WsAddErrorString( WS_ERROR *handle, const WS_STRING *str )
519 struct error *error = (struct error *)handle;
520 WCHAR *chars;
521 HRESULT hr;
523 TRACE( "%p %p\n", handle, str );
525 if (!error || !str) return E_INVALIDARG;
527 EnterCriticalSection( &error->cs );
529 if (error->magic != ERROR_MAGIC)
531 hr = E_INVALIDARG;
532 goto done;
534 if (!(chars = ws_alloc( error->heap, str->length * sizeof(*chars) )))
536 hr = E_OUTOFMEMORY;
537 goto done;
540 if ( (hr = grow_strs_array( error )) != S_OK )
542 ws_free( error->heap, chars, str->length * sizeof(*chars) );
543 goto done;
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;
550 error->strs_count++;
552 done:
553 LeaveCriticalSection( &error->cs );
554 TRACE( "returning %#lx\n", hr );
555 return 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;
569 BOOL nil = FALSE;
570 HRESULT hr = S_OK;
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 *))
578 return E_INVALIDARG;
580 EnterCriticalSection( &error->cs );
582 if (error->magic != ERROR_MAGIC)
584 hr = E_INVALIDARG;
585 goto done;
588 if (!error->fault || !error->fault->detail)
590 nil = TRUE;
591 goto done;
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;
603 goto done;
606 if (desc->action && error->fault_action.length &&
607 WsXmlStringEquals( desc->action, &error->fault_action, NULL ) != S_OK)
609 nil = TRUE;
610 goto done;
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)
616 goto done;
618 done:
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 );
628 return 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;
638 HRESULT hr = S_OK;
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" );
647 return E_NOTIMPL;
650 EnterCriticalSection( &error->cs );
652 if (error->magic != ERROR_MAGIC)
654 hr = E_INVALIDARG;
655 goto done;
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) );
662 else
663 hr = E_INVALIDARG;
665 done:
666 LeaveCriticalSection( &error->cs );
667 TRACE( "returning %#lx\n", hr );
668 return 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;
678 HRESULT hr = S_OK;
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" );
687 return E_NOTIMPL;
690 EnterCriticalSection( &error->cs );
692 if (error->magic != ERROR_MAGIC)
694 hr = E_INVALIDARG;
695 goto done;
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 );
702 else
703 hr = E_INVALIDARG;
705 done:
706 LeaveCriticalSection( &error->cs );
707 TRACE( "returning %#lx\n", hr );
708 return hr;