2 * Web Services on Devices
4 * Copyright 2017-2018 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wsdapi_internal.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "webservices.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
33 #define APP_MAX_DELAY 500
35 static const WCHAR
*discoveryTo
= L
"urn:schemas-xmlsoap-org:ws:2005:04:discovery";
37 static const WCHAR
*actionProbe
= L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
39 static const WCHAR
*addressingNsUri
= L
"http://schemas.xmlsoap.org/ws/2004/08/addressing";
40 static const WCHAR
*discoveryNsUri
= L
"http://schemas.xmlsoap.org/ws/2005/04/discovery";
41 static const WCHAR
*envelopeNsUri
= L
"http://www.w3.org/2003/05/soap-envelope";
43 static const WCHAR
*addressingPrefix
= L
"wsa";
44 static const WCHAR
*discoveryPrefix
= L
"wsd";
45 static const WCHAR
*envelopePrefix
= L
"soap";
46 static const WCHAR
*headerString
= L
"Header";
47 static const WCHAR
*actionString
= L
"Action";
48 static const WCHAR
*messageIdString
= L
"MessageID";
49 static const WCHAR
*toString
= L
"To";
50 static const WCHAR
*relatesToString
= L
"RelatesTo";
51 static const WCHAR
*appSequenceString
= L
"AppSequence";
52 static const WCHAR
*instanceIdString
= L
"InstanceId";
53 static const WCHAR
*messageNumberString
= L
"MessageNumber";
54 static const WCHAR
*sequenceIdString
= L
"SequenceId";
55 static const WCHAR
*bodyString
= L
"Body";
56 static const WCHAR
*helloString
= L
"Hello";
57 static const WCHAR
*probeString
= L
"Probe";
58 static const WCHAR
*probeMatchString
= L
"ProbeMatch";
59 static const WCHAR
*probeMatchesString
= L
"ProbeMatches";
60 static const WCHAR
*byeString
= L
"Bye";
61 static const WCHAR
*endpointReferenceString
= L
"EndpointReference";
62 static const WCHAR
*addressString
= L
"Address";
63 static const WCHAR
*referenceParametersString
= L
"ReferenceParameters";
64 static const WCHAR
*typesString
= L
"Types";
65 static const WCHAR
*scopesString
= L
"Scopes";
66 static const WCHAR
*xAddrsString
= L
"XAddrs";
67 static const WCHAR
*metadataVersionString
= L
"MetadataVersion";
69 struct discovered_namespace
76 static LPWSTR
utf8_to_wide(void *parent
, const char *utf8_str
, int length
)
78 int utf8_str_len
= 0, chars_needed
= 0, bytes_needed
= 0;
79 LPWSTR new_str
= NULL
;
81 if (utf8_str
== NULL
) return NULL
;
83 utf8_str_len
= (length
< 0) ? lstrlenA(utf8_str
) : length
;
84 chars_needed
= MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, NULL
, 0);
86 if (chars_needed
<= 0) return NULL
;
88 bytes_needed
= sizeof(WCHAR
) * (chars_needed
+ 1);
89 new_str
= WSDAllocateLinkedMemory(parent
, bytes_needed
);
91 MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, new_str
, chars_needed
);
92 new_str
[chars_needed
] = 0;
97 static char *wide_to_utf8(LPCWSTR wide_string
, int *length
)
99 char *new_string
= NULL
;
101 if (wide_string
== NULL
)
104 *length
= WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, NULL
, 0, NULL
, NULL
);
109 new_string
= heap_alloc(*length
);
110 WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, new_string
, *length
, NULL
, NULL
);
115 static WS_XML_STRING
*populate_xml_string(LPCWSTR str
)
117 WS_XML_STRING
*xml
= heap_alloc_zero(sizeof(WS_XML_STRING
));
123 xml
->bytes
= (BYTE
*)wide_to_utf8(str
, &utf8Length
);
125 if (xml
->bytes
== NULL
)
131 xml
->dictionary
= NULL
;
133 xml
->length
= (xml
->bytes
== NULL
) ? 0 : (utf8Length
- 1);
138 static inline void free_xml_string(WS_XML_STRING
*value
)
143 heap_free(value
->bytes
);
148 static HRESULT
write_xml_attribute(WSDXML_ATTRIBUTE
*attribute
, WS_XML_WRITER
*writer
)
150 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
151 WS_XML_UTF16_TEXT utf16_text
;
152 HRESULT ret
= E_OUTOFMEMORY
;
155 if (attribute
== NULL
)
158 /* Start the attribute */
159 local_name
= populate_xml_string(attribute
->Name
->LocalName
);
160 if (local_name
== NULL
) goto cleanup
;
162 if (attribute
->Name
->Space
== NULL
)
164 element_ns
= populate_xml_string(L
"");
165 if (element_ns
== NULL
) goto cleanup
;
171 element_ns
= populate_xml_string(attribute
->Name
->Space
->Uri
);
172 if (element_ns
== NULL
) goto cleanup
;
174 ns_prefix
= populate_xml_string(attribute
->Name
->Space
->PreferredPrefix
);
175 if (ns_prefix
== NULL
) goto cleanup
;
178 ret
= WsWriteStartAttribute(writer
, ns_prefix
, local_name
, element_ns
, FALSE
, NULL
);
179 if (FAILED(ret
)) goto cleanup
;
181 text_len
= lstrlenW(attribute
->Value
);
183 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
184 utf16_text
.bytes
= (BYTE
*)attribute
->Value
;
185 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
187 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
188 if (FAILED(ret
)) goto cleanup
;
190 ret
= WsWriteEndAttribute(writer
, NULL
);
191 if (FAILED(ret
)) goto cleanup
;
194 free_xml_string(local_name
);
195 free_xml_string(element_ns
);
196 free_xml_string(ns_prefix
);
201 static HRESULT
write_xml_element(WSDXML_ELEMENT
*element
, WS_XML_WRITER
*writer
)
203 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
204 WSDXML_ATTRIBUTE
*current_attribute
;
205 WS_XML_UTF16_TEXT utf16_text
;
206 WSDXML_NODE
*current_child
;
207 WSDXML_TEXT
*node_as_text
;
209 HRESULT ret
= E_OUTOFMEMORY
;
214 /* Start the element */
215 local_name
= populate_xml_string(element
->Name
->LocalName
);
216 if (local_name
== NULL
) goto cleanup
;
218 element_ns
= populate_xml_string(element
->Name
->Space
->Uri
);
219 if (element_ns
== NULL
) goto cleanup
;
221 ns_prefix
= populate_xml_string(element
->Name
->Space
->PreferredPrefix
);
222 if (ns_prefix
== NULL
) goto cleanup
;
224 ret
= WsWriteStartElement(writer
, ns_prefix
, local_name
, element_ns
, NULL
);
225 if (FAILED(ret
)) goto cleanup
;
227 /* Write attributes */
228 current_attribute
= element
->FirstAttribute
;
230 while (current_attribute
!= NULL
)
232 ret
= write_xml_attribute(current_attribute
, writer
);
233 if (FAILED(ret
)) goto cleanup
;
234 current_attribute
= current_attribute
->Next
;
237 /* Write child elements */
238 current_child
= element
->FirstChild
;
240 while (current_child
!= NULL
)
242 if (current_child
->Type
== ElementType
)
244 ret
= write_xml_element((WSDXML_ELEMENT
*)current_child
, writer
);
245 if (FAILED(ret
)) goto cleanup
;
247 else if (current_child
->Type
== TextType
)
249 node_as_text
= (WSDXML_TEXT
*)current_child
;
250 text_len
= lstrlenW(node_as_text
->Text
);
252 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
253 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
254 utf16_text
.bytes
= (BYTE
*)node_as_text
->Text
;
256 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
257 if (FAILED(ret
)) goto cleanup
;
260 current_child
= current_child
->Next
;
263 /* End the element */
264 ret
= WsWriteEndElement(writer
, NULL
);
267 free_xml_string(local_name
);
268 free_xml_string(element_ns
);
269 free_xml_string(ns_prefix
);
274 static HRESULT
add_child_element(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
,
275 LPCWSTR name
, LPCWSTR text
, WSDXML_ELEMENT
**out
)
277 WSDXML_ELEMENT
*element_obj
;
278 WSDXML_NAME
*name_obj
;
281 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
);
282 if (FAILED(ret
)) return ret
;
284 ret
= WSDXMLBuildAnyForSingleElement(name_obj
, text
, &element_obj
);
285 WSDFreeLinkedMemory(name_obj
);
287 if (FAILED(ret
)) return ret
;
289 /* Add the element as a child - this will link the element's memory allocation to the parent's */
290 ret
= WSDXMLAddChild(parent
, element_obj
);
294 WSDFreeLinkedMemory(element_obj
);
298 if (out
!= NULL
) *out
= element_obj
;
302 HRESULT
register_namespaces(IWSDXMLContext
*xml_context
)
306 ret
= IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, NULL
);
307 if (FAILED(ret
)) return ret
;
309 ret
= IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, NULL
);
310 if (FAILED(ret
)) return ret
;
312 return IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, NULL
);
315 static BOOL
create_guid(LPWSTR buffer
)
317 WCHAR
* uuidString
= NULL
;
320 if (UuidCreate(&uuid
) != RPC_S_OK
)
323 UuidToStringW(&uuid
, (RPC_WSTR
*)&uuidString
);
325 if (uuidString
== NULL
)
328 wsprintfW(buffer
, L
"urn:uuid:%s", uuidString
);
329 RpcStringFreeW((RPC_WSTR
*)&uuidString
);
334 static void populate_soap_header(WSD_SOAP_HEADER
*header
, LPCWSTR to
, LPCWSTR action
, LPCWSTR message_id
,
335 WSD_APP_SEQUENCE
*sequence
, const WSDXML_ELEMENT
*any_headers
)
337 ZeroMemory(header
, sizeof(WSD_SOAP_HEADER
));
340 header
->Action
= action
;
341 header
->MessageID
= message_id
;
342 header
->AppSequence
= sequence
;
343 header
->AnyHeaders
= (WSDXML_ELEMENT
*)any_headers
;
345 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
348 #define MAX_ULONGLONG_STRING_SIZE 25
350 static LPWSTR
ulonglong_to_string(void *parent
, ULONGLONG value
)
354 ret
= WSDAllocateLinkedMemory(parent
, MAX_ULONGLONG_STRING_SIZE
* sizeof(WCHAR
));
359 wsprintfW(ret
, L
"%I64u", value
);
363 static WSDXML_ATTRIBUTE
*add_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
)
365 WSDXML_ATTRIBUTE
*attribute
, *cur_attrib
;
366 WSDXML_NAME
*name_obj
= NULL
;
370 name_obj
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_NAME
));
371 name_obj
->LocalName
= duplicate_string(name_obj
, name
);
372 name_obj
->Space
= NULL
;
376 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
380 attribute
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_ATTRIBUTE
));
382 if (attribute
== NULL
)
384 WSDFreeLinkedMemory(name_obj
);
388 attribute
->Element
= parent
;
389 attribute
->Name
= name_obj
;
390 attribute
->Next
= NULL
;
391 attribute
->Value
= NULL
;
393 if (name_obj
!= NULL
)
394 WSDAttachLinkedMemory(attribute
, name_obj
);
396 if (parent
->FirstAttribute
== NULL
)
398 /* Make this the first attribute of the parent */
399 parent
->FirstAttribute
= attribute
;
403 /* Find the last attribute and add this as the next one */
404 cur_attrib
= parent
->FirstAttribute
;
406 while (cur_attrib
->Next
!= NULL
)
408 cur_attrib
= cur_attrib
->Next
;
411 cur_attrib
->Next
= attribute
;
417 static void remove_attribute(WSDXML_ELEMENT
*parent
, WSDXML_ATTRIBUTE
*attribute
)
419 WSDXML_ATTRIBUTE
*cur_attrib
;
421 /* Find the last attribute and add this as the next one */
422 cur_attrib
= parent
->FirstAttribute
;
424 if (cur_attrib
== attribute
)
425 parent
->FirstAttribute
= cur_attrib
->Next
;
428 while (cur_attrib
!= NULL
)
430 /* Is our attribute the next attribute? */
431 if (cur_attrib
->Next
== attribute
)
433 /* Remove it from the list */
434 cur_attrib
->Next
= attribute
->Next
;
438 cur_attrib
= cur_attrib
->Next
;
442 WSDFreeLinkedMemory(attribute
);
445 static HRESULT
add_ulonglong_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
448 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
450 if (attribute
== NULL
)
453 attribute
->Value
= ulonglong_to_string(attribute
, value
);
455 if (attribute
->Value
== NULL
)
457 remove_attribute(parent
, attribute
);
464 static HRESULT
add_string_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
467 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
469 if (attribute
== NULL
)
472 attribute
->Value
= duplicate_string(attribute
, value
);
474 if (attribute
->Value
== NULL
)
476 remove_attribute(parent
, attribute
);
483 static BOOL
add_discovered_namespace(struct list
*namespaces
, WSDXML_NAMESPACE
*discovered_ns
)
485 struct discovered_namespace
*ns
;
487 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct discovered_namespace
, entry
)
489 if (lstrcmpW(ns
->uri
, discovered_ns
->Uri
) == 0)
490 return TRUE
; /* Already added */
493 ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct discovered_namespace
));
498 ns
->prefix
= duplicate_string(ns
, discovered_ns
->PreferredPrefix
);
499 ns
->uri
= duplicate_string(ns
, discovered_ns
->Uri
);
501 if ((ns
->prefix
== NULL
) || (ns
->uri
== NULL
))
504 list_add_tail(namespaces
, &ns
->entry
);
508 static HRESULT
build_types_list(LPWSTR buffer
, size_t buffer_size
, const WSD_NAME_LIST
*list
, struct list
*namespaces
)
510 LPWSTR current_buf_pos
= buffer
;
511 size_t memory_needed
= 0;
512 const WSD_NAME_LIST
*cur
= list
;
516 /* Calculate space needed, including NULL character, colon and potential trailing space */
517 memory_needed
= sizeof(WCHAR
) * (lstrlenW(cur
->Element
->LocalName
) +
518 lstrlenW(cur
->Element
->Space
->PreferredPrefix
) + 3);
520 if (current_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
524 *current_buf_pos
++ = ' ';
526 current_buf_pos
+= wsprintfW(current_buf_pos
, L
"%s:%s", cur
->Element
->Space
->PreferredPrefix
,
527 cur
->Element
->LocalName
);
529 /* Record the namespace in the discovered namespaces list */
530 if (!add_discovered_namespace(namespaces
, cur
->Element
->Space
))
534 } while (cur
!= NULL
);
539 static HRESULT
build_uri_list(LPWSTR buffer
, size_t buffer_size
, const WSD_URI_LIST
*list
)
541 size_t memory_needed
= 0, string_len
= 0;
542 const WSD_URI_LIST
*cur
= list
;
543 LPWSTR cur_buf_pos
= buffer
;
547 /* Calculate space needed, including trailing space */
548 string_len
= lstrlenW(cur
->Element
);
549 memory_needed
= (string_len
+ 1) * sizeof(WCHAR
);
551 if (cur_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
555 *cur_buf_pos
++ = ' ';
557 memcpy(cur_buf_pos
, cur
->Element
, memory_needed
);
558 cur_buf_pos
+= string_len
;
561 } while (cur
!= NULL
);
566 static HRESULT
duplicate_element(WSDXML_ELEMENT
*parent
, const WSDXML_ELEMENT
*node
, struct list
*namespaces
)
568 WSDXML_ATTRIBUTE
*cur_attribute
, *new_attribute
, *last_attribute
= NULL
;
569 WSDXML_ELEMENT
*new_element
;
570 WSDXML_TEXT
*text_node
;
571 WSDXML_NODE
*cur_node
;
574 /* First record the namespace in the discovered namespaces list */
575 if (!add_discovered_namespace(namespaces
, node
->Name
->Space
))
578 ret
= WSDXMLBuildAnyForSingleElement(node
->Name
, NULL
, &new_element
);
579 if (FAILED(ret
)) return ret
;
581 /* Duplicate the nodes */
582 cur_node
= node
->FirstChild
;
584 while (cur_node
!= NULL
)
586 if (cur_node
->Type
== ElementType
)
588 ret
= duplicate_element(new_element
, (WSDXML_ELEMENT
*)cur_node
, namespaces
);
589 if (FAILED(ret
)) goto cleanup
;
591 else if (cur_node
->Type
== TextType
)
593 text_node
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_TEXT
));
594 if (text_node
== NULL
) goto failed
;
596 text_node
->Node
.Parent
= NULL
;
597 text_node
->Node
.Next
= NULL
;
598 text_node
->Node
.Type
= TextType
;
599 text_node
->Text
= duplicate_string(text_node
, ((WSDXML_TEXT
*)cur_node
)->Text
);
601 if (text_node
->Text
== NULL
) goto failed
;
603 ret
= WSDXMLAddChild(new_element
, (WSDXML_ELEMENT
*)text_node
);
604 if (FAILED(ret
)) goto cleanup
;
607 cur_node
= cur_node
->Next
;
610 /* Duplicate the attributes */
611 cur_attribute
= node
->FirstAttribute
;
613 while (cur_attribute
!= NULL
)
615 if ((cur_attribute
->Name
->Space
!= NULL
) && (!add_discovered_namespace(namespaces
, cur_attribute
->Name
->Space
)))
618 new_attribute
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_ATTRIBUTE
));
619 if (new_attribute
== NULL
) goto failed
;
621 new_attribute
->Element
= new_element
;
622 new_attribute
->Name
= duplicate_name(new_attribute
, cur_attribute
->Name
);
623 new_attribute
->Value
= duplicate_string(new_attribute
, cur_attribute
->Value
);
624 new_attribute
->Next
= NULL
;
626 if ((new_attribute
->Name
== NULL
) || (new_attribute
->Value
== NULL
)) goto failed
;
628 if (last_attribute
== NULL
)
629 new_element
->FirstAttribute
= new_attribute
;
631 last_attribute
->Next
= new_attribute
;
633 last_attribute
= new_attribute
;
634 cur_attribute
= cur_attribute
->Next
;
637 ret
= WSDXMLAddChild(parent
, new_element
);
638 if (FAILED(ret
)) goto cleanup
;
646 WSDXMLCleanupElement(new_element
);
650 static HRESULT
create_soap_header_xml_elements(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
,
651 struct list
*discovered_namespaces
, WSDXML_ELEMENT
**out_element
)
653 WSDXML_ELEMENT
*header_element
= NULL
, *app_sequence_element
= NULL
, *temp_element
;
654 WSDXML_NAME
*header_name
= NULL
;
658 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, envelopeNsUri
, headerString
, &header_name
);
659 if (FAILED(ret
)) goto cleanup
;
661 ret
= WSDXMLBuildAnyForSingleElement(header_name
, NULL
, &header_element
);
662 if (FAILED(ret
)) goto cleanup
;
664 WSDFreeLinkedMemory(header_name
);
667 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, actionString
, header
->Action
, &temp_element
);
668 if (FAILED(ret
)) goto cleanup
;
671 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, messageIdString
, header
->MessageID
, &temp_element
);
672 if (FAILED(ret
)) goto cleanup
;
675 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, toString
, header
->To
, &temp_element
);
676 if (FAILED(ret
)) goto cleanup
;
679 if (header
->RelatesTo
.MessageID
!= NULL
)
681 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, relatesToString
,
682 header
->RelatesTo
.MessageID
, &temp_element
);
683 if (FAILED(ret
)) goto cleanup
;
686 /* <d:AppSequence> */
687 ret
= add_child_element(xml_context
, header_element
, discoveryNsUri
, appSequenceString
, L
"", &app_sequence_element
);
688 if (FAILED(ret
)) goto cleanup
;
690 /* InstanceId attribute */
691 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, instanceIdString
, min(UINT_MAX
,
692 header
->AppSequence
->InstanceId
));
693 if (FAILED(ret
)) goto cleanup
;
695 /* SequenceID attribute */
696 if (header
->AppSequence
->SequenceId
!= NULL
)
698 ret
= add_string_attribute(xml_context
, app_sequence_element
, NULL
, sequenceIdString
, header
->AppSequence
->SequenceId
);
699 if (FAILED(ret
)) goto cleanup
;
702 /* MessageNumber attribute */
703 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, messageNumberString
, min(UINT_MAX
,
704 header
->AppSequence
->MessageNumber
));
705 if (FAILED(ret
)) goto cleanup
;
707 /* </d:AppSequence> */
709 /* Write any headers */
710 if (header
->AnyHeaders
!= NULL
)
712 ret
= duplicate_element(header_element
, header
->AnyHeaders
, discovered_namespaces
);
713 if (FAILED(ret
)) goto cleanup
;
718 *out_element
= header_element
;
722 if (header_name
!= NULL
) WSDFreeLinkedMemory(header_name
);
723 WSDXMLCleanupElement(header_element
);
728 static HRESULT
create_soap_envelope(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
729 WS_HEAP
**heap
, char **output_xml
, ULONG
*xml_length
, struct list
*discovered_namespaces
)
731 WS_XML_STRING
*actual_envelope_prefix
= NULL
, *envelope_uri_xmlstr
= NULL
, *tmp_prefix
= NULL
, *tmp_uri
= NULL
;
732 WSDXML_NAMESPACE
*addressing_ns
= NULL
, *discovery_ns
= NULL
, *envelope_ns
= NULL
;
733 WSDXML_ELEMENT
*header_element
= NULL
;
734 struct discovered_namespace
*ns
;
735 WS_XML_BUFFER
*buffer
= NULL
;
736 WS_XML_WRITER
*writer
= NULL
;
737 WS_XML_STRING envelope
;
738 HRESULT ret
= E_OUTOFMEMORY
;
739 static BYTE envelopeString
[] = "Envelope";
741 /* Create the necessary XML prefixes */
742 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, &addressing_ns
))) goto cleanup
;
743 if (!add_discovered_namespace(discovered_namespaces
, addressing_ns
)) goto cleanup
;
745 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, &discovery_ns
))) goto cleanup
;
746 if (!add_discovered_namespace(discovered_namespaces
, discovery_ns
)) goto cleanup
;
748 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, &envelope_ns
))) goto cleanup
;
749 if (!add_discovered_namespace(discovered_namespaces
, envelope_ns
)) goto cleanup
;
751 envelope
.bytes
= envelopeString
;
752 envelope
.length
= sizeof(envelopeString
) - 1;
753 envelope
.dictionary
= NULL
;
756 actual_envelope_prefix
= populate_xml_string(envelope_ns
->PreferredPrefix
);
757 envelope_uri_xmlstr
= populate_xml_string(envelope_ns
->Uri
);
759 if ((actual_envelope_prefix
== NULL
) || (envelope_uri_xmlstr
== NULL
)) goto cleanup
;
761 /* Now try to create the appropriate WebServices buffers, etc */
762 ret
= WsCreateHeap(16384, 4096, NULL
, 0, heap
, NULL
);
763 if (FAILED(ret
)) goto cleanup
;
765 ret
= WsCreateXmlBuffer(*heap
, NULL
, 0, &buffer
, NULL
);
766 if (FAILED(ret
)) goto cleanup
;
768 ret
= WsCreateWriter(NULL
, 0, &writer
, NULL
);
769 if (FAILED(ret
)) goto cleanup
;
771 ret
= WsSetOutputToBuffer(writer
, buffer
, NULL
, 0, NULL
);
772 if (FAILED(ret
)) goto cleanup
;
774 /* Create the header XML elements */
775 ret
= create_soap_header_xml_elements(xml_context
, header
, discovered_namespaces
, &header_element
);
776 if (FAILED(ret
)) goto cleanup
;
779 ret
= WsWriteStartElement(writer
, actual_envelope_prefix
, &envelope
, envelope_uri_xmlstr
, NULL
);
780 if (FAILED(ret
)) goto cleanup
;
782 LIST_FOR_EACH_ENTRY(ns
, discovered_namespaces
, struct discovered_namespace
, entry
)
784 tmp_prefix
= populate_xml_string(ns
->prefix
);
785 tmp_uri
= populate_xml_string(ns
->uri
);
787 if ((tmp_prefix
== NULL
) || (tmp_uri
== NULL
)) goto cleanup
;
789 ret
= WsWriteXmlnsAttribute(writer
, tmp_prefix
, tmp_uri
, FALSE
, NULL
);
790 if (FAILED(ret
)) goto cleanup
;
792 free_xml_string(tmp_prefix
);
793 free_xml_string(tmp_uri
);
799 /* Write the header */
800 ret
= write_xml_element(header_element
, writer
);
801 if (FAILED(ret
)) goto cleanup
;
804 ret
= write_xml_element(body_element
, writer
);
805 if (FAILED(ret
)) goto cleanup
;
807 ret
= WsWriteEndElement(writer
, NULL
);
808 if (FAILED(ret
)) goto cleanup
;
812 /* Generate the bytes of the document */
813 ret
= WsWriteXmlBufferToBytes(writer
, buffer
, NULL
, NULL
, 0, *heap
, (void**)output_xml
, xml_length
, NULL
);
814 if (FAILED(ret
)) goto cleanup
;
817 WSDFreeLinkedMemory(addressing_ns
);
818 WSDFreeLinkedMemory(discovery_ns
);
819 WSDFreeLinkedMemory(envelope_ns
);
821 WSDXMLCleanupElement(header_element
);
823 free_xml_string(actual_envelope_prefix
);
824 free_xml_string(envelope_uri_xmlstr
);
827 WsFreeWriter(writer
);
829 /* Don't free the heap unless the operation has failed */
830 if ((FAILED(ret
)) && (*heap
!= NULL
))
839 static HRESULT
write_and_send_message(IWSDiscoveryPublisherImpl
*impl
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
840 struct list
*discovered_namespaces
, IWSDUdpAddress
*remote_address
, int max_initial_delay
)
842 static const char xml_header
[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
843 ULONG xml_length
= 0, xml_header_len
= sizeof(xml_header
) - 1;
844 WS_HEAP
*heap
= NULL
;
849 ret
= create_soap_envelope(impl
->xmlContext
, header
, body_element
, &heap
, &xml
, &xml_length
, discovered_namespaces
);
850 if (ret
!= S_OK
) return ret
;
852 /* Prefix the XML header */
853 full_xml
= heap_alloc(xml_length
+ xml_header_len
+ 1);
855 if (full_xml
== NULL
)
858 return E_OUTOFMEMORY
;
861 memcpy(full_xml
, xml_header
, xml_header_len
);
862 memcpy(full_xml
+ xml_header_len
, xml
, xml_length
);
863 full_xml
[xml_length
+ xml_header_len
] = 0;
865 if (remote_address
== NULL
)
867 /* Send the message via UDP multicast */
868 ret
= send_udp_multicast(impl
, full_xml
, xml_length
+ xml_header_len
, max_initial_delay
) ? S_OK
: E_FAIL
;
872 /* Send the message via UDP unicast */
873 ret
= send_udp_unicast(full_xml
, xml_length
+ xml_header_len
, remote_address
, max_initial_delay
);
882 HRESULT
send_hello_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
883 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
884 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*hdr_any
, const WSDXML_ELEMENT
*ref_param_any
,
885 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
887 WSDXML_ELEMENT
*body_element
= NULL
, *hello_element
, *endpoint_reference_element
, *ref_params_element
;
888 struct list
*discoveredNamespaces
= NULL
;
889 WSDXML_NAME
*body_name
= NULL
;
890 WSD_SOAP_HEADER soapHeader
;
891 WSD_APP_SEQUENCE sequence
;
892 WCHAR message_id
[64];
893 HRESULT ret
= E_OUTOFMEMORY
;
896 sequence
.InstanceId
= instance_id
;
897 sequence
.MessageNumber
= msg_num
;
898 sequence
.SequenceId
= session_id
;
900 if (!create_guid(message_id
)) goto failed
;
902 discoveredNamespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
903 if (!discoveredNamespaces
) goto failed
;
905 list_init(discoveredNamespaces
);
907 populate_soap_header(&soapHeader
, discoveryTo
, L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello", message_id
, &sequence
, hdr_any
);
909 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
910 if (FAILED(ret
)) goto cleanup
;
912 /* <soap:Body>, <wsd:Hello> */
913 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
914 if (FAILED(ret
)) goto cleanup
;
916 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, helloString
, NULL
, &hello_element
);
917 if (FAILED(ret
)) goto cleanup
;
919 /* <wsa:EndpointReference>, <wsa:Address> */
920 ret
= add_child_element(impl
->xmlContext
, hello_element
, addressingNsUri
, endpointReferenceString
, NULL
,
921 &endpoint_reference_element
);
922 if (FAILED(ret
)) goto cleanup
;
924 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
925 if (FAILED(ret
)) goto cleanup
;
927 /* Write any reference parameters */
928 if (ref_param_any
!= NULL
)
930 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, referenceParametersString
,
931 NULL
, &ref_params_element
);
932 if (FAILED(ret
)) goto cleanup
;
934 ret
= duplicate_element(ref_params_element
, ref_param_any
, discoveredNamespaces
);
935 if (FAILED(ret
)) goto cleanup
;
938 /* Write any endpoint reference headers */
939 if (endpoint_ref_any
!= NULL
)
941 ret
= duplicate_element(endpoint_reference_element
, endpoint_ref_any
, discoveredNamespaces
);
942 if (FAILED(ret
)) goto cleanup
;
946 if (types_list
!= NULL
)
948 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
949 if (buffer
== NULL
) goto failed
;
951 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discoveredNamespaces
);
952 if (FAILED(ret
)) goto cleanup
;
954 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
955 if (FAILED(ret
)) goto cleanup
;
959 if (scopes_list
!= NULL
)
961 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
962 if (buffer
== NULL
) goto failed
;
964 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
965 if (FAILED(ret
)) goto cleanup
;
967 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
968 if (FAILED(ret
)) goto cleanup
;
972 if (xaddrs_list
!= NULL
)
974 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
975 if (buffer
== NULL
) goto failed
;
977 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
978 if (FAILED(ret
)) goto cleanup
;
980 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
981 if (FAILED(ret
)) goto cleanup
;
984 /* <wsd:MetadataVersion> */
985 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, metadataVersionString
,
986 ulonglong_to_string(hello_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
988 if (FAILED(ret
)) goto cleanup
;
990 /* Write any body elements */
993 ret
= duplicate_element(hello_element
, any
, discoveredNamespaces
);
994 if (FAILED(ret
)) goto cleanup
;
997 /* Write and send the message */
998 ret
= write_and_send_message(impl
, &soapHeader
, body_element
, discoveredNamespaces
, NULL
, APP_MAX_DELAY
);
1002 ret
= E_OUTOFMEMORY
;
1005 WSDFreeLinkedMemory(body_name
);
1006 WSDFreeLinkedMemory(body_element
);
1007 WSDFreeLinkedMemory(discoveredNamespaces
);
1012 HRESULT
send_bye_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG instance_id
, ULONGLONG msg_num
,
1013 LPCWSTR session_id
, const WSDXML_ELEMENT
*any
)
1015 WSDXML_ELEMENT
*body_element
= NULL
, *bye_element
, *endpoint_reference_element
;
1016 struct list
*discovered_namespaces
= NULL
;
1017 WSDXML_NAME
*body_name
= NULL
;
1018 WSD_SOAP_HEADER soap_header
;
1019 WSD_APP_SEQUENCE sequence
;
1020 WCHAR message_id
[64];
1021 HRESULT ret
= E_OUTOFMEMORY
;
1023 sequence
.InstanceId
= instance_id
;
1024 sequence
.MessageNumber
= msg_num
;
1025 sequence
.SequenceId
= session_id
;
1027 if (!create_guid(message_id
)) goto failed
;
1029 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1030 if (!discovered_namespaces
) goto failed
;
1032 list_init(discovered_namespaces
);
1034 populate_soap_header(&soap_header
, discoveryTo
, L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye", message_id
, &sequence
, NULL
);
1036 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1037 if (FAILED(ret
)) goto cleanup
;
1039 /* <soap:Body>, <wsd:Bye> */
1040 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1041 if (FAILED(ret
)) goto cleanup
;
1043 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, byeString
, NULL
, &bye_element
);
1044 if (FAILED(ret
)) goto cleanup
;
1046 /* <wsa:EndpointReference>, <wsa:Address> */
1047 ret
= add_child_element(impl
->xmlContext
, bye_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1048 &endpoint_reference_element
);
1049 if (FAILED(ret
)) goto cleanup
;
1051 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
1052 if (FAILED(ret
)) goto cleanup
;
1054 /* Write any body elements */
1057 ret
= duplicate_element(bye_element
, any
, discovered_namespaces
);
1058 if (FAILED(ret
)) goto cleanup
;
1061 /* Write and send the message */
1062 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, NULL
, 0);
1066 ret
= E_OUTOFMEMORY
;
1069 WSDFreeLinkedMemory(body_name
);
1070 WSDFreeLinkedMemory(body_element
);
1071 WSDFreeLinkedMemory(discovered_namespaces
);
1076 HRESULT
send_probe_matches_message(IWSDiscoveryPublisherImpl
*impl
, const WSD_SOAP_MESSAGE
*probe_msg
,
1077 IWSDMessageParameters
*message_params
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
1078 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
1079 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*header_any
, const WSDXML_ELEMENT
*ref_param_any
,
1080 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
1082 WSDXML_ELEMENT
*body_element
= NULL
, *probe_matches_element
, *probe_match_element
, *endpoint_ref_element
;
1083 WSDXML_ELEMENT
*ref_params_element
= NULL
;
1084 struct list
*discovered_namespaces
= NULL
;
1085 IWSDUdpAddress
*remote_udp_addr
= NULL
;
1086 IWSDAddress
*remote_addr
= NULL
;
1087 WSDXML_NAME
*body_name
= NULL
;
1088 WSD_SOAP_HEADER soap_header
;
1089 WSD_APP_SEQUENCE sequence
;
1094 ret
= IWSDMessageParameters_GetRemoteAddress(message_params
, &remote_addr
);
1098 WARN("Unable to retrieve remote address from IWSDMessageParameters\n");
1102 ret
= IWSDAddress_QueryInterface(remote_addr
, &IID_IWSDUdpAddress
, (LPVOID
*) &remote_udp_addr
);
1106 WARN("Remote address is not a UDP address\n");
1110 sequence
.InstanceId
= instance_id
;
1111 sequence
.MessageNumber
= msg_num
;
1112 sequence
.SequenceId
= session_id
;
1114 if (!create_guid(msg_id
)) goto failed
;
1116 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1117 if (!discovered_namespaces
) goto failed
;
1119 list_init(discovered_namespaces
);
1121 populate_soap_header(&soap_header
, L
"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous",
1122 L
"http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches", msg_id
, &sequence
, header_any
);
1123 soap_header
.RelatesTo
.MessageID
= probe_msg
->Header
.MessageID
;
1125 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1126 if (FAILED(ret
)) goto cleanup
;
1128 /* <soap:Body>, <wsd:ProbeMatches> */
1129 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1130 if (FAILED(ret
)) goto cleanup
;
1132 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, probeMatchesString
, NULL
,
1133 &probe_matches_element
);
1134 if (FAILED(ret
)) goto cleanup
;
1136 /* <wsd:ProbeMatch> */
1137 ret
= add_child_element(impl
->xmlContext
, probe_matches_element
, discoveryNsUri
, probeMatchString
, NULL
,
1138 &probe_match_element
);
1139 if (FAILED(ret
)) goto cleanup
;
1141 /* <wsa:EndpointReference>, <wsa:Address> */
1142 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1143 &endpoint_ref_element
);
1144 if (FAILED(ret
)) goto cleanup
;
1146 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, addressString
, id
, NULL
);
1147 if (FAILED(ret
)) goto cleanup
;
1149 /* Write any reference parameters */
1150 if (ref_param_any
!= NULL
)
1152 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, referenceParametersString
,
1153 NULL
, &ref_params_element
);
1154 if (FAILED(ret
)) goto cleanup
;
1156 ret
= duplicate_element(ref_params_element
, ref_param_any
, discovered_namespaces
);
1157 if (FAILED(ret
)) goto cleanup
;
1160 /* Write any endpoint reference headers */
1161 if (endpoint_ref_any
!= NULL
)
1163 ret
= duplicate_element(endpoint_ref_element
, endpoint_ref_any
, discovered_namespaces
);
1164 if (FAILED(ret
)) goto cleanup
;
1168 if (types_list
!= NULL
)
1170 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1171 if (buffer
== NULL
) goto failed
;
1173 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discovered_namespaces
);
1174 if (FAILED(ret
)) goto cleanup
;
1176 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
1177 if (FAILED(ret
)) goto cleanup
;
1181 if (scopes_list
!= NULL
)
1183 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1184 if (buffer
== NULL
) goto failed
;
1186 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
1187 if (FAILED(ret
)) goto cleanup
;
1189 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
1190 if (FAILED(ret
)) goto cleanup
;
1194 if (xaddrs_list
!= NULL
)
1196 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1197 if (buffer
== NULL
) goto failed
;
1199 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
1200 if (FAILED(ret
)) goto cleanup
;
1202 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
1203 if (FAILED(ret
)) goto cleanup
;
1206 /* <wsd:MetadataVersion> */
1207 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, metadataVersionString
,
1208 ulonglong_to_string(probe_match_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
1209 if (FAILED(ret
)) goto cleanup
;
1211 /* Write any body elements */
1214 ret
= duplicate_element(probe_match_element
, any
, discovered_namespaces
);
1215 if (FAILED(ret
)) goto cleanup
;
1218 /* Write and send the message */
1219 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, remote_udp_addr
, APP_MAX_DELAY
);
1226 WSDFreeLinkedMemory(body_name
);
1227 WSDFreeLinkedMemory(body_element
);
1228 WSDFreeLinkedMemory(discovered_namespaces
);
1230 if (remote_udp_addr
!= NULL
) IWSDUdpAddress_Release(remote_udp_addr
);
1231 if (remote_addr
!= NULL
) IWSDAddress_Release(remote_addr
);
1236 static LPWSTR
xml_text_to_wide_string(void *parent_memory
, WS_XML_TEXT
*text
)
1238 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
)
1240 WS_XML_UTF8_TEXT
*utf8_text
= (WS_XML_UTF8_TEXT
*) text
;
1241 return utf8_to_wide(parent_memory
, (const char *) utf8_text
->value
.bytes
, utf8_text
->value
.length
);
1243 else if (text
->textType
== WS_XML_TEXT_TYPE_UTF16
)
1245 WS_XML_UTF16_TEXT
*utf_16_text
= (WS_XML_UTF16_TEXT
*) text
;
1246 return duplicate_string(parent_memory
, (LPCWSTR
) utf_16_text
->bytes
);
1249 FIXME("Support for text type %d not implemented.\n", text
->textType
);
1253 static inline BOOL
read_isspace(unsigned int ch
)
1255 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
1258 static HRESULT
str_to_uint64(const unsigned char *str
, ULONG len
, UINT64 max
, UINT64
*ret
)
1260 const unsigned char *ptr
= str
;
1263 while (len
&& read_isspace(*ptr
)) { ptr
++; len
--; }
1264 while (len
&& read_isspace(ptr
[len
- 1])) { len
--; }
1265 if (!len
) return WS_E_INVALID_FORMAT
;
1271 if (!isdigit(*ptr
)) return WS_E_INVALID_FORMAT
;
1274 if ((*ret
> max
/ 10 || *ret
* 10 > max
- val
)) return WS_E_NUMERIC_OVERFLOW
;
1275 *ret
= *ret
* 10 + val
;
1282 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
1284 static HRESULT
wide_text_to_ulonglong(LPCWSTR text
, ULONGLONG
*value
)
1290 utf8_text
= wide_to_utf8(text
, &utf8_length
);
1292 if (utf8_text
== NULL
) return E_OUTOFMEMORY
;
1293 if (utf8_length
== 1) return E_FAIL
;
1295 ret
= str_to_uint64((const unsigned char *) utf8_text
, utf8_length
- 1, MAX_UINT64
, value
);
1296 heap_free(utf8_text
);
1301 static HRESULT
move_to_element(WS_XML_READER
*reader
, const char *element_name
, WS_XML_STRING
*uri
)
1303 WS_XML_STRING envelope
;
1307 envelope
.bytes
= (BYTE
*) element_name
;
1308 envelope
.length
= strlen(element_name
);
1309 envelope
.dictionary
= NULL
;
1312 ret
= WsReadToStartElement(reader
, &envelope
, uri
, &found
, NULL
);
1313 if (FAILED(ret
)) return ret
;
1315 return found
? ret
: E_FAIL
;
1318 static void trim_trailing_slash(LPWSTR uri
)
1320 /* Trim trailing slash from URI */
1321 int uri_len
= lstrlenW(uri
);
1322 if (uri_len
> 0 && uri
[uri_len
- 1] == '/') uri
[uri_len
- 1] = 0;
1325 static HRESULT
ws_element_to_wsdxml_element(WS_XML_READER
*reader
, IWSDXMLContext
*context
, WSDXML_ELEMENT
*parent_element
)
1327 WSDXML_ATTRIBUTE
*cur_wsd_attrib
= NULL
, *new_wsd_attrib
= NULL
;
1328 const WS_XML_ELEMENT_NODE
*element_node
= NULL
;
1329 WSDXML_ELEMENT
*cur_element
= parent_element
;
1330 const WS_XML_TEXT_NODE
*text_node
= NULL
;
1331 LPWSTR uri
= NULL
, element_name
= NULL
;
1332 WS_XML_STRING
*ns_string
= NULL
;
1333 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1334 WSDXML_ELEMENT
*element
= NULL
;
1335 const WS_XML_NODE
*node
= NULL
;
1336 WSDXML_NAME
*name
= NULL
;
1337 WSDXML_TEXT
*text
= NULL
;
1343 if (cur_element
== NULL
) break;
1345 ret
= WsReadNode(reader
, NULL
);
1346 if (FAILED(ret
)) goto cleanup
;
1348 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1349 if (FAILED(ret
)) goto cleanup
;
1351 switch (node
->nodeType
)
1353 case WS_XML_NODE_TYPE_ELEMENT
:
1354 element_node
= (const WS_XML_ELEMENT_NODE
*) node
;
1356 uri
= utf8_to_wide(NULL
, (const char *) element_node
->ns
->bytes
, element_node
->ns
->length
);
1357 if (uri
== NULL
) goto outofmemory
;
1359 /* Link element_name to uri so they will be freed at the same time */
1360 element_name
= utf8_to_wide(uri
, (const char *) element_node
->localName
->bytes
,
1361 element_node
->localName
->length
);
1362 if (element_name
== NULL
) goto outofmemory
;
1364 trim_trailing_slash(uri
);
1366 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1367 if (FAILED(ret
)) goto cleanup
;
1369 WSDFreeLinkedMemory(uri
);
1372 ret
= WSDXMLBuildAnyForSingleElement(name
, NULL
, &element
);
1373 if (FAILED(ret
)) goto cleanup
;
1374 WSDXMLAddChild(cur_element
, element
);
1376 WSDFreeLinkedMemory(name
);
1379 cur_wsd_attrib
= NULL
;
1381 /* Add attributes */
1382 for (i
= 0; i
< element_node
->attributeCount
; i
++)
1384 attrib
= element_node
->attributes
[i
];
1385 if (attrib
->isXmlNs
) continue;
1387 new_wsd_attrib
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_ATTRIBUTE
));
1388 if (new_wsd_attrib
== NULL
) goto outofmemory
;
1390 ns_string
= attrib
->ns
;
1391 if (ns_string
->length
== 0) ns_string
= element_node
->ns
;
1393 uri
= utf8_to_wide(NULL
, (const char *) ns_string
->bytes
, ns_string
->length
);
1394 if (uri
== NULL
) goto outofmemory
;
1396 trim_trailing_slash(uri
);
1398 /* Link element_name to uri so they will be freed at the same time */
1399 element_name
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1400 if (element_name
== NULL
) goto outofmemory
;
1402 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1403 if (FAILED(ret
)) goto cleanup
;
1405 WSDFreeLinkedMemory(uri
);
1408 new_wsd_attrib
->Value
= xml_text_to_wide_string(new_wsd_attrib
, attrib
->value
);
1409 if (new_wsd_attrib
->Value
== NULL
) goto outofmemory
;
1411 new_wsd_attrib
->Name
= name
;
1412 new_wsd_attrib
->Element
= cur_element
;
1413 new_wsd_attrib
->Next
= NULL
;
1415 WSDAttachLinkedMemory(new_wsd_attrib
, name
);
1418 if (cur_wsd_attrib
== NULL
)
1419 element
->FirstAttribute
= new_wsd_attrib
;
1421 cur_wsd_attrib
->Next
= new_wsd_attrib
;
1423 cur_wsd_attrib
= new_wsd_attrib
;
1426 cur_element
= element
;
1429 case WS_XML_NODE_TYPE_TEXT
:
1430 text_node
= (const WS_XML_TEXT_NODE
*) node
;
1432 if (cur_element
== NULL
)
1434 WARN("No parent element open but encountered text element!\n");
1438 if (cur_element
->FirstChild
!= NULL
)
1440 WARN("Text node encountered but parent already has child!\n");
1444 text
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_TEXT
));
1445 if (text
== NULL
) goto outofmemory
;
1447 text
->Node
.Parent
= element
;
1448 text
->Node
.Next
= NULL
;
1449 text
->Node
.Type
= TextType
;
1450 text
->Text
= xml_text_to_wide_string(text
, text_node
->text
);
1452 if (text
->Text
== NULL
)
1454 WARN("Text node returned null string.\n");
1455 WSDFreeLinkedMemory(text
);
1459 cur_element
->FirstChild
= (WSDXML_NODE
*) text
;
1462 case WS_XML_NODE_TYPE_END_ELEMENT
:
1463 /* Go up a level to the parent element */
1464 cur_element
= cur_element
->Node
.Parent
;
1475 ret
= E_OUTOFMEMORY
;
1478 /* Free uri and element_name if applicable */
1479 WSDFreeLinkedMemory(uri
);
1480 WSDFreeLinkedMemory(name
);
1484 static WSDXML_ELEMENT
*find_element(WSDXML_ELEMENT
*parent
, LPCWSTR name
, LPCWSTR ns_uri
)
1486 WSDXML_ELEMENT
*cur
= (WSDXML_ELEMENT
*) parent
->FirstChild
;
1490 if ((lstrcmpW(cur
->Name
->LocalName
, name
) == 0) && (lstrcmpW(cur
->Name
->Space
->Uri
, ns_uri
) == 0))
1493 cur
= (WSDXML_ELEMENT
*) cur
->Node
.Next
;
1499 static void remove_element(WSDXML_ELEMENT
*element
)
1503 if (element
== NULL
)
1506 if (element
->Node
.Parent
->FirstChild
== (WSDXML_NODE
*) element
)
1507 element
->Node
.Parent
->FirstChild
= element
->Node
.Next
;
1510 cur
= element
->Node
.Parent
->FirstChild
;
1514 if (cur
->Next
== (WSDXML_NODE
*) element
)
1516 cur
->Next
= element
->Node
.Next
;
1524 WSDDetachLinkedMemory(element
);
1525 WSDFreeLinkedMemory(element
);
1528 static WSD_NAME_LIST
*build_types_list_from_string(IWSDXMLContext
*context
, LPCWSTR buffer
, void *parent
)
1530 WSD_NAME_LIST
*list
= NULL
, *cur_list
= NULL
, *prev_list
= NULL
;
1531 LPWSTR name_start
= NULL
, temp_buffer
= NULL
;
1532 LPCWSTR prefix_start
= buffer
;
1533 WSDXML_NAMESPACE
*ns
;
1540 temp_buffer
= duplicate_string(parent
, buffer
);
1541 if (temp_buffer
== NULL
) goto cleanup
;
1543 buffer_len
= lstrlenW(temp_buffer
);
1545 list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1546 if (list
== NULL
) goto cleanup
;
1548 ZeroMemory(list
, sizeof(WSD_NAME_LIST
));
1549 prefix_start
= temp_buffer
;
1551 for (i
= 0; i
< buffer_len
; i
++)
1553 if (temp_buffer
[i
] == ':')
1556 name_start
= &temp_buffer
[i
+ 1];
1558 else if ((temp_buffer
[i
] == ' ') || (i
== buffer_len
- 1))
1560 WSDXML_NAMESPACE
*known_ns
;
1562 if (temp_buffer
[i
] == ' ')
1565 if (cur_list
== NULL
)
1569 cur_list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1570 if (cur_list
== NULL
) goto cleanup
;
1572 prev_list
->Next
= cur_list
;
1575 name
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAME
));
1576 if (name
== NULL
) goto cleanup
;
1578 ns
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAMESPACE
));
1579 if (ns
== NULL
) goto cleanup
;
1581 ZeroMemory(ns
, sizeof(WSDXML_NAMESPACE
));
1582 ns
->PreferredPrefix
= duplicate_string(ns
, prefix_start
);
1584 known_ns
= xml_context_find_namespace_by_prefix(context
, ns
->PreferredPrefix
);
1586 if (known_ns
!= NULL
)
1587 ns
->Uri
= duplicate_string(ns
, known_ns
->Uri
);
1590 name
->LocalName
= duplicate_string(name
, name_start
);
1592 cur_list
->Element
= name
;
1593 prefix_start
= &temp_buffer
[i
+ 1];
1598 WSDFreeLinkedMemory(temp_buffer
);
1602 WSDFreeLinkedMemory(list
);
1603 WSDFreeLinkedMemory(temp_buffer
);
1608 static WSDXML_TYPE
*generate_type(LPCWSTR uri
, void *parent
)
1610 WSDXML_TYPE
*type
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_TYPE
));
1615 type
->Uri
= duplicate_string(parent
, uri
);
1621 static BOOL
is_duplicate_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
)
1623 struct message_id
*msg_id
, *msg_id_cursor
;
1627 EnterCriticalSection(&impl
->message_ids_critical_section
);
1629 LIST_FOR_EACH_ENTRY_SAFE(msg_id
, msg_id_cursor
, &impl
->message_ids
, struct message_id
, entry
)
1631 if (lstrcmpW(msg_id
->id
, id
) == 0)
1638 msg_id
= heap_alloc(sizeof(*msg_id
));
1639 if (!msg_id
) goto end
;
1641 len
= (lstrlenW(id
) + 1) * sizeof(WCHAR
);
1642 msg_id
->id
= heap_alloc(len
);
1650 memcpy(msg_id
->id
, id
, len
);
1651 list_add_tail(&impl
->message_ids
, &msg_id
->entry
);
1654 LeaveCriticalSection(&impl
->message_ids_critical_section
);
1658 HRESULT
read_message(IWSDiscoveryPublisherImpl
*impl
, const char *xml
, int xml_length
, WSD_SOAP_MESSAGE
**out_msg
, int *msg_type
)
1660 WSDXML_ELEMENT
*envelope
= NULL
, *header_element
, *appsequence_element
, *body_element
;
1661 WS_XML_READER_TEXT_ENCODING encoding
;
1662 WS_XML_ELEMENT_NODE
*envelope_node
;
1663 WSD_SOAP_MESSAGE
*soap_msg
= NULL
;
1664 WS_XML_READER_BUFFER_INPUT input
;
1665 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1666 IWSDXMLContext
*context
= NULL
;
1667 WS_XML_STRING
*soap_uri
= NULL
;
1668 const WS_XML_NODE
*node
;
1669 WS_XML_READER
*reader
= NULL
;
1670 LPCWSTR value
= NULL
;
1672 WS_HEAP
*heap
= NULL
;
1676 *msg_type
= MSGTYPE_UNKNOWN
;
1678 ret
= WsCreateHeap(16384, 4096, NULL
, 0, &heap
, NULL
);
1679 if (FAILED(ret
)) goto cleanup
;
1681 ret
= WsCreateReader(NULL
, 0, &reader
, NULL
);
1682 if (FAILED(ret
)) goto cleanup
;
1684 encoding
.encoding
.encodingType
= WS_XML_READER_ENCODING_TYPE_TEXT
;
1685 encoding
.charSet
= WS_CHARSET_AUTO
;
1687 input
.input
.inputType
= WS_XML_READER_INPUT_TYPE_BUFFER
;
1688 input
.encodedData
= (char *) xml
;
1689 input
.encodedDataSize
= xml_length
;
1691 ret
= WsSetInput(reader
, (WS_XML_READER_ENCODING
*) &encoding
, (WS_XML_READER_INPUT
*) &input
, NULL
, 0, NULL
);
1692 if (FAILED(ret
)) goto cleanup
;
1694 soap_uri
= populate_xml_string(envelopeNsUri
);
1695 if (soap_uri
== NULL
) goto outofmemory
;
1697 ret
= move_to_element(reader
, "Envelope", soap_uri
);
1698 if (FAILED(ret
)) goto cleanup
;
1700 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1701 if (FAILED(ret
)) goto cleanup
;
1703 if (node
->nodeType
!= WS_XML_NODE_TYPE_ELEMENT
)
1705 WARN("Unexpected node type (%d)\n", node
->nodeType
);
1710 envelope_node
= (WS_XML_ELEMENT_NODE
*) node
;
1712 ret
= WSDXMLCreateContext(&context
);
1713 if (FAILED(ret
)) goto cleanup
;
1715 /* Find XML namespaces from the envelope element's attributes */
1716 for (i
= 0; i
< envelope_node
->attributeCount
; i
++)
1718 attrib
= envelope_node
->attributes
[i
];
1720 if (attrib
->isXmlNs
)
1722 uri
= utf8_to_wide(NULL
, (const char *) attrib
->ns
->bytes
, attrib
->ns
->length
);
1723 if (uri
== NULL
) continue;
1725 trim_trailing_slash(uri
);
1727 prefix
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1731 WSDFreeLinkedMemory(uri
);
1735 IWSDXMLContext_AddNamespace(context
, uri
, prefix
, NULL
);
1736 WSDFreeLinkedMemory(uri
);
1740 /* Create the SOAP message to return to the caller */
1741 soap_msg
= WSDAllocateLinkedMemory(NULL
, sizeof(WSD_SOAP_MESSAGE
));
1742 if (soap_msg
== NULL
) goto outofmemory
;
1744 ZeroMemory(soap_msg
, sizeof(WSD_SOAP_MESSAGE
));
1746 envelope
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSDXML_ELEMENT
));
1747 if (envelope
== NULL
) goto outofmemory
;
1749 ZeroMemory(envelope
, sizeof(WSDXML_ELEMENT
));
1751 ret
= ws_element_to_wsdxml_element(reader
, context
, envelope
);
1752 if (FAILED(ret
)) goto cleanup
;
1754 /* Find the header element */
1755 header_element
= find_element(envelope
, headerString
, envelopeNsUri
);
1757 if (header_element
== NULL
)
1759 WARN("Unable to find header element in received SOAP message\n");
1764 ret
= WSDXMLGetValueFromAny(addressingNsUri
, actionString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1765 if (FAILED(ret
)) goto cleanup
;
1766 soap_msg
->Header
.Action
= duplicate_string(soap_msg
, value
);
1767 if (soap_msg
->Header
.Action
== NULL
) goto outofmemory
;
1769 ret
= WSDXMLGetValueFromAny(addressingNsUri
, toString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1770 if (FAILED(ret
)) goto cleanup
;
1771 soap_msg
->Header
.To
= duplicate_string(soap_msg
, value
);
1772 if (soap_msg
->Header
.To
== NULL
) goto outofmemory
;
1774 ret
= WSDXMLGetValueFromAny(addressingNsUri
, messageIdString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1775 if (FAILED(ret
)) goto cleanup
;
1777 /* Detect duplicate messages */
1778 if (is_duplicate_message(impl
, value
))
1784 soap_msg
->Header
.MessageID
= duplicate_string(soap_msg
, value
);
1785 if (soap_msg
->Header
.MessageID
== NULL
) goto outofmemory
;
1787 /* Look for optional AppSequence element */
1788 appsequence_element
= find_element(header_element
, appSequenceString
, discoveryNsUri
);
1790 if (appsequence_element
!= NULL
)
1792 WSDXML_ATTRIBUTE
*current_attrib
;
1794 soap_msg
->Header
.AppSequence
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_APP_SEQUENCE
));
1795 if (soap_msg
->Header
.AppSequence
== NULL
) goto outofmemory
;
1797 ZeroMemory(soap_msg
->Header
.AppSequence
, sizeof(WSD_APP_SEQUENCE
));
1799 current_attrib
= appsequence_element
->FirstAttribute
;
1801 while (current_attrib
!= NULL
)
1803 if (lstrcmpW(current_attrib
->Name
->Space
->Uri
, discoveryNsUri
) != 0)
1805 current_attrib
= current_attrib
->Next
;
1809 if (lstrcmpW(current_attrib
->Name
->LocalName
, instanceIdString
) == 0)
1811 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->InstanceId
);
1812 if (FAILED(ret
)) goto cleanup
;
1814 else if (lstrcmpW(current_attrib
->Name
->LocalName
, messageNumberString
) == 0)
1816 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->MessageNumber
);
1817 if (FAILED(ret
)) goto cleanup
;
1819 else if (lstrcmpW(current_attrib
->Name
->LocalName
, sequenceIdString
) == 0)
1821 soap_msg
->Header
.AppSequence
->SequenceId
= duplicate_string(soap_msg
, current_attrib
->Value
);
1822 if (soap_msg
->Header
.AppSequence
->SequenceId
== NULL
) goto outofmemory
;
1825 current_attrib
= current_attrib
->Next
;
1829 /* Now detach and free known headers to leave the "any" elements */
1830 remove_element(find_element(header_element
, actionString
, addressingNsUri
));
1831 remove_element(find_element(header_element
, toString
, addressingNsUri
));
1832 remove_element(find_element(header_element
, messageIdString
, addressingNsUri
));
1833 remove_element(find_element(header_element
, appSequenceString
, discoveryNsUri
));
1835 soap_msg
->Header
.AnyHeaders
= (WSDXML_ELEMENT
*) header_element
->FirstChild
;
1837 if (soap_msg
->Header
.AnyHeaders
!= NULL
)
1838 soap_msg
->Header
.AnyHeaders
->Node
.Parent
= NULL
;
1840 /* Find the body element */
1841 body_element
= find_element(envelope
, bodyString
, envelopeNsUri
);
1843 if (body_element
== NULL
)
1845 WARN("Unable to find body element in received SOAP message\n");
1850 /* Now figure out which message we've been sent */
1851 if (lstrcmpW(soap_msg
->Header
.Action
, actionProbe
) == 0)
1853 WSDXML_ELEMENT
*probe_element
;
1854 WSD_PROBE
*probe
= NULL
;
1856 probe_element
= find_element(body_element
, probeString
, discoveryNsUri
);
1857 if (probe_element
== NULL
) goto cleanup
;
1859 probe
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_PROBE
));
1860 if (probe
== NULL
) goto cleanup
;
1862 ZeroMemory(probe
, sizeof(WSD_PROBE
));
1864 /* Check for the "types" element */
1865 ret
= WSDXMLGetValueFromAny(discoveryNsUri
, typesString
, (WSDXML_ELEMENT
*) probe_element
->FirstChild
, &value
);
1869 WARN("Unable to find Types element in received Probe message\n");
1873 probe
->Types
= build_types_list_from_string(context
, value
, probe
);
1875 /* Now detach and free known headers to leave the "any" elements */
1876 remove_element(find_element(probe_element
, typesString
, discoveryNsUri
));
1877 remove_element(find_element(probe_element
, scopesString
, discoveryNsUri
));
1879 probe
->Any
= (WSDXML_ELEMENT
*) probe_element
->FirstChild
;
1881 if (probe
->Any
!= NULL
)
1882 probe
->Any
->Node
.Parent
= NULL
;
1884 soap_msg
->Body
= probe
;
1885 soap_msg
->BodyType
= generate_type(actionProbe
, soap_msg
);
1886 if (soap_msg
->BodyType
== NULL
) goto cleanup
;
1888 *out_msg
= soap_msg
;
1889 soap_msg
= NULL
; /* caller will clean this up */
1890 *msg_type
= MSGTYPE_PROBE
;
1896 ret
= E_OUTOFMEMORY
;
1899 free_xml_string(soap_uri
);
1900 WSDFreeLinkedMemory(soap_msg
);
1901 if (context
!= NULL
) IWSDXMLContext_Release(context
);
1902 if (reader
!= NULL
) WsFreeReader(reader
);
1903 if (heap
!= NULL
) WsFreeHeap(heap
);