| Server IP : 209.209.40.120 / Your IP : 216.73.217.112 Web Server : Microsoft-IIS/10.0 System : Windows NT NEWWWW 10.0 build 17763 (Windows Server 2019) i586 User : NEWWWW$ ( 0) PHP Version : 8.3.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/Program Files (x86)/Windows Kits/10/Source/10.0.19041.0/ucrt/inc/ |
Upload File : |
//
// corecrt_internal_win32_buffer.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines template-based utilities for handling call-twice
// Win32 APIs, where you first call the Win32 API with null or a fixed sized buffer,
// and if there is not enough space, allocate a dynamically sized buffer.
#pragma once
#include <corecrt_internal.h>
#pragma pack(push, _CRT_PACKING)
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// __crt_win32_buffer_debug_info
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// This is a class that can be used to describe the block_use, file_name, line_number
// debug data that is sometimes shuffled around between function calls.
class __crt_win32_buffer_debug_info
{
#ifndef _DEBUG
public:
__crt_win32_buffer_debug_info(int, char const *, int)
{
}
#else /* ^^^^ Release ^^^^ / vvvv Debug vvvv */
public:
__crt_win32_buffer_debug_info(
int const initial_block_use,
char const * const initial_file_name,
int const initial_line_number
)
: _block_use(initial_block_use),
_file_name(initial_file_name),
_line_number(initial_line_number)
{
}
int block_use() const
{
return _block_use;
}
char const * file_name() const
{
return _file_name;
}
int line_number() const
{
return _line_number;
}
private:
int _block_use;
char const * _file_name;
int _line_number;
#endif /* _DEBUG */
};
class __crt_win32_buffer_empty_debug_info
{
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// __crt_win32_buffer resize policies
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// These classes are used to describe the different resize policies that a
// __crt_win32_buffer can have.
struct __crt_win32_buffer_internal_dynamic_resizing
{
using debug_info_type = __crt_win32_buffer_empty_debug_info;
_Check_return_
static errno_t allocate(void ** const address, size_t const size, debug_info_type const&)
{
void * const ret = _malloc_crt(size);
*address = ret;
if (ret == nullptr) {
return ENOMEM;
}
return 0;
}
static void deallocate(void * const ptr, debug_info_type const&)
{
_free_crt(ptr);
}
};
struct __crt_win32_buffer_public_dynamic_resizing
{
using debug_info_type = __crt_win32_buffer_debug_info;
_Check_return_
static errno_t allocate(void ** const address, size_t const size, debug_info_type const& debug_info)
{
UNREFERENCED_PARAMETER(debug_info); // only used in debug mode
void * const ret = _malloc_dbg(
size,
debug_info.block_use(),
debug_info.file_name(),
debug_info.line_number()
);
*address = ret;
if (ret == nullptr) {
return ENOMEM;
}
return 0;
}
static void deallocate(void * const ptr, debug_info_type const& debug_info)
{
UNREFERENCED_PARAMETER(debug_info); // only used in debug mode
_free_dbg(ptr, debug_info.block_use());
}
};
struct __crt_win32_buffer_no_resizing
{
using debug_info_type = __crt_win32_buffer_empty_debug_info;
_Check_return_
static errno_t allocate(void ** const, size_t const, debug_info_type const&)
{
errno = ERANGE; // buffer not large enough
return ERANGE;
}
static void deallocate(void * const, debug_info_type const&)
{
}
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// __crt_win32_buffer, __crt_internal_win32_buffer
// __crt_public_win32_buffer, __crt_no_alloc_win32_buffer
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Class and typedefs for buffers that support calling a win32 function and automatically
// resizing if needed.
template <typename Character, typename ResizePolicy>
class __crt_win32_buffer : private ResizePolicy::debug_info_type
{ // Buffer type to enable Win32 call-twice-if-not-enough-space APIs.
// Using this type allows us to use a local buffer if possible and allocate if needed.
public:
using char_type = Character;
using debug_info_type = typename ResizePolicy::debug_info_type;
__crt_win32_buffer()
: debug_info_type(),
_initial_string(nullptr),
_initial_capacity(0),
_string(nullptr),
_capacity(0),
_size(0),
_is_dynamic(false)
{
}
explicit __crt_win32_buffer(debug_info_type const& debug_info)
: debug_info_type(debug_info),
_initial_string(nullptr),
_initial_capacity(0),
_string(nullptr),
_capacity(0),
_size(0),
_is_dynamic(false)
{
}
template <size_t N>
__crt_win32_buffer(Character (&buffer)[N])
: debug_info_type(),
_initial_string(buffer),
_initial_capacity(N),
_string(buffer),
_capacity(N),
_size(0),
_is_dynamic(false)
{
}
template <size_t N>
__crt_win32_buffer(Character (&buffer)[N], debug_info_type const& debug_info)
: debug_info_type(debug_info),
_initial_string(buffer),
_initial_capacity(N),
_string(buffer),
_capacity(N),
_size(0),
_is_dynamic(false)
{
}
__crt_win32_buffer(
Character * const buffer,
size_t const buffer_capacity
)
: debug_info_type(),
_initial_string(buffer),
_initial_capacity(buffer_capacity),
_string(buffer),
_capacity(buffer_capacity),
_size(0),
_is_dynamic(false)
{
}
__crt_win32_buffer(
Character * const buffer,
size_t const buffer_capacity,
debug_info_type const& debug_info
)
: debug_info_type(debug_info),
_initial_string(buffer),
_initial_capacity(buffer_capacity),
_string(buffer),
_capacity(buffer_capacity),
_size(0),
_is_dynamic(false)
{
}
~__crt_win32_buffer()
{
_deallocate();
}
__crt_win32_buffer(__crt_win32_buffer const&) = delete;
__crt_win32_buffer& operator=(__crt_win32_buffer const&) = delete;
__crt_win32_buffer(__crt_win32_buffer&&) = delete;
__crt_win32_buffer& operator=(__crt_win32_buffer&&) = delete;
char_type * data()
{
return _string;
}
char_type const * data() const
{
return _string;
}
size_t size() const
{
return _size;
}
void size(size_t new_size)
{
_size = new_size;
}
size_t capacity() const
{
return _capacity;
}
void reset()
{
_deallocate();
_reset_no_dealloc();
}
char_type * detach()
{
if (_string == nullptr || _size == 0) {
return nullptr;
}
char_type * return_val{};
if (!_is_dynamic && _size > 0) {
// This pointer needs to live longer than the stack buffer
// Allocate + Copy
ResizePolicy::allocate(
reinterpret_cast<void **>(&return_val),
_size * sizeof(Character),
debug_info()
);
memcpy_s(return_val, _size, _string, _capacity);
} else {
return_val = _string;
}
_reset_no_dealloc();
return return_val;
}
template <typename Win32Function>
errno_t call_win32_function(Win32Function const& win32_function)
{ // Suitable for more Win32 calls, where a size is returned
// if there is not enough space.
size_t const required_size = win32_function(_string, static_cast<DWORD>(_capacity));
if (required_size == 0) {
__acrt_errno_map_os_error(GetLastError());
return errno;
}
if (required_size <= _capacity) {
// Had enough space, data was written, save size and return
_size = required_size;
return 0;
}
size_t const required_size_plus_null_terminator = required_size + 1;
errno_t const alloc_err = allocate(required_size_plus_null_terminator);
if (alloc_err)
{
return alloc_err;
}
// Upon success, return value is number of characters written, minus the null terminator.
size_t const required_size2 = win32_function(_string, static_cast<DWORD>(_capacity));
if (required_size2 == 0) {
__acrt_errno_map_os_error(GetLastError());
return errno;
}
// Capacity should be large enough at this point.
_size = required_size2;
return 0;
}
debug_info_type const& debug_info() const
{
return static_cast<debug_info_type const&>(*this);
}
errno_t allocate(size_t requested_size)
{
_deallocate();
errno_t err = ResizePolicy::allocate(
reinterpret_cast<void **>(&_string),
requested_size * sizeof(Character),
debug_info()
);
if (err) {
_is_dynamic = false;
_capacity = 0;
return err;
}
_is_dynamic = true;
_capacity = requested_size;
return 0;
}
void set_to_nullptr()
{
_deallocate();
_string = nullptr;
_capacity = 0;
_size = 0;
}
private:
void _reset_no_dealloc()
{
_string = _initial_string;
_capacity = _initial_capacity;
_size = 0;
}
void _deallocate()
{
if (_is_dynamic) {
ResizePolicy::deallocate(_string, debug_info());
_is_dynamic = false;
}
}
char_type * const _initial_string;
size_t _initial_capacity;
char_type * _string;
size_t _capacity;
size_t _size;
bool _is_dynamic;
};
template <typename Character>
using __crt_internal_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_internal_dynamic_resizing>;
template <typename Character>
using __crt_public_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_public_dynamic_resizing>;
template <typename Character>
using __crt_no_alloc_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_no_resizing>;
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// UTF-8 or ACP Helper
//
// Some POSIX functions have historically used the ACP for doing narrow->wide
// conversions. In order to support UTF-8 with these functions, they've been
// modified so that they use CP_UTF8 when current locale is UTF-8, but the ACP
// otherwise in order to preserve backwards compatibility.
//
// These POSIX functions can call __acrt_get_utf8_acp_compatibility_codepage to grab
// the code page they should use for their conversions.
//
// The Win32 ANSI "*A" APIs also use this to preserve their behavior as using the ACP, unless
// the current locale is set to UTF-8.
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
inline unsigned int __acrt_get_utf8_acp_compatibility_codepage()
{
_LocaleUpdate locale_update(nullptr);
unsigned int const current_code_page = locale_update.GetLocaleT()->locinfo->_public._locale_lc_codepage;
if (current_code_page == CP_UTF8) {
return CP_UTF8;
}
bool const use_oem_code_page = !__acrt_AreFileApisANSI();
if (use_oem_code_page) {
return CP_OEMCP;
}
return CP_ACP;
}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Win32 APIs using __crt_win32_buffer
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// See complete list of internal conversion functions in corecrt_internal_traits.h
template <typename FromChar, typename ToChar, typename CvtFunction, typename ResizePolicy>
errno_t __acrt_convert_wcs_mbs(
FromChar const * const null_terminated_input_string,
__crt_win32_buffer<ToChar, ResizePolicy>& win32_buffer,
CvtFunction const& cvt_func,
_locale_t locale
)
{
// Common code path for conversions using mbstowcs and wcstombs.
if (null_terminated_input_string == nullptr) {
win32_buffer.set_to_nullptr();
return 0;
}
// No empty string special case - mbstowcs/wcstombs handles them.
size_t const required_size = cvt_func(nullptr, null_terminated_input_string, 0, locale);
if (required_size == static_cast<size_t>(-1)) {
return errno;
}
size_t const required_size_plus_null_terminator = required_size + 1;
if (required_size_plus_null_terminator > win32_buffer.capacity()) {
errno_t const alloc_err = win32_buffer.allocate(required_size_plus_null_terminator);
if (alloc_err != 0) {
return alloc_err;
}
}
size_t const chars_converted = cvt_func(win32_buffer.data(), null_terminated_input_string, win32_buffer.capacity(), locale);
if (chars_converted == static_cast<size_t>(-1) || chars_converted == win32_buffer.capacity()) {
// check for error or if output is not null terminated
return errno;
}
win32_buffer.size(chars_converted);
return 0;
}
template <typename FromChar, typename ToChar, typename CvtFunction, typename ResizePolicy>
errno_t __acrt_convert_wcs_mbs_cp(
FromChar const * const null_terminated_input_string,
__crt_win32_buffer<ToChar, ResizePolicy>& win32_buffer,
CvtFunction const& cvt_func,
unsigned int const code_page
)
{
// Common code path for conversions using MultiByteToWideChar and WideCharToMultiByte with null terminated inputs.
if (null_terminated_input_string == nullptr) {
win32_buffer.set_to_nullptr();
return 0;
}
// Special Case: Empty strings are not valid input to MultiByteToWideChar/WideCharToMultiByte
if (null_terminated_input_string[0] == '\0') {
if (win32_buffer.capacity() == 0) {
errno_t alloc_err = win32_buffer.allocate(1);
if (alloc_err != 0) {
return alloc_err;
}
}
win32_buffer.data()[0] = '\0';
win32_buffer.size(0);
return 0;
}
size_t const required_size_plus_null_terminator = cvt_func(
code_page,
null_terminated_input_string,
nullptr,
0
);
if (required_size_plus_null_terminator == 0) {
__acrt_errno_map_os_error(::GetLastError());
return errno;
}
if (required_size_plus_null_terminator > win32_buffer.capacity()) {
errno_t alloc_err = win32_buffer.allocate(required_size_plus_null_terminator);
if (alloc_err != 0) {
return alloc_err;
}
}
size_t const chars_converted_plus_null_terminator = cvt_func(
code_page,
null_terminated_input_string,
win32_buffer.data(),
win32_buffer.capacity()
);
if (chars_converted_plus_null_terminator == 0) {
__acrt_errno_map_os_error(::GetLastError());
return errno;
}
win32_buffer.size(chars_converted_plus_null_terminator - 1); // size does not include the null terminator
return 0;
}
template <typename ResizePolicy>
errno_t __acrt_wcs_to_mbs(
wchar_t const * const null_terminated_input_string,
__crt_win32_buffer<char, ResizePolicy>& win32_buffer,
_locale_t locale = nullptr
)
{
_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
return __acrt_convert_wcs_mbs(
null_terminated_input_string,
win32_buffer,
_wcstombs_l,
locale
);
_END_SECURE_CRT_DEPRECATION_DISABLE
}
template <typename ResizePolicy>
errno_t __acrt_wcs_to_mbs_cp(
wchar_t const * const null_terminated_input_string,
__crt_win32_buffer<char, ResizePolicy>& win32_buffer,
unsigned int const code_page
)
{
auto const wcs_to_mbs = [](
unsigned int const code_page,
wchar_t const * const null_terminated_input_string,
char * const buffer,
size_t const buffer_size)
{
// Return value includes null terminator.
return __acrt_WideCharToMultiByte(
code_page,
0,
null_terminated_input_string,
-1,
buffer,
static_cast<int>(buffer_size),
nullptr,
nullptr
);
};
return __acrt_convert_wcs_mbs_cp(
null_terminated_input_string,
win32_buffer,
wcs_to_mbs,
code_page
);
}
template <typename ResizePolicy>
errno_t __acrt_mbs_to_wcs(
char const * const null_terminated_input_string,
__crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer,
_locale_t locale = nullptr
)
{
_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
return __acrt_convert_wcs_mbs(
null_terminated_input_string,
win32_buffer,
_mbstowcs_l,
locale
);
_END_SECURE_CRT_DEPRECATION_DISABLE
}
template <typename ResizePolicy>
errno_t __acrt_mbs_to_wcs_cp(
char const * const null_terminated_input_string,
__crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer,
unsigned int const code_page
)
{
auto const mbs_to_wcs = [](
unsigned int const code_page,
char const * const null_terminated_input_string,
wchar_t * const buffer,
size_t const buffer_size)
{
// Return value includes null terminator.
return __acrt_MultiByteToWideChar(
code_page,
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
null_terminated_input_string,
-1,
buffer,
static_cast<int>(buffer_size)
);
};
return __acrt_convert_wcs_mbs_cp(
null_terminated_input_string,
win32_buffer,
mbs_to_wcs,
code_page
);
}
// Array overloads are useful for __try contexts where objects with unwind semantics cannot be used.
template <size_t N>
size_t __acrt_wcs_to_mbs_array(
wchar_t const * const null_terminated_input_string,
char (&buffer)[N],
_locale_t locale = nullptr
)
{
__crt_no_alloc_win32_buffer<char> win32_buffer(buffer);
if (__acrt_wcs_to_mbs(null_terminated_input_string, win32_buffer, locale) != 0) {
return 0;
}
return win32_buffer.size();
}
template <size_t N>
size_t __acrt_wcs_to_mbs_cp_array(
wchar_t const * const null_terminated_input_string,
char (&buffer)[N],
unsigned int const code_page
)
{
__crt_no_alloc_win32_buffer<char> win32_buffer(buffer);
if (__acrt_wcs_to_mbs_cp(null_terminated_input_string, win32_buffer, code_page) != 0) {
return 0;
}
return win32_buffer.size();
}
template <size_t N>
size_t __acrt_mbs_to_wcs_array(
char const * const null_terminated_input_string,
wchar_t (&buffer)[N],
_locale_t locale = nullptr
)
{
__crt_no_alloc_win32_buffer<wchar_t> win32_buffer(buffer);
if (__acrt_mbs_to_wcs(null_terminated_input_string, win32_buffer, locale) != 0) {
return 0;
}
return win32_buffer.size();
}
template <size_t N>
size_t __acrt_mbs_to_wcs_cp_array(
char const * const null_terminated_input_string,
wchar_t (&buffer)[N],
unsigned int const code_page
)
{
__crt_no_alloc_win32_buffer<wchar_t> win32_buffer(buffer);
if (__acrt_wcs_to_mbs_cp(null_terminated_input_string, win32_buffer, code_page) != 0) {
return 0;
}
return win32_buffer.size();
}
template <typename ResizePolicy>
errno_t __acrt_get_current_directory_wide(
__crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer
)
{
return win32_buffer.call_win32_function([](wchar_t * buffer, DWORD buffer_length)
{
return ::GetCurrentDirectoryW(buffer_length, buffer);
});
}
template <typename ResizePolicy>
errno_t __acrt_get_current_directory_narrow_acp_or_utf8(
__crt_win32_buffer<char, ResizePolicy>& win32_buffer
)
{
wchar_t default_buffer_space[_MAX_PATH];
__crt_internal_win32_buffer<wchar_t> wide_buffer(default_buffer_space);
errno_t const err = __acrt_get_current_directory_wide(wide_buffer);
if (err != 0) {
return err;
}
return __acrt_wcs_to_mbs_cp(
wide_buffer.data(),
win32_buffer,
__acrt_get_utf8_acp_compatibility_codepage()
);
}
template <typename ResizePolicy>
errno_t __acrt_get_full_path_name_wide(
wchar_t const * const lpFileName,
__crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer
)
{
return win32_buffer.call_win32_function([lpFileName](wchar_t * buffer, DWORD buffer_length)
{
return ::GetFullPathNameW(
lpFileName,
buffer_length,
buffer,
nullptr
);
});
}
template <typename ResizePolicy>
errno_t __acrt_get_full_path_name_narrow_acp_or_utf8(
char const * const lpFileName,
__crt_win32_buffer<char, ResizePolicy>& win32_buffer
)
{
wchar_t default_buffer_space[_MAX_PATH];
__crt_internal_win32_buffer<wchar_t> wide_buffer(default_buffer_space);
wchar_t default_file_name_space[_MAX_PATH];
__crt_internal_win32_buffer<wchar_t> wide_file_name(default_file_name_space);
unsigned int const code_page = __acrt_get_utf8_acp_compatibility_codepage();
errno_t const cvt_err = __acrt_mbs_to_wcs_cp(
lpFileName,
wide_file_name,
code_page
);
if (cvt_err != 0)
{
return cvt_err;
}
errno_t const err = __acrt_get_full_path_name_wide(wide_file_name.data(), wide_buffer);
if (err != 0)
{
return err;
}
return __acrt_wcs_to_mbs_cp(
wide_buffer.data(),
win32_buffer,
code_page
);
}
#pragma pack(pop)