blob: 5048377ab099eefd02c112fc07935c524eb913f1 [file]
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
/*++
Module Name:
misc/bstr.cpp
Abstract:
Implementation of bstr related functionality
--*/
#include "pal/palinternal.h"
// Redefining here to not have to pull in all of palrt.h in order to get intsafe
#define S_OK ((HRESULT)0x00000000L)
#define E_INVALIDARG ((HRESULT) 0x80070057L)
#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
#define FAILED(Status) ((HRESULT)(Status)<0)
#define STDAPICALLTYPE __stdcall
#define NULL 0
#define STDAPI_(type) EXTERN_C type STDAPICALLTYPE
#include "pal_assert.h"
#include "rt/intsafe.h"
#define WIN32_ALLOC_ALIGN (16 - 1)
PALIMPORT size_t __cdecl PAL_wcslen(const WCHAR *);
typedef WCHAR OLECHAR;
typedef WCHAR *BSTR;
inline HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result)
{
if (result == nullptr)
return E_INVALIDARG;
// +2 for the null terminator
// + DWORD_PTR to store the byte length of the string
int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN;
if (isByteLen)
{
if (SUCCEEDED(ULongAdd(constant, cchSize, result)))
{
*result = *result & ~WIN32_ALLOC_ALIGN;
return NOERROR;
}
}
else
{
ULONG temp = 0; // should not use in-place addition in ULongAdd
if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) &
SUCCEEDED(ULongAdd(temp, constant, result)))
{
*result = *result & ~WIN32_ALLOC_ALIGN;
return NOERROR;
}
}
return INTSAFE_E_ARITHMETIC_OVERFLOW;
}
/***
*BSTR SysAllocStringLen(char*, unsigned int)
*Purpose:
* Allocation a bstr of the given length and initialize with
* the pasted in string
*
*Entry:
* [optional]
*
*Exit:
* return value = BSTR, NULL if the allocation failed.
*
***********************************************************************/
STDAPI_(BSTR) SysAllocStringLen(const OLECHAR *psz, UINT len)
{
BSTR bstr;
DWORD cbTotal = 0;
if (FAILED(CbSysStringSize(len, FALSE, &cbTotal)))
return NULL;
bstr = (OLECHAR *)HeapAlloc(GetProcessHeap(), 0, cbTotal);
if(bstr != NULL) {
#if defined(_WIN64)
// NOTE: There are some apps which peek back 4 bytes to look at
// the size of the BSTR. So, in case of 64-bit code,
// we need to ensure that the BSTR length can be found by
// looking one DWORD before the BSTR pointer.
*(DWORD_PTR *)bstr = (DWORD_PTR) 0;
bstr = (BSTR) ((char *) bstr + sizeof (DWORD));
#endif
*(DWORD FAR*)bstr = (DWORD)len * sizeof(OLECHAR);
bstr = (BSTR) ((char*) bstr + sizeof(DWORD));
if(psz != NULL){
memcpy(bstr, psz, len * sizeof(OLECHAR));
}
bstr[len] = '\0'; // always 0 terminate
}
return bstr;
}
/***
*void SysFreeString(BSTR)
*Purpose:
* Free a bstr using the passed in string
*
*Entry:
* BSTR to free
*
*Exit:
* return value = void
*
***********************************************************************/
STDAPI_(void) SysFreeString(BSTR bstr)
{
if (bstr != NULL)
{
bstr = (BSTR) ((char*) bstr - sizeof(DWORD));
#if defined(_WIN64)
bstr = (BSTR) ((char*) bstr - sizeof(DWORD));
#endif
HeapFree(GetProcessHeap(), 0, (LPVOID) bstr);
}
}
/***
*UINT SysStringLen(BSTR)
*Purpose:
* Return the length of the string in characters (not including null terminator)
*
*Entry:
* BSTR whose length to return
*
*Exit:
* return value = length of the string
*
***********************************************************************/
STDAPI_(UINT) SysStringLen(BSTR bstr)
{
if (bstr == NULL)
{
return 0;
}
return (UINT)((((DWORD FAR*)bstr)[-1]) / sizeof(OLECHAR));
}
/***
*BSTR SysAllocString(char*)
*Purpose:
* Allocation a bstr using the passed in string
*
*Entry:
* String to create a bstr for
*
*Exit:
* return value = BSTR, NULL if allocation failed
*
***********************************************************************/
STDAPI_(BSTR) SysAllocString(const OLECHAR* psz)
{
if(psz == NULL)
{
return NULL;
}
return SysAllocStringLen(psz, (DWORD)PAL_wcslen(psz));
}