blob: dfbe3689623461720acda08560128b9dd5f2a435 [file] [log] [blame]
/*
* Copyright 2014 Martin Storsjo
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <string.h>
#include "windows.h"
#include "winerror.h"
#include "hstring.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winstring);
struct hstring_private
{
LPWSTR buffer;
UINT32 length;
BOOL reference;
LONG refcount;
};
static const WCHAR empty[1];
C_ASSERT(sizeof(struct hstring_private) <= sizeof(HSTRING_HEADER));
static inline struct hstring_private *impl_from_HSTRING(HSTRING string)
{
return (struct hstring_private *)string;
}
static inline struct hstring_private *impl_from_HSTRING_HEADER(HSTRING_HEADER *header)
{
return (struct hstring_private *)header;
}
static inline struct hstring_private *impl_from_HSTRING_BUFFER(HSTRING_BUFFER buffer)
{
return (struct hstring_private *)buffer;
}
static BOOL alloc_string(UINT32 len, HSTRING *out)
{
struct hstring_private *priv;
priv = HeapAlloc(GetProcessHeap(), 0, sizeof(*priv) + (len + 1) * sizeof(*priv->buffer));
if (!priv)
return FALSE;
priv->buffer = (LPWSTR)(priv + 1);
priv->length = len;
priv->reference = FALSE;
priv->refcount = 1;
priv->buffer[len] = '\0';
*out = (HSTRING)priv;
return TRUE;
}
/***********************************************************************
* WindowsCreateString (combase.@)
*/
HRESULT WINAPI WindowsCreateString(LPCWSTR ptr, UINT32 len,
HSTRING *out)
{
struct hstring_private *priv;
TRACE("(%s, %u, %p)\n", debugstr_wn(ptr, len), len, out);
if (out == NULL)
return E_INVALIDARG;
if (len == 0)
{
*out = NULL;
return S_OK;
}
if (ptr == NULL)
return E_POINTER;
if (!alloc_string(len, out))
return E_OUTOFMEMORY;
priv = impl_from_HSTRING(*out);
memcpy(priv->buffer, ptr, len * sizeof(*priv->buffer));
return S_OK;
}
/***********************************************************************
* WindowsCreateStringReference (combase.@)
*/
HRESULT WINAPI WindowsCreateStringReference(LPCWSTR ptr, UINT32 len,
HSTRING_HEADER *header, HSTRING *out)
{
struct hstring_private *priv = impl_from_HSTRING_HEADER(header);
TRACE("(%s, %u, %p, %p)\n", debugstr_wn(ptr, len), len, header, out);
if (out == NULL || header == NULL)
return E_INVALIDARG;
if (ptr != NULL && ptr[len] != '\0')
return E_INVALIDARG;
if (len == 0)
{
*out = NULL;
return S_OK;
}
if (ptr == NULL)
return E_POINTER;
priv->buffer = (LPWSTR)ptr;
priv->length = len;
priv->reference = TRUE;
*out = (HSTRING)header;
return S_OK;
}
/***********************************************************************
* WindowsDeleteString (combase.@)
*/
HRESULT WINAPI WindowsDeleteString(HSTRING str)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p)\n", str);
if (str == NULL)
return S_OK;
if (priv->reference)
return S_OK;
if (InterlockedDecrement(&priv->refcount) == 0)
HeapFree(GetProcessHeap(), 0, priv);
return S_OK;
}
/***********************************************************************
* WindowsDuplicateString (combase.@)
*/
HRESULT WINAPI WindowsDuplicateString(HSTRING str, HSTRING *out)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p, %p)\n", str, out);
if (out == NULL)
return E_INVALIDARG;
if (str == NULL)
{
*out = NULL;
return S_OK;
}
if (priv->reference)
return WindowsCreateString(priv->buffer, priv->length, out);
InterlockedIncrement(&priv->refcount);
*out = str;
return S_OK;
}
/***********************************************************************
* WindowsPreallocateStringBuffer (combase.@)
*/
HRESULT WINAPI WindowsPreallocateStringBuffer(UINT32 len, WCHAR **outptr,
HSTRING_BUFFER *out)
{
struct hstring_private *priv;
HSTRING str;
TRACE("(%u, %p, %p)\n", len, outptr, out);
if (outptr == NULL || out == NULL)
return E_POINTER;
if (len == 0)
{
*outptr = (LPWSTR)empty;
*out = NULL;
return S_OK;
}
if (!alloc_string(len, &str))
return E_OUTOFMEMORY;
priv = impl_from_HSTRING(str);
*outptr = priv->buffer;
*out = (HSTRING_BUFFER)str;
return S_OK;
}
/***********************************************************************
* WindowsDeleteStringBuffer (combase.@)
*/
HRESULT WINAPI WindowsDeleteStringBuffer(HSTRING_BUFFER buf)
{
TRACE("(%p)\n", buf);
return WindowsDeleteString((HSTRING)buf);
}
/***********************************************************************
* WindowsPromoteStringBuffer (combase.@)
*/
HRESULT WINAPI WindowsPromoteStringBuffer(HSTRING_BUFFER buf, HSTRING *out)
{
struct hstring_private *priv = impl_from_HSTRING_BUFFER(buf);
TRACE("(%p, %p)\n", buf, out);
if (out == NULL)
return E_POINTER;
if (buf == NULL)
{
*out = NULL;
return S_OK;
}
if (priv->buffer[priv->length] != 0 || priv->reference || priv->refcount != 1)
return E_INVALIDARG;
*out = (HSTRING)buf;
return S_OK;
}
/***********************************************************************
* WindowsGetStringLen (combase.@)
*/
UINT32 WINAPI WindowsGetStringLen(HSTRING str)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p)\n", str);
if (str == NULL)
return 0;
return priv->length;
}
/***********************************************************************
* WindowsGetStringRawBuffer (combase.@)
*/
LPCWSTR WINAPI WindowsGetStringRawBuffer(HSTRING str, UINT32 *len)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p, %p)\n", str, len);
if (str == NULL)
{
if (len)
*len = 0;
return empty;
}
if (len)
*len = priv->length;
return priv->buffer;
}
/***********************************************************************
* WindowsStringHasEmbeddedNull (combase.@)
*/
HRESULT WINAPI WindowsStringHasEmbeddedNull(HSTRING str, BOOL *out)
{
UINT32 i;
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p, %p)\n", str, out);
if (out == NULL)
return E_INVALIDARG;
if (str == NULL)
{
*out = FALSE;
return S_OK;
}
for (i = 0; i < priv->length; i++)
{
if (priv->buffer[i] == '\0')
{
*out = TRUE;
return S_OK;
}
}
*out = FALSE;
return S_OK;
}
/***********************************************************************
* WindowsSubstring (combase.@)
*/
HRESULT WINAPI WindowsSubstring(HSTRING str, UINT32 start, HSTRING *out)
{
struct hstring_private *priv = impl_from_HSTRING(str);
UINT32 len = WindowsGetStringLen(str);
TRACE("(%p, %u, %p)\n", str, start, out);
if (out == NULL)
return E_INVALIDARG;
if (start > len)
return E_BOUNDS;
if (start == len)
{
*out = NULL;
return S_OK;
}
return WindowsCreateString(&priv->buffer[start], len - start, out);
}
/***********************************************************************
* WindowsSubstringWithSpecifiedLength (combase.@)
*/
HRESULT WINAPI WindowsSubstringWithSpecifiedLength(HSTRING str, UINT32 start, UINT32 len, HSTRING *out)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p, %u, %u, %p)\n", str, start, len, out);
if (out == NULL)
return E_INVALIDARG;
if (start + len < start ||
start + len > WindowsGetStringLen(str))
return E_BOUNDS;
if (len == 0)
{
*out = NULL;
return S_OK;
}
return WindowsCreateString(&priv->buffer[start], len, out);
}
/***********************************************************************
* WindowsConcatString (combase.@)
*/
HRESULT WINAPI WindowsConcatString(HSTRING str1, HSTRING str2, HSTRING *out)
{
struct hstring_private *priv1 = impl_from_HSTRING(str1);
struct hstring_private *priv2 = impl_from_HSTRING(str2);
struct hstring_private *priv;
TRACE("(%p, %p, %p)\n", str1, str2, out);
if (out == NULL)
return E_INVALIDARG;
if (str1 == NULL)
return WindowsDuplicateString(str2, out);
if (str2 == NULL)
return WindowsDuplicateString(str1, out);
if (!priv1->length && !priv2->length)
{
*out = NULL;
return S_OK;
}
if (!alloc_string(priv1->length + priv2->length, out))
return E_OUTOFMEMORY;
priv = impl_from_HSTRING(*out);
memcpy(priv->buffer, priv1->buffer, priv1->length * sizeof(*priv1->buffer));
memcpy(priv->buffer + priv1->length, priv2->buffer, priv2->length * sizeof(*priv2->buffer));
return S_OK;
}
/***********************************************************************
* WindowsIsStringEmpty (combase.@)
*/
BOOL WINAPI WindowsIsStringEmpty(HSTRING str)
{
struct hstring_private *priv = impl_from_HSTRING(str);
TRACE("(%p)\n", str);
if (str == NULL)
return TRUE;
return priv->length == 0;
}
/***********************************************************************
* WindowsCompareStringOrdinal (combase.@)
*/
HRESULT WINAPI WindowsCompareStringOrdinal(HSTRING str1, HSTRING str2, INT32 *res)
{
struct hstring_private *priv1 = impl_from_HSTRING(str1);
struct hstring_private *priv2 = impl_from_HSTRING(str2);
const WCHAR *buf1 = empty, *buf2 = empty;
UINT32 len1 = 0, len2 = 0;
TRACE("(%p, %p, %p)\n", str1, str2, res);
if (res == NULL)
return E_INVALIDARG;
if (str1 == str2)
{
*res = 0;
return S_OK;
}
if (str1)
{
buf1 = priv1->buffer;
len1 = priv1->length;
}
if (str2)
{
buf2 = priv2->buffer;
len2 = priv2->length;
}
*res = CompareStringOrdinal(buf1, len1, buf2, len2, FALSE) - CSTR_EQUAL;
return S_OK;
}
/***********************************************************************
* WindowsTrimStringStart (combase.@)
*/
HRESULT WINAPI WindowsTrimStringStart(HSTRING str1, HSTRING str2, HSTRING *out)
{
struct hstring_private *priv1 = impl_from_HSTRING(str1);
struct hstring_private *priv2 = impl_from_HSTRING(str2);
UINT32 start;
TRACE("(%p, %p, %p)\n", str1, str2, out);
if (!out || !str2 || !priv2->length)
return E_INVALIDARG;
if (!str1)
{
*out = NULL;
return S_OK;
}
for (start = 0; start < priv1->length; start++)
{
if (!memchrW(priv2->buffer, priv1->buffer[start], priv2->length))
break;
}
return start ? WindowsCreateString(&priv1->buffer[start], priv1->length - start, out) :
WindowsDuplicateString(str1, out);
}
/***********************************************************************
* WindowsTrimStringEnd (combase.@)
*/
HRESULT WINAPI WindowsTrimStringEnd(HSTRING str1, HSTRING str2, HSTRING *out)
{
struct hstring_private *priv1 = impl_from_HSTRING(str1);
struct hstring_private *priv2 = impl_from_HSTRING(str2);
UINT32 len;
TRACE("(%p, %p, %p)\n", str1, str2, out);
if (!out || !str2 || !priv2->length)
return E_INVALIDARG;
if (!str1)
{
*out = NULL;
return S_OK;
}
for (len = priv1->length; len > 0; len--)
{
if (!memchrW(priv2->buffer, priv1->buffer[len - 1], priv2->length))
break;
}
return (len < priv1->length) ? WindowsCreateString(priv1->buffer, len, out) :
WindowsDuplicateString(str1, out);
}