wsdapi: Implement AddNamespace.

Signed-off-by: Owen Rudge <orudge@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Owen Rudge 2017-05-30 23:05:45 +01:00 committed by Alexandre Julliard
parent 9a134711e6
commit bf20953260
3 changed files with 209 additions and 26 deletions

View File

@ -1,6 +1,6 @@
MODULE = wsdapi.dll
IMPORTLIB = wsdapi
IMPORTS = kernel32
IMPORTS = user32
C_SRCS = \
discovery.c \

View File

@ -64,7 +64,7 @@ static void BuildAnyForSingleElement_tests(void)
ok(hr == S_OK, "BuildAnyForSingleElement failed with %08x\n", hr);
ok(element->Name != &name, "element->Name has not been duplicated\n");
todo_wine ok(element->Name->Space != name.Space, "element->Name->Space has not been duplicated\n");
ok(element->Name->Space != name.Space, "element->Name->Space has not been duplicated\n");
ok(element->Name->LocalName != name.LocalName, "element->LocalName has not been duplicated\n");
ok(lstrcmpW(element->Name->LocalName, name.LocalName) == 0, "element->LocalName = %s, expected %s\n",
wine_dbgstr_w(element->Name->LocalName), wine_dbgstr_w(name.LocalName));
@ -80,7 +80,7 @@ static void BuildAnyForSingleElement_tests(void)
ok(hr == S_OK, "BuildAnyForSingleElement failed with %08x\n", hr);
ok(element->Name != &name, "element->Name has not been duplicated\n");
todo_wine ok(element->Name->Space != name.Space, "element->Name->Space has not been duplicated\n");
ok(element->Name->Space != name.Space, "element->Name->Space has not been duplicated\n");
ok(element->Name->LocalName != name.LocalName, "element->LocalName has not been duplicated\n");
ok(lstrcmpW(element->Name->LocalName, name.LocalName) == 0, "element->LocalName = %s, expected %s\n",
wine_dbgstr_w(element->Name->LocalName), wine_dbgstr_w(name.LocalName));
@ -290,24 +290,24 @@ static void XMLContext_AddNamespace_tests(void)
/* Test calling AddNamespace with invalid arguments */
hr = IWSDXMLContext_AddNamespace(context, NULL, NULL, NULL);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
hr = IWSDXMLContext_AddNamespace(context, ns1Uri, NULL, NULL);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
hr = IWSDXMLContext_AddNamespace(context, NULL, prefix1, NULL);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
/* Test calling AddNamespace without the ppNamespace parameter */
hr = IWSDXMLContext_AddNamespace(context, ns1Uri, prefix1, NULL);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Now retrieve the created namespace */
hr = IWSDXMLContext_AddNamespace(context, ns1Uri, prefix1, &ns1);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns1 != NULL, "ns1 == NULL\n");
ok(ns1 != NULL, "ns1 == NULL\n");
if (ns1 != NULL)
{
@ -321,20 +321,20 @@ static void XMLContext_AddNamespace_tests(void)
/* Test calling AddNamespace with parameters that are too large */
hr = IWSDXMLContext_AddNamespace(context, largeText, prefix2, &ns2);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
hr = IWSDXMLContext_AddNamespace(context, ns2Uri, largeText, &ns2);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
hr = IWSDXMLContext_AddNamespace(context, largeText, largeText, &ns2);
todo_wine ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
ok(hr == E_INVALIDARG, "AddNamespace failed with %08x\n", hr);
/* Test calling AddNamespace with a conflicting prefix */
hr = IWSDXMLContext_AddNamespace(context, ns2Uri, prefix1, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns2 != NULL, "ns2 == NULL\n");
ok(ns2 != NULL, "ns2 == NULL\n");
if (ns2 != NULL)
{
@ -351,10 +351,10 @@ static void XMLContext_AddNamespace_tests(void)
/* Try explicitly creating a prefix called 'un1' */
hr = IWSDXMLContext_AddNamespace(context, ns4Uri, unPrefix1, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns2 != NULL, "ns2 == NULL\n");
ok(ns2 != NULL, "ns2 == NULL\n");
if (ns2 != NULL)
{
@ -365,10 +365,10 @@ static void XMLContext_AddNamespace_tests(void)
/* Test with one more conflicting prefix */
hr = IWSDXMLContext_AddNamespace(context, ns3Uri, prefix1, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns2 != NULL, "ns2 == NULL\n");
ok(ns2 != NULL, "ns2 == NULL\n");
if (ns2 != NULL)
{
@ -379,10 +379,10 @@ static void XMLContext_AddNamespace_tests(void)
/* Try renaming a prefix */
hr = IWSDXMLContext_AddNamespace(context, ns3Uri, prefix2, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns2 != NULL, "ns2 == NULL\n");
ok(ns2 != NULL, "ns2 == NULL\n");
if (ns2 != NULL)
{
@ -454,7 +454,7 @@ static void XMLContext_AddNameToNamespace_tests(void)
/* Try creating a namespace explicitly */
hr = IWSDXMLContext_AddNamespace(context, ns2Uri, prefix2, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Now add a name to it */
hr = IWSDXMLContext_AddNameToNamespace(context, ns2Uri, name2Text, &name2);
@ -483,10 +483,10 @@ static void XMLContext_AddNameToNamespace_tests(void)
/* Now re-retrieve ns2 */
hr = IWSDXMLContext_AddNamespace(context, ns2Uri, prefix2, &ns2);
todo_wine ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
ok(hr == S_OK, "AddNamespace failed with %08x\n", hr);
/* Check the returned structure */
todo_wine ok(ns2 != NULL, "ns2 == NULL\n");
ok(ns2 != NULL, "ns2 == NULL\n");
if (ns2 != NULL)
{

View File

@ -25,6 +25,7 @@
#include "windef.h"
#include "winbase.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "wsdapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(wsdapi);
@ -44,6 +45,29 @@ static LPWSTR duplicate_string(void *parentMemoryBlock, LPCWSTR value)
return dup;
}
static WSDXML_NAMESPACE *duplicate_namespace(void *parentMemoryBlock, WSDXML_NAMESPACE *ns)
{
WSDXML_NAMESPACE *newNs;
newNs = WSDAllocateLinkedMemory(parentMemoryBlock, sizeof(WSDXML_NAMESPACE));
if (newNs == NULL)
{
return NULL;
}
newNs->Encoding = ns->Encoding;
/* On Windows, both Names and NamesCount are set to null even if there are names present */
newNs->NamesCount = 0;
newNs->Names = NULL;
newNs->PreferredPrefix = duplicate_string(newNs, ns->PreferredPrefix);
newNs->Uri = duplicate_string(newNs, ns->Uri);
return newNs;
}
static WSDXML_NAME *duplicate_name(void *parentMemoryBlock, WSDXML_NAME *name)
{
WSDXML_NAME *dup;
@ -55,7 +79,7 @@ static WSDXML_NAME *duplicate_name(void *parentMemoryBlock, WSDXML_NAME *name)
return NULL;
}
dup->Space = name->Space;
dup->Space = duplicate_namespace(dup, name->Space);
dup->LocalName = duplicate_string(dup, name->LocalName);
if (dup->LocalName == NULL)
@ -216,12 +240,101 @@ HRESULT WINAPI WSDXMLCleanupElement(WSDXML_ELEMENT *pAny)
/* IWSDXMLContext implementation */
struct xmlNamespace
{
struct list entry;
WSDXML_NAMESPACE *namespace;
};
typedef struct IWSDXMLContextImpl
{
IWSDXMLContext IWSDXMLContext_iface;
LONG ref;
struct list *namespaces;
int nextUnknownPrefix;
} IWSDXMLContextImpl;
static WSDXML_NAMESPACE *find_namespace(struct list *namespaces, LPCWSTR uri)
{
struct xmlNamespace *ns;
LIST_FOR_EACH_ENTRY(ns, namespaces, struct xmlNamespace, entry)
{
if (lstrcmpW(ns->namespace->Uri, uri) == 0)
{
return ns->namespace;
}
}
return NULL;
}
static BOOL is_prefix_unique(struct list *namespaces, LPCWSTR prefix)
{
struct xmlNamespace *ns;
LIST_FOR_EACH_ENTRY(ns, namespaces, struct xmlNamespace, entry)
{
if (lstrcmpW(ns->namespace->PreferredPrefix, prefix) == 0)
{
return FALSE;
}
}
return TRUE;
}
static LPWSTR generate_namespace_prefix(IWSDXMLContextImpl *impl, void *parentMemoryBlock, LPCWSTR uri)
{
WCHAR formatString[] = { 'u','n','%','d', 0 };
WCHAR suggestedPrefix[7];
/* Find a unique prefix */
while (impl->nextUnknownPrefix < 1000)
{
wsprintfW(suggestedPrefix, formatString, impl->nextUnknownPrefix++);
/* For the unlikely event where somebody has explicitly created a prefix called 'unX', check it is unique */
if (is_prefix_unique(impl->namespaces, suggestedPrefix))
{
return duplicate_string(parentMemoryBlock, suggestedPrefix);
}
}
return NULL;
}
static WSDXML_NAMESPACE *add_namespace(struct list *namespaces, LPCWSTR uri)
{
struct xmlNamespace *ns = WSDAllocateLinkedMemory(namespaces, sizeof(struct xmlNamespace));
if (ns == NULL)
{
return NULL;
}
ns->namespace = WSDAllocateLinkedMemory(ns, sizeof(WSDXML_NAMESPACE));
if (ns->namespace == NULL)
{
WSDFreeLinkedMemory(ns);
return NULL;
}
ZeroMemory(ns->namespace, sizeof(WSDXML_NAMESPACE));
ns->namespace->Uri = duplicate_string(ns->namespace, uri);
if (ns->namespace->Uri == NULL)
{
WSDFreeLinkedMemory(ns);
return NULL;
}
list_add_tail(namespaces, &ns->entry);
return ns->namespace;
}
static inline IWSDXMLContextImpl *impl_from_IWSDXMLContext(IWSDXMLContext *iface)
{
return CONTAINING_RECORD(iface, IWSDXMLContextImpl, IWSDXMLContext_iface);
@ -282,8 +395,68 @@ static ULONG WINAPI IWSDXMLContextImpl_Release(IWSDXMLContext *iface)
static HRESULT WINAPI IWSDXMLContextImpl_AddNamespace(IWSDXMLContext *iface, LPCWSTR pszUri, LPCWSTR pszSuggestedPrefix, WSDXML_NAMESPACE **ppNamespace)
{
FIXME("(%p, %s, %s, %p)\n", iface, debugstr_w(pszUri), debugstr_w(pszSuggestedPrefix), ppNamespace);
return E_NOTIMPL;
IWSDXMLContextImpl *This = impl_from_IWSDXMLContext(iface);
WSDXML_NAMESPACE *ns;
LPCWSTR newPrefix = NULL;
BOOL setNewPrefix;
TRACE("(%p, %s, %s, %p)\n", This, debugstr_w(pszUri), debugstr_w(pszSuggestedPrefix), ppNamespace);
if ((pszUri == NULL) || (pszSuggestedPrefix == NULL) || (lstrlenW(pszUri) > WSD_MAX_TEXT_LENGTH) ||
(lstrlenW(pszSuggestedPrefix) > WSD_MAX_TEXT_LENGTH))
{
return E_INVALIDARG;
}
ns = find_namespace(This->namespaces, pszUri);
if (ns == NULL)
{
ns = add_namespace(This->namespaces, pszUri);
if (ns == NULL)
{
return E_OUTOFMEMORY;
}
}
setNewPrefix = (ns->PreferredPrefix == NULL);
if ((ns->PreferredPrefix == NULL) || (lstrcmpW(ns->PreferredPrefix, pszSuggestedPrefix) != 0))
{
newPrefix = pszSuggestedPrefix;
setNewPrefix = TRUE;
}
if (setNewPrefix)
{
WSDFreeLinkedMemory((void *)ns->PreferredPrefix);
if ((newPrefix != NULL) && (is_prefix_unique(This->namespaces, newPrefix)))
{
ns->PreferredPrefix = duplicate_string(ns, newPrefix);
}
else
{
ns->PreferredPrefix = generate_namespace_prefix(This, ns, pszUri);
if (ns->PreferredPrefix == NULL)
{
return E_FAIL;
}
}
}
if (ppNamespace != NULL)
{
*ppNamespace = duplicate_namespace(NULL, ns);
if (*ppNamespace == NULL)
{
return E_OUTOFMEMORY;
}
}
return S_OK;
}
static HRESULT WINAPI IWSDXMLContextImpl_AddNameToNamespace(IWSDXMLContext *iface, LPCWSTR pszUri, LPCWSTR pszName, WSDXML_NAME **ppName)
@ -338,6 +511,16 @@ HRESULT WINAPI WSDXMLCreateContext(IWSDXMLContext **ppContext)
obj->IWSDXMLContext_iface.lpVtbl = &xmlcontext_vtbl;
obj->ref = 1;
obj->namespaces = WSDAllocateLinkedMemory(obj, sizeof(struct list));
obj->nextUnknownPrefix = 0;
if (obj->namespaces == NULL)
{
WSDFreeLinkedMemory(obj);
return E_OUTOFMEMORY;
}
list_init(obj->namespaces);
*ppContext = &obj->IWSDXMLContext_iface;
TRACE("Returning iface %p\n", *ppContext);