dbghelp: Return a Unicode path in path_find_symbol_file().
[wine.git] / dlls / wsdapi / xml.c
blob98bdec6b0dfa966878c9588f150b16204cc7c336
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "wsdapi_internal.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi);
30 LPWSTR duplicate_string(void *parentMemoryBlock, LPCWSTR value)
32 int valueLen;
33 LPWSTR dup;
35 valueLen = lstrlenW(value) + 1;
37 dup = WSDAllocateLinkedMemory(parentMemoryBlock, valueLen * sizeof(WCHAR));
39 if (dup) memcpy(dup, value, valueLen * sizeof(WCHAR));
40 return dup;
43 static WSDXML_NAMESPACE *duplicate_namespace(void *parentMemoryBlock, WSDXML_NAMESPACE *ns)
45 WSDXML_NAMESPACE *newNs;
47 newNs = WSDAllocateLinkedMemory(parentMemoryBlock, sizeof(WSDXML_NAMESPACE));
49 if (newNs == NULL)
51 return NULL;
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;
58 newNs->Names = NULL;
60 newNs->PreferredPrefix = duplicate_string(newNs, ns->PreferredPrefix);
61 newNs->Uri = duplicate_string(newNs, ns->Uri);
63 return newNs;
66 WSDXML_NAME *duplicate_name(void *parentMemoryBlock, WSDXML_NAME *name)
68 WSDXML_NAME *dup;
70 dup = WSDAllocateLinkedMemory(parentMemoryBlock, sizeof(WSDXML_NAME));
72 if (dup == NULL)
74 return NULL;
77 dup->Space = duplicate_namespace(dup, name->Space);
78 dup->LocalName = duplicate_string(dup, name->LocalName);
80 if (dup->LocalName == NULL)
82 WSDFreeLinkedMemory(dup);
83 return NULL;
86 return 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))
97 return E_INVALIDARG;
100 /* See if the parent already has a child */
101 currentNode = pParent->FirstChild;
103 if (currentNode == NULL)
105 pParent->FirstChild = (WSDXML_NODE *)pChild;
107 else
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);
118 return S_OK;
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))
129 return E_INVALIDARG;
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;
139 else
141 /* Find the last sibling node and make the second element the next sibling */
142 while (1)
144 if (currentNode->Next == NULL)
146 currentNode->Next = (WSDXML_NODE *)pSecond;
147 break;
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);
160 return S_OK;
163 HRESULT WINAPI WSDXMLBuildAnyForSingleElement(WSDXML_NAME *pElementName, LPCWSTR pszText, WSDXML_ELEMENT **ppAny)
165 WSDXML_TEXT *child;
167 TRACE("(%p, %s, %p)\n", pElementName, debugstr_w(pszText), ppAny);
169 if ((pElementName == NULL) || ((pszText != NULL) && (lstrlenW(pszText) > WSD_MAX_TEXT_LENGTH)))
171 return E_INVALIDARG;
174 if (ppAny == NULL)
176 return E_POINTER;
179 *ppAny = WSDAllocateLinkedMemory(NULL, sizeof(WSDXML_ELEMENT));
181 if (*ppAny == NULL)
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;
196 if (pszText != NULL)
198 child = WSDAllocateLinkedMemory(*ppAny, sizeof(WSDXML_TEXT));
200 if (child == NULL)
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;
220 return S_OK;
223 HRESULT WINAPI WSDXMLCleanupElement(WSDXML_ELEMENT *pAny)
225 TRACE("(%p)\n", pAny);
227 if (pAny == NULL)
229 return E_INVALIDARG;
232 WSDFreeLinkedMemory(pAny);
233 return S_OK;
236 HRESULT WINAPI WSDXMLGetValueFromAny(const WCHAR *pszNamespace, const WCHAR *pszName, WSDXML_ELEMENT *pAny, LPCWSTR *ppszValue)
238 WSDXML_ELEMENT *element;
239 WSDXML_TEXT *text;
241 if (pAny == NULL)
242 return E_INVALIDARG;
244 if (ppszValue == NULL)
245 return E_POINTER;
247 if ((pszNamespace == NULL) || (pszName == NULL) || (lstrlenW(pszNamespace) > WSD_MAX_TEXT_LENGTH) || (lstrlenW(pszName) > WSD_MAX_TEXT_LENGTH))
248 return E_INVALIDARG;
250 element = pAny;
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))
260 return E_FAIL;
263 text = (WSDXML_TEXT *) element->FirstChild;
264 *ppszValue = (LPCWSTR) text->Text;
266 return S_OK;
270 element = (WSDXML_ELEMENT *) element->Node.Next;
273 return E_FAIL;
276 /* IWSDXMLContext implementation */
278 struct xmlNamespace
280 struct list entry;
281 WSDXML_NAMESPACE *namespace;
284 typedef struct IWSDXMLContextImpl
286 IWSDXMLContext IWSDXMLContext_iface;
287 LONG ref;
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;
305 return NULL;
308 static WSDXML_NAME *find_name(WSDXML_NAMESPACE *ns, LPCWSTR name)
310 int i;
312 for (i = 0; i < ns->NamesCount; i++)
314 if (lstrcmpW(ns->Names[i].LocalName, name) == 0)
316 return &ns->Names[i];
320 return NULL;
323 static WSDXML_NAME *add_name(WSDXML_NAMESPACE *ns, LPCWSTR name)
325 WSDXML_NAME *names;
326 WSDXML_NAME *newName;
327 int i;
329 names = WSDAllocateLinkedMemory(ns, sizeof(WSDXML_NAME) * (ns->NamesCount + 1));
331 if (names == NULL)
333 return NULL;
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);
350 ns->Names = names;
352 newName = &names[ns->NamesCount];
354 newName->LocalName = duplicate_string(names, name);
355 newName->Space = ns;
357 if (newName->LocalName == NULL)
359 return NULL;
362 ns->NamesCount++;
363 return newName;
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)
374 return FALSE;
378 return TRUE;
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);
398 return NULL;
401 static WSDXML_NAMESPACE *add_namespace(struct list *namespaces, LPCWSTR uri)
403 struct xmlNamespace *ns = WSDAllocateLinkedMemory(namespaces, sizeof(struct xmlNamespace));
405 if (ns == NULL)
407 return NULL;
410 ns->namespace = WSDAllocateLinkedMemory(ns, sizeof(WSDXML_NAMESPACE));
412 if (ns->namespace == NULL)
414 WSDFreeLinkedMemory(ns);
415 return NULL;
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);
424 return NULL;
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);
442 if (!ppv)
444 WARN("Invalid parameter\n");
445 return E_INVALIDARG;
448 *ppv = NULL;
450 if (IsEqualIID(riid, &IID_IUnknown) ||
451 IsEqualIID(riid, &IID_IWSDXMLContext))
453 *ppv = &This->IWSDXMLContext_iface;
455 else
457 WARN("Unknown IID %s\n", debugstr_guid(riid));
458 return E_NOINTERFACE;
461 IUnknown_AddRef((IUnknown*)*ppv);
462 return S_OK;
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);
471 return 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);
481 if (ref == 0)
483 WSDFreeLinkedMemory(This);
486 return ref;
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;
494 BOOL setNewPrefix;
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))
501 return E_INVALIDARG;
504 ns = find_namespace(This->namespaces, pszUri);
506 if (ns == NULL)
508 ns = add_namespace(This->namespaces, pszUri);
510 if (ns == NULL)
512 return E_OUTOFMEMORY;
516 setNewPrefix = (ns->PreferredPrefix == NULL);
518 if ((ns->PreferredPrefix == NULL) || (lstrcmpW(ns->PreferredPrefix, pszSuggestedPrefix) != 0))
520 newPrefix = pszSuggestedPrefix;
521 setNewPrefix = TRUE;
524 if (setNewPrefix)
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);
533 else
535 ns->PreferredPrefix = generate_namespace_prefix(This, ns, pszUri);
536 if (ns->PreferredPrefix == NULL)
538 return E_FAIL;
543 if (ppNamespace != NULL)
545 *ppNamespace = duplicate_namespace(NULL, ns);
547 if (*ppNamespace == NULL)
549 return E_OUTOFMEMORY;
553 return S_OK;
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;
560 WSDXML_NAME *name;
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))
566 return E_INVALIDARG;
569 ns = find_namespace(This->namespaces, pszUri);
571 if (ns == NULL)
573 /* The namespace doesn't exist, add it */
574 ns = add_namespace(This->namespaces, pszUri);
576 if (ns == NULL)
578 return E_OUTOFMEMORY;
581 ns->PreferredPrefix = generate_namespace_prefix(This, ns, pszUri);
582 if (ns->PreferredPrefix == NULL)
584 return E_FAIL;
588 name = find_name(ns, pszName);
590 if (name == NULL)
592 name = add_name(ns, pszName);
594 if (name == NULL)
596 return E_OUTOFMEMORY;
600 if (ppName != NULL)
602 *ppName = duplicate_name(NULL, name);
604 if (*ppName == NULL)
606 return E_OUTOFMEMORY;
610 return S_OK;
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);
616 return E_NOTIMPL;
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);
622 return E_NOTIMPL;
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");
645 return E_POINTER;
648 *ppContext = NULL;
650 obj = WSDAllocateLinkedMemory(NULL, sizeof(*obj));
652 if (!obj)
654 return E_OUTOFMEMORY;
657 obj->IWSDXMLContext_iface.lpVtbl = &xmlcontext_vtbl;
658 obj->ref = 1;
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);
673 return S_OK;
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;
689 return NULL;