mirror of https://github.com/PCSX2/pcsx2.git
234 lines
7.2 KiB
C++
234 lines
7.2 KiB
C++
//*********************************************************
|
|
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// This code is licensed under the MIT License.
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
//
|
|
//*********************************************************
|
|
//! @file
|
|
//! Windows STL helpers: custom allocators for STL containers
|
|
#ifndef __WIL_STL_INCLUDED
|
|
#define __WIL_STL_INCLUDED
|
|
|
|
#include "common.h"
|
|
#include "resource.h"
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <utility>
|
|
#if _HAS_CXX17
|
|
#include <string_view>
|
|
#endif
|
|
|
|
/// @cond
|
|
#ifndef WI_STL_FAIL_FAST_IF
|
|
#define WI_STL_FAIL_FAST_IF FAIL_FAST_IF
|
|
#endif
|
|
/// @endcond
|
|
|
|
#if defined(WIL_ENABLE_EXCEPTIONS)
|
|
|
|
namespace wil
|
|
{
|
|
/** Secure allocator for STL containers.
|
|
The `wil::secure_allocator` allocator calls `SecureZeroMemory` before deallocating
|
|
memory. This provides a mechanism for secure STL containers such as `wil::secure_vector`,
|
|
`wil::secure_string`, and `wil::secure_wstring`. */
|
|
template <typename T>
|
|
struct secure_allocator : public std::allocator<T>
|
|
{
|
|
template <typename Other>
|
|
struct rebind
|
|
{
|
|
using other = secure_allocator<Other>;
|
|
};
|
|
|
|
secure_allocator() : std::allocator<T>()
|
|
{
|
|
}
|
|
|
|
~secure_allocator() = default;
|
|
|
|
secure_allocator(const secure_allocator& a) : std::allocator<T>(a)
|
|
{
|
|
}
|
|
|
|
template <class U>
|
|
secure_allocator(const secure_allocator<U>& a) : std::allocator<T>(a)
|
|
{
|
|
}
|
|
|
|
T* allocate(size_t n)
|
|
{
|
|
return std::allocator<T>::allocate(n);
|
|
}
|
|
|
|
void deallocate(T* p, size_t n)
|
|
{
|
|
SecureZeroMemory(p, sizeof(T) * n);
|
|
std::allocator<T>::deallocate(p, n);
|
|
}
|
|
};
|
|
|
|
//! `wil::secure_vector` will be securely zeroed before deallocation.
|
|
template <typename Type>
|
|
using secure_vector = std::vector<Type, secure_allocator<Type>>;
|
|
//! `wil::secure_wstring` will be securely zeroed before deallocation.
|
|
using secure_wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>, wil::secure_allocator<wchar_t>>;
|
|
//! `wil::secure_string` will be securely zeroed before deallocation.
|
|
using secure_string = std::basic_string<char, std::char_traits<char>, wil::secure_allocator<char>>;
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
template <>
|
|
struct string_maker<std::wstring>
|
|
{
|
|
HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT
|
|
try
|
|
{
|
|
m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0');
|
|
return S_OK;
|
|
}
|
|
catch (...)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
wchar_t* buffer()
|
|
{
|
|
return &m_value[0];
|
|
}
|
|
|
|
HRESULT trim_at_existing_null(size_t length)
|
|
{
|
|
m_value.erase(length);
|
|
return S_OK;
|
|
}
|
|
|
|
std::wstring release()
|
|
{
|
|
return std::wstring(std::move(m_value));
|
|
}
|
|
|
|
static PCWSTR get(const std::wstring& value)
|
|
{
|
|
return value.c_str();
|
|
}
|
|
|
|
private:
|
|
std::wstring m_value;
|
|
};
|
|
} // namespace details
|
|
/// @endcond
|
|
|
|
// str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
|
|
// This is the overload for std::wstring. Other overloads available in resource.h.
|
|
inline PCWSTR str_raw_ptr(const std::wstring& str)
|
|
{
|
|
return str.c_str();
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
/**
|
|
zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty).
|
|
* zstring_view can be used for storing string literals without "forgetting" the length or that it is nul-terminated.
|
|
* A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a nul-terminated
|
|
string_view as a plain string view.
|
|
* A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated.
|
|
*/
|
|
template <class TChar>
|
|
class basic_zstring_view : public std::basic_string_view<TChar>
|
|
{
|
|
using size_type = typename std::basic_string_view<TChar>::size_type;
|
|
|
|
public:
|
|
constexpr basic_zstring_view() noexcept = default;
|
|
constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default;
|
|
constexpr basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default;
|
|
|
|
constexpr basic_zstring_view(const TChar* pStringData, size_type stringLength) noexcept :
|
|
std::basic_string_view<TChar>(pStringData, stringLength)
|
|
{
|
|
if (pStringData[stringLength] != 0)
|
|
{
|
|
WI_STL_FAIL_FAST_IF(true);
|
|
}
|
|
}
|
|
|
|
template <size_t stringArrayLength>
|
|
constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept :
|
|
std::basic_string_view<TChar>(&stringArray[0], length_n(&stringArray[0], stringArrayLength))
|
|
{
|
|
}
|
|
|
|
// Construct from nul-terminated char ptr. To prevent this from overshadowing array construction,
|
|
// we disable this constructor if the value is an array (including string literal).
|
|
template <typename TPtr, std::enable_if_t<std::is_convertible<TPtr, const TChar*>::value && !std::is_array<TPtr>::value>* = nullptr>
|
|
constexpr basic_zstring_view(TPtr&& pStr) noexcept : std::basic_string_view<TChar>(std::forward<TPtr>(pStr))
|
|
{
|
|
}
|
|
|
|
constexpr basic_zstring_view(const std::basic_string<TChar>& str) noexcept :
|
|
std::basic_string_view<TChar>(&str[0], str.size())
|
|
{
|
|
}
|
|
|
|
// basic_string_view [] precondition won't let us read view[view.size()]; so we define our own.
|
|
WI_NODISCARD constexpr const TChar& operator[](size_type idx) const noexcept
|
|
{
|
|
WI_ASSERT(idx <= this->size() && this->data() != nullptr);
|
|
return this->data()[idx];
|
|
}
|
|
|
|
WI_NODISCARD constexpr const TChar* c_str() const noexcept
|
|
{
|
|
WI_ASSERT(this->data() == nullptr || this->data()[this->size()] == 0);
|
|
return this->data();
|
|
}
|
|
|
|
private:
|
|
// Bounds-checked version of char_traits::length, like strnlen. Requires that the input contains a null terminator.
|
|
static constexpr size_type length_n(_In_reads_opt_(buf_size) const TChar* str, size_type buf_size) noexcept
|
|
{
|
|
const std::basic_string_view<TChar> view(str, buf_size);
|
|
auto pos = view.find_first_of(TChar());
|
|
if (pos == view.npos)
|
|
{
|
|
WI_STL_FAIL_FAST_IF(true);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
// The following basic_string_view methods must not be allowed because they break the nul-termination.
|
|
using std::basic_string_view<TChar>::swap;
|
|
using std::basic_string_view<TChar>::remove_suffix;
|
|
};
|
|
|
|
using zstring_view = basic_zstring_view<char>;
|
|
using zwstring_view = basic_zstring_view<wchar_t>;
|
|
|
|
inline namespace literals
|
|
{
|
|
constexpr zstring_view operator"" _zv(const char* str, std::size_t len) noexcept
|
|
{
|
|
return zstring_view(str, len);
|
|
}
|
|
|
|
constexpr zwstring_view operator"" _zv(const wchar_t* str, std::size_t len) noexcept
|
|
{
|
|
return zwstring_view(str, len);
|
|
}
|
|
} // namespace literals
|
|
|
|
#endif // _HAS_CXX17
|
|
|
|
} // namespace wil
|
|
|
|
#endif // WIL_ENABLE_EXCEPTIONS
|
|
|
|
#endif // __WIL_STL_INCLUDED
|