2 * Web Services on Devices
4 * Copyright 2017 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
25 #include "wsdapi_internal.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
30 LPWSTR
duplicate_string(void *parentMemoryBlock
, LPCWSTR value
)
35 valueLen
= lstrlenW(value
) + 1;
37 dup
= WSDAllocateLinkedMemory(parentMemoryBlock
, valueLen
* sizeof(WCHAR
));
39 if (dup
) memcpy(dup
, value
, valueLen
* sizeof(WCHAR
));
43 static WSDXML_NAMESPACE
*duplicate_namespace(void *parentMemoryBlock
, WSDXML_NAMESPACE
*ns
)
45 WSDXML_NAMESPACE
*newNs
;
47 newNs
= WSDAllocateLinkedMemory(parentMemoryBlock
, sizeof(WSDXML_NAMESPACE
));
54 newNs
->Encoding
= ns
->Encoding
;
56 /* On Windows, both Names and NamesCount are set to null even if there are names present */
57 newNs
->NamesCount
= 0;
60 newNs
->PreferredPrefix
= duplicate_string(newNs
, ns
->PreferredPrefix
);
61 newNs
->Uri
= duplicate_string(newNs
, ns
->Uri
);
66 WSDXML_NAME
*duplicate_name(void *parentMemoryBlock
, WSDXML_NAME
*name
)
70 dup
= WSDAllocateLinkedMemory(parentMemoryBlock
, sizeof(WSDXML_NAME
));
77 dup
->Space
= duplicate_namespace(dup
, name
->Space
);
78 dup
->LocalName
= duplicate_string(dup
, name
->LocalName
);
80 if (dup
->LocalName
== NULL
)
82 WSDFreeLinkedMemory(dup
);
89 HRESULT WINAPI
WSDXMLAddChild(WSDXML_ELEMENT
*pParent
, WSDXML_ELEMENT
*pChild
)
91 WSDXML_NODE
*currentNode
;
93 TRACE("(%p, %p)\n", pParent
, pChild
);
95 if ((pParent
== NULL
) || (pChild
== NULL
) || (pChild
->Node
.Parent
!= NULL
))
100 /* See if the parent already has a child */
101 currentNode
= pParent
->FirstChild
;
103 if (currentNode
== NULL
)
105 pParent
->FirstChild
= (WSDXML_NODE
*)pChild
;
109 /* Find the last sibling node and make this child the next sibling */
110 WSDXMLAddSibling((WSDXML_ELEMENT
*)currentNode
, pChild
);
113 pChild
->Node
.Parent
= pParent
;
115 /* Link the memory allocations */
116 WSDAttachLinkedMemory(pParent
, pChild
);
121 HRESULT WINAPI
WSDXMLAddSibling(WSDXML_ELEMENT
*pFirst
, WSDXML_ELEMENT
*pSecond
)
123 WSDXML_NODE
*currentNode
;
125 TRACE("(%p, %p)\n", pFirst
, pSecond
);
127 if ((pFirst
== NULL
) || (pSecond
== NULL
))
132 /* See if the first node already has a sibling */
133 currentNode
= pFirst
->Node
.Next
;
135 if (currentNode
== NULL
)
137 pFirst
->Node
.Next
= (WSDXML_NODE
*)pSecond
;
141 /* Find the last sibling node and make the second element the next sibling */
144 if (currentNode
->Next
== NULL
)
146 currentNode
->Next
= (WSDXML_NODE
*)pSecond
;
150 currentNode
= currentNode
->Next
;
154 /* Reparent the second node under the first */
155 pSecond
->Node
.Parent
= pFirst
->Node
.Parent
;
157 /* Link the memory allocations */
158 WSDAttachLinkedMemory(pFirst
->Node
.Parent
, pSecond
);
163 HRESULT WINAPI
WSDXMLBuildAnyForSingleElement(WSDXML_NAME
*pElementName
, LPCWSTR pszText
, WSDXML_ELEMENT
**ppAny
)
167 TRACE("(%p, %s, %p)\n", pElementName
, debugstr_w(pszText
), ppAny
);
169 if ((pElementName
== NULL
) || ((pszText
!= NULL
) && (lstrlenW(pszText
) > WSD_MAX_TEXT_LENGTH
)))
179 *ppAny
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_ELEMENT
));
183 return E_OUTOFMEMORY
;
186 ZeroMemory(*ppAny
, sizeof(WSDXML_ELEMENT
));
188 (*ppAny
)->Name
= duplicate_name(*ppAny
, pElementName
);
190 if ((*ppAny
)->Name
== NULL
)
192 WSDFreeLinkedMemory(*ppAny
);
193 return E_OUTOFMEMORY
;
198 child
= WSDAllocateLinkedMemory(*ppAny
, sizeof(WSDXML_TEXT
));
202 WSDFreeLinkedMemory(*ppAny
);
203 return E_OUTOFMEMORY
;
206 child
->Node
.Parent
= *ppAny
;
207 child
->Node
.Next
= NULL
;
208 child
->Node
.Type
= TextType
;
209 child
->Text
= duplicate_string(child
, pszText
);
211 if (child
->Text
== NULL
)
213 WSDFreeLinkedMemory(*ppAny
);
214 return E_OUTOFMEMORY
;
217 (*ppAny
)->FirstChild
= (WSDXML_NODE
*)child
;
223 HRESULT WINAPI
WSDXMLCleanupElement(WSDXML_ELEMENT
*pAny
)
225 TRACE("(%p)\n", pAny
);
232 WSDFreeLinkedMemory(pAny
);
236 HRESULT WINAPI
WSDXMLGetValueFromAny(const WCHAR
*pszNamespace
, const WCHAR
*pszName
, WSDXML_ELEMENT
*pAny
, LPCWSTR
*ppszValue
)
238 WSDXML_ELEMENT
*element
;
244 if (ppszValue
== NULL
)
247 if ((pszNamespace
== NULL
) || (pszName
== NULL
) || (lstrlenW(pszNamespace
) > WSD_MAX_TEXT_LENGTH
) || (lstrlenW(pszName
) > WSD_MAX_TEXT_LENGTH
))
252 while (element
!= NULL
)
254 if (element
->Node
.Type
== ElementType
)
256 if ((lstrcmpW(element
->Name
->LocalName
, pszName
) == 0) && (lstrcmpW(element
->Name
->Space
->Uri
, pszNamespace
) == 0))
258 if ((element
->FirstChild
== NULL
) || (element
->FirstChild
->Type
!= TextType
))
263 text
= (WSDXML_TEXT
*) element
->FirstChild
;
264 *ppszValue
= (LPCWSTR
) text
->Text
;
270 element
= (WSDXML_ELEMENT
*) element
->Node
.Next
;
276 /* IWSDXMLContext implementation */
281 WSDXML_NAMESPACE
*namespace;
284 typedef struct IWSDXMLContextImpl
286 IWSDXMLContext IWSDXMLContext_iface
;
289 struct list
*namespaces
;
290 int nextUnknownPrefix
;
291 } IWSDXMLContextImpl
;
293 static WSDXML_NAMESPACE
*find_namespace(struct list
*namespaces
, LPCWSTR uri
)
295 struct xmlNamespace
*ns
;
297 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
299 if (lstrcmpW(ns
->namespace->Uri
, uri
) == 0)
301 return ns
->namespace;
308 static WSDXML_NAME
*find_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
312 for (i
= 0; i
< ns
->NamesCount
; i
++)
314 if (lstrcmpW(ns
->Names
[i
].LocalName
, name
) == 0)
316 return &ns
->Names
[i
];
323 static WSDXML_NAME
*add_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
326 WSDXML_NAME
*newName
;
329 names
= WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAME
) * (ns
->NamesCount
+ 1));
336 if (ns
->NamesCount
> 0)
338 /* Copy the existing names array over to the new allocation */
339 memcpy(names
, ns
->Names
, sizeof(WSDXML_NAME
) * ns
->NamesCount
);
341 for (i
= 0; i
< ns
->NamesCount
; i
++)
343 /* Attach the local name memory to the new names allocation */
344 WSDAttachLinkedMemory(names
, names
[i
].LocalName
);
347 WSDFreeLinkedMemory(ns
->Names
);
352 newName
= &names
[ns
->NamesCount
];
354 newName
->LocalName
= duplicate_string(names
, name
);
357 if (newName
->LocalName
== NULL
)
366 static BOOL
is_prefix_unique(struct list
*namespaces
, LPCWSTR prefix
)
368 struct xmlNamespace
*ns
;
370 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
372 if (lstrcmpW(ns
->namespace->PreferredPrefix
, prefix
) == 0)
381 static LPWSTR
generate_namespace_prefix(IWSDXMLContextImpl
*impl
, void *parentMemoryBlock
, LPCWSTR uri
)
383 WCHAR formatString
[] = { 'u','n','%','d', 0 };
384 WCHAR suggestedPrefix
[7];
386 /* Find a unique prefix */
387 while (impl
->nextUnknownPrefix
< 1000)
389 wsprintfW(suggestedPrefix
, formatString
, impl
->nextUnknownPrefix
++);
391 /* For the unlikely event where somebody has explicitly created a prefix called 'unX', check it is unique */
392 if (is_prefix_unique(impl
->namespaces
, suggestedPrefix
))
394 return duplicate_string(parentMemoryBlock
, suggestedPrefix
);
401 static WSDXML_NAMESPACE
*add_namespace(struct list
*namespaces
, LPCWSTR uri
)
403 struct xmlNamespace
*ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct xmlNamespace
));
410 ns
->namespace = WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAMESPACE
));
412 if (ns
->namespace == NULL
)
414 WSDFreeLinkedMemory(ns
);
418 ZeroMemory(ns
->namespace, sizeof(WSDXML_NAMESPACE
));
419 ns
->namespace->Uri
= duplicate_string(ns
->namespace, uri
);
421 if (ns
->namespace->Uri
== NULL
)
423 WSDFreeLinkedMemory(ns
);
427 list_add_tail(namespaces
, &ns
->entry
);
428 return ns
->namespace;
431 static inline IWSDXMLContextImpl
*impl_from_IWSDXMLContext(IWSDXMLContext
*iface
)
433 return CONTAINING_RECORD(iface
, IWSDXMLContextImpl
, IWSDXMLContext_iface
);
436 static HRESULT WINAPI
IWSDXMLContextImpl_QueryInterface(IWSDXMLContext
*iface
, REFIID riid
, void **ppv
)
438 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
440 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppv
);
444 WARN("Invalid parameter\n");
450 if (IsEqualIID(riid
, &IID_IUnknown
) ||
451 IsEqualIID(riid
, &IID_IWSDXMLContext
))
453 *ppv
= &This
->IWSDXMLContext_iface
;
457 WARN("Unknown IID %s\n", debugstr_guid(riid
));
458 return E_NOINTERFACE
;
461 IUnknown_AddRef((IUnknown
*)*ppv
);
465 static ULONG WINAPI
IWSDXMLContextImpl_AddRef(IWSDXMLContext
*iface
)
467 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
468 ULONG ref
= InterlockedIncrement(&This
->ref
);
470 TRACE("(%p) ref=%d\n", This
, ref
);
474 static ULONG WINAPI
IWSDXMLContextImpl_Release(IWSDXMLContext
*iface
)
476 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
477 ULONG ref
= InterlockedDecrement(&This
->ref
);
479 TRACE("(%p) ref=%d\n", This
, ref
);
483 WSDFreeLinkedMemory(This
);
489 static HRESULT WINAPI
IWSDXMLContextImpl_AddNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszSuggestedPrefix
, WSDXML_NAMESPACE
**ppNamespace
)
491 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
492 WSDXML_NAMESPACE
*ns
;
493 LPCWSTR newPrefix
= NULL
;
496 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszSuggestedPrefix
), ppNamespace
);
498 if ((pszUri
== NULL
) || (pszSuggestedPrefix
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) ||
499 (lstrlenW(pszSuggestedPrefix
) > WSD_MAX_TEXT_LENGTH
))
504 ns
= find_namespace(This
->namespaces
, pszUri
);
508 ns
= add_namespace(This
->namespaces
, pszUri
);
512 return E_OUTOFMEMORY
;
516 setNewPrefix
= (ns
->PreferredPrefix
== NULL
);
518 if ((ns
->PreferredPrefix
== NULL
) || (lstrcmpW(ns
->PreferredPrefix
, pszSuggestedPrefix
) != 0))
520 newPrefix
= pszSuggestedPrefix
;
526 WSDFreeLinkedMemory((void *)ns
->PreferredPrefix
);
527 ns
->PreferredPrefix
= NULL
;
529 if ((newPrefix
!= NULL
) && (is_prefix_unique(This
->namespaces
, newPrefix
)))
531 ns
->PreferredPrefix
= duplicate_string(ns
, newPrefix
);
535 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
536 if (ns
->PreferredPrefix
== NULL
)
543 if (ppNamespace
!= NULL
)
545 *ppNamespace
= duplicate_namespace(NULL
, ns
);
547 if (*ppNamespace
== NULL
)
549 return E_OUTOFMEMORY
;
556 static HRESULT WINAPI
IWSDXMLContextImpl_AddNameToNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszName
, WSDXML_NAME
**ppName
)
558 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
559 WSDXML_NAMESPACE
*ns
;
562 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszName
), ppName
);
564 if ((pszUri
== NULL
) || (pszName
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) || (lstrlenW(pszName
) > WSD_MAX_TEXT_LENGTH
))
569 ns
= find_namespace(This
->namespaces
, pszUri
);
573 /* The namespace doesn't exist, add it */
574 ns
= add_namespace(This
->namespaces
, pszUri
);
578 return E_OUTOFMEMORY
;
581 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
582 if (ns
->PreferredPrefix
== NULL
)
588 name
= find_name(ns
, pszName
);
592 name
= add_name(ns
, pszName
);
596 return E_OUTOFMEMORY
;
602 *ppName
= duplicate_name(NULL
, name
);
606 return E_OUTOFMEMORY
;
613 static HRESULT WINAPI
IWSDXMLContextImpl_SetNamespaces(IWSDXMLContext
*iface
, const PCWSDXML_NAMESPACE
*pNamespaces
, WORD wNamespacesCount
, BYTE bLayerNumber
)
615 FIXME("(%p, %p, %d, %d)\n", iface
, pNamespaces
, wNamespacesCount
, bLayerNumber
);
619 static HRESULT WINAPI
IWSDXMLContextImpl_SetTypes(IWSDXMLContext
*iface
, const PCWSDXML_TYPE
*pTypes
, DWORD dwTypesCount
, BYTE bLayerNumber
)
621 FIXME("(%p, %p, %d, %d)\n", iface
, pTypes
, dwTypesCount
, bLayerNumber
);
625 static const IWSDXMLContextVtbl xmlcontext_vtbl
=
627 IWSDXMLContextImpl_QueryInterface
,
628 IWSDXMLContextImpl_AddRef
,
629 IWSDXMLContextImpl_Release
,
630 IWSDXMLContextImpl_AddNamespace
,
631 IWSDXMLContextImpl_AddNameToNamespace
,
632 IWSDXMLContextImpl_SetNamespaces
,
633 IWSDXMLContextImpl_SetTypes
636 HRESULT WINAPI
WSDXMLCreateContext(IWSDXMLContext
**ppContext
)
638 IWSDXMLContextImpl
*obj
;
640 TRACE("(%p)\n", ppContext
);
642 if (ppContext
== NULL
)
644 WARN("Invalid parameter: ppContext == NULL\n");
650 obj
= WSDAllocateLinkedMemory(NULL
, sizeof(*obj
));
654 return E_OUTOFMEMORY
;
657 obj
->IWSDXMLContext_iface
.lpVtbl
= &xmlcontext_vtbl
;
659 obj
->namespaces
= WSDAllocateLinkedMemory(obj
, sizeof(struct list
));
660 obj
->nextUnknownPrefix
= 0;
662 if (obj
->namespaces
== NULL
)
664 WSDFreeLinkedMemory(obj
);
665 return E_OUTOFMEMORY
;
668 list_init(obj
->namespaces
);
670 *ppContext
= &obj
->IWSDXMLContext_iface
;
671 TRACE("Returning iface %p\n", *ppContext
);
676 WSDXML_NAMESPACE
*xml_context_find_namespace_by_prefix(IWSDXMLContext
*context
, LPCWSTR prefix
)
678 IWSDXMLContextImpl
*impl
= impl_from_IWSDXMLContext(context
);
679 struct xmlNamespace
*ns
;
681 if (prefix
== NULL
) return NULL
;
683 LIST_FOR_EACH_ENTRY(ns
, impl
->namespaces
, struct xmlNamespace
, entry
)
685 if (lstrcmpW(ns
->namespace->PreferredPrefix
, prefix
) == 0)
686 return ns
->namespace;