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
27 #include "wine/debug.h"
28 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
33 #define WSD_MAX_TEXT_LENGTH 8192
35 static LPWSTR
duplicate_string(void *parentMemoryBlock
, LPCWSTR value
)
40 valueLen
= lstrlenW(value
) + 1;
42 dup
= WSDAllocateLinkedMemory(parentMemoryBlock
, valueLen
* sizeof(WCHAR
));
44 if (dup
) memcpy(dup
, value
, valueLen
* sizeof(WCHAR
));
48 static WSDXML_NAMESPACE
*duplicate_namespace(void *parentMemoryBlock
, WSDXML_NAMESPACE
*ns
)
50 WSDXML_NAMESPACE
*newNs
;
52 newNs
= WSDAllocateLinkedMemory(parentMemoryBlock
, sizeof(WSDXML_NAMESPACE
));
59 newNs
->Encoding
= ns
->Encoding
;
61 /* On Windows, both Names and NamesCount are set to null even if there are names present */
62 newNs
->NamesCount
= 0;
65 newNs
->PreferredPrefix
= duplicate_string(newNs
, ns
->PreferredPrefix
);
66 newNs
->Uri
= duplicate_string(newNs
, ns
->Uri
);
71 static WSDXML_NAME
*duplicate_name(void *parentMemoryBlock
, WSDXML_NAME
*name
)
75 dup
= WSDAllocateLinkedMemory(parentMemoryBlock
, sizeof(WSDXML_NAME
));
82 dup
->Space
= duplicate_namespace(dup
, name
->Space
);
83 dup
->LocalName
= duplicate_string(dup
, name
->LocalName
);
85 if (dup
->LocalName
== NULL
)
87 WSDFreeLinkedMemory(dup
);
94 HRESULT WINAPI
WSDXMLAddChild(WSDXML_ELEMENT
*pParent
, WSDXML_ELEMENT
*pChild
)
96 WSDXML_NODE
*currentNode
;
98 TRACE("(%p, %p)\n", pParent
, pChild
);
100 if ((pParent
== NULL
) || (pChild
== NULL
) || (pChild
->Node
.Parent
!= NULL
))
105 /* See if the parent already has a child */
106 currentNode
= pParent
->FirstChild
;
108 if (currentNode
== NULL
)
110 pParent
->FirstChild
= (WSDXML_NODE
*)pChild
;
114 /* Find the last sibling node and make this child the next sibling */
115 WSDXMLAddSibling((WSDXML_ELEMENT
*)currentNode
, pChild
);
118 pChild
->Node
.Parent
= pParent
;
120 /* Link the memory allocations */
121 WSDAttachLinkedMemory(pParent
, pChild
);
126 HRESULT WINAPI
WSDXMLAddSibling(WSDXML_ELEMENT
*pFirst
, WSDXML_ELEMENT
*pSecond
)
128 WSDXML_NODE
*currentNode
;
130 TRACE("(%p, %p)\n", pFirst
, pSecond
);
132 if ((pFirst
== NULL
) || (pSecond
== NULL
))
137 /* See if the first node already has a sibling */
138 currentNode
= pFirst
->Node
.Next
;
140 if (currentNode
== NULL
)
142 pFirst
->Node
.Next
= (WSDXML_NODE
*)pSecond
;
146 /* Find the last sibling node and make the second element the next sibling */
149 if (currentNode
->Next
== NULL
)
151 currentNode
->Next
= (WSDXML_NODE
*)pSecond
;
155 currentNode
= currentNode
->Next
;
159 /* Reparent the second node under the first */
160 pSecond
->Node
.Parent
= pFirst
->Node
.Parent
;
162 /* Link the memory allocations */
163 WSDAttachLinkedMemory(pFirst
->Node
.Parent
, pSecond
);
168 HRESULT WINAPI
WSDXMLBuildAnyForSingleElement(WSDXML_NAME
*pElementName
, LPCWSTR pszText
, WSDXML_ELEMENT
**ppAny
)
172 TRACE("(%p, %s, %p)\n", pElementName
, debugstr_w(pszText
), ppAny
);
174 if ((pElementName
== NULL
) || ((pszText
!= NULL
) && (lstrlenW(pszText
) > WSD_MAX_TEXT_LENGTH
)))
184 *ppAny
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_ELEMENT
));
188 return E_OUTOFMEMORY
;
191 ZeroMemory(*ppAny
, sizeof(WSDXML_ELEMENT
));
193 (*ppAny
)->Name
= duplicate_name(*ppAny
, pElementName
);
195 if ((*ppAny
)->Name
== NULL
)
197 WSDFreeLinkedMemory(*ppAny
);
198 return E_OUTOFMEMORY
;
203 child
= WSDAllocateLinkedMemory(*ppAny
, sizeof(WSDXML_TEXT
));
207 WSDFreeLinkedMemory(*ppAny
);
208 return E_OUTOFMEMORY
;
211 child
->Node
.Parent
= *ppAny
;
212 child
->Node
.Next
= NULL
;
213 child
->Node
.Type
= TextType
;
214 child
->Text
= duplicate_string(child
, pszText
);
216 if (child
->Text
== NULL
)
218 WSDFreeLinkedMemory(*ppAny
);
219 return E_OUTOFMEMORY
;
222 (*ppAny
)->FirstChild
= (WSDXML_NODE
*)child
;
228 HRESULT WINAPI
WSDXMLCleanupElement(WSDXML_ELEMENT
*pAny
)
230 TRACE("(%p)\n", pAny
);
237 WSDFreeLinkedMemory(pAny
);
241 HRESULT WINAPI
WSDXMLGetValueFromAny(const WCHAR
*pszNamespace
, const WCHAR
*pszName
, WSDXML_ELEMENT
*pAny
, LPCWSTR
*ppszValue
)
243 WSDXML_ELEMENT
*element
;
249 if (ppszValue
== NULL
)
252 if ((pszNamespace
== NULL
) || (pszName
== NULL
) || (lstrlenW(pszNamespace
) > WSD_MAX_TEXT_LENGTH
) || (lstrlenW(pszName
) > WSD_MAX_TEXT_LENGTH
))
257 while (element
!= NULL
)
259 if (element
->Node
.Type
== ElementType
)
261 if ((lstrcmpW(element
->Name
->LocalName
, pszName
) == 0) && (lstrcmpW(element
->Name
->Space
->Uri
, pszNamespace
) == 0))
263 if ((element
->FirstChild
== NULL
) || (element
->FirstChild
->Type
!= TextType
))
268 text
= (WSDXML_TEXT
*) element
->FirstChild
;
269 *ppszValue
= (LPCWSTR
) text
->Text
;
275 element
= (WSDXML_ELEMENT
*) element
->Node
.Next
;
281 /* IWSDXMLContext implementation */
286 WSDXML_NAMESPACE
*namespace;
289 typedef struct IWSDXMLContextImpl
291 IWSDXMLContext IWSDXMLContext_iface
;
294 struct list
*namespaces
;
295 int nextUnknownPrefix
;
296 } IWSDXMLContextImpl
;
298 static WSDXML_NAMESPACE
*find_namespace(struct list
*namespaces
, LPCWSTR uri
)
300 struct xmlNamespace
*ns
;
302 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
304 if (lstrcmpW(ns
->namespace->Uri
, uri
) == 0)
306 return ns
->namespace;
313 static WSDXML_NAME
*find_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
317 for (i
= 0; i
< ns
->NamesCount
; i
++)
319 if (lstrcmpW(ns
->Names
[i
].LocalName
, name
) == 0)
321 return &ns
->Names
[i
];
328 static WSDXML_NAME
*add_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
331 WSDXML_NAME
*newName
;
334 names
= WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAME
) * (ns
->NamesCount
+ 1));
341 if (ns
->NamesCount
> 0)
343 /* Copy the existing names array over to the new allocation */
344 memcpy(names
, ns
->Names
, sizeof(WSDXML_NAME
) * ns
->NamesCount
);
346 for (i
= 0; i
< ns
->NamesCount
; i
++)
348 /* Attach the local name memory to the new names allocation */
349 WSDAttachLinkedMemory(names
, names
[i
].LocalName
);
352 WSDFreeLinkedMemory(ns
->Names
);
357 newName
= &names
[ns
->NamesCount
];
359 newName
->LocalName
= duplicate_string(names
, name
);
362 if (newName
->LocalName
== NULL
)
371 static BOOL
is_prefix_unique(struct list
*namespaces
, LPCWSTR prefix
)
373 struct xmlNamespace
*ns
;
375 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
377 if (lstrcmpW(ns
->namespace->PreferredPrefix
, prefix
) == 0)
386 static LPWSTR
generate_namespace_prefix(IWSDXMLContextImpl
*impl
, void *parentMemoryBlock
, LPCWSTR uri
)
388 WCHAR formatString
[] = { 'u','n','%','d', 0 };
389 WCHAR suggestedPrefix
[7];
391 /* Find a unique prefix */
392 while (impl
->nextUnknownPrefix
< 1000)
394 wsprintfW(suggestedPrefix
, formatString
, impl
->nextUnknownPrefix
++);
396 /* For the unlikely event where somebody has explicitly created a prefix called 'unX', check it is unique */
397 if (is_prefix_unique(impl
->namespaces
, suggestedPrefix
))
399 return duplicate_string(parentMemoryBlock
, suggestedPrefix
);
406 static WSDXML_NAMESPACE
*add_namespace(struct list
*namespaces
, LPCWSTR uri
)
408 struct xmlNamespace
*ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct xmlNamespace
));
415 ns
->namespace = WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAMESPACE
));
417 if (ns
->namespace == NULL
)
419 WSDFreeLinkedMemory(ns
);
423 ZeroMemory(ns
->namespace, sizeof(WSDXML_NAMESPACE
));
424 ns
->namespace->Uri
= duplicate_string(ns
->namespace, uri
);
426 if (ns
->namespace->Uri
== NULL
)
428 WSDFreeLinkedMemory(ns
);
432 list_add_tail(namespaces
, &ns
->entry
);
433 return ns
->namespace;
436 static inline IWSDXMLContextImpl
*impl_from_IWSDXMLContext(IWSDXMLContext
*iface
)
438 return CONTAINING_RECORD(iface
, IWSDXMLContextImpl
, IWSDXMLContext_iface
);
441 static HRESULT WINAPI
IWSDXMLContextImpl_QueryInterface(IWSDXMLContext
*iface
, REFIID riid
, void **ppv
)
443 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
445 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppv
);
449 WARN("Invalid parameter\n");
455 if (IsEqualIID(riid
, &IID_IUnknown
) ||
456 IsEqualIID(riid
, &IID_IWSDXMLContext
))
458 *ppv
= &This
->IWSDXMLContext_iface
;
462 WARN("Unknown IID %s\n", debugstr_guid(riid
));
463 return E_NOINTERFACE
;
466 IUnknown_AddRef((IUnknown
*)*ppv
);
470 static ULONG WINAPI
IWSDXMLContextImpl_AddRef(IWSDXMLContext
*iface
)
472 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
473 ULONG ref
= InterlockedIncrement(&This
->ref
);
475 TRACE("(%p) ref=%d\n", This
, ref
);
479 static ULONG WINAPI
IWSDXMLContextImpl_Release(IWSDXMLContext
*iface
)
481 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
482 ULONG ref
= InterlockedDecrement(&This
->ref
);
484 TRACE("(%p) ref=%d\n", This
, ref
);
488 WSDFreeLinkedMemory(This
);
494 static HRESULT WINAPI
IWSDXMLContextImpl_AddNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszSuggestedPrefix
, WSDXML_NAMESPACE
**ppNamespace
)
496 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
497 WSDXML_NAMESPACE
*ns
;
498 LPCWSTR newPrefix
= NULL
;
501 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszSuggestedPrefix
), ppNamespace
);
503 if ((pszUri
== NULL
) || (pszSuggestedPrefix
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) ||
504 (lstrlenW(pszSuggestedPrefix
) > WSD_MAX_TEXT_LENGTH
))
509 ns
= find_namespace(This
->namespaces
, pszUri
);
513 ns
= add_namespace(This
->namespaces
, pszUri
);
517 return E_OUTOFMEMORY
;
521 setNewPrefix
= (ns
->PreferredPrefix
== NULL
);
523 if ((ns
->PreferredPrefix
== NULL
) || (lstrcmpW(ns
->PreferredPrefix
, pszSuggestedPrefix
) != 0))
525 newPrefix
= pszSuggestedPrefix
;
531 WSDFreeLinkedMemory((void *)ns
->PreferredPrefix
);
532 ns
->PreferredPrefix
= NULL
;
534 if ((newPrefix
!= NULL
) && (is_prefix_unique(This
->namespaces
, newPrefix
)))
536 ns
->PreferredPrefix
= duplicate_string(ns
, newPrefix
);
540 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
541 if (ns
->PreferredPrefix
== NULL
)
548 if (ppNamespace
!= NULL
)
550 *ppNamespace
= duplicate_namespace(NULL
, ns
);
552 if (*ppNamespace
== NULL
)
554 return E_OUTOFMEMORY
;
561 static HRESULT WINAPI
IWSDXMLContextImpl_AddNameToNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszName
, WSDXML_NAME
**ppName
)
563 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
564 WSDXML_NAMESPACE
*ns
;
567 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszName
), ppName
);
569 if ((pszUri
== NULL
) || (pszName
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) || (lstrlenW(pszName
) > WSD_MAX_TEXT_LENGTH
))
574 ns
= find_namespace(This
->namespaces
, pszUri
);
578 /* The namespace doesn't exist, add it */
579 ns
= add_namespace(This
->namespaces
, pszUri
);
583 return E_OUTOFMEMORY
;
586 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
587 if (ns
->PreferredPrefix
== NULL
)
593 name
= find_name(ns
, pszName
);
597 name
= add_name(ns
, pszName
);
601 return E_OUTOFMEMORY
;
607 *ppName
= duplicate_name(NULL
, name
);
611 return E_OUTOFMEMORY
;
618 static HRESULT WINAPI
IWSDXMLContextImpl_SetNamespaces(IWSDXMLContext
*iface
, const PCWSDXML_NAMESPACE
*pNamespaces
, WORD wNamespacesCount
, BYTE bLayerNumber
)
620 FIXME("(%p, %p, %d, %d)\n", iface
, pNamespaces
, wNamespacesCount
, bLayerNumber
);
624 static HRESULT WINAPI
IWSDXMLContextImpl_SetTypes(IWSDXMLContext
*iface
, const PCWSDXML_TYPE
*pTypes
, DWORD dwTypesCount
, BYTE bLayerNumber
)
626 FIXME("(%p, %p, %d, %d)\n", iface
, pTypes
, dwTypesCount
, bLayerNumber
);
630 static const IWSDXMLContextVtbl xmlcontext_vtbl
=
632 IWSDXMLContextImpl_QueryInterface
,
633 IWSDXMLContextImpl_AddRef
,
634 IWSDXMLContextImpl_Release
,
635 IWSDXMLContextImpl_AddNamespace
,
636 IWSDXMLContextImpl_AddNameToNamespace
,
637 IWSDXMLContextImpl_SetNamespaces
,
638 IWSDXMLContextImpl_SetTypes
641 HRESULT WINAPI
WSDXMLCreateContext(IWSDXMLContext
**ppContext
)
643 IWSDXMLContextImpl
*obj
;
645 TRACE("(%p)\n", ppContext
);
647 if (ppContext
== NULL
)
649 WARN("Invalid parameter: ppContext == NULL\n");
655 obj
= WSDAllocateLinkedMemory(NULL
, sizeof(*obj
));
659 return E_OUTOFMEMORY
;
662 obj
->IWSDXMLContext_iface
.lpVtbl
= &xmlcontext_vtbl
;
664 obj
->namespaces
= WSDAllocateLinkedMemory(obj
, sizeof(struct list
));
665 obj
->nextUnknownPrefix
= 0;
667 if (obj
->namespaces
== NULL
)
669 WSDFreeLinkedMemory(obj
);
670 return E_OUTOFMEMORY
;
673 list_init(obj
->namespaces
);
675 *ppContext
= &obj
->IWSDXMLContext_iface
;
676 TRACE("Returning iface %p\n", *ppContext
);