Signed-off-by: Owen Rudge orudge@codeweavers.com --- dlls/wsdapi/Makefile.in | 2 +- dlls/wsdapi/soap.c | 423 +++++++++++++++++++++++++++++++++++++++++- dlls/wsdapi/wsdapi_internal.h | 4 + dlls/wsdapi/xml.c | 2 +- 4 files changed, 427 insertions(+), 4 deletions(-)
On Wed, Mar 07, 2018 at 10:51:53PM +0000, Owen Rudge wrote:
Signed-off-by: Owen Rudge orudge@codeweavers.com
dlls/wsdapi/Makefile.in | 2 +- dlls/wsdapi/soap.c | 423 +++++++++++++++++++++++++++++++++++++++++- dlls/wsdapi/wsdapi_internal.h | 4 + dlls/wsdapi/xml.c | 2 +- 4 files changed, 427 insertions(+), 4 deletions(-)
There's a lot going on in the patch, can you split it?
diff --git a/dlls/wsdapi/Makefile.in b/dlls/wsdapi/Makefile.in index 2e7c448125..762a3b2f12 100644 --- a/dlls/wsdapi/Makefile.in +++ b/dlls/wsdapi/Makefile.in @@ -1,6 +1,6 @@ MODULE = wsdapi.dll IMPORTLIB = wsdapi -IMPORTS = rpcrt4 user32 ws2_32 +IMPORTS = rpcrt4 user32 webservices ws2_32
C_SRCS = \ address.c \ diff --git a/dlls/wsdapi/soap.c b/dlls/wsdapi/soap.c index 09b2215840..12b60ce23e 100644 --- a/dlls/wsdapi/soap.c +++ b/dlls/wsdapi/soap.c @@ -25,6 +25,8 @@
#include "wsdapi_internal.h" #include "wine/debug.h" +#include "wine/heap.h" +#include "webservices.h"
WINE_DEFAULT_DEBUG_CHANNEL(wsdapi);
@@ -58,12 +60,209 @@ static const WCHAR envelopeNsUri[] = { 'w','w','w','.','w','3','.','o','r','g','/', '2','0','0','3','/','0','5','/','s','o','a','p','-','e','n','v','e','l','o','p','e', 0 };
+static const WCHAR addressingPrefix[] = { 'w','s','a', 0 }; +static const WCHAR discoveryPrefix[] = { 'w','s','d', 0 }; +static const WCHAR envelopePrefix[] = { 's','o','a','p', 0 }; +static const WCHAR headerString[] = { 'H','e','a','d','e','r', 0 }; +static const WCHAR actionString[] = { 'A','c','t','i','o','n', 0 }; +static const WCHAR messageIdString[] = { 'M','e','s','s','a','g','e','I','D', 0 }; +static const WCHAR toString[] = { 'T','o', 0 }; +static const WCHAR relatesToString[] = { 'R','e','l','a','t','e','s','T','o', 0 }; +static const WCHAR appSequenceString[] = { 'A','p','p','S','e','q','u','e','n','c','e', 0 }; +static const WCHAR emptyString[] = { 0 }; static const WCHAR bodyString[] = { 'B','o','d','y', 0 }; static const WCHAR helloString[] = { 'H','e','l','l','o', 0 }; static const WCHAR endpointReferenceString[] = { 'E','n','d','p','o','i','n','t','R','e','f','e','r','e','n','c','e', 0 }; static const WCHAR addressString[] = { 'A','d','d','r','e','s','s', 0 }; static const WCHAR metadataVersionString[] = { 'M','e','t','a','d','a','t','a','V','e','r','s','i','o','n', 0 };
+struct discovered_namespace +{
- struct list entry;
- LPCWSTR prefix;
- LPCWSTR uri;
+};
+static char *wide_to_utf8(LPCWSTR wideString) +{
- char *newString = NULL;
- int sizeNeeded = 0;
- if (wideString == NULL)
return NULL;
- sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wideString, -1, NULL, 0, NULL, NULL);
- if (sizeNeeded < 0)
return NULL;
- newString = heap_alloc(sizeNeeded);
- WideCharToMultiByte(CP_UTF8, 0, wideString, -1, newString, sizeNeeded, NULL, NULL);
- return newString;
+}
+static WS_XML_STRING *populate_xml_string(LPCWSTR str) +{
- WS_XML_STRING *xml = heap_alloc_zero(sizeof(WS_XML_STRING));
- if (xml == NULL)
return NULL;
- xml->bytes = (BYTE *)wide_to_utf8(str);
- if (xml->bytes == NULL)
- {
heap_free(xml);
return NULL;
- }
- xml->dictionary = NULL;
- xml->id = 0;
- xml->length = (xml->bytes == NULL) ? 0 : lstrlenA((LPCSTR)xml->bytes);
- return xml;
+}
+static inline void free_xml_string(WS_XML_STRING *value) +{
- if (value == NULL)
return;
- if (value->bytes != NULL)
heap_free(value->bytes);
- heap_free(value);
+}
+static BOOL write_xml_attribute(WSDXML_ATTRIBUTE *attribute, WS_XML_WRITER *writer) +{
- WS_XML_STRING *localName = NULL, *elementNs = NULL, *nsPrefix = NULL;
- WS_XML_UTF16_TEXT utf16Text;
- BOOL retVal = FALSE;
- HRESULT ret;
- if (attribute == NULL)
return TRUE;
- /* Start the attribute */
- localName = populate_xml_string(attribute->Name->LocalName);
- if (localName == NULL) goto cleanup;
- if (attribute->Name->Space == NULL)
- {
elementNs = populate_xml_string(emptyString);
if (elementNs == NULL) goto cleanup;
nsPrefix = NULL;
- }
- else
- {
elementNs = populate_xml_string(attribute->Name->Space->Uri);
if (elementNs == NULL) goto cleanup;
nsPrefix = populate_xml_string(attribute->Name->Space->PreferredPrefix);
if (nsPrefix == NULL) goto cleanup;
- }
- ret = WsWriteStartAttribute(writer, nsPrefix, localName, elementNs, FALSE, NULL);
- if (FAILED(ret)) goto cleanup;
- utf16Text.text.textType = WS_XML_TEXT_TYPE_UTF16;
- utf16Text.bytes = (BYTE *)attribute->Value;
- utf16Text.byteCount = lstrlenW(attribute->Value) * sizeof(WCHAR);
- ret = WsWriteText(writer, (WS_XML_TEXT *)&utf16Text, NULL);
- if (FAILED(ret)) goto cleanup;
- ret = WsWriteEndAttribute(writer, NULL);
- if (FAILED(ret)) goto cleanup;
- retVal = TRUE;
+cleanup:
- free_xml_string(localName);
- free_xml_string(elementNs);
- free_xml_string(nsPrefix);
- return retVal;
+}
+static BOOL write_xml_element(WSDXML_ELEMENT *element, WS_XML_WRITER *writer) +{
- WS_XML_STRING *localName = NULL, *elementNs = NULL, *nsPrefix = NULL;
- WSDXML_ATTRIBUTE *currentAttribute;
- WS_XML_UTF16_TEXT utf16Text;
- WSDXML_NODE *currentChild;
- WSDXML_TEXT *nodeAsText;
- BOOL retVal = FALSE;
- HRESULT ret;
- int textLen;
- if (element == NULL)
return TRUE;
- /* Start the element */
- localName = populate_xml_string(element->Name->LocalName);
- if (localName == NULL) goto cleanup;
- elementNs = populate_xml_string(element->Name->Space->Uri);
- if (elementNs == NULL) goto cleanup;
- nsPrefix = populate_xml_string(element->Name->Space->PreferredPrefix);
- if (nsPrefix == NULL) goto cleanup;
- ret = WsWriteStartElement(writer, nsPrefix, localName, elementNs, NULL);
- if (FAILED(ret)) goto cleanup;
- /* Write attributes */
- currentAttribute = element->FirstAttribute;
- while (currentAttribute != NULL)
- {
if (!write_xml_attribute(currentAttribute, writer)) goto cleanup;
currentAttribute = currentAttribute->Next;
- }
- /* Write child elements */
- currentChild = element->FirstChild;
- while (currentChild != NULL)
- {
if (currentChild->Type == ElementType)
{
if (!write_xml_element((WSDXML_ELEMENT *)currentChild, writer)) goto cleanup;
}
else if (currentChild->Type == TextType)
{
nodeAsText = (WSDXML_TEXT *)currentChild;
textLen = lstrlenW(nodeAsText->Text);
utf16Text.text.textType = WS_XML_TEXT_TYPE_UTF16;
utf16Text.bytes = (BYTE *)nodeAsText->Text;
utf16Text.byteCount = min(WSD_MAX_TEXT_LENGTH, textLen) * sizeof(WCHAR);
ret = WsWriteText(writer, (WS_XML_TEXT *)&utf16Text, NULL);
if (FAILED(ret)) goto cleanup;
}
currentChild = currentChild->Next;
- }
- /* End the element */
- ret = WsWriteEndElement(writer, NULL);
- if (FAILED(ret)) goto cleanup;
- retVal = TRUE;
+cleanup:
- free_xml_string(localName);
- free_xml_string(elementNs);
- free_xml_string(nsPrefix);
- return retVal;
+}
static WSDXML_ELEMENT *add_child_element(IWSDXMLContext *xmlContext, WSDXML_ELEMENT *parent, LPCWSTR nsUri, LPCWSTR name, LPCWSTR text) { WSDXML_ELEMENT *elementObj; @@ -141,11 +340,231 @@ static LPWSTR ulonglong_to_string(void *parent, ULONGLONG value) return ret; }
+static BOOL add_discovered_namespace(struct list *namespaces, WSDXML_NAMESPACE *discoveredNs) +{
- struct discovered_namespace *ns;
- LIST_FOR_EACH_ENTRY(ns, namespaces, struct discovered_namespace, entry)
- {
if (lstrcmpW(ns->uri, discoveredNs->Uri) == 0)
return TRUE; /* Already added */
- }
- ns = WSDAllocateLinkedMemory(namespaces, sizeof(struct discovered_namespace));
- if (ns == NULL)
return FALSE;
- ns->prefix = duplicate_string(ns, discoveredNs->PreferredPrefix);
- ns->uri = duplicate_string(ns, discoveredNs->Uri);
- if ((ns->prefix == NULL) || (ns->uri == NULL))
return FALSE;
- list_add_tail(namespaces, &ns->entry);
- return TRUE;
+}
+static WSDXML_ELEMENT *create_soap_header_xml_elements(IWSDXMLContext *xmlContext, WSD_SOAP_HEADER *header, struct list *discoveredNamespaces) +{
- WSDXML_ELEMENT *headerElement, *appSequenceElement;
- WSDXML_NAME *headerName = NULL;
- /* <s:Header> */
- if (FAILED(IWSDXMLContext_AddNameToNamespace(xmlContext, envelopeNsUri, headerString, &headerName))) goto cleanup;
If the above condition succeeds, then it'll jump to cleanup with headerElement uninitialized.
- if (FAILED(WSDXMLBuildAnyForSingleElement(headerName, NULL, &headerElement))) goto cleanup;
- WSDFreeLinkedMemory(headerName);
- /* <a:Action> */
- if (add_child_element(xmlContext, headerElement, addressingNsUri, actionString, header->Action) == NULL) goto cleanup;
- /* <a:MessageId> */
- if (add_child_element(xmlContext, headerElement, addressingNsUri, messageIdString, header->MessageID) == NULL) goto cleanup;
- /* <a:To> */
- if (add_child_element(xmlContext, headerElement, addressingNsUri, toString, header->To) == NULL) goto cleanup;
- /* <a:RelatesTo> */
- if (header->RelatesTo.MessageID != NULL)
if (add_child_element(xmlContext, headerElement, addressingNsUri, relatesToString, header->RelatesTo.MessageID) == NULL) goto cleanup;
- /* <d:AppSequence> */
- appSequenceElement = add_child_element(xmlContext, headerElement, discoveryNsUri, appSequenceString, emptyString);
- if (appSequenceElement == NULL) goto cleanup;
- /* TODO: InstanceId attribute */
- /* TODO: MessageNumber attribute */
- /* TODO: SequenceID attribute */
- /* </d:AppSequence> */
- /* TODO: Write any headers */
- /* </s:Header> */
- return headerElement;
+cleanup:
- if (headerName != NULL) WSDFreeLinkedMemory(headerName);
- WSDXMLCleanupElement(headerElement);
- return NULL;
+}
+static BOOL create_soap_envelope(IWSDXMLContext *xmlContext, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *bodyElement, WS_HEAP **heap, char **outputXml, ULONG *xmlLength, struct list *discoveredNamespaces) +{
- WS_XML_STRING *actualEnvelopePrefix = NULL, *envelopeUriXmlStr = NULL, *tmpPrefix = NULL, *tmpUri = NULL;
- WSDXML_NAMESPACE *addressingNs = NULL, *discoveryNs = NULL, *envelopeNs = NULL;
- WSDXML_ELEMENT *headerElement = NULL;
- struct discovered_namespace *ns;
- WS_XML_BUFFER *buffer = NULL;
- WS_XML_WRITER *writer = NULL;
- WS_XML_STRING envelope;
- BOOL retVal = FALSE;
- HRESULT ret;
- /* Create the necessary XML prefixes */
- if (FAILED(IWSDXMLContext_AddNamespace(xmlContext, addressingNsUri, addressingPrefix, &addressingNs))) goto cleanup;
- if (!add_discovered_namespace(discoveredNamespaces, addressingNs)) goto cleanup;
- if (FAILED(IWSDXMLContext_AddNamespace(xmlContext, discoveryNsUri, discoveryPrefix, &discoveryNs))) goto cleanup;
- if (!add_discovered_namespace(discoveredNamespaces, discoveryNs)) goto cleanup;
- if (FAILED(IWSDXMLContext_AddNamespace(xmlContext, envelopeNsUri, envelopePrefix, &envelopeNs))) goto cleanup;
- if (!add_discovered_namespace(discoveredNamespaces, envelopeNs)) goto cleanup;
- envelope.bytes = (BYTE*)"Envelope";
- envelope.length = strlen((const char *) envelope.bytes);
- envelope.dictionary = NULL;
- envelope.id = 0;
- actualEnvelopePrefix = populate_xml_string(envelopeNs->PreferredPrefix);
- envelopeUriXmlStr = populate_xml_string(envelopeNs->Uri);
- if ((actualEnvelopePrefix == NULL) || (envelopeUriXmlStr == NULL)) goto cleanup;
- /* Now try to create the appropriate WebServices buffers, etc */
- ret = WsCreateHeap(16384, 4096, NULL, 0, heap, NULL);
- if (FAILED(ret)) goto cleanup;
- ret = WsCreateXmlBuffer(*heap, NULL, 0, &buffer, NULL);
- if (FAILED(ret)) goto cleanup;
- ret = WsCreateWriter(NULL, 0, &writer, NULL);
- if (FAILED(ret)) goto cleanup;
- ret = WsSetOutputToBuffer(writer, buffer, NULL, 0, NULL);
- if (FAILED(ret)) goto cleanup;
- /* Create the header XML elements */
- headerElement = create_soap_header_xml_elements(xmlContext, header, discoveredNamespaces);
- if (headerElement == NULL) goto cleanup;
- /* <s:Envelope> */
- ret = WsWriteStartElement(writer, actualEnvelopePrefix, &envelope, envelopeUriXmlStr, NULL);
- if (FAILED(ret)) goto cleanup;
- LIST_FOR_EACH_ENTRY(ns, discoveredNamespaces, struct discovered_namespace, entry)
- {
tmpPrefix = populate_xml_string(ns->prefix);
tmpUri = populate_xml_string(ns->uri);
if ((tmpPrefix == NULL) || (tmpUri == NULL)) goto cleanup;
ret = WsWriteXmlnsAttribute(writer, tmpPrefix, tmpUri, FALSE, NULL);
if (FAILED(ret)) goto cleanup;
free_xml_string(tmpPrefix);
free_xml_string(tmpUri);
- }
- tmpPrefix = NULL;
- tmpUri = NULL;
- /* Write the header */
- if (!write_xml_element(headerElement, writer)) goto cleanup;
- /* Write the body */
- if (!write_xml_element(bodyElement, writer)) goto cleanup;
- ret = WsWriteEndElement(writer, NULL);
- if (FAILED(ret)) goto cleanup;
- /* </s:Envelope> */
- /* Generate the bytes of the document */
- ret = WsWriteXmlBufferToBytes(writer, buffer, NULL, NULL, 0, *heap, (void**)outputXml, xmlLength, NULL);
- if (FAILED(ret)) goto cleanup;
- retVal = TRUE;
+cleanup:
- WSDFreeLinkedMemory(addressingNs);
- WSDFreeLinkedMemory(discoveryNs);
- WSDFreeLinkedMemory(envelopeNs);
- WSDXMLCleanupElement(headerElement);
- free_xml_string(actualEnvelopePrefix);
- free_xml_string(envelopeUriXmlStr);
- if (writer != NULL)
WsFreeWriter(writer);
- /* Don't free the heap unless the operation has failed */
- if ((!retVal) && (*heap != NULL))
- {
WsFreeHeap(*heap);
*heap = NULL;
- }
- return retVal;
+}
static BOOL write_and_send_message(IWSDiscoveryPublisherImpl *impl, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *bodyElement, struct list *discoveredNamespaces, IWSDUdpAddress *remoteAddress, int maxInitialDelay) {
- FIXME("stub\n");
- return FALSE;
- const char *xmlHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
- WS_HEAP *heap = NULL;
- ULONG xmlLength = 0;
- int xmlHeaderLen;
- char *xml = NULL;
- char *fullXml;
- BOOL ret = FALSE;
- if (!create_soap_envelope(impl->xmlContext, header, bodyElement, &heap, &xml, &xmlLength, discoveredNamespaces))
return FALSE;
- /* Prefix the XML header */
- xmlHeaderLen = strlen(xmlHeader);
- fullXml = heap_alloc_zero(xmlLength + xmlHeaderLen + 1);
- if (fullXml == NULL)
- {
WsFreeHeap(heap);
return FALSE;
- }
- memcpy(fullXml, xmlHeader, xmlHeaderLen);
- memcpy(fullXml + xmlHeaderLen, xml, xmlLength);
- if (remoteAddress == NULL)
- {
/* TODO: Send the message via UDP multicast */
FIXME("TODO: Send the message via UDP multicast\n");
- }
- else
- {
/* TODO: Send the message via UDP unicast */
FIXME("TODO: Send the message via UDP unicast\n");
- }
- heap_free(fullXml);
- WsFreeHeap(heap);
- return ret;
}
HRESULT send_hello_message(IWSDiscoveryPublisherImpl *impl, LPCWSTR pszId, ULONGLONG ullMetadataVersion, ULONGLONG ullInstanceId, diff --git a/dlls/wsdapi/wsdapi_internal.h b/dlls/wsdapi/wsdapi_internal.h index 4f8ce91d36..c9c5a72bfc 100644 --- a/dlls/wsdapi/wsdapi_internal.h +++ b/dlls/wsdapi/wsdapi_internal.h @@ -56,4 +56,8 @@ HRESULT send_hello_message(IWSDiscoveryPublisherImpl *impl, LPCWSTR pszId, ULONG const WSD_URI_LIST *pXAddrsList, const WSDXML_ELEMENT *pHeaderAny, const WSDXML_ELEMENT *pReferenceParameterAny, const WSDXML_ELEMENT *pEndpointReferenceAny, const WSDXML_ELEMENT *pAny);
+/* xml.c */
+LPWSTR duplicate_string(void *parentMemoryBlock, LPCWSTR value);
#endif diff --git a/dlls/wsdapi/xml.c b/dlls/wsdapi/xml.c index 4d6319c36b..fc02d8b2d4 100644 --- a/dlls/wsdapi/xml.c +++ b/dlls/wsdapi/xml.c @@ -27,7 +27,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(wsdapi);
-static LPWSTR duplicate_string(void *parentMemoryBlock, LPCWSTR value) +LPWSTR duplicate_string(void *parentMemoryBlock, LPCWSTR value) { int valueLen; LPWSTR dup;
There's a lot going on in the patch, can you split it?
If I reorder the patch set as mentioned in my previous message, it should be easier to split this up in a meaningful way. Many of the helper functions would not be required until certain types of data are added to the XML (e.g., attributes).
If the above condition succeeds, then it'll jump to cleanup with
headerElement uninitialized.
Thanks, I'll fix that and will check for any similar instances.
Cheers,
Owen
On Mon, Mar 12, 2018 at 12:11:14PM +0000, Owen Rudge wrote:
There's a lot going on in the patch, can you split it?
If I reorder the patch set as mentioned in my previous message, it should be easier to split this up in a meaningful way. Many of the helper functions would not be required until certain types of data are added to the XML (e.g., attributes).
Great, that would help a lot.
Huw.