user32: Remove some misleading TODOs.
[wine.git] / dlls / combase / string.c
blobdfbe3689623461720acda08560128b9dd5f2a435
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>
21 #include "windows.h"
22 #include "winerror.h"
23 #include "hstring.h"
24 #include "wine/unicode.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(winstring);
29 struct hstring_private
31 LPWSTR buffer;
32 UINT32 length;
33 BOOL reference;
34 LONG refcount;
37 static const WCHAR empty[1];
39 C_ASSERT(sizeof(struct hstring_private) <= sizeof(HSTRING_HEADER));
41 static inline struct hstring_private *impl_from_HSTRING(HSTRING string)
43 return (struct hstring_private *)string;
46 static inline struct hstring_private *impl_from_HSTRING_HEADER(HSTRING_HEADER *header)
48 return (struct hstring_private *)header;
51 static inline struct hstring_private *impl_from_HSTRING_BUFFER(HSTRING_BUFFER buffer)
53 return (struct hstring_private *)buffer;
56 static BOOL alloc_string(UINT32 len, HSTRING *out)
58 struct hstring_private *priv;
59 priv = HeapAlloc(GetProcessHeap(), 0, sizeof(*priv) + (len + 1) * sizeof(*priv->buffer));
60 if (!priv)
61 return FALSE;
62 priv->buffer = (LPWSTR)(priv + 1);
63 priv->length = len;
64 priv->reference = FALSE;
65 priv->refcount = 1;
66 priv->buffer[len] = '\0';
67 *out = (HSTRING)priv;
68 return TRUE;
71 /***********************************************************************
72 * WindowsCreateString (combase.@)
74 HRESULT WINAPI WindowsCreateString(LPCWSTR ptr, UINT32 len,
75 HSTRING *out)
77 struct hstring_private *priv;
79 TRACE("(%s, %u, %p)\n", debugstr_wn(ptr, len), len, out);
81 if (out == NULL)
82 return E_INVALIDARG;
83 if (len == 0)
85 *out = NULL;
86 return S_OK;
88 if (ptr == NULL)
89 return E_POINTER;
90 if (!alloc_string(len, out))
91 return E_OUTOFMEMORY;
92 priv = impl_from_HSTRING(*out);
93 memcpy(priv->buffer, ptr, len * sizeof(*priv->buffer));
94 return S_OK;
97 /***********************************************************************
98 * WindowsCreateStringReference (combase.@)
100 HRESULT WINAPI WindowsCreateStringReference(LPCWSTR ptr, UINT32 len,
101 HSTRING_HEADER *header, HSTRING *out)
103 struct hstring_private *priv = impl_from_HSTRING_HEADER(header);
105 TRACE("(%s, %u, %p, %p)\n", debugstr_wn(ptr, len), len, header, out);
107 if (out == NULL || header == NULL)
108 return E_INVALIDARG;
109 if (ptr != NULL && ptr[len] != '\0')
110 return E_INVALIDARG;
111 if (len == 0)
113 *out = NULL;
114 return S_OK;
116 if (ptr == NULL)
117 return E_POINTER;
118 priv->buffer = (LPWSTR)ptr;
119 priv->length = len;
120 priv->reference = TRUE;
121 *out = (HSTRING)header;
122 return S_OK;
125 /***********************************************************************
126 * WindowsDeleteString (combase.@)
128 HRESULT WINAPI WindowsDeleteString(HSTRING str)
130 struct hstring_private *priv = impl_from_HSTRING(str);
132 TRACE("(%p)\n", str);
134 if (str == NULL)
135 return S_OK;
136 if (priv->reference)
137 return S_OK;
138 if (InterlockedDecrement(&priv->refcount) == 0)
139 HeapFree(GetProcessHeap(), 0, priv);
140 return S_OK;
143 /***********************************************************************
144 * WindowsDuplicateString (combase.@)
146 HRESULT WINAPI WindowsDuplicateString(HSTRING str, HSTRING *out)
148 struct hstring_private *priv = impl_from_HSTRING(str);
150 TRACE("(%p, %p)\n", str, out);
152 if (out == NULL)
153 return E_INVALIDARG;
154 if (str == NULL)
156 *out = NULL;
157 return S_OK;
159 if (priv->reference)
160 return WindowsCreateString(priv->buffer, priv->length, out);
161 InterlockedIncrement(&priv->refcount);
162 *out = str;
163 return S_OK;
166 /***********************************************************************
167 * WindowsPreallocateStringBuffer (combase.@)
169 HRESULT WINAPI WindowsPreallocateStringBuffer(UINT32 len, WCHAR **outptr,
170 HSTRING_BUFFER *out)
172 struct hstring_private *priv;
173 HSTRING str;
175 TRACE("(%u, %p, %p)\n", len, outptr, out);
177 if (outptr == NULL || out == NULL)
178 return E_POINTER;
179 if (len == 0)
181 *outptr = (LPWSTR)empty;
182 *out = NULL;
183 return S_OK;
186 if (!alloc_string(len, &str))
187 return E_OUTOFMEMORY;
188 priv = impl_from_HSTRING(str);
189 *outptr = priv->buffer;
190 *out = (HSTRING_BUFFER)str;
191 return S_OK;
194 /***********************************************************************
195 * WindowsDeleteStringBuffer (combase.@)
197 HRESULT WINAPI WindowsDeleteStringBuffer(HSTRING_BUFFER buf)
199 TRACE("(%p)\n", buf);
201 return WindowsDeleteString((HSTRING)buf);
204 /***********************************************************************
205 * WindowsPromoteStringBuffer (combase.@)
207 HRESULT WINAPI WindowsPromoteStringBuffer(HSTRING_BUFFER buf, HSTRING *out)
209 struct hstring_private *priv = impl_from_HSTRING_BUFFER(buf);
211 TRACE("(%p, %p)\n", buf, out);
213 if (out == NULL)
214 return E_POINTER;
215 if (buf == NULL)
217 *out = NULL;
218 return S_OK;
220 if (priv->buffer[priv->length] != 0 || priv->reference || priv->refcount != 1)
221 return E_INVALIDARG;
222 *out = (HSTRING)buf;
223 return S_OK;
226 /***********************************************************************
227 * WindowsGetStringLen (combase.@)
229 UINT32 WINAPI WindowsGetStringLen(HSTRING str)
231 struct hstring_private *priv = impl_from_HSTRING(str);
233 TRACE("(%p)\n", str);
235 if (str == NULL)
236 return 0;
237 return priv->length;
240 /***********************************************************************
241 * WindowsGetStringRawBuffer (combase.@)
243 LPCWSTR WINAPI WindowsGetStringRawBuffer(HSTRING str, UINT32 *len)
245 struct hstring_private *priv = impl_from_HSTRING(str);
247 TRACE("(%p, %p)\n", str, len);
249 if (str == NULL)
251 if (len)
252 *len = 0;
253 return empty;
255 if (len)
256 *len = priv->length;
257 return priv->buffer;
260 /***********************************************************************
261 * WindowsStringHasEmbeddedNull (combase.@)
263 HRESULT WINAPI WindowsStringHasEmbeddedNull(HSTRING str, BOOL *out)
265 UINT32 i;
266 struct hstring_private *priv = impl_from_HSTRING(str);
268 TRACE("(%p, %p)\n", str, out);
270 if (out == NULL)
271 return E_INVALIDARG;
272 if (str == NULL)
274 *out = FALSE;
275 return S_OK;
277 for (i = 0; i < priv->length; i++)
279 if (priv->buffer[i] == '\0')
281 *out = TRUE;
282 return S_OK;
285 *out = FALSE;
286 return S_OK;
289 /***********************************************************************
290 * WindowsSubstring (combase.@)
292 HRESULT WINAPI WindowsSubstring(HSTRING str, UINT32 start, HSTRING *out)
294 struct hstring_private *priv = impl_from_HSTRING(str);
295 UINT32 len = WindowsGetStringLen(str);
297 TRACE("(%p, %u, %p)\n", str, start, out);
299 if (out == NULL)
300 return E_INVALIDARG;
301 if (start > len)
302 return E_BOUNDS;
303 if (start == len)
305 *out = NULL;
306 return S_OK;
308 return WindowsCreateString(&priv->buffer[start], len - start, out);
311 /***********************************************************************
312 * WindowsSubstringWithSpecifiedLength (combase.@)
314 HRESULT WINAPI WindowsSubstringWithSpecifiedLength(HSTRING str, UINT32 start, UINT32 len, HSTRING *out)
316 struct hstring_private *priv = impl_from_HSTRING(str);
318 TRACE("(%p, %u, %u, %p)\n", str, start, len, out);
320 if (out == NULL)
321 return E_INVALIDARG;
322 if (start + len < start ||
323 start + len > WindowsGetStringLen(str))
324 return E_BOUNDS;
325 if (len == 0)
327 *out = NULL;
328 return S_OK;
330 return WindowsCreateString(&priv->buffer[start], len, out);
333 /***********************************************************************
334 * WindowsConcatString (combase.@)
336 HRESULT WINAPI WindowsConcatString(HSTRING str1, HSTRING str2, HSTRING *out)
338 struct hstring_private *priv1 = impl_from_HSTRING(str1);
339 struct hstring_private *priv2 = impl_from_HSTRING(str2);
340 struct hstring_private *priv;
342 TRACE("(%p, %p, %p)\n", str1, str2, out);
344 if (out == NULL)
345 return E_INVALIDARG;
346 if (str1 == NULL)
347 return WindowsDuplicateString(str2, out);
348 if (str2 == NULL)
349 return WindowsDuplicateString(str1, out);
350 if (!priv1->length && !priv2->length)
352 *out = NULL;
353 return S_OK;
355 if (!alloc_string(priv1->length + priv2->length, out))
356 return E_OUTOFMEMORY;
357 priv = impl_from_HSTRING(*out);
358 memcpy(priv->buffer, priv1->buffer, priv1->length * sizeof(*priv1->buffer));
359 memcpy(priv->buffer + priv1->length, priv2->buffer, priv2->length * sizeof(*priv2->buffer));
360 return S_OK;
363 /***********************************************************************
364 * WindowsIsStringEmpty (combase.@)
366 BOOL WINAPI WindowsIsStringEmpty(HSTRING str)
368 struct hstring_private *priv = impl_from_HSTRING(str);
370 TRACE("(%p)\n", str);
372 if (str == NULL)
373 return TRUE;
374 return priv->length == 0;
377 /***********************************************************************
378 * WindowsCompareStringOrdinal (combase.@)
380 HRESULT WINAPI WindowsCompareStringOrdinal(HSTRING str1, HSTRING str2, INT32 *res)
382 struct hstring_private *priv1 = impl_from_HSTRING(str1);
383 struct hstring_private *priv2 = impl_from_HSTRING(str2);
384 const WCHAR *buf1 = empty, *buf2 = empty;
385 UINT32 len1 = 0, len2 = 0;
387 TRACE("(%p, %p, %p)\n", str1, str2, res);
389 if (res == NULL)
390 return E_INVALIDARG;
391 if (str1 == str2)
393 *res = 0;
394 return S_OK;
396 if (str1)
398 buf1 = priv1->buffer;
399 len1 = priv1->length;
401 if (str2)
403 buf2 = priv2->buffer;
404 len2 = priv2->length;
406 *res = CompareStringOrdinal(buf1, len1, buf2, len2, FALSE) - CSTR_EQUAL;
407 return S_OK;
410 /***********************************************************************
411 * WindowsTrimStringStart (combase.@)
413 HRESULT WINAPI WindowsTrimStringStart(HSTRING str1, HSTRING str2, HSTRING *out)
415 struct hstring_private *priv1 = impl_from_HSTRING(str1);
416 struct hstring_private *priv2 = impl_from_HSTRING(str2);
417 UINT32 start;
419 TRACE("(%p, %p, %p)\n", str1, str2, out);
421 if (!out || !str2 || !priv2->length)
422 return E_INVALIDARG;
423 if (!str1)
425 *out = NULL;
426 return S_OK;
428 for (start = 0; start < priv1->length; start++)
430 if (!memchrW(priv2->buffer, priv1->buffer[start], priv2->length))
431 break;
433 return start ? WindowsCreateString(&priv1->buffer[start], priv1->length - start, out) :
434 WindowsDuplicateString(str1, out);
437 /***********************************************************************
438 * WindowsTrimStringEnd (combase.@)
440 HRESULT WINAPI WindowsTrimStringEnd(HSTRING str1, HSTRING str2, HSTRING *out)
442 struct hstring_private *priv1 = impl_from_HSTRING(str1);
443 struct hstring_private *priv2 = impl_from_HSTRING(str2);
444 UINT32 len;
446 TRACE("(%p, %p, %p)\n", str1, str2, out);
448 if (!out || !str2 || !priv2->length)
449 return E_INVALIDARG;
450 if (!str1)
452 *out = NULL;
453 return S_OK;
455 for (len = priv1->length; len > 0; len--)
457 if (!memchrW(priv2->buffer, priv1->buffer[len - 1], priv2->length))
458 break;
460 return (len < priv1->length) ? WindowsCreateString(priv1->buffer, len, out) :
461 WindowsDuplicateString(str1, out);