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
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(winstring
);
29 #define HSTRING_REFERENCE_FLAG 1
37 struct hstring_private
39 struct hstring_header header
;
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
));
70 priv
->header
.flags
= 0;
71 priv
->buffer
= (LPWSTR
)(priv
+ 1);
72 priv
->header
.length
= len
;
74 priv
->buffer
[len
] = '\0';
80 /***********************************************************************
81 * WindowsCreateString (combase.@)
83 HRESULT WINAPI
WindowsCreateString(LPCWSTR ptr
, UINT32 len
,
86 struct hstring_private
*priv
;
88 TRACE("(%s, %u, %p)\n", debugstr_wn(ptr
, len
), len
, out
);
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
));
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
)
118 if (ptr
!= NULL
&& ptr
[len
] != '\0')
128 priv
->buffer
= (LPWSTR
)ptr
;
129 priv
->header
.length
= len
;
130 priv
->header
.flags
= HSTRING_REFERENCE_FLAG
;
132 *out
= (HSTRING
)priv
;
136 /***********************************************************************
137 * WindowsDeleteString (combase.@)
139 HRESULT WINAPI
WindowsDeleteString(HSTRING str
)
141 struct hstring_private
*priv
= impl_from_HSTRING(str
);
143 TRACE("(%p)\n", str
);
147 if (priv
->header
.flags
& HSTRING_REFERENCE_FLAG
)
149 if (InterlockedDecrement(&priv
->refcount
) == 0)
150 HeapFree(GetProcessHeap(), 0, priv
);
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
);
170 if (priv
->header
.flags
& HSTRING_REFERENCE_FLAG
)
171 return WindowsCreateString(priv
->buffer
, priv
->header
.length
, out
);
172 InterlockedIncrement(&priv
->refcount
);
177 /***********************************************************************
178 * WindowsPreallocateStringBuffer (combase.@)
180 HRESULT WINAPI
WindowsPreallocateStringBuffer(UINT32 len
, WCHAR
**outptr
,
183 struct hstring_private
*priv
;
186 TRACE("(%u, %p, %p)\n", len
, outptr
, out
);
188 if (outptr
== NULL
|| out
== NULL
)
192 *outptr
= (LPWSTR
)empty
;
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
;
205 /***********************************************************************
206 * WindowsDeleteStringBuffer (combase.@)
208 HRESULT WINAPI
WindowsDeleteStringBuffer(HSTRING_BUFFER buf
)
210 struct hstring_private
*priv
= NULL
;
212 TRACE("(%p)\n", 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
);
236 if (priv
->buffer
[priv
->header
.length
] != 0 || priv
->header
.flags
& HSTRING_REFERENCE_FLAG
|| priv
->refcount
!= 1)
238 *out
= (HSTRING
)priv
;
242 /***********************************************************************
243 * WindowsGetStringLen (combase.@)
245 UINT32 WINAPI
WindowsGetStringLen(HSTRING str
)
247 struct hstring_private
*priv
= impl_from_HSTRING(str
);
249 TRACE("(%p)\n", str
);
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
);
272 *len
= priv
->header
.length
;
276 /***********************************************************************
277 * WindowsStringHasEmbeddedNull (combase.@)
279 HRESULT WINAPI
WindowsStringHasEmbeddedNull(HSTRING str
, BOOL
*out
)
282 struct hstring_private
*priv
= impl_from_HSTRING(str
);
284 TRACE("(%p, %p)\n", str
, out
);
293 for (i
= 0; i
< priv
->header
.length
; i
++)
295 if (priv
->buffer
[i
] == '\0')
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
);
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
);
338 if (start
+ len
< start
||
339 start
+ len
> WindowsGetStringLen(str
))
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
);
363 return WindowsDuplicateString(str2
, out
);
365 return WindowsDuplicateString(str1
, out
);
366 if (!priv1
->header
.length
&& !priv2
->header
.length
)
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
));
379 /***********************************************************************
380 * WindowsIsStringEmpty (combase.@)
382 BOOL WINAPI
WindowsIsStringEmpty(HSTRING str
)
384 struct hstring_private
*priv
= impl_from_HSTRING(str
);
386 TRACE("(%p)\n", str
);
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
);
414 buf1
= priv1
->buffer
;
415 len1
= priv1
->header
.length
;
419 buf2
= priv2
->buffer
;
420 len2
= priv2
->header
.length
;
422 *res
= CompareStringOrdinal(buf1
, len1
, buf2
, len2
, FALSE
) - CSTR_EQUAL
;
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
);
435 TRACE("(%p, %p, %p)\n", str1
, str2
, out
);
437 if (!out
|| !str2
|| !priv2
->header
.length
)
444 for (start
= 0; start
< priv1
->header
.length
; start
++)
446 if (!wmemchr(priv2
->buffer
, priv1
->buffer
[start
], priv2
->header
.length
))
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
);
462 TRACE("(%p, %p, %p)\n", str1
, str2
, out
);
464 if (!out
|| !str2
|| !priv2
->header
.length
)
471 for (len
= priv1
->header
.length
; len
> 0; len
--)
473 if (!wmemchr(priv2
->buffer
, priv1
->buffer
[len
- 1], priv2
->header
.length
))
476 return (len
< priv1
->header
.length
) ? WindowsCreateString(priv1
->buffer
, len
, out
) :
477 WindowsDuplicateString(str1
, out
);