win32u: Respect per-monitor thread dpi awareness when getting window from point.
[wine.git] / dlls / combase / string.c
blob1345870cf2f427dfccffea8de1509b3259b2f411
1 /*
2 * Copyright 2014 Martin Storsjo
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <string.h>
20 #include <wchar.h>
22 #include "windows.h"
23 #include "winerror.h"
24 #include "hstring.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(winstring);
29 #define HSTRING_REFERENCE_FLAG 1
31 struct hstring_header
33 UINT32 flags;
34 UINT32 length;
35 UINT32 padding1;
36 UINT32 padding2;
37 const WCHAR *str;
40 struct hstring_private
42 struct hstring_header header;
43 LONG refcount;
44 WCHAR buffer[1];
47 static const WCHAR empty[1];
49 C_ASSERT(sizeof(struct hstring_header) <= sizeof(HSTRING_HEADER));
51 static inline struct hstring_private *impl_from_HSTRING(HSTRING string)
53 return (struct hstring_private *)string;
56 static inline struct hstring_private *impl_from_HSTRING_HEADER(HSTRING_HEADER *header)
58 return CONTAINING_RECORD(header, struct hstring_private, header);
61 static inline struct hstring_private *impl_from_HSTRING_BUFFER(HSTRING_BUFFER buffer)
63 return CONTAINING_RECORD(buffer, struct hstring_private, buffer);
66 static BOOL alloc_string(UINT32 len, HSTRING *out)
68 struct hstring_private *priv;
69 priv = malloc(offsetof(struct hstring_private, buffer[len+1]));
70 if (!priv)
71 return FALSE;
73 priv->header.flags = 0;
74 priv->header.length = len;
75 priv->header.str = priv->buffer;
77 priv->refcount = 1;
78 priv->buffer[len] = '\0';
80 *out = (HSTRING)priv;
81 return TRUE;
84 /***********************************************************************
85 * WindowsCreateString (combase.@)
87 HRESULT WINAPI WindowsCreateString(LPCWSTR ptr, UINT32 len,
88 HSTRING *out)
90 struct hstring_private *priv;
92 TRACE("(%s, %u, %p)\n", debugstr_wn(ptr, len), len, out);
94 if (out == NULL)
95 return E_INVALIDARG;
96 if (len == 0)
98 *out = NULL;
99 return S_OK;
101 if (ptr == NULL)
102 return E_POINTER;
103 if (!alloc_string(len, out))
104 return E_OUTOFMEMORY;
105 priv = impl_from_HSTRING(*out);
106 memcpy(priv->buffer, ptr, len * sizeof(*priv->buffer));
107 return S_OK;
110 /***********************************************************************
111 * WindowsCreateStringReference (combase.@)
113 HRESULT WINAPI WindowsCreateStringReference(LPCWSTR ptr, UINT32 len,
114 HSTRING_HEADER *header, HSTRING *out)
116 struct hstring_private *priv = impl_from_HSTRING_HEADER(header);
118 TRACE("(%s, %u, %p, %p)\n", debugstr_wn(ptr, len), len, header, out);
120 if (out == NULL || header == NULL)
121 return E_INVALIDARG;
122 if (ptr != NULL && ptr[len] != '\0')
123 return E_INVALIDARG;
124 if (len == 0)
126 *out = NULL;
127 return S_OK;
129 if (ptr == NULL)
130 return E_POINTER;
132 priv->header.str = ptr;
133 priv->header.length = len;
134 priv->header.flags = HSTRING_REFERENCE_FLAG;
136 *out = (HSTRING)priv;
137 return S_OK;
140 /***********************************************************************
141 * WindowsDeleteString (combase.@)
143 HRESULT WINAPI WindowsDeleteString(HSTRING str)
145 struct hstring_private *priv = impl_from_HSTRING(str);
147 TRACE("(%p)\n", str);
149 if (str == NULL)
150 return S_OK;
151 if (priv->header.flags & HSTRING_REFERENCE_FLAG)
152 return S_OK;
153 if (InterlockedDecrement(&priv->refcount) == 0)
154 free(priv);
155 return S_OK;
158 /***********************************************************************
159 * WindowsDuplicateString (combase.@)
161 HRESULT WINAPI WindowsDuplicateString(HSTRING str, HSTRING *out)
163 struct hstring_private *priv = impl_from_HSTRING(str);
165 TRACE("(%p, %p)\n", str, out);
167 if (out == NULL)
168 return E_INVALIDARG;
169 if (str == NULL)
171 *out = NULL;
172 return S_OK;
174 if (priv->header.flags & HSTRING_REFERENCE_FLAG)
175 return WindowsCreateString(priv->header.str, priv->header.length, out);
176 InterlockedIncrement(&priv->refcount);
177 *out = str;
178 return S_OK;
181 /***********************************************************************
182 * WindowsPreallocateStringBuffer (combase.@)
184 HRESULT WINAPI WindowsPreallocateStringBuffer(UINT32 len, WCHAR **outptr,
185 HSTRING_BUFFER *out)
187 struct hstring_private *priv;
188 HSTRING str;
190 TRACE("(%u, %p, %p)\n", len, outptr, out);
192 if (outptr == NULL || out == NULL)
193 return E_POINTER;
194 if (len == 0)
196 *outptr = (LPWSTR)empty;
197 *out = NULL;
198 return S_OK;
201 if (!alloc_string(len, &str))
202 return E_OUTOFMEMORY;
203 priv = impl_from_HSTRING(str);
204 *outptr = priv->buffer;
205 *out = (HSTRING_BUFFER)&priv->buffer;
206 return S_OK;
209 /***********************************************************************
210 * WindowsDeleteStringBuffer (combase.@)
212 HRESULT WINAPI WindowsDeleteStringBuffer(HSTRING_BUFFER buf)
214 struct hstring_private *priv = NULL;
216 TRACE("(%p)\n", buf);
218 if(buf)
219 priv = impl_from_HSTRING_BUFFER(buf);
221 return WindowsDeleteString((HSTRING)priv);
224 /***********************************************************************
225 * WindowsPromoteStringBuffer (combase.@)
227 HRESULT WINAPI WindowsPromoteStringBuffer(HSTRING_BUFFER buf, HSTRING *out)
229 struct hstring_private *priv = impl_from_HSTRING_BUFFER(buf);
231 TRACE("(%p, %p)\n", buf, out);
233 if (out == NULL)
234 return E_POINTER;
235 if (buf == NULL)
237 *out = NULL;
238 return S_OK;
240 if (priv->buffer[priv->header.length] != 0 || priv->header.flags & HSTRING_REFERENCE_FLAG || priv->refcount != 1)
241 return E_INVALIDARG;
242 *out = (HSTRING)priv;
243 return S_OK;
246 /***********************************************************************
247 * WindowsGetStringLen (combase.@)
249 UINT32 WINAPI WindowsGetStringLen(HSTRING str)
251 struct hstring_private *priv = impl_from_HSTRING(str);
253 TRACE("(%p)\n", str);
255 if (str == NULL)
256 return 0;
257 return priv->header.length;
260 /***********************************************************************
261 * WindowsGetStringRawBuffer (combase.@)
263 LPCWSTR WINAPI WindowsGetStringRawBuffer(HSTRING str, UINT32 *len)
265 struct hstring_private *priv = impl_from_HSTRING(str);
267 TRACE("(%p, %p)\n", str, len);
269 if (str == NULL)
271 if (len)
272 *len = 0;
273 return empty;
275 if (len)
276 *len = priv->header.length;
277 return priv->header.str;
280 /***********************************************************************
281 * WindowsStringHasEmbeddedNull (combase.@)
283 HRESULT WINAPI WindowsStringHasEmbeddedNull(HSTRING str, BOOL *out)
285 UINT32 i;
286 struct hstring_private *priv = impl_from_HSTRING(str);
288 TRACE("(%p, %p)\n", str, out);
290 if (out == NULL)
291 return E_INVALIDARG;
292 if (str == NULL)
294 *out = FALSE;
295 return S_OK;
297 for (i = 0; i < priv->header.length; i++)
299 if (priv->header.str[i] == '\0')
301 *out = TRUE;
302 return S_OK;
305 *out = FALSE;
306 return S_OK;
309 /***********************************************************************
310 * WindowsSubstring (combase.@)
312 HRESULT WINAPI WindowsSubstring(HSTRING str, UINT32 start, HSTRING *out)
314 struct hstring_private *priv = impl_from_HSTRING(str);
315 UINT32 len = WindowsGetStringLen(str);
317 TRACE("(%p, %u, %p)\n", str, start, out);
319 if (out == NULL)
320 return E_INVALIDARG;
321 if (start > len)
322 return E_BOUNDS;
323 if (start == len)
325 *out = NULL;
326 return S_OK;
328 return WindowsCreateString(&priv->header.str[start], len - start, out);
331 /***********************************************************************
332 * WindowsSubstringWithSpecifiedLength (combase.@)
334 HRESULT WINAPI WindowsSubstringWithSpecifiedLength(HSTRING str, UINT32 start, UINT32 len, HSTRING *out)
336 struct hstring_private *priv = impl_from_HSTRING(str);
338 TRACE("(%p, %u, %u, %p)\n", str, start, len, out);
340 if (out == NULL)
341 return E_INVALIDARG;
342 if (start + len < start ||
343 start + len > WindowsGetStringLen(str))
344 return E_BOUNDS;
345 if (len == 0)
347 *out = NULL;
348 return S_OK;
350 return WindowsCreateString(&priv->header.str[start], len, out);
353 /***********************************************************************
354 * WindowsConcatString (combase.@)
356 HRESULT WINAPI WindowsConcatString(HSTRING str1, HSTRING str2, HSTRING *out)
358 struct hstring_private *priv1 = impl_from_HSTRING(str1);
359 struct hstring_private *priv2 = impl_from_HSTRING(str2);
360 struct hstring_private *priv;
362 TRACE("(%p, %p, %p)\n", str1, str2, out);
364 if (out == NULL)
365 return E_INVALIDARG;
366 if (str1 == NULL)
367 return WindowsDuplicateString(str2, out);
368 if (str2 == NULL)
369 return WindowsDuplicateString(str1, out);
370 if (!priv1->header.length && !priv2->header.length)
372 *out = NULL;
373 return S_OK;
375 if (!alloc_string(priv1->header.length + priv2->header.length, out))
376 return E_OUTOFMEMORY;
377 priv = impl_from_HSTRING(*out);
378 memcpy(priv->buffer, priv1->header.str, priv1->header.length * sizeof(*priv1->buffer));
379 memcpy(priv->buffer + priv1->header.length, priv2->header.str, priv2->header.length * sizeof(*priv2->buffer));
380 return S_OK;
383 /***********************************************************************
384 * WindowsIsStringEmpty (combase.@)
386 BOOL WINAPI WindowsIsStringEmpty(HSTRING str)
388 struct hstring_private *priv = impl_from_HSTRING(str);
390 TRACE("(%p)\n", str);
392 if (str == NULL)
393 return TRUE;
394 return priv->header.length == 0;
397 /***********************************************************************
398 * WindowsCompareStringOrdinal (combase.@)
400 HRESULT WINAPI WindowsCompareStringOrdinal(HSTRING str1, HSTRING str2, INT32 *res)
402 struct hstring_private *priv1 = impl_from_HSTRING(str1);
403 struct hstring_private *priv2 = impl_from_HSTRING(str2);
404 const WCHAR *buf1 = empty, *buf2 = empty;
405 UINT32 len1 = 0, len2 = 0;
407 TRACE("(%p, %p, %p)\n", str1, str2, res);
409 if (res == NULL)
410 return E_INVALIDARG;
411 if (str1 == str2)
413 *res = 0;
414 return S_OK;
416 if (str1)
418 buf1 = priv1->header.str;
419 len1 = priv1->header.length;
421 if (str2)
423 buf2 = priv2->header.str;
424 len2 = priv2->header.length;
426 *res = CompareStringOrdinal(buf1, len1, buf2, len2, FALSE) - CSTR_EQUAL;
427 return S_OK;
430 /***********************************************************************
431 * WindowsTrimStringStart (combase.@)
433 HRESULT WINAPI WindowsTrimStringStart(HSTRING str1, HSTRING str2, HSTRING *out)
435 struct hstring_private *priv1 = impl_from_HSTRING(str1);
436 struct hstring_private *priv2 = impl_from_HSTRING(str2);
437 UINT32 start;
439 TRACE("(%p, %p, %p)\n", str1, str2, out);
441 if (!out || !str2 || !priv2->header.length)
442 return E_INVALIDARG;
443 if (!str1)
445 *out = NULL;
446 return S_OK;
448 for (start = 0; start < priv1->header.length; start++)
450 if (!wmemchr(priv2->header.str, priv1->header.str[start], priv2->header.length))
451 break;
453 return start ? WindowsCreateString(&priv1->header.str[start], priv1->header.length - start, out) :
454 WindowsDuplicateString(str1, out);
457 /***********************************************************************
458 * WindowsTrimStringEnd (combase.@)
460 HRESULT WINAPI WindowsTrimStringEnd(HSTRING str1, HSTRING str2, HSTRING *out)
462 struct hstring_private *priv1 = impl_from_HSTRING(str1);
463 struct hstring_private *priv2 = impl_from_HSTRING(str2);
464 UINT32 len;
466 TRACE("(%p, %p, %p)\n", str1, str2, out);
468 if (!out || !str2 || !priv2->header.length)
469 return E_INVALIDARG;
470 if (!str1)
472 *out = NULL;
473 return S_OK;
475 for (len = priv1->header.length; len > 0; len--)
477 if (!wmemchr(priv2->header.str, priv1->header.str[len - 1], priv2->header.length))
478 break;
480 return (len < priv1->header.length) ? WindowsCreateString(priv1->header.str, len, out) :
481 WindowsDuplicateString(str1, out);