combase: Move length from hstring_private to hstring_header.
[wine.git] / dlls / combase / string.c
blob1e1e60db758daf1399f57dcf599f52519564deb9
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;
37 struct hstring_private
39 struct hstring_header header;
40 LPWSTR buffer;
41 LONG refcount;
44 static const WCHAR empty[1];
46 C_ASSERT(sizeof(struct hstring_header) <= sizeof(HSTRING_HEADER));
48 static inline struct hstring_private *impl_from_HSTRING(HSTRING string)
50 return (struct hstring_private *)string;
53 static inline struct hstring_private *impl_from_HSTRING_HEADER(HSTRING_HEADER *header)
55 return CONTAINING_RECORD(header, struct hstring_private, header);
58 static inline struct hstring_private *impl_from_HSTRING_BUFFER(HSTRING_BUFFER buffer)
60 return CONTAINING_RECORD(buffer, struct hstring_private, buffer);
63 static BOOL alloc_string(UINT32 len, HSTRING *out)
65 struct hstring_private *priv;
66 priv = HeapAlloc(GetProcessHeap(), 0, sizeof(*priv) + (len + 1) * sizeof(*priv->buffer));
67 if (!priv)
68 return FALSE;
70 priv->header.flags = 0;
71 priv->buffer = (LPWSTR)(priv + 1);
72 priv->header.length = len;
73 priv->refcount = 1;
74 priv->buffer[len] = '\0';
76 *out = (HSTRING)priv;
77 return TRUE;
80 /***********************************************************************
81 * WindowsCreateString (combase.@)
83 HRESULT WINAPI WindowsCreateString(LPCWSTR ptr, UINT32 len,
84 HSTRING *out)
86 struct hstring_private *priv;
88 TRACE("(%s, %u, %p)\n", debugstr_wn(ptr, len), len, out);
90 if (out == NULL)
91 return E_INVALIDARG;
92 if (len == 0)
94 *out = NULL;
95 return S_OK;
97 if (ptr == NULL)
98 return E_POINTER;
99 if (!alloc_string(len, out))
100 return E_OUTOFMEMORY;
101 priv = impl_from_HSTRING(*out);
102 memcpy(priv->buffer, ptr, len * sizeof(*priv->buffer));
103 return S_OK;
106 /***********************************************************************
107 * WindowsCreateStringReference (combase.@)
109 HRESULT WINAPI WindowsCreateStringReference(LPCWSTR ptr, UINT32 len,
110 HSTRING_HEADER *header, HSTRING *out)
112 struct hstring_private *priv = impl_from_HSTRING_HEADER(header);
114 TRACE("(%s, %u, %p, %p)\n", debugstr_wn(ptr, len), len, header, out);
116 if (out == NULL || header == NULL)
117 return E_INVALIDARG;
118 if (ptr != NULL && ptr[len] != '\0')
119 return E_INVALIDARG;
120 if (len == 0)
122 *out = NULL;
123 return S_OK;
125 if (ptr == NULL)
126 return E_POINTER;
128 priv->buffer = (LPWSTR)ptr;
129 priv->header.length = len;
130 priv->header.flags = HSTRING_REFERENCE_FLAG;
132 *out = (HSTRING)priv;
133 return S_OK;
136 /***********************************************************************
137 * WindowsDeleteString (combase.@)
139 HRESULT WINAPI WindowsDeleteString(HSTRING str)
141 struct hstring_private *priv = impl_from_HSTRING(str);
143 TRACE("(%p)\n", str);
145 if (str == NULL)
146 return S_OK;
147 if (priv->header.flags & HSTRING_REFERENCE_FLAG)
148 return S_OK;
149 if (InterlockedDecrement(&priv->refcount) == 0)
150 HeapFree(GetProcessHeap(), 0, priv);
151 return S_OK;
154 /***********************************************************************
155 * WindowsDuplicateString (combase.@)
157 HRESULT WINAPI WindowsDuplicateString(HSTRING str, HSTRING *out)
159 struct hstring_private *priv = impl_from_HSTRING(str);
161 TRACE("(%p, %p)\n", str, out);
163 if (out == NULL)
164 return E_INVALIDARG;
165 if (str == NULL)
167 *out = NULL;
168 return S_OK;
170 if (priv->header.flags & HSTRING_REFERENCE_FLAG)
171 return WindowsCreateString(priv->buffer, priv->header.length, out);
172 InterlockedIncrement(&priv->refcount);
173 *out = str;
174 return S_OK;
177 /***********************************************************************
178 * WindowsPreallocateStringBuffer (combase.@)
180 HRESULT WINAPI WindowsPreallocateStringBuffer(UINT32 len, WCHAR **outptr,
181 HSTRING_BUFFER *out)
183 struct hstring_private *priv;
184 HSTRING str;
186 TRACE("(%u, %p, %p)\n", len, outptr, out);
188 if (outptr == NULL || out == NULL)
189 return E_POINTER;
190 if (len == 0)
192 *outptr = (LPWSTR)empty;
193 *out = NULL;
194 return S_OK;
197 if (!alloc_string(len, &str))
198 return E_OUTOFMEMORY;
199 priv = impl_from_HSTRING(str);
200 *outptr = priv->buffer;
201 *out = (HSTRING_BUFFER)&priv->buffer;
202 return S_OK;
205 /***********************************************************************
206 * WindowsDeleteStringBuffer (combase.@)
208 HRESULT WINAPI WindowsDeleteStringBuffer(HSTRING_BUFFER buf)
210 struct hstring_private *priv = NULL;
212 TRACE("(%p)\n", buf);
214 if(buf)
215 priv = impl_from_HSTRING_BUFFER(buf);
217 return WindowsDeleteString((HSTRING)priv);
220 /***********************************************************************
221 * WindowsPromoteStringBuffer (combase.@)
223 HRESULT WINAPI WindowsPromoteStringBuffer(HSTRING_BUFFER buf, HSTRING *out)
225 struct hstring_private *priv = impl_from_HSTRING_BUFFER(buf);
227 TRACE("(%p, %p)\n", buf, out);
229 if (out == NULL)
230 return E_POINTER;
231 if (buf == NULL)
233 *out = NULL;
234 return S_OK;
236 if (priv->buffer[priv->header.length] != 0 || priv->header.flags & HSTRING_REFERENCE_FLAG || priv->refcount != 1)
237 return E_INVALIDARG;
238 *out = (HSTRING)priv;
239 return S_OK;
242 /***********************************************************************
243 * WindowsGetStringLen (combase.@)
245 UINT32 WINAPI WindowsGetStringLen(HSTRING str)
247 struct hstring_private *priv = impl_from_HSTRING(str);
249 TRACE("(%p)\n", str);
251 if (str == NULL)
252 return 0;
253 return priv->header.length;
256 /***********************************************************************
257 * WindowsGetStringRawBuffer (combase.@)
259 LPCWSTR WINAPI WindowsGetStringRawBuffer(HSTRING str, UINT32 *len)
261 struct hstring_private *priv = impl_from_HSTRING(str);
263 TRACE("(%p, %p)\n", str, len);
265 if (str == NULL)
267 if (len)
268 *len = 0;
269 return empty;
271 if (len)
272 *len = priv->header.length;
273 return priv->buffer;
276 /***********************************************************************
277 * WindowsStringHasEmbeddedNull (combase.@)
279 HRESULT WINAPI WindowsStringHasEmbeddedNull(HSTRING str, BOOL *out)
281 UINT32 i;
282 struct hstring_private *priv = impl_from_HSTRING(str);
284 TRACE("(%p, %p)\n", str, out);
286 if (out == NULL)
287 return E_INVALIDARG;
288 if (str == NULL)
290 *out = FALSE;
291 return S_OK;
293 for (i = 0; i < priv->header.length; i++)
295 if (priv->buffer[i] == '\0')
297 *out = TRUE;
298 return S_OK;
301 *out = FALSE;
302 return S_OK;
305 /***********************************************************************
306 * WindowsSubstring (combase.@)
308 HRESULT WINAPI WindowsSubstring(HSTRING str, UINT32 start, HSTRING *out)
310 struct hstring_private *priv = impl_from_HSTRING(str);
311 UINT32 len = WindowsGetStringLen(str);
313 TRACE("(%p, %u, %p)\n", str, start, out);
315 if (out == NULL)
316 return E_INVALIDARG;
317 if (start > len)
318 return E_BOUNDS;
319 if (start == len)
321 *out = NULL;
322 return S_OK;
324 return WindowsCreateString(&priv->buffer[start], len - start, out);
327 /***********************************************************************
328 * WindowsSubstringWithSpecifiedLength (combase.@)
330 HRESULT WINAPI WindowsSubstringWithSpecifiedLength(HSTRING str, UINT32 start, UINT32 len, HSTRING *out)
332 struct hstring_private *priv = impl_from_HSTRING(str);
334 TRACE("(%p, %u, %u, %p)\n", str, start, len, out);
336 if (out == NULL)
337 return E_INVALIDARG;
338 if (start + len < start ||
339 start + len > WindowsGetStringLen(str))
340 return E_BOUNDS;
341 if (len == 0)
343 *out = NULL;
344 return S_OK;
346 return WindowsCreateString(&priv->buffer[start], len, out);
349 /***********************************************************************
350 * WindowsConcatString (combase.@)
352 HRESULT WINAPI WindowsConcatString(HSTRING str1, HSTRING str2, HSTRING *out)
354 struct hstring_private *priv1 = impl_from_HSTRING(str1);
355 struct hstring_private *priv2 = impl_from_HSTRING(str2);
356 struct hstring_private *priv;
358 TRACE("(%p, %p, %p)\n", str1, str2, out);
360 if (out == NULL)
361 return E_INVALIDARG;
362 if (str1 == NULL)
363 return WindowsDuplicateString(str2, out);
364 if (str2 == NULL)
365 return WindowsDuplicateString(str1, out);
366 if (!priv1->header.length && !priv2->header.length)
368 *out = NULL;
369 return S_OK;
371 if (!alloc_string(priv1->header.length + priv2->header.length, out))
372 return E_OUTOFMEMORY;
373 priv = impl_from_HSTRING(*out);
374 memcpy(priv->buffer, priv1->buffer, priv1->header.length * sizeof(*priv1->buffer));
375 memcpy(priv->buffer + priv1->header.length, priv2->buffer, priv2->header.length * sizeof(*priv2->buffer));
376 return S_OK;
379 /***********************************************************************
380 * WindowsIsStringEmpty (combase.@)
382 BOOL WINAPI WindowsIsStringEmpty(HSTRING str)
384 struct hstring_private *priv = impl_from_HSTRING(str);
386 TRACE("(%p)\n", str);
388 if (str == NULL)
389 return TRUE;
390 return priv->header.length == 0;
393 /***********************************************************************
394 * WindowsCompareStringOrdinal (combase.@)
396 HRESULT WINAPI WindowsCompareStringOrdinal(HSTRING str1, HSTRING str2, INT32 *res)
398 struct hstring_private *priv1 = impl_from_HSTRING(str1);
399 struct hstring_private *priv2 = impl_from_HSTRING(str2);
400 const WCHAR *buf1 = empty, *buf2 = empty;
401 UINT32 len1 = 0, len2 = 0;
403 TRACE("(%p, %p, %p)\n", str1, str2, res);
405 if (res == NULL)
406 return E_INVALIDARG;
407 if (str1 == str2)
409 *res = 0;
410 return S_OK;
412 if (str1)
414 buf1 = priv1->buffer;
415 len1 = priv1->header.length;
417 if (str2)
419 buf2 = priv2->buffer;
420 len2 = priv2->header.length;
422 *res = CompareStringOrdinal(buf1, len1, buf2, len2, FALSE) - CSTR_EQUAL;
423 return S_OK;
426 /***********************************************************************
427 * WindowsTrimStringStart (combase.@)
429 HRESULT WINAPI WindowsTrimStringStart(HSTRING str1, HSTRING str2, HSTRING *out)
431 struct hstring_private *priv1 = impl_from_HSTRING(str1);
432 struct hstring_private *priv2 = impl_from_HSTRING(str2);
433 UINT32 start;
435 TRACE("(%p, %p, %p)\n", str1, str2, out);
437 if (!out || !str2 || !priv2->header.length)
438 return E_INVALIDARG;
439 if (!str1)
441 *out = NULL;
442 return S_OK;
444 for (start = 0; start < priv1->header.length; start++)
446 if (!wmemchr(priv2->buffer, priv1->buffer[start], priv2->header.length))
447 break;
449 return start ? WindowsCreateString(&priv1->buffer[start], priv1->header.length - start, out) :
450 WindowsDuplicateString(str1, out);
453 /***********************************************************************
454 * WindowsTrimStringEnd (combase.@)
456 HRESULT WINAPI WindowsTrimStringEnd(HSTRING str1, HSTRING str2, HSTRING *out)
458 struct hstring_private *priv1 = impl_from_HSTRING(str1);
459 struct hstring_private *priv2 = impl_from_HSTRING(str2);
460 UINT32 len;
462 TRACE("(%p, %p, %p)\n", str1, str2, out);
464 if (!out || !str2 || !priv2->header.length)
465 return E_INVALIDARG;
466 if (!str1)
468 *out = NULL;
469 return S_OK;
471 for (len = priv1->header.length; len > 0; len--)
473 if (!wmemchr(priv2->buffer, priv1->buffer[len - 1], priv2->header.length))
474 break;
476 return (len < priv1->header.length) ? WindowsCreateString(priv1->buffer, len, out) :
477 WindowsDuplicateString(str1, out);