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 /* IWSDXMLContext implementation */
246 WSDXML_NAMESPACE
*namespace;
249 typedef struct IWSDXMLContextImpl
251 IWSDXMLContext IWSDXMLContext_iface
;
254 struct list
*namespaces
;
255 int nextUnknownPrefix
;
256 } IWSDXMLContextImpl
;
258 static WSDXML_NAMESPACE
*find_namespace(struct list
*namespaces
, LPCWSTR uri
)
260 struct xmlNamespace
*ns
;
262 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
264 if (lstrcmpW(ns
->namespace->Uri
, uri
) == 0)
266 return ns
->namespace;
273 static WSDXML_NAME
*find_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
277 for (i
= 0; i
< ns
->NamesCount
; i
++)
279 if (lstrcmpW(ns
->Names
[i
].LocalName
, name
) == 0)
281 return &ns
->Names
[i
];
288 static WSDXML_NAME
*add_name(WSDXML_NAMESPACE
*ns
, LPCWSTR name
)
291 WSDXML_NAME
*newName
;
294 names
= WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAME
) * (ns
->NamesCount
+ 1));
301 if (ns
->NamesCount
> 0)
303 /* Copy the existing names array over to the new allocation */
304 memcpy(names
, ns
->Names
, sizeof(WSDXML_NAME
) * ns
->NamesCount
);
306 for (i
= 0; i
< ns
->NamesCount
; i
++)
308 /* Attach the local name memory to the new names allocation */
309 WSDAttachLinkedMemory(names
, names
[i
].LocalName
);
312 WSDFreeLinkedMemory(ns
->Names
);
317 newName
= &names
[ns
->NamesCount
];
319 newName
->LocalName
= duplicate_string(names
, name
);
322 if (newName
->LocalName
== NULL
)
331 static BOOL
is_prefix_unique(struct list
*namespaces
, LPCWSTR prefix
)
333 struct xmlNamespace
*ns
;
335 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct xmlNamespace
, entry
)
337 if (lstrcmpW(ns
->namespace->PreferredPrefix
, prefix
) == 0)
346 static LPWSTR
generate_namespace_prefix(IWSDXMLContextImpl
*impl
, void *parentMemoryBlock
, LPCWSTR uri
)
348 WCHAR formatString
[] = { 'u','n','%','d', 0 };
349 WCHAR suggestedPrefix
[7];
351 /* Find a unique prefix */
352 while (impl
->nextUnknownPrefix
< 1000)
354 wsprintfW(suggestedPrefix
, formatString
, impl
->nextUnknownPrefix
++);
356 /* For the unlikely event where somebody has explicitly created a prefix called 'unX', check it is unique */
357 if (is_prefix_unique(impl
->namespaces
, suggestedPrefix
))
359 return duplicate_string(parentMemoryBlock
, suggestedPrefix
);
366 static WSDXML_NAMESPACE
*add_namespace(struct list
*namespaces
, LPCWSTR uri
)
368 struct xmlNamespace
*ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct xmlNamespace
));
375 ns
->namespace = WSDAllocateLinkedMemory(ns
, sizeof(WSDXML_NAMESPACE
));
377 if (ns
->namespace == NULL
)
379 WSDFreeLinkedMemory(ns
);
383 ZeroMemory(ns
->namespace, sizeof(WSDXML_NAMESPACE
));
384 ns
->namespace->Uri
= duplicate_string(ns
->namespace, uri
);
386 if (ns
->namespace->Uri
== NULL
)
388 WSDFreeLinkedMemory(ns
);
392 list_add_tail(namespaces
, &ns
->entry
);
393 return ns
->namespace;
396 static inline IWSDXMLContextImpl
*impl_from_IWSDXMLContext(IWSDXMLContext
*iface
)
398 return CONTAINING_RECORD(iface
, IWSDXMLContextImpl
, IWSDXMLContext_iface
);
401 static HRESULT WINAPI
IWSDXMLContextImpl_QueryInterface(IWSDXMLContext
*iface
, REFIID riid
, void **ppv
)
403 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
405 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppv
);
409 WARN("Invalid parameter\n");
415 if (IsEqualIID(riid
, &IID_IUnknown
) ||
416 IsEqualIID(riid
, &IID_IWSDXMLContext
))
418 *ppv
= &This
->IWSDXMLContext_iface
;
422 WARN("Unknown IID %s\n", debugstr_guid(riid
));
423 return E_NOINTERFACE
;
426 IUnknown_AddRef((IUnknown
*)*ppv
);
430 static ULONG WINAPI
IWSDXMLContextImpl_AddRef(IWSDXMLContext
*iface
)
432 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
433 ULONG ref
= InterlockedIncrement(&This
->ref
);
435 TRACE("(%p) ref=%d\n", This
, ref
);
439 static ULONG WINAPI
IWSDXMLContextImpl_Release(IWSDXMLContext
*iface
)
441 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
442 ULONG ref
= InterlockedDecrement(&This
->ref
);
444 TRACE("(%p) ref=%d\n", This
, ref
);
448 WSDFreeLinkedMemory(This
);
454 static HRESULT WINAPI
IWSDXMLContextImpl_AddNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszSuggestedPrefix
, WSDXML_NAMESPACE
**ppNamespace
)
456 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
457 WSDXML_NAMESPACE
*ns
;
458 LPCWSTR newPrefix
= NULL
;
461 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszSuggestedPrefix
), ppNamespace
);
463 if ((pszUri
== NULL
) || (pszSuggestedPrefix
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) ||
464 (lstrlenW(pszSuggestedPrefix
) > WSD_MAX_TEXT_LENGTH
))
469 ns
= find_namespace(This
->namespaces
, pszUri
);
473 ns
= add_namespace(This
->namespaces
, pszUri
);
477 return E_OUTOFMEMORY
;
481 setNewPrefix
= (ns
->PreferredPrefix
== NULL
);
483 if ((ns
->PreferredPrefix
== NULL
) || (lstrcmpW(ns
->PreferredPrefix
, pszSuggestedPrefix
) != 0))
485 newPrefix
= pszSuggestedPrefix
;
491 WSDFreeLinkedMemory((void *)ns
->PreferredPrefix
);
493 if ((newPrefix
!= NULL
) && (is_prefix_unique(This
->namespaces
, newPrefix
)))
495 ns
->PreferredPrefix
= duplicate_string(ns
, newPrefix
);
499 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
500 if (ns
->PreferredPrefix
== NULL
)
507 if (ppNamespace
!= NULL
)
509 *ppNamespace
= duplicate_namespace(NULL
, ns
);
511 if (*ppNamespace
== NULL
)
513 return E_OUTOFMEMORY
;
520 static HRESULT WINAPI
IWSDXMLContextImpl_AddNameToNamespace(IWSDXMLContext
*iface
, LPCWSTR pszUri
, LPCWSTR pszName
, WSDXML_NAME
**ppName
)
522 IWSDXMLContextImpl
*This
= impl_from_IWSDXMLContext(iface
);
523 WSDXML_NAMESPACE
*ns
;
526 TRACE("(%p, %s, %s, %p)\n", This
, debugstr_w(pszUri
), debugstr_w(pszName
), ppName
);
528 if ((pszUri
== NULL
) || (pszName
== NULL
) || (lstrlenW(pszUri
) > WSD_MAX_TEXT_LENGTH
) || (lstrlenW(pszName
) > WSD_MAX_TEXT_LENGTH
))
533 ns
= find_namespace(This
->namespaces
, pszUri
);
537 /* The namespace doesn't exist, add it */
538 ns
= add_namespace(This
->namespaces
, pszUri
);
542 return E_OUTOFMEMORY
;
545 ns
->PreferredPrefix
= generate_namespace_prefix(This
, ns
, pszUri
);
546 if (ns
->PreferredPrefix
== NULL
)
552 name
= find_name(ns
, pszName
);
556 name
= add_name(ns
, pszName
);
560 return E_OUTOFMEMORY
;
566 *ppName
= duplicate_name(NULL
, name
);
570 return E_OUTOFMEMORY
;
577 static HRESULT WINAPI
IWSDXMLContextImpl_SetNamespaces(IWSDXMLContext
*iface
, const PCWSDXML_NAMESPACE
*pNamespaces
, WORD wNamespacesCount
, BYTE bLayerNumber
)
579 FIXME("(%p, %p, %d, %d)\n", iface
, pNamespaces
, wNamespacesCount
, bLayerNumber
);
583 static HRESULT WINAPI
IWSDXMLContextImpl_SetTypes(IWSDXMLContext
*iface
, const PCWSDXML_TYPE
*pTypes
, DWORD dwTypesCount
, BYTE bLayerNumber
)
585 FIXME("(%p, %p, %d, %d)\n", iface
, pTypes
, dwTypesCount
, bLayerNumber
);
589 static const IWSDXMLContextVtbl xmlcontext_vtbl
=
591 IWSDXMLContextImpl_QueryInterface
,
592 IWSDXMLContextImpl_AddRef
,
593 IWSDXMLContextImpl_Release
,
594 IWSDXMLContextImpl_AddNamespace
,
595 IWSDXMLContextImpl_AddNameToNamespace
,
596 IWSDXMLContextImpl_SetNamespaces
,
597 IWSDXMLContextImpl_SetTypes
600 HRESULT WINAPI
WSDXMLCreateContext(IWSDXMLContext
**ppContext
)
602 IWSDXMLContextImpl
*obj
;
604 TRACE("(%p)\n", ppContext
);
606 if (ppContext
== NULL
)
608 WARN("Invalid parameter: ppContext == NULL\n");
614 obj
= WSDAllocateLinkedMemory(NULL
, sizeof(*obj
));
618 return E_OUTOFMEMORY
;
621 obj
->IWSDXMLContext_iface
.lpVtbl
= &xmlcontext_vtbl
;
623 obj
->namespaces
= WSDAllocateLinkedMemory(obj
, sizeof(struct list
));
624 obj
->nextUnknownPrefix
= 0;
626 if (obj
->namespaces
== NULL
)
628 WSDFreeLinkedMemory(obj
);
629 return E_OUTOFMEMORY
;
632 list_init(obj
->namespaces
);
634 *ppContext
= &obj
->IWSDXMLContext_iface
;
635 TRACE("Returning iface %p\n", *ppContext
);