[UCRT] Import Microsoft.Windows.SDK.CRTSource version 10.0.22621.3

Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3
License: MIT
This commit is contained in:
Timo Kreuzer 2024-05-11 07:03:12 +02:00
parent f1b60c66f0
commit 04e0dc4a7a
568 changed files with 115483 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,931 @@
//
// corecrt_internal_big_integer.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// A lightweight high precision integer type for use by the binary floating
// point <=> decimal string conversion functions.
//
#include <corecrt_internal.h>
#include <float.h>
#include <stdint.h>
// CRT_REFACTOR TODO We should be building the whole CRT /O2 /GL. For the moment,
// just ensure that everything using big_integer is optimized for maximum speed.
#ifndef _DEBUG
#if !defined(_BEGIN_PRAGMA_OPTIMIZE_DISABLE)
#define _BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \
__pragma(optimize(flags, off))
#define _BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \
__pragma(optimize(flags, on))
#define _END_PRAGMA_OPTIMIZE() \
__pragma(optimize("", on))
#endif
_BEGIN_PRAGMA_OPTIMIZE_ENABLE("gt", MSFT:4499494, "Optimize for maximum speed")
#endif
namespace __crt_strtox {
// A lightweight, sufficiently functional high-precision integer type for use in
// the binary floating point <=> decimal string conversions. We define only the
// operations (and in some cases parts of operations) that are actually used.
//
// We require sufficient precision to represent the reciprocal of the smallest
// representable value (the smallest denormal, 2^-1074). During parsing, we may
// also consider up to 768 decimal digits. For this, we require an additional
// log2(10^768) bits of precision. Finally, we require 54 bits of space for
// pre-division numerator shifting, because double explicitly stores 52 bits,
// implicitly stores 1 bit, and we need 1 more bit for rounding.
//
// PERFORMANCE NOTE: We intentionally do not initialize the _data array when a
// big_integer object is constructed. Profiling showed that zero initialization
// caused a substantial performance hit. Initialization of the _data array is
// not necessary: all operations on the big_integer type are carefully written
// to only access elements at indices [0, _used], and all operations correctly
// update _used as the utilized size increases.
struct big_integer
{
__forceinline big_integer() throw()
: _used(0)
{
#ifdef _DEBUG
memset(_data, 0xcc, sizeof(_data));
#endif
}
__forceinline big_integer(big_integer const& other) throw()
: _used(other._used)
{
memcpy_s(_data, sizeof(_data), other._data, other._used * sizeof(uint32_t));
}
__forceinline big_integer& operator=(big_integer const& other) throw()
{
_used = other._used;
memcpy_s(_data, sizeof(_data), other._data, other._used * sizeof(uint32_t));
return *this;
}
enum : uint32_t
{
maximum_bits =
1074 + // 1074 bits required to represent 2^1074
2552 + // ceil(log2(10^768))
54, // shift space
element_bits = sizeof(uint32_t) * CHAR_BIT,
element_count = (maximum_bits + element_bits - 1) / element_bits
};
uint32_t _used; // The number of elements currently in use
uint32_t _data[element_count]; // The number, stored in little endian form
};
__forceinline bool __cdecl operator==(big_integer const& lhs, big_integer const& rhs) throw()
{
if (lhs._used != rhs._used)
return false;
for (uint32_t i = 0; i != lhs._used; ++i)
{
if (lhs._data[i] != rhs._data[i])
return false;
}
return true;
}
__forceinline bool __cdecl operator!=(big_integer const& lhs, big_integer const& rhs) throw()
{
return !(rhs == lhs);
}
__forceinline bool __cdecl operator<(big_integer const& lhs, big_integer const& rhs) throw()
{
if (lhs._used > rhs._used)
return false;
if (lhs._used < rhs._used)
return true;
uint32_t i = lhs._used - 1;
for (; i != static_cast<uint32_t>(-1) && lhs._data[i] == rhs._data[i]; --i)
{
// No-op
}
if (i == static_cast<uint32_t>(-1))
return false;
if (lhs._data[i] <= rhs._data[i])
return true;
return false;
}
__forceinline bool __cdecl operator>=(big_integer const& lhs, big_integer const& rhs) throw()
{
return !(lhs < rhs);
}
__forceinline big_integer __cdecl make_big_integer(uint64_t const value) throw()
{
big_integer x{};
x._data[0] = value & 0xffffffff;
x._data[1] = value >> 32;
x._used = x._data[1] == 0 ? 1 : 2;
return x;
}
__forceinline big_integer __cdecl make_big_integer_power_of_two(uint32_t const power) throw()
{
uint32_t const one = 1;
big_integer x{};
uint32_t const element_index = power / big_integer::element_bits;
uint32_t const bit_index = power % big_integer::element_bits;
memset(x._data, 0, element_index * sizeof(uint32_t));
x._data[element_index] = (one << bit_index);
x._used = element_index + 1;
return x;
}
__forceinline bool __cdecl is_zero(big_integer const& value) throw()
{
return value._used == 0;
}
__forceinline uint32_t __cdecl bit_scan_reverse(uint32_t const value) throw()
{
unsigned long index = 0;
if (_BitScanReverse(&index, value))
return index + 1;
return 0;
}
__forceinline uint32_t __cdecl bit_scan_reverse(uint64_t const value) throw()
{
if (value > UINT32_MAX)
{
return bit_scan_reverse(reinterpret_cast<uint32_t const*>(&value)[1]) + 32;
}
else
{
return bit_scan_reverse(reinterpret_cast<uint32_t const*>(&value)[0]);
}
}
__forceinline uint32_t __cdecl bit_scan_reverse(big_integer const& x) throw()
{
if (x._used == 0)
{
return 0;
}
return (x._used - 1) * big_integer::element_bits + bit_scan_reverse(x._data[x._used - 1]);
}
// Shifts the high precision integer x by n bits to the left. Returns true if
// the left shift was successful; false if it overflowed. When overflow occurs,
// the high precision integer is reset to zero.
__forceinline bool __cdecl shift_left(big_integer& x, uint32_t const n) throw()
{
uint32_t const unit_shift = n / big_integer::element_bits;
uint32_t const bit_shift = n % big_integer::element_bits;
uint64_t const one = 1;
uint32_t const msb_bits = bit_shift;
uint32_t const lsb_bits = big_integer::element_bits - msb_bits;
uint32_t const lsb_mask = static_cast<uint32_t>((one << lsb_bits) - one);
uint32_t const msb_mask = ~lsb_mask;
bool const bit_shifts_into_next_unit = bit_shift > (big_integer::element_bits - bit_scan_reverse(x._data[x._used - 1]));
bool const unit_shift_will_overflow = x._used + unit_shift > big_integer::element_count;
if (unit_shift_will_overflow)
{
x = big_integer{};
return false;
}
uint32_t const new_used =
x._used + unit_shift + static_cast<uint32_t>(bit_shifts_into_next_unit);
if (new_used > big_integer::element_count)
{
x = big_integer{};
return false;
}
for (uint32_t destination_index = new_used - 1; destination_index != unit_shift - 1; --destination_index)
{
uint32_t const upper_source_index = destination_index - unit_shift;
uint32_t const lower_source_index = destination_index - unit_shift - 1;
uint32_t const upper_source = upper_source_index < x._used ? x._data[upper_source_index] : 0;
uint32_t const lower_source = lower_source_index < x._used ? x._data[lower_source_index] : 0;
uint32_t const shifted_upper_source = (upper_source & lsb_mask) << msb_bits;
uint32_t const shifted_lower_source = (lower_source & msb_mask) >> lsb_bits;
uint32_t const combined_shifted_source = shifted_upper_source | shifted_lower_source;
x._data[destination_index] = combined_shifted_source;
}
for (uint32_t destination_index = 0; destination_index != unit_shift; ++destination_index)
{
x._data[destination_index] = 0;
}
x._used = new_used;
return true;
}
// Adds a 32-bit value to the high-precision integer x. Returns true if the
// addition was successful; false if it overflowed. When overflow occurs, the
// high precision integer is reset to zero.
__forceinline bool __cdecl add(big_integer& x, uint32_t const value) throw()
{
if (value == 0)
{
return true;
}
uint32_t carry = value;
for (uint32_t i = 0; i != x._used; ++i)
{
uint64_t const result = static_cast<uint64_t>(x._data[i]) + carry;
x._data[i] = static_cast<uint32_t>(result);
carry = static_cast<uint32_t>(result >> 32);
}
if (carry != 0)
{
if (x._used < big_integer::element_count)
{
x._data[x._used] = carry;
++x._used;
}
else
{
x = big_integer{};
return false;
}
}
return true;
}
__forceinline uint32_t __cdecl add_carry(
uint32_t& u1,
uint32_t const u2,
uint32_t const u_carry
) throw()
{
uint64_t const uu = static_cast<uint64_t>(u1) + u2 + u_carry;
u1 = static_cast<uint32_t>(uu);
return static_cast<uint32_t>(uu >> 32);
}
__forceinline uint32_t __cdecl add_multiply_carry(
uint32_t& u_add,
uint32_t const u_mul_1,
uint32_t const u_mul_2,
uint32_t const u_carry
) throw()
{
uint64_t const uu_res = static_cast<uint64_t>(u_mul_1) * u_mul_2 + u_add + u_carry;
u_add = static_cast<uint32_t>(uu_res);
return reinterpret_cast<unsigned const*>(&uu_res)[1];
}
__forceinline uint32_t __cdecl multiply_core(
_Inout_updates_all_(multiplicand_count) uint32_t* const multiplicand,
uint32_t const multiplicand_count,
uint32_t const multiplier
) throw()
{
uint32_t carry = 0;
for (uint32_t i = 0; i != multiplicand_count; ++i)
{
uint64_t const result = static_cast<uint64_t>(multiplicand[i]) * multiplier + carry;
multiplicand[i] = static_cast<uint32_t>(result);
carry = static_cast<uint32_t>(result >> 32);
}
return carry;
}
// Multiplies the high precision multiplicand by a 32-bit multiplier. Returns
// true if the multiplication was successful; false if it overflowed. When
// overflow occurs, the multiplicand is reset to zero.
__forceinline bool __cdecl multiply(big_integer& multiplicand, uint32_t const multiplier) throw()
{
if (multiplier == 0)
{
multiplicand = big_integer{};
return true;
}
if (multiplier == 1)
{
return true;
}
if (multiplicand._used == 0)
{
return true;
}
uint32_t const carry = multiply_core(multiplicand._data, multiplicand._used, multiplier);
if (carry != 0)
{
if (multiplicand._used < big_integer::element_count)
{
multiplicand._data[multiplicand._used] = carry;
++multiplicand._used;
}
else
{
multiplicand = big_integer{};
return false;
}
}
return true;
}
// This high precision integer division implementation was translated from the
// implementation of System.Numerics.BigIntegerBuilder.Mul in the .NET Framework
// sources. It multiplies the multiplicand by the multiplier and returns true
// if the multiplication was successful; false if it overflowed. When overflow
// occurs, the multiplicand is reset to zero.
__forceinline bool __cdecl multiply(big_integer& multiplicand, big_integer const& multiplier) throw()
{
if (multiplier._used <= 1)
{
return multiply(multiplicand, multiplier._data[0]);
}
if (multiplicand._used <= 1)
{
uint32_t const small_multiplier = multiplicand._data[0];
multiplicand = multiplier;
return multiply(multiplicand, small_multiplier);
}
// We prefer more iterations on the inner loop and fewer on the outer:
bool const multiplier_is_shorter = multiplier._used < multiplicand._used;
uint32_t const* const rgu1 = multiplier_is_shorter ? multiplier._data : multiplicand._data;
uint32_t const* const rgu2 = multiplier_is_shorter ? multiplicand._data : multiplier._data;
uint32_t const cu1 = multiplier_is_shorter ? multiplier._used : multiplicand._used;
uint32_t const cu2 = multiplier_is_shorter ? multiplicand._used : multiplier._used;
big_integer result{};
for (uint32_t iu1 = 0; iu1 != cu1; ++iu1)
{
uint32_t const u_cur = rgu1[iu1];
if (u_cur == 0)
{
if (iu1 == result._used)
{
result._data[iu1] = 0;
result._used = iu1 + 1;
}
continue;
}
uint32_t u_carry = 0;
uint32_t iu_res = iu1;
for (uint32_t iu2 = 0; iu2 != cu2 && iu_res != big_integer::element_count; ++iu2, ++iu_res)
{
if (iu_res == result._used)
{
result._data[iu_res] = 0;
result._used = iu_res + 1;
}
u_carry = add_multiply_carry(result._data[iu_res], u_cur, rgu2[iu2], u_carry);
}
while (u_carry != 0 && iu_res != big_integer::element_count)
{
if (iu_res == result._used)
{
result._data[iu_res] = 0;
result._used = iu_res + 1;
}
u_carry = add_carry(result._data[iu_res++], 0, u_carry);
}
if (iu_res == big_integer::element_count)
{
multiplicand = big_integer{};
return false;
}
}
// Store the result in the multiplicand and compute the actual number of
// elements used:
multiplicand = result;
return true;
}
// Multiplies the high precision integer x by 10^power. Returns true if the
// multiplication was successful; false if it overflowed. When overflow occurs,
// the high precision integer is reset to zero.
__forceinline bool __cdecl multiply_by_power_of_ten(big_integer& x, uint32_t const power) throw()
{
// To improve performance, we use a table of precomputed powers of ten, from
// 10^10 through 10^380, in increments of ten. In its unpacked form, as an
// array of big_integer objects, this table consists mostly of zero elements.
// Thus, we store the table in a packed form, trimming leading and trailing
// zero elements. We provide an index that is used to unpack powers from the
// table, using the function that appears after this function in this file.
//
// The minimum value representable with double precision is 5E-324. With
// this table we can thus compute most multiplications with a single multiply.
static uint32_t const large_power_data[] =
{
0x540be400, 0x00000002, 0x63100000, 0x6bc75e2d, 0x00000005, 0x40000000, 0x4674edea, 0x9f2c9cd0,
0x0000000c, 0xb9f56100, 0x5ca4bfab, 0x6329f1c3, 0x0000001d, 0xb5640000, 0xc40534fd, 0x926687d2,
0x6c3b15f9, 0x00000044, 0x10000000, 0x946590d9, 0xd762422c, 0x9a224501, 0x4f272617, 0x0000009f,
0x07950240, 0x245689c1, 0xc5faa71c, 0x73c86d67, 0xebad6ddc, 0x00000172, 0xcec10000, 0x63a22764,
0xefa418ca, 0xcdd17b25, 0x6bdfef70, 0x9dea3e1f, 0x0000035f, 0xe4000000, 0xcdc3fe6e, 0x66bc0c6a,
0x2e391f32, 0x5a450203, 0x71d2f825, 0xc3c24a56, 0x000007da, 0xa82e8f10, 0xaab24308, 0x8e211a7c,
0xf38ace40, 0x84c4ce0b, 0x7ceb0b27, 0xad2594c3, 0x00001249, 0xdd1a4000, 0xcc9f54da, 0xdc5961bf,
0xc75cabab, 0xf505440c, 0xd1bc1667, 0xfbb7af52, 0x608f8d29, 0x00002a94, 0x21000000, 0x17bb8a0c,
0x56af8ea4, 0x06479fa9, 0x5d4bb236, 0x80dc5fe0, 0xf0feaa0a, 0xa88ed940, 0x6b1a80d0, 0x00006323,
0x324c3864, 0x8357c796, 0xe44a42d5, 0xd9a92261, 0xbd3c103d, 0x91e5f372, 0xc0591574, 0xec1da60d,
0x102ad96c, 0x0000e6d3, 0x1e851000, 0x6e4f615b, 0x187b2a69, 0x0450e21c, 0x2fdd342b, 0x635027ee,
0xa6c97199, 0x8e4ae916, 0x17082e28, 0x1a496e6f, 0x0002196e, 0x32400000, 0x04ad4026, 0xf91e7250,
0x2994d1d5, 0x665bcdbb, 0xa23b2e96, 0x65fa7ddb, 0x77de53ac, 0xb020a29b, 0xc6bff953, 0x4b9425ab,
0x0004e34d, 0xfbc32d81, 0x5222d0f4, 0xb70f2850, 0x5713f2f3, 0xdc421413, 0xd6395d7d, 0xf8591999,
0x0092381c, 0x86b314d6, 0x7aa577b9, 0x12b7fe61, 0x000b616a, 0x1d11e400, 0x56c3678d, 0x3a941f20,
0x9b09368b, 0xbd706908, 0x207665be, 0x9b26c4eb, 0x1567e89d, 0x9d15096e, 0x7132f22b, 0xbe485113,
0x45e5a2ce, 0x001a7f52, 0xbb100000, 0x02f79478, 0x8c1b74c0, 0xb0f05d00, 0xa9dbc675, 0xe2d9b914,
0x650f72df, 0x77284b4c, 0x6df6e016, 0x514391c2, 0x2795c9cf, 0xd6e2ab55, 0x9ca8e627, 0x003db1a6,
0x40000000, 0xf4ecd04a, 0x7f2388f0, 0x580a6dc5, 0x43bf046f, 0xf82d5dc3, 0xee110848, 0xfaa0591c,
0xcdf4f028, 0x192ea53f, 0xbcd671a0, 0x7d694487, 0x10f96e01, 0x791a569d, 0x008fa475, 0xb9b2e100,
0x8288753c, 0xcd3f1693, 0x89b43a6b, 0x089e87de, 0x684d4546, 0xfddba60c, 0xdf249391, 0x3068ec13,
0x99b44427, 0xb68141ee, 0x5802cac3, 0xd96851f1, 0x7d7625a2, 0x014e718d, 0xfb640000, 0xf25a83e6,
0x9457ad0f, 0x0080b511, 0x2029b566, 0xd7c5d2cf, 0xa53f6d7d, 0xcdb74d1c, 0xda9d70de, 0xb716413d,
0x71d0ca4e, 0xd7e41398, 0x4f403a90, 0xf9ab3fe2, 0x264d776f, 0x030aafe6, 0x10000000, 0x09ab5531,
0xa60c58d2, 0x566126cb, 0x6a1c8387, 0x7587f4c1, 0x2c44e876, 0x41a047cf, 0xc908059e, 0xa0ba063e,
0xe7cfc8e8, 0xe1fac055, 0xef0144b2, 0x24207eb0, 0xd1722573, 0xe4b8f981, 0x071505ae, 0x7a3b6240,
0xcea45d4f, 0x4fe24133, 0x210f6d6d, 0xe55633f2, 0x25c11356, 0x28ebd797, 0xd396eb84, 0x1e493b77,
0x471f2dae, 0x96ad3820, 0x8afaced1, 0x4edecddb, 0x5568c086, 0xb2695da1, 0x24123c89, 0x107d4571,
0x1c410000, 0x6e174a27, 0xec62ae57, 0xef2289aa, 0xb6a2fbdd, 0x17e1efe4, 0x3366bdf2, 0x37b48880,
0xbfb82c3e, 0x19acde91, 0xd4f46408, 0x35ff6a4e, 0x67566a0e, 0x40dbb914, 0x782a3bca, 0x6b329b68,
0xf5afc5d9, 0x266469bc, 0xe4000000, 0xfb805ff4, 0xed55d1af, 0x9b4a20a8, 0xab9757f8, 0x01aefe0a,
0x4a2ca67b, 0x1ebf9569, 0xc7c41c29, 0xd8d5d2aa, 0xd136c776, 0x93da550c, 0x9ac79d90, 0x254bcba8,
0x0df07618, 0xf7a88809, 0x3a1f1074, 0xe54811fc, 0x59638ead, 0x97cbe710, 0x26d769e8, 0xb4e4723e,
0x5b90aa86, 0x9c333922, 0x4b7a0775, 0x2d47e991, 0x9a6ef977, 0x160b40e7, 0x0c92f8c4, 0xf25ff010,
0x25c36c11, 0xc9f98b42, 0x730b919d, 0x05ff7caf, 0xb0432d85, 0x2d2b7569, 0xa657842c, 0xd01fef10,
0xc77a4000, 0xe8b862e5, 0x10d8886a, 0xc8cd98e5, 0x108955c5, 0xd059b655, 0x58fbbed4, 0x03b88231,
0x034c4519, 0x194dc939, 0x1fc500ac, 0x794cc0e2, 0x3bc980a1, 0xe9b12dd1, 0x5e6d22f8, 0x7b38899a,
0xce7919d8, 0x78c67672, 0x79e5b99f, 0xe494034e, 0x00000001, 0xa1000000, 0x6c5cd4e9, 0x9be47d6f,
0xf93bd9e7, 0x77626fa1, 0xc68b3451, 0xde2b59e8, 0xcf3cde58, 0x2246ff58, 0xa8577c15, 0x26e77559,
0x17776753, 0xebe6b763, 0xe3fd0a5f, 0x33e83969, 0xa805a035, 0xf631b987, 0x211f0f43, 0xd85a43db,
0xab1bf596, 0x683f19a2, 0x00000004, 0xbe7dfe64, 0x4bc9042f, 0xe1f5edb0, 0x8fa14eda, 0xe409db73,
0x674fee9c, 0xa9159f0d, 0xf6b5b5d6, 0x7338960e, 0xeb49c291, 0x5f2b97cc, 0x0f383f95, 0x2091b3f6,
0xd1783714, 0xc1d142df, 0x153e22de, 0x8aafdf57, 0x77f5e55f, 0xa3e7ca8b, 0x032f525b, 0x42e74f3d,
0x0000000a, 0xf4dd1000, 0x5d450952, 0xaeb442e1, 0xa3b3342e, 0x3fcda36f, 0xb4287a6e, 0x4bc177f7,
0x67d2c8d0, 0xaea8f8e0, 0xadc93b67, 0x6cc856b3, 0x959d9d0b, 0x5b48c100, 0x4abe8a3d, 0x52d936f4,
0x71dbe84d, 0xf91c21c5, 0x4a458109, 0xd7aad86a, 0x08e14c7c, 0x759ba59c, 0xe43c8800, 0x00000017,
0x92400000, 0x04f110d4, 0x186472be, 0x8736c10c, 0x1478abfb, 0xfc51af29, 0x25eb9739, 0x4c2b3015,
0xa1030e0b, 0x28fe3c3b, 0x7788fcba, 0xb89e4358, 0x733de4a4, 0x7c46f2c2, 0x8f746298, 0xdb19210f,
0x2ea3b6ae, 0xaa5014b2, 0xea39ab8d, 0x97963442, 0x01dfdfa9, 0xd2f3d3fe, 0xa0790280, 0x00000037,
0x509c9b01, 0xc7dcadf1, 0x383dad2c, 0x73c64d37, 0xea6d67d0, 0x519ba806, 0xc403f2f8, 0xa052e1a2,
0xd710233a, 0x448573a9, 0xcf12d9ba, 0x70871803, 0x52dc3a9b, 0xe5b252e8, 0x0717fb4e, 0xbe4da62f,
0x0aabd7e1, 0x8c62ed4f, 0xceb9ec7b, 0xd4664021, 0xa1158300, 0xcce375e6, 0x842f29f2, 0x00000081,
0x7717e400, 0xd3f5fb64, 0xa0763d71, 0x7d142fe9, 0x33f44c66, 0xf3b8f12e, 0x130f0d8e, 0x734c9469,
0x60260fa8, 0x3c011340, 0xcc71880a, 0x37a52d21, 0x8adac9ef, 0x42bb31b4, 0xd6f94c41, 0xc88b056c,
0xe20501b8, 0x5297ed7c, 0x62c361c4, 0x87dad8aa, 0xb833eade, 0x94f06861, 0x13cc9abd, 0x8dc1d56a,
0x0000012d, 0x13100000, 0xc67a36e8, 0xf416299e, 0xf3493f0a, 0x77a5a6cf, 0xa4be23a3, 0xcca25b82,
0x3510722f, 0xbe9d447f, 0xa8c213b8, 0xc94c324e, 0xbc9e33ad, 0x76acfeba, 0x2e4c2132, 0x3e13cd32,
0x70fe91b4, 0xbb5cd936, 0x42149785, 0x46cc1afd, 0xe638ddf8, 0x690787d2, 0x1a02d117, 0x3eb5f1fe,
0xc3b9abae, 0x1c08ee6f, 0x000002be, 0x40000000, 0x8140c2aa, 0x2cf877d9, 0x71e1d73d, 0xd5e72f98,
0x72516309, 0xafa819dd, 0xd62a5a46, 0x2a02dcce, 0xce46ddfe, 0x2713248d, 0xb723d2ad, 0xc404bb19,
0xb706cc2b, 0x47b1ebca, 0x9d094bdc, 0xc5dc02ca, 0x31e6518e, 0x8ec35680, 0x342f58a8, 0x8b041e42,
0xfebfe514, 0x05fffc13, 0x6763790f, 0x66d536fd, 0xb9e15076, 0x00000662, 0x67b06100, 0xd2010a1a,
0xd005e1c0, 0xdb12733b, 0xa39f2e3f, 0x61b29de2, 0x2a63dce2, 0x942604bc, 0x6170d59b, 0xc2e32596,
0x140b75b9, 0x1f1d2c21, 0xb8136a60, 0x89d23ba2, 0x60f17d73, 0xc6cad7df, 0x0669df2b, 0x24b88737,
0x669306ed, 0x19496eeb, 0x938ddb6f, 0x5e748275, 0xc56e9a36, 0x3690b731, 0xc82842c5, 0x24ae798e,
0x00000ede, 0x41640000, 0xd5889ac1, 0xd9432c99, 0xa280e71a, 0x6bf63d2e, 0x8249793d, 0x79e7a943,
0x22fde64a, 0xe0d6709a, 0x05cacfef, 0xbd8da4d7, 0xe364006c, 0xa54edcb3, 0xa1a8086e, 0x748f459e,
0xfc8e54c8, 0xcc74c657, 0x42b8c3d4, 0x57d9636e, 0x35b55bcc, 0x6c13fee9, 0x1ac45161, 0xb595badb,
0xa1f14e9d, 0xdcf9e750, 0x07637f71, 0xde2f9f2b, 0x0000229d, 0x10000000, 0x3c5ebd89, 0xe3773756,
0x3dcba338, 0x81d29e4f, 0xa4f79e2c, 0xc3f9c774, 0x6a1ce797, 0xac5fe438, 0x07f38b9c, 0xd588ecfa,
0x3e5ac1ac, 0x85afccce, 0x9d1f3f70, 0xe82d6dd3, 0x177d180c, 0x5e69946f, 0x648e2ce1, 0x95a13948,
0x340fe011, 0xb4173c58, 0x2748f694, 0x7c2657bd, 0x758bda2e, 0x3b8090a0, 0x2ddbb613, 0x6dcf4890,
0x24e4047e, 0x00005099,
};
struct unpack_index
{
uint16_t _offset; // The offset of this power's initial byte in the array
uint8_t _zeroes; // The number of omitted leading zero elements
uint8_t _size; // The number of elements present for this power
};
static unpack_index const large_power_indices[] =
{
{ 0, 0, 2 }, { 2, 0, 3 }, { 5, 0, 4 }, { 9, 1, 4 },
{ 13, 1, 5 }, { 18, 1, 6 }, { 24, 2, 6 }, { 30, 2, 7 },
{ 37, 2, 8 }, { 45, 3, 8 }, { 53, 3, 9 }, { 62, 3, 10 },
{ 72, 4, 10 }, { 82, 4, 11 }, { 93, 4, 12 }, { 105, 5, 12 },
{ 117, 5, 13 }, { 130, 5, 14 }, { 144, 5, 15 }, { 159, 6, 15 },
{ 174, 6, 16 }, { 190, 6, 17 }, { 207, 7, 17 }, { 224, 7, 18 },
{ 242, 7, 19 }, { 261, 8, 19 }, { 280, 8, 21 }, { 301, 8, 22 },
{ 323, 9, 22 }, { 345, 9, 23 }, { 368, 9, 24 }, { 392, 10, 24 },
{ 416, 10, 25 }, { 441, 10, 26 }, { 467, 10, 27 }, { 494, 11, 27 },
{ 521, 11, 28 }, { 549, 11, 29 },
};
uint32_t large_power = power / 10;
while (large_power != 0)
{
uint32_t const current_power = large_power > _countof(large_power_indices)
? _countof(large_power_indices)
: large_power;
unpack_index const& index = large_power_indices[current_power - 1];
big_integer multiplier{};
multiplier._used = index._size + index._zeroes;
uint32_t const* const source = large_power_data + index._offset;
memset(multiplier._data, 0, index._zeroes * sizeof(uint32_t));
memcpy(multiplier._data + index._zeroes, source, index._size * sizeof(uint32_t));
if (!multiply(x, multiplier))
{
x = big_integer{};
return false;
}
large_power -= current_power;
}
static uint32_t const small_powers_of_ten[9] =
{
10,
100,
1000,
1000 * 10,
1000 * 100,
1000 * 1000,
1000 * 1000 * 10,
1000 * 1000 * 100,
1000 * 1000 * 1000
};
uint32_t const small_power = power % 10;
if (small_power != 0)
{
if (!multiply(x, small_powers_of_ten[small_power - 1]))
{
return false;
}
}
return true;
}
// The following non-compiled functions are the generators for the big powers of
// ten table found in multiply_by_power_of_ten(). This code is provided for
// future use if the table needs to be amended. Do not remove this code.
/*
uint32_t count_leading_zeroes(big_integer const& x)
{
for (uint32_t i = 0; i != x._used; ++i)
{
if (x._data[i] != 0)
return i;
}
return 0;
}
void generate_table()
{
std::vector<uint32_t> elements;
std::vector<unpack_index> indices;
for (uint32_t i = 10; i != 390; i += 10)
{
big_integer x = make_big_integer(1);
for (uint32_t j = 0; j != i; ++j)
{
multiply(x, 10);
}
unpack_index index{};
index._offset = elements.size();
index._zeroes = count_leading_zeroes(x);
index._size = x._used - index._zeroes;
for (uint32_t j = index._zeroes; j != x._used; ++j)
{
elements.push_back(x._data[j]);
}
indices.push_back(index);
}
printf("static uint32_t const large_power_data[] = \n{");
for (uint32_t i = 0; i != elements.size(); ++i)
{
printf("%s0x%08x, ", i % 8 == 0 ? "\n " : "", elements[i]);
}
printf("\n};\n");
printf("static unpack_index const large_power_indices[] = \n{\n");
for (uint32_t i = 0; i != indices.size(); ++i)
{
printf("%s{ %4u, %2u, %2u }, ",
i % 4 == 0 ? "\n " : "",
indices[i]._offset,
indices[i]._zeroes,
indices[i]._size);
}
printf("};\n");
}
*/
// Computes the number of zeroes higher than the most significant set bit in 'u'
__forceinline uint32_t __cdecl count_sequential_high_zeroes(uint32_t const u) throw()
{
unsigned long result;
return _BitScanReverse(&result, u) ? 31 - result : 32;
}
// PERFORMANCE NOTE: On x86, for multiplication of a 64-bit unsigned integer by
// a 32-bit unsigned integer, the compiler will generate a call to _allmul. For
// division-heavy conversions, the inline assembly version presented here gives a
// 10% overall performance improvement (not 10% faster division--10% faster total).
// This function [1] uses only two 32-bit multiplies instead of the three required
// for general 64-bit x 64-bit multiplication, and [2] is inlineable, allowing the
// compile to elide the extreme overhead of calling the _allmul function.
#if defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)
__forceinline uint64_t __cdecl multiply_64_32(
uint64_t const multiplicand,
uint32_t const multiplier
) throw()
{
__asm
{
mov eax, dword ptr [multiplicand + 4]
mul multiplier
mov ecx, eax
mov eax, dword ptr [multiplicand]
mul multiplier
add edx, ecx
}
}
#else
__forceinline uint64_t __cdecl multiply_64_32(
uint64_t const multiplicand,
uint32_t const multiplier
) throw()
{
return multiplicand * multiplier;
}
#endif
// This high precision integer division implementation was translated from the
// implementation of System.Numerics.BigIntegerBuilder.ModDivCore in the .NET
// Framework sources. It computes both quotient and remainder: the remainder
// is stored in the numerator argument, and the least significant 32 bits of the
// quotient are returned from the function.
inline uint64_t __cdecl divide(
big_integer & numerator,
big_integer const& denominator
) throw()
{
// If the numerator is zero, then both the quotient and remainder are zero:
if (numerator._used == 0)
{
return 0;
}
// If the denominator is zero, then uh oh. We can't divide by zero:
if (denominator._used == 0)
{
_ASSERTE(("Division by zero", false));
return 0;
}
uint32_t max_numerator_element_index = numerator._used - 1;
uint32_t max_denominator_element_index = denominator._used - 1;
// The numerator and denominator are both nonzero. If the denominator is
// only one element wide, we can take the fast route:
if (max_denominator_element_index == 0)
{
uint32_t const small_denominator = denominator._data[0];
if (small_denominator == 1)
{
uint32_t const quotient = numerator._data[0];
numerator = big_integer{};
return quotient;
}
if (max_numerator_element_index == 0)
{
uint32_t const small_numerator = numerator._data[0];
numerator = big_integer{};
numerator._data[0] = small_numerator % small_denominator;
numerator._used = numerator._data[0] > 0 ? 1 : 0;
return small_numerator / small_denominator;
}
// We count down in the next loop, so the last assignment to quotient
// will be the correct one.
uint64_t quotient = 0;
uint64_t uu = 0;
for (uint32_t iv = max_numerator_element_index; iv != static_cast<uint32_t>(-1); --iv)
{
uu = (uu << 32) | numerator._data[iv];
quotient = (quotient << 32) + static_cast<uint32_t>(uu / small_denominator);
uu %= small_denominator;
}
numerator = big_integer{};
numerator._data[1] = static_cast<uint32_t>(uu >> 32);
numerator._data[0] = static_cast<uint32_t>(uu );
numerator._used = numerator._data[1] > 0 ? 2 : 1;
return quotient;
}
if (max_denominator_element_index > max_numerator_element_index)
{
return 0;
}
uint32_t cu_den = max_denominator_element_index + 1;
int32_t cu_diff = max_numerator_element_index - max_denominator_element_index;
// Determine whether the result will have cu_diff or cu_diff + 1 digits:
int32_t cu_quo = cu_diff;
for (int32_t iu = max_numerator_element_index; ; --iu)
{
if (iu < cu_diff)
{
++cu_quo;
break;
}
if (denominator._data[iu - cu_diff] != numerator._data[iu])
{
if (denominator._data[iu - cu_diff] < numerator._data[iu])
{
++cu_quo;
}
break;
}
}
if (cu_quo == 0)
{
return 0;
}
// Get the uint to use for the trial divisions. We normalize so the
// high bit is set:
uint32_t u_den = denominator._data[cu_den - 1];
uint32_t u_den_next = denominator._data[cu_den - 2];
uint32_t cbit_shift_left = count_sequential_high_zeroes(u_den);
uint32_t cbit_shift_right = 32 - cbit_shift_left;
if (cbit_shift_left > 0)
{
u_den = (u_den << cbit_shift_left) | (u_den_next >> cbit_shift_right);
u_den_next <<= cbit_shift_left;
if (cu_den > 2)
{
u_den_next |= denominator._data[cu_den - 3] >> cbit_shift_right;
}
}
uint64_t quotient{};
for (int32_t iu = cu_quo; --iu >= 0; )
{
// Get the high (normalized) bits of the numerator:
uint32_t u_num_hi = (iu + cu_den <= max_numerator_element_index)
? numerator._data[iu + cu_den]
: 0;
uint64_t uu_num = numerator._data[iu + cu_den - 1];
reinterpret_cast<uint32_t*>(&uu_num)[1] = u_num_hi;
uint32_t u_num_next = numerator._data[iu + cu_den - 2];
if (cbit_shift_left > 0)
{
uu_num = (uu_num << cbit_shift_left) | (u_num_next >> cbit_shift_right);
u_num_next <<= cbit_shift_left;
if (iu + cu_den >= 3)
{
u_num_next |= numerator._data[iu + cu_den - 3] >> cbit_shift_right;
}
}
// Divide to get the quotient digit:
uint64_t uu_quo = uu_num / u_den;
uint64_t uu_rem = static_cast<uint32_t>(uu_num % u_den);
if (uu_quo > UINT32_MAX)
{
uu_rem += u_den * (uu_quo - UINT32_MAX);
uu_quo = UINT32_MAX;
}
while (uu_rem <= UINT32_MAX && uu_quo * u_den_next > ((uu_rem << 32) | u_num_next))
{
--uu_quo;
uu_rem += u_den;
}
// Multiply and subtract. Note that uu_quo may be one too large. If
// we have a borrow at the end, we'll add the denominator back on and
// decrement uu_quo.
if (uu_quo > 0)
{
uint64_t uu_borrow = 0;
for (uint32_t iu2 = 0; iu2 < cu_den; ++iu2)
{
uu_borrow += multiply_64_32(uu_quo, denominator._data[iu2]);
uint32_t const u_sub = static_cast<uint32_t>(uu_borrow);
uu_borrow >>= 32;
if (numerator._data[iu + iu2] < u_sub)
{
++uu_borrow;
}
numerator._data[iu + iu2] -= u_sub;
}
if (u_num_hi < uu_borrow)
{
// Add, tracking carry:
uint32_t u_carry = 0;
for (uint32_t iu2 = 0; iu2 < cu_den; ++iu2)
{
uint64_t const sum =
static_cast<uint64_t>(numerator._data[iu + iu2]) +
static_cast<uint64_t>(denominator._data[iu2]) +
u_carry;
numerator._data[iu + iu2] = static_cast<uint32_t>(sum);
u_carry = sum >> 32;
}
--uu_quo;
}
max_numerator_element_index = iu + cu_den - 1;
}
quotient = (quotient << 32) + static_cast<uint32_t>(uu_quo);
}
// Trim the remainder:
for (uint32_t i = max_numerator_element_index + 1; i < numerator._used; ++i)
{
numerator._data[i] = 0;
}
numerator._used = max_numerator_element_index + 1;
while (numerator._used != 0 && numerator._data[numerator._used - 1] == 0)
{
--numerator._used;
}
return quotient;
}
} // namespace __crt_strtox

View file

@ -0,0 +1,220 @@
//
// corecrt_internal_fltintrn.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Floating point conversion routines for internal use. This is a C++ header.
//
#pragma once
#include <corecrt_internal.h>
#include <float.h>
#include <stdint.h>
#include <stdlib.h>
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Types
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename FloatingType>
struct __acrt_floating_type_traits;
template <>
struct __acrt_floating_type_traits<float>
{
enum : int32_t
{
mantissa_bits = FLT_MANT_DIG,
exponent_bits = sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
maximum_binary_exponent = FLT_MAX_EXP - 1,
minimum_binary_exponent = FLT_MIN_EXP - 1,
exponent_bias = 127
};
enum : uint32_t
{
exponent_mask = (1u << (exponent_bits )) - 1,
normal_mantissa_mask = (1u << (mantissa_bits )) - 1,
denormal_mantissa_mask = (1u << (mantissa_bits - 1)) - 1,
special_nan_mantissa_mask = (1u << (mantissa_bits - 2))
};
struct components_type
{
uint32_t _mantissa : mantissa_bits - 1;
uint32_t _exponent : exponent_bits;
uint32_t _sign : 1;
};
static_assert(sizeof(components_type) == sizeof(float), "unexpected components size");
};
template <>
struct __acrt_floating_type_traits<double>
{
enum : int32_t
{
mantissa_bits = DBL_MANT_DIG,
exponent_bits = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
maximum_binary_exponent = DBL_MAX_EXP - 1,
minimum_binary_exponent = DBL_MIN_EXP - 1,
exponent_bias = 1023
};
enum : uint64_t
{
exponent_mask = (1ui64 << (exponent_bits )) - 1,
normal_mantissa_mask = (1ui64 << (mantissa_bits )) - 1,
denormal_mantissa_mask = (1ui64 << (mantissa_bits - 1)) - 1,
special_nan_mantissa_mask = (1ui64 << (mantissa_bits - 2))
};
struct components_type
{
uint64_t _mantissa : mantissa_bits - 1;
uint64_t _exponent : exponent_bits;
uint64_t _sign : 1;
};
static_assert(sizeof(components_type) == sizeof(double), "unexpected components size");
};
enum class __acrt_fp_class : uint32_t
{
finite,
infinity,
quiet_nan,
signaling_nan,
indeterminate,
};
enum class __acrt_has_trailing_digits
{
trailing,
no_trailing
};
// Precision is the number of digits after the decimal point, but
// this has different implications for how many digits need to be
// generated based upon how the number will be formatted.
enum class __acrt_precision_style
{
fixed, // 123.456 %f style requires '3' precision to generate 6 digits to format "123.456".
scientific // 123.456 %e style requires '5' precision to generate 6 digits to format "1.23456e+02".
};
// This rounding mode is used to know if we are using functions like gcvt vs printf
enum class __acrt_rounding_mode
{
legacy,
standard
};
inline __acrt_fp_class __cdecl __acrt_fp_classify(double const& value) throw()
{
using floating_traits = __acrt_floating_type_traits<double>;
using components_type = floating_traits::components_type;
components_type const& components = reinterpret_cast<components_type const&>(value);
bool const value_is_nan_or_infinity = components._exponent == (1u << floating_traits::exponent_bits) - 1;
if (!value_is_nan_or_infinity)
{
return __acrt_fp_class::finite;
}
else if (components._mantissa == 0)
{
return __acrt_fp_class::infinity;
}
else if (components._sign == 1 && components._mantissa == floating_traits::special_nan_mantissa_mask)
{
return __acrt_fp_class::indeterminate;
}
else if (components._mantissa & floating_traits::special_nan_mantissa_mask) // Quiet NAN
{
return __acrt_fp_class::quiet_nan;
}
else // Signaling NAN
{
return __acrt_fp_class::signaling_nan;
}
}
inline bool __cdecl __acrt_fp_is_negative(double const& value) throw()
{
using floating_traits = __acrt_floating_type_traits<double>;
using components_type = floating_traits::components_type;
components_type const& components = reinterpret_cast<components_type const&>(value);
return components._sign == 1;
}
struct _strflt
{
int sign; // Zero if positive otherwise negative
int decpt; // Exponent of floating point number
char* mantissa; // Pointer to mantissa in string form
};
typedef _strflt* STRFLT;
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Floating Point Conversion Routines
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_CRT_BEGIN_C_HEADER
// Result buffer count for __acrt_fp_format has a minimum value that depends on the precision requested.
// This requirement originates and propagates from the fp_format_e_internal function (in convert\cvt.cpp)
// This macro can be used to annotate result_buffer_count in the below functions
#define _In_fits_precision_(precision_arg) \
_When_(precision_arg <= 0, _Pre_satisfies_(_Curr_ > 9)) \
_When_(precision_arg > 0, _Pre_satisfies_(_Curr_ > 9 + precision_arg))
_Success_(return == 0)
errno_t __cdecl __acrt_fp_format(
_In_ double const* value,
_Maybe_unsafe_(_Inout_updates_z_, result_buffer_count) char* result_buffer,
_In_fits_precision_(precision) size_t result_buffer_count,
_Out_writes_(scratch_buffer_count) char* scratch_buffer,
_In_ size_t scratch_buffer_count,
_In_ int format,
_In_ int precision,
_In_ uint64_t options,
_In_ __acrt_rounding_mode rounding_mode,
_Inout_ __crt_cached_ptd_host& ptd
);
errno_t __cdecl __acrt_fp_strflt_to_string(
_Out_writes_z_(buffer_count) char* buffer,
_When_((digits > 0), _In_ _Pre_satisfies_(buffer_count > digits + 1))
_When_((digits <= 0), _In_ _Pre_satisfies_(buffer_count > 1))
_In_ size_t buffer_count,
_In_ int digits,
_Inout_ STRFLT value,
_In_ __acrt_has_trailing_digits trailing_digits,
_In_ __acrt_rounding_mode rounding_mode,
_Inout_ __crt_cached_ptd_host& ptd
);
__acrt_has_trailing_digits __cdecl __acrt_fltout(
_In_ _CRT_DOUBLE value,
_In_ unsigned precision,
_In_ __acrt_precision_style precision_style,
_Out_ STRFLT result,
_Out_writes_z_(buffer_count) char* buffer,
_In_ size_t buffer_count
);
_CRT_END_C_HEADER

View file

@ -0,0 +1,328 @@
//
// corecrt_internal_lowio.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines internal utilities for working with the lowio
// library. This header may only be included in C++ translation units.
//
#pragma once
#include <fcntl.h>
#include <io.h>
#include <corecrt_internal_traits.h>
#include <share.h>
#include <stdint.h>
#include <stdlib.h>
_CRT_BEGIN_C_HEADER
#define LF 10 /* line feed */
#define CR 13 /* carriage return */
#define CTRLZ 26 /* ctrl-z means eof for text */
// Real default size for stdio buffers
#define _INTERNAL_BUFSIZ 4096
#define _SMALL_BUFSIZ 512
/* Most significant Bit */
#define _msbit(c) ((c) & 0x80)
/* Independent byte has most significant bit set to 0 */
#define _utf8_is_independent(c) (_msbit(c) == 0)
/* Get no of trailing bytes from the lookup table */
// 1 for pattern 110xxxxx - 1 trailbyte
// 2 for pattern 1110xxxx - 2 trailbytes
// 3 for pattern 11110xxx - 3 trailbytes
// 0 for everything else, including invalid patterns.
// We return 0 for invalid patterns because we rely on MultiByteToWideChar to
// do the validations.
extern char _lookuptrailbytes[256];
__inline char _utf8_no_of_trailbytes(const unsigned char c)
{
return _lookuptrailbytes[c];
}
// It may be faster to just look up the bytes than to use the lookup table.
//__inline char _utf8_no_of_trailbytes(const unsigned char c)
//{
// // ASCII range is a single character
// if ((c & 0x80) == 0) return 0;
// // Trail bytes 10xxxxxx aren't lead bytes
// if ((c & 0x40) == 0) return 0;
// // 110xxxxx is a 2 byte sequence (1 trail byte)
// if ((c & 0x20) == 0) return 1;
// // 1110xxxx is a 3 byte sequence (2 trail bytes)
// if ((c & 0x10) == 0) return 2;
// // 11110xxx is a 4 byte sequence (3 trail bytes)
// if ((c & 0x08) == 0) return 3;
// // Anything with 5 or more lead bits is illegal
// return 0;
//}
/* Any leadbyte will have the patterns 11000xxx 11100xxx or 11110xxx */
#define _utf8_is_leadbyte(c) (_utf8_no_of_trailbytes(static_cast<const unsigned char>(c)) != 0)
enum class __crt_lowio_text_mode : char
{
ansi = 0, // Regular text
utf8 = 1, // UTF-8 encoded
utf16le = 2, // UTF-16LE encoded
};
// osfile flag values
enum : unsigned char
{
FOPEN = 0x01, // file handle open
FEOFLAG = 0x02, // end of file has been encountered
FCRLF = 0x04, // CR-LF across read buffer (in text mode)
FPIPE = 0x08, // file handle refers to a pipe
FNOINHERIT = 0x10, // file handle opened _O_NOINHERIT
FAPPEND = 0x20, // file handle opened O_APPEND
FDEV = 0x40, // file handle refers to device
FTEXT = 0x80, // file handle is in text mode
};
typedef char __crt_lowio_pipe_lookahead[3];
/*
* Control structure for lowio file handles
*/
struct __crt_lowio_handle_data
{
CRITICAL_SECTION lock;
intptr_t osfhnd; // underlying OS file HANDLE
__int64 startpos; // File position that matches buffer start
unsigned char osfile; // Attributes of file (e.g., open in text mode?)
__crt_lowio_text_mode textmode;
__crt_lowio_pipe_lookahead _pipe_lookahead;
uint8_t unicode : 1; // Was the file opened as unicode?
uint8_t utf8translations : 1; // Buffer contains translations other than CRLF
uint8_t dbcsBufferUsed : 1; // Is the dbcsBuffer in use?
char mbBuffer[MB_LEN_MAX]; // Buffer for the lead byte of DBCS when converting from DBCS to Unicode
// Or for the first up to 3 bytes of a UTF-8 character
};
// The log-base-2 of the number of elements in each array of lowio file objects
#define IOINFO_L2E 6
// The number of elements in each array of lowio file objects
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
// The hard maximum number of arrays of lowio file objects that may be allocated
#define IOINFO_ARRAYS 128
// The maximum number of lowio file objects that may be allocated at any one time
#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
#define STDIO_HANDLES_COUNT 3
/*
* Access macros for getting at an __crt_lowio_handle_data struct and its fields from a
* file handle
*/
#define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
#define _osfhnd(i) (_pioinfo(i)->osfhnd)
#define _osfile(i) (_pioinfo(i)->osfile)
#define _pipe_lookahead(i) (_pioinfo(i)->_pipe_lookahead)
#define _textmode(i) (_pioinfo(i)->textmode)
#define _tm_unicode(i) (_pioinfo(i)->unicode)
#define _startpos(i) (_pioinfo(i)->startpos)
#define _utf8translations(i) (_pioinfo(i)->utf8translations)
#define _mbBuffer(i) (_pioinfo(i)->mbBuffer)
#define _dbcsBuffer(i) (_pioinfo(i)->mbBuffer[0])
#define _dbcsBufferUsed(i) (_pioinfo(i)->dbcsBufferUsed)
/*
* Safer versions of the above macros. Currently, only _osfile_safe is
* used.
*/
#define _pioinfo_safe(i) ((((i) != -1) && ((i) != -2)) ? _pioinfo(i) : &__badioinfo)
#define _osfile_safe(i) (_pioinfo_safe(i)->osfile)
#define _textmode_safe(i) (_pioinfo_safe(i)->textmode)
#define _tm_unicode_safe(i) (_pioinfo_safe(i)->unicode)
typedef __crt_lowio_handle_data* __crt_lowio_handle_data_array[IOINFO_ARRAYS];
// Special, static lowio file object used only for more graceful handling
// of a C file handle value of -1 (results from common errors at the stdio
// level).
extern __crt_lowio_handle_data __badioinfo;
// The umask value
extern int _umaskval;
// Global array of pointers to the arrays of lowio file objects.
extern __crt_lowio_handle_data_array __pioinfo;
// The number of handles for which file objects have been allocated. This
// number is such that for any fh in [0, _nhandle), _pioinfo(fh) is well-
// formed.
extern int _nhandle;
int __cdecl _alloc_osfhnd(void);
int __cdecl _free_osfhnd(int);
int __cdecl __acrt_lowio_set_os_handle(int, intptr_t);
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal lowio functions
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_Success_(return == 0)
errno_t __cdecl _sopen_nolock(
_Out_ int* _UnlockFlag,
_Out_ int* _FileHandle,
_In_z_ char const* _FileName,
_In_ int _OpenFlag,
_In_ int _ShareFlag,
_In_ int _PermissionFlag,
_In_ int _SecureFlag
);
_Success_(return == 0)
errno_t __cdecl _wsopen_nolock(
_Out_ int* _UnlockFlag,
_Out_ int* _FileHandle,
_In_z_ wchar_t const* _FileName,
_In_ int _OpenFlag,
_In_ int _ShareFlag,
_In_ int _PermissionFlag,
_In_ int _SecureFlag
);
_Check_return_
__crt_lowio_handle_data* __cdecl __acrt_lowio_create_handle_array();
void __cdecl __acrt_lowio_destroy_handle_array(
_Pre_maybenull_ _Post_invalid_ _In_reads_opt_(IOINFO_ARRAY_ELTS) __crt_lowio_handle_data* _Array
);
_Check_return_opt_
errno_t __cdecl __acrt_lowio_ensure_fh_exists(
_In_ int _FileHandle
);
void __cdecl __acrt_lowio_lock_fh (_In_ int _FileHandle);
void __cdecl __acrt_lowio_unlock_fh(_In_ int _FileHandle);
extern "C++"
{
template <typename Action>
auto __acrt_lowio_lock_fh_and_call(int const fh, Action&& action) throw()
-> decltype(action())
{
return __crt_seh_guarded_call<decltype(action())>()(
[fh]() { __acrt_lowio_lock_fh(fh); },
action,
[fh]() { __acrt_lowio_unlock_fh(fh); });
}
}
// console_invalid_handle indicates that CONOUT$ or CONIN$ could not be created
// console_uninitialized_handle indicates that the handle has not yet been initialized
const HANDLE _console_invalid_handle = reinterpret_cast<HANDLE>(-1);
const HANDLE _console_uninitialized_handle = reinterpret_cast<HANDLE>(-2);
BOOL __cdecl __dcrt_lowio_ensure_console_input_initialized(void);
BOOL __cdecl __dcrt_read_console_input(
_Out_ PINPUT_RECORD lpBuffer,
_In_ DWORD nLength,
_Out_ LPDWORD lpNumberOfEventsRead
);
BOOL __cdecl __dcrt_read_console(
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfCharsToRead,
_Out_ LPDWORD lpNumberOfCharsRead
);
BOOL __cdecl __dcrt_get_number_of_console_input_events(
_Out_ LPDWORD lpcNumberOfEvents
);
BOOL __cdecl __dcrt_peek_console_input_a(
_Out_ PINPUT_RECORD lpBuffer,
_In_ DWORD nLength,
_Out_ LPDWORD lpNumberOfEventsRead
);
BOOL __cdecl __dcrt_get_input_console_mode(
_Out_ LPDWORD lpMode
);
BOOL __cdecl __dcrt_set_input_console_mode(
_In_ DWORD dwMode
);
BOOL __cdecl __dcrt_lowio_ensure_console_output_initialized(void);
BOOL __cdecl __dcrt_write_console(
_In_ void const * lpBuffer,
_In_ DWORD nNumberOfCharsToWrite,
_Out_ LPDWORD lpNumberOfCharsWritten
);
_Check_return_ int __cdecl _chsize_nolock(_In_ int _FileHandle,_In_ __int64 _Size);
_Check_return_opt_ int __cdecl _close_nolock(_In_ int _FileHandle);
_Check_return_opt_ long __cdecl _lseek_nolock(_In_ int _FileHandle, _In_ long _Offset, _In_ int _Origin);
_Check_return_ int __cdecl _setmode_nolock(_In_ int _FileHandle, _In_ int _Mode);
_Check_return_ _Success_(return >= 0 && return <= _MaxCharCount) int __cdecl _read_nolock(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void * _DstBuf, _In_ unsigned int _MaxCharCount);
_Check_return_ int __cdecl _write_nolock(_In_ int _FileHandle, _In_reads_bytes_(_MaxCharCount) const void * _Buf, _In_ unsigned int _MaxCharCount, __crt_cached_ptd_host& _Ptd);
_Check_return_opt_ __int64 __cdecl _lseeki64_nolock(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin);
// Temporary until non-PTD propagating versions can be replaced:
_Check_return_ int __cdecl _chsize_nolock_internal(_In_ int _FileHandle, _In_ __int64 _Size, _Inout_ __crt_cached_ptd_host& _Ptd);
_Check_return_opt_ __int64 __cdecl _lseeki64_nolock_internal(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin, _Inout_ __crt_cached_ptd_host& _Ptd);
_Check_return_opt_ int __cdecl _close_nolock_internal(_In_ int _FileHandle, _Inout_ __crt_cached_ptd_host& _Ptd);
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal stdio functions with PTD propagation
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_Check_return_opt_
int __cdecl _close_internal(
_In_ int _FileHandle,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_opt_
long __cdecl _lseek_internal(
_In_ int _FileHandle,
_In_ long _Offset,
_In_ int _Origin,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_opt_
__int64 __cdecl _lseeki64_internal(
_In_ int _FileHandle,
_In_ __int64 _Offset,
_In_ int _Origin,
_Inout_ __crt_cached_ptd_host& _Ptd
);
int __cdecl _write_internal(
_In_ int _FileHandle,
_In_reads_bytes_(_MaxCharCount) void const* _Buf,
_In_ unsigned int _MaxCharCount,
_Inout_ __crt_cached_ptd_host& _Ptd
);
// fileno for stdout, stdin & stderr when there is no console
#define _NO_CONSOLE_FILENO ((intptr_t)-2)
_CRT_END_C_HEADER

View file

@ -0,0 +1,152 @@
//
// corecrt_internal_mbstring.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines internal utilities for working with the multibyte
// character and string library.
//
#pragma once
#include <corecrt_internal.h>
#include <mbctype.h>
#include <mbstring.h>
#include <uchar.h>
_CRT_BEGIN_C_HEADER
// Multibyte full-width-latin upper/lower info
#define NUM_ULINFO 6
/* internal use macros since tolower/toupper are locale-dependent */
#define _mbbisupper(_c) ((_mbctype.value()[(_c) + 1] & _SBUP) == _SBUP)
#define _mbbislower(_c) ((_mbctype.value()[(_c) + 1] & _SBLOW) == _SBLOW)
#define _mbbtolower(_c) (_mbbisupper(_c) ? _mbcasemap.value()[_c] : _c)
#define _mbbtoupper(_c) (_mbbislower(_c) ? _mbcasemap.value()[_c] : _c)
#define _ismbbtruelead_l(_lb,_ch,p) (!(_lb) && _ismbblead_l((_ch), p))
#define _mbbisupper_l(_c, p) ((p->mbcinfo->mbctype[(_c) + 1] & _SBUP) == _SBUP)
#define _mbbislower_l(_c, p) ((p->mbcinfo->mbctype[(_c) + 1] & _SBLOW) == _SBLOW)
#define _mbbtolower_l(_c, p) (_mbbisupper_l(_c, p) ? p->mbcinfo->mbcasemap[_c] : _c)
#define _mbbtoupper_l(_c, p) (_mbbislower_l(_c, p) ? p->mbcinfo->mbcasemap[_c] : _c)
/* define full-width-latin upper/lower ranges */
#define _MBUPPERLOW1_MT(p) p->mbcinfo->mbulinfo[0]
#define _MBUPPERHIGH1_MT(p) p->mbcinfo->mbulinfo[1]
#define _MBCASEDIFF1_MT(p) p->mbcinfo->mbulinfo[2]
#define _MBUPPERLOW2_MT(p) p->mbcinfo->mbulinfo[3]
#define _MBUPPERHIGH2_MT(p) p->mbcinfo->mbulinfo[4]
#define _MBCASEDIFF2_MT(p) p->mbcinfo->mbulinfo[5]
// Kanji-specific ranges
#define _MBHIRALOW 0x829f // Hiragana
#define _MBHIRAHIGH 0x82f1
#define _MBKATALOW 0x8340 // Katakana
#define _MBKATAHIGH 0x8396
#define _MBKATAEXCEPT 0x837f // Exception
#define _MBKIGOULOW 0x8141 // Kanji punctuation
#define _MBKIGOUHIGH 0x81ac
#define _MBKIGOUEXCEPT 0x817f // Exception
// Macros used in the implementation of the classification functions.
// These accesses of _locale_pctype are internal and guarded by bounds checks when used.
#define _ismbbalnum_l(_c, pt) ((((pt)->locinfo->_public._locale_pctype)[_c] & \
(_ALPHA|_DIGIT)) || \
(((pt)->mbcinfo->mbctype+1)[_c] & _MS))
#define _ismbbalpha_l(_c, pt) ((((pt)->locinfo->_public._locale_pctype)[_c] & \
(_ALPHA)) || \
(((pt)->mbcinfo->mbctype+1)[_c] & _MS))
#define _ismbbgraph_l(_c, pt) ((((pt)->locinfo->_public._locale_pctype)[_c] & \
(_PUNCT|_ALPHA|_DIGIT)) || \
(((pt)->mbcinfo->mbctype+1)[_c] & (_MS|_MP)))
#define _ismbbprint_l(_c, pt) ((((pt)->locinfo->_public._locale_pctype)[_c] & \
(_BLANK|_PUNCT|_ALPHA|_DIGIT)) || \
(((pt)->mbcinfo->mbctype + 1)[_c] & (_MS|_MP)))
#define _ismbbpunct_l(_c, pt) ((((pt)->locinfo->_public._locale_pctype)[_c] & _PUNCT) || \
(((pt)->mbcinfo->mbctype+1)[_c] & _MP))
#define _ismbbblank_l(_c, pt) (((_c) == '\t') ? _BLANK : (((pt)->locinfo->_public._locale_pctype)[_c] & _BLANK) || \
(((pt)->mbcinfo->mbctype+1)[_c] & _MP))
// Note that these are intended for double byte character sets (DBCS) and so UTF-8 doesn't consider either to be true for any bytes
// (for UTF-8 we never set _M1 or _M2 in this array)
#define _ismbblead_l(_c, p) ((p->mbcinfo->mbctype + 1)[_c] & _M1)
#define _ismbbtrail_l(_c, p) ((p->mbcinfo->mbctype + 1)[_c] & _M2)
#ifdef __cplusplus
extern "C" inline int __cdecl __dcrt_multibyte_check_type(
unsigned int const c,
_locale_t const locale,
unsigned short const category_bits,
bool const expected
)
{
// Return false if we are not in a supported multibyte codepage:
if (!locale->mbcinfo->ismbcodepage)
return FALSE;
int const code_page = locale->mbcinfo->mbcodepage;
char const bytes[] = { static_cast<char>((c >> 8) & 0xff), static_cast<char>(c & 0xff) };
// The 'c' "character" could be two one-byte multibyte characters, so we
// need room in the type array to handle this. If 'c' is two one-byte
// multibyte characters, the second element in the type array will be
// nonzero.
unsigned short ctypes[2] = { };
if (__acrt_GetStringTypeA(locale, CT_CTYPE1, bytes, _countof(bytes), ctypes, code_page, TRUE) == 0)
return FALSE;
// Ensure 'c' is a single multibyte character:
if (ctypes[1] != 0)
return FALSE;
// Test the category:
return static_cast<bool>((ctypes[0] & category_bits) != 0) == expected ? TRUE : FALSE;
}
#endif
_Check_return_wat_
extern "C" errno_t __cdecl _wctomb_internal(
_Out_opt_ int* _SizeConverted,
_Out_writes_opt_z_(_SizeInBytes) char* _MbCh,
_In_ size_t _SizeInBytes,
_In_ wchar_t _WCh,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Success_(return != -1)
extern "C" int __cdecl _mbtowc_internal(
_Pre_notnull_ _Post_z_ wchar_t* _DstCh,
_In_reads_or_z_opt_(_SrcSizeInBytes) char const* _SrcCh,
_In_ size_t _SrcSizeInBytes,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_CRT_END_C_HEADER
namespace __crt_mbstring
{
size_t __cdecl __c16rtomb_utf8(char* s, char16_t c16, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __c32rtomb_utf8(char* s, char32_t c32, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __mbrtoc16_utf8(char16_t* pc32, const char* s, size_t n, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __mbrtoc32_utf8(char32_t* pc32, const char* s, size_t n, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __mbrtowc_utf8(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __mbsrtowcs_utf8(wchar_t* dst, const char** src, size_t len, mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t __cdecl __wcsrtombs_utf8(char* dst, const wchar_t** src, size_t len, mbstate_t* ps, __crt_cached_ptd_host& ptd);
constexpr size_t INVALID = static_cast<size_t>(-1);
constexpr size_t INCOMPLETE = static_cast<size_t>(-2);
size_t return_illegal_sequence(mbstate_t* ps, __crt_cached_ptd_host& ptd);
size_t reset_and_return(size_t retval, mbstate_t* ps);
}

View file

@ -0,0 +1,569 @@
//
// corecrt_internal_ptd_propagation.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Consistently querying for per-thread data puts a significant overhead
// on runtime of the UCRT. Instead of re-querying the PTD every time it is
// needed, the goal going forward is to propagate the PTD, locale, global state index,
// and errno information between function calls via an argument.
// This header contains support for PTD propagation, disables common
// macros that invoke errno, and provides internal-only functions that
// propagate the per-thread data.
#pragma once
#include <corecrt_internal.h>
#include <stdlib.h>
_CRT_BEGIN_C_HEADER
// To grab the PTD, we also must query the global state index. Both of the FlsGetValue calls must be protected
// from modifying the Win32 error state, so must be guarded by GetLastError()/SetLastError().
// This function is provided so that if we already know the global state index and already
// have a Win32 error guard object, we can avoid doing it again for getting the PTD.
__acrt_ptd* __cdecl __acrt_getptd_noexit_explicit(__crt_scoped_get_last_error_reset const&, size_t global_state_index);
#ifdef __cplusplus
extern "C++"
{
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// PTD Data Host
//
// Upon public function entry, one of these objects should be instantiated in order
// to host all the per-thread data for the rest of the function call. If any per-thread
// data is required, it will be requested once for the full runtime of the function.
// Additionally, changes to errno and doserrno will be recorded here instead, so that
// the actual errno value will only be updated once, and will never be queried.
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class __crt_cached_ptd_host
{ // The goal of this class is to minimize the number of calls to FlsGetValue()/SetLastError().
// Each call into the UCRT can use this class to lazily get and update:
// * The __acrt_ptd:
// * errno / doserrno
// * locale / multibyte info
// * The global state index
// while calling GetFlsValue the minimum number of times.
//
// -- PTD and Global State Index --
// Upon the first request of the PTD, both of these are updated at once. The global state index
// is required for getting the correct PTD, and both need to be guarded with
// a __crt_scoped_get_last_error_reset to prevent affecting the Win32 error.
// If the global state index is requested prior to the PTD, only the global state index is updated.
// -- Locale and Multibyte Info --
// If given a valid _locale_t during construction, it is used for the locale data.
// If the locale has not yet been set by a call to setlocale(), the initial locale
// data for the C locale is used instead.
// Otherwise, we wait until get_locale() is first called before querying the PTD
// and locking the locale from any other changes until the destructor is called
// (i.e. when the UCRT function call is completed).
// -- errno and _doserrno --
// This can be accessed directly via get_raw_ptd()->_terrno / _tdoserrno, but
// checking errno results between internal function calls
// (for example, printf can call wctomb and then check errno)
// is a significant source of overhead.
// Instead, both errno and doserrno changes are recorded locally in this class
// and the values in the PTD are only updated once this class is destroyed and the
// UCRT function call is complete.
// This means that if you must check errno after calling another function, if errno
// is not set then no PTD access was required. Using this instead of accessing errno
// directly removed all PTD access in many printf scenarios.
// Do not pass this directly, use __crt_cached_ptd_host&.
// When the PTD is queried by a child function, the parent will also not need to re-query.
public:
enum class locale_status : unsigned char
{
uninitialized,
updated_on_construction,
updated_via_ptd
};
explicit __crt_cached_ptd_host(_locale_t const locale = nullptr) throw()
: _ptd(nullptr), _current_global_state_index_valid(false), _locale_status(locale_status::uninitialized)
{
if (locale)
{
_locale_pointers = *locale;
_locale_status = locale_status::updated_on_construction;
}
else if (!__acrt_locale_changed())
{
_locale_pointers = __acrt_initial_locale_pointers;
_locale_status = locale_status::updated_on_construction;
}
}
~__crt_cached_ptd_host() throw()
{
if (_locale_status == locale_status::updated_via_ptd)
{
// We only locked the PTD from locale propagation if we are using
// the locale data from the PTD.
__acrt_enable_global_locale_sync(_ptd); // The PTD must be valid if locale was updated via the PTD.
}
if (_current_errno.valid())
{
get_raw_ptd()->_terrno = _current_errno.unsafe_value();
}
if (_current_doserrno.valid())
{
get_raw_ptd()->_tdoserrno = _current_doserrno.unsafe_value();
}
}
__crt_cached_ptd_host(__crt_cached_ptd_host const&) = delete;
__crt_cached_ptd_host& operator=(__crt_cached_ptd_host const&) = delete;
_locale_t get_locale() throw()
{
update_locale();
return &_locale_pointers;
}
size_t get_current_global_state_index() throw()
{
return check_synchronize_global_state_index();
}
__acrt_ptd * get_raw_ptd() throw()
{
return check_synchronize_per_thread_data();
}
__acrt_ptd * get_raw_ptd_noexit() throw()
{
return try_synchronize_per_thread_data();
}
template <typename T>
struct cached
{
public:
cached() throw()
: _valid(false)
{}
bool valid() const throw()
{
return _valid;
}
T set(T new_value) throw()
{
_valid = true;
_value = new_value;
return new_value;
}
T value_or(T const alternative) const throw()
{
if (_valid)
{
return _value;
}
return alternative;
}
bool check(T const value) const throw()
{
return _valid && _value == value;
}
class guard
{
public:
explicit guard(cached& parent) throw()
: _parent(parent), _copy(parent), _enabled(true)
{
}
~guard() throw()
{
if (_enabled)
{
_parent = _copy;
}
}
guard(guard const&) = delete;
guard& operator=(guard const&) = delete;
void disable() throw()
{
_enabled = false;
}
void enable() throw()
{
_enabled = true;
}
private:
cached& _parent;
cached _copy;
bool _enabled;
};
guard create_guard() throw()
{
return guard(*this);
}
T unsafe_value() throw()
{
// Must check status beforehand.
return _value;
}
private:
cached(cached const&) = default;
cached(cached&&) = default;
cached& operator=(cached const&) = default;
cached& operator=(cached&&) = default;
T _value;
bool _valid;
};
auto& get_errno() throw()
{
return _current_errno;
}
auto& get_doserrno() throw()
{
return _current_doserrno;
}
private:
__forceinline void update_locale() throw()
{ // Avoid costs for function call if locale doesn't need to be updated.
if (_locale_status == locale_status::uninitialized)
{
update_locale_slow();
}
}
void update_locale_slow() throw()
{
__acrt_ptd * const ptd_ptr = get_raw_ptd();
_locale_pointers.locinfo = ptd_ptr->_locale_info;
_locale_pointers.mbcinfo = ptd_ptr->_multibyte_info;
// _get_raw_ptd() will update _current_global_state_index
__acrt_update_locale_info_explicit(
ptd_ptr, &_locale_pointers.locinfo, _current_global_state_index
);
__acrt_update_multibyte_info_explicit(
ptd_ptr, &_locale_pointers.mbcinfo, _current_global_state_index
);
if ((ptd_ptr->_own_locale & _PER_THREAD_LOCALE_BIT) == 0)
{
// Skip re-synchronization with the global locale to prevent the
// locale from changing half-way through the call.
__acrt_disable_global_locale_sync(ptd_ptr);
_locale_status = locale_status::updated_via_ptd;
}
}
__forceinline __acrt_ptd * check_synchronize_per_thread_data() throw()
{
if (_ptd == nullptr)
{
if (force_synchronize_per_thread_data() == nullptr)
{
abort();
}
}
return _ptd;
}
__forceinline __acrt_ptd * try_synchronize_per_thread_data() throw()
{
if (_ptd == nullptr)
{
return force_synchronize_per_thread_data();
}
return _ptd;
}
__acrt_ptd * force_synchronize_per_thread_data() throw()
{ // This function should be called at most once per UCRT function call.
// Update all per-thread variables to minimize number of GetLastError() calls.
__crt_scoped_get_last_error_reset const last_error_reset;
return _ptd = __acrt_getptd_noexit_explicit(
last_error_reset,
check_synchronize_global_state_index(last_error_reset)
);
}
size_t check_synchronize_global_state_index() throw()
{
if (!_current_global_state_index_valid)
{
__crt_scoped_get_last_error_reset const last_error_reset;
return force_synchronize_global_state_index(last_error_reset);
}
return _current_global_state_index;
}
size_t check_synchronize_global_state_index(__crt_scoped_get_last_error_reset const& last_error_reset) throw()
{
if (!_current_global_state_index_valid)
{
return force_synchronize_global_state_index(last_error_reset);
}
return _current_global_state_index;
}
size_t force_synchronize_global_state_index(__crt_scoped_get_last_error_reset const& last_error_reset) throw()
{
_current_global_state_index = __crt_state_management::get_current_state_index(last_error_reset);
_current_global_state_index_valid = true;
return _current_global_state_index;
}
__acrt_ptd * _ptd;
size_t _current_global_state_index;
bool _current_global_state_index_valid;
__crt_locale_pointers _locale_pointers;
locale_status _locale_status;
cached<errno_t> _current_errno;
cached<unsigned long> _current_doserrno;
};
namespace __crt_state_management
{
// If we have already grabbed the PTD, then we also grabbed the current global state index
// and can use the global state index cached inside the __crt_cached_ptd_host.
template <typename T>
T& dual_state_global<T>::value(__crt_cached_ptd_host& ptd) throw()
{
return _value[ptd.get_current_global_state_index()];
}
template <typename T>
T const& dual_state_global<T>::value(__crt_cached_ptd_host& ptd) const throw()
{
return _value[ptd.get_current_global_state_index()];
}
}
} // extern "C++"
#endif // __cplusplus
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Validation Macros / Errno update functions
//
// All the UCRT _VALIDATE_* macros will set errno directly on error.
// These new validation macros use __crt_cached_ptd_host& instead to prevent overhead.
//
// If this header is included, then the old validation/errno macros are #undef-ed to
// to prevent accidental calling of errno.
//
// _ALLOW_OLD_VALIDATE_MACROS is provided as an escape hatch for files that need to include
// this header, but still have code paths that require the old validate macros.
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#ifndef _ALLOW_OLD_VALIDATE_MACROS
// Use this to allow the validate macros without PTD propagation in a source file.
#undef _INVALID_PARAMETER
#undef _VALIDATE_CLEAR_OSSERR_RETURN
#undef _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE
#undef _VALIDATE_RETURN
#undef _VALIDATE_RETURN_ERRCODE
#undef _VALIDATE_RETURN_ERRCODE_NOEXC
#undef _VALIDATE_RETURN_NOERRNO
#undef _VALIDATE_RETURN_NOEXC
#undef _VALIDATE_RETURN_VOID
#undef _ERRCHECK_SPRINTF
#undef _VALIDATE_STREAM_ANSI_RETURN
#undef _CHECK_FH_RETURN
#undef _CHECK_FH_CLEAR_OSSERR_RETURN
#undef _CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE
#undef _VALIDATE_CLEAR_OSSERR_RETURN
#undef errno
#undef _doserrno
#endif // _ALLOW_OLD_VALIDATE_MACROS
// Validate macros whose counterparts are from internal_shared.h
#ifdef _DEBUG
#define _UCRT_INVALID_PARAMETER(ptd, expr) _invalid_parameter_internal(expr, __FUNCTIONW__, __FILEW__, __LINE__, 0, ptd)
#else // _DEBUG
#define _UCRT_INVALID_PARAMETER(ptd, expr) _invalid_parameter_internal(nullptr, nullptr, nullptr, 0, 0, ptd)
#endif // _DEBUG
#define _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, expr, errorcode, retexpr) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_doserrno().set(0L); \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (retexpr); \
} \
}
#define _UCRT_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(ptd, expr, errorcode) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_doserrno().set(0L); \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (errorcode); \
} \
}
#define _UCRT_VALIDATE_RETURN(ptd, expr, errorcode, retexpr) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (retexpr); \
} \
}
#define _UCRT_VALIDATE_RETURN_ERRCODE(ptd, expr, errorcode) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (errorcode); \
} \
}
#define _UCRT_VALIDATE_RETURN_ERRCODE_NOEXC(ptd, expr, errorcode) \
{ \
if (!(expr)) \
{ \
return (ptd).get_errno().set((errorcode)); \
} \
}
#define _UCRT_VALIDATE_RETURN_NOERRNO(ptd, expr, retexpr) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (retexpr); \
} \
}
#define _UCRT_VALIDATE_RETURN_NOEXC(ptd, expr, errorcode, retexpr) \
{ \
if (!(expr)) \
{ \
(ptd).get_errno().set((errorcode)); \
return (retexpr); \
} \
}
#define _UCRT_VALIDATE_RETURN_VOID(ptd, expr, errorcode) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return; \
} \
}
// Validate macros whose counterparts are from corecrt_internal.h
#define _UCRT_VALIDATE_STREAM_ANSI_RETURN(ptd, stream, errorcode, retexpr) \
{ \
__crt_stdio_stream const _Stream((stream)); \
int fn; \
_UCRT_VALIDATE_RETURN((ptd), ( \
(_Stream.is_string_backed()) || \
(fn = _fileno(_Stream.public_stream()), \
((_textmode_safe(fn) == __crt_lowio_text_mode::ansi) && \
!_tm_unicode_safe(fn)))), \
(errorcode), (retexpr)) \
}
#define _UCRT_CHECK_FH_RETURN(ptd, handle, errorcode, retexpr) \
{ \
if ((handle) == _NO_CONSOLE_FILENO) \
{ \
(ptd).get_errno().set((errorcode)); \
return (retexpr); \
} \
}
#define _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, handle, errorcode, retexpr) \
{ \
if ((handle) == _NO_CONSOLE_FILENO) \
{ \
(ptd).get_doserrno().set(0L); \
(ptd).get_errno().set((errorcode)); \
return (retexpr); \
} \
}
#define _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE(ptd, handle, retexpr) \
{ \
if ((handle) == _NO_CONSOLE_FILENO) \
{ \
(ptd).get_doserrno().set(0L); \
return (retexpr); \
} \
}
#define _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, expr, errorcode, retexpr) \
{ \
int _Expr_val = !!(expr); \
_ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \
if (!(_Expr_val)) \
{ \
(ptd).get_doserrno().set(0L); \
(ptd).get_errno().set((errorcode)); \
_UCRT_INVALID_PARAMETER((ptd), _CRT_WIDE(#expr)); \
return (retexpr); \
} \
}
_CRT_END_C_HEADER

View file

@ -0,0 +1,130 @@
/***
*corecrt_internal_securecrt.h - contains declarations of internal routines and variables for securecrt
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Declares routines and variables used internally in the SecureCRT implementation.
* In this include file we define the macros needed to implement the secure functions
* inlined in the *.inl files like tcscpy_s.inl, etc.
*
* [Internal]
*
****/
#pragma once
#ifndef _INC_INTERNAL_SECURECRT
#define _INC_INTERNAL_SECURECRT
#include <corecrt_internal.h>
#include <errno.h>
/* string resetting */
#define _FILL_STRING _SECURECRT__FILL_STRING
#define _FILL_BYTE _SECURECRT__FILL_BYTE
#define _RESET_STRING(_String, _Size) \
*(_String) = 0; \
_FILL_STRING((_String), (_Size), 1);
/* validations */
#define _VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
_VALIDATE_RETURN((_String) != NULL && (_Size) > 0, EINVAL, (_Ret))
#define _VALIDATE_STRING(_String, _Size) \
_VALIDATE_STRING_ERROR((_String), (_Size), EINVAL)
#define _VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \
_VALIDATE_RETURN((_Pointer) != NULL, (_ErrorCode), (_Ret))
#define _VALIDATE_POINTER_ERROR(_Pointer, _Ret) \
_VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret))
#define _VALIDATE_POINTER(_Pointer) \
_VALIDATE_POINTER_ERROR((_Pointer), EINVAL)
#define _VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \
_VALIDATE_RETURN((_Condition), (_ErrorCode), (_Ret))
#define _VALIDATE_CONDITION_ERROR(_Condition, _Ret) \
_VALIDATE_CONDITION_ERROR_RETURN((_Condition), EINVAL, (_Ret))
#define _VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \
if ((_Pointer) == NULL) \
{ \
_RESET_STRING((_String), (_Size)); \
_VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret)) \
}
#define _VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \
_VALIDATE_POINTER_RESET_STRING_ERROR((_Pointer), (_String), (_Size), EINVAL)
#define _RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \
_VALIDATE_RETURN((L"Buffer is too small" && 0), ERANGE, _Ret)
#define _RETURN_BUFFER_TOO_SMALL(_String, _Size) \
_RETURN_BUFFER_TOO_SMALL_ERROR((_String), (_Size), ERANGE)
#define _RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \
_VALIDATE_RETURN((L"String is not null terminated" && 0), EINVAL, EINVAL)
#define _RETURN_EINVAL \
_VALIDATE_RETURN((L"Invalid parameter", 0), EINVAL, EINVAL)
#define _RETURN_ERROR(_Msg, _Ret) \
_VALIDATE_RETURN(((_Msg), 0), EINVAL, _Ret)
/* returns without calling _invalid_parameter */
#define _RETURN_NO_ERROR \
return 0
/* Note that _RETURN_TRUNCATE does not set errno */
#define _RETURN_TRUNCATE \
return STRUNCATE
#define _SET_MBCS_ERROR \
(errno = EILSEQ)
#define _RETURN_MBCS_ERROR \
return _SET_MBCS_ERROR
/* locale dependent */
#define _LOCALE_ARG \
_LocInfo
#define _LOCALE_ARG_DECL \
_locale_t _LOCALE_ARG
#define _LOCALE_UPDATE \
_LocaleUpdate _LocUpdate(_LOCALE_ARG)
#define _ISMBBLEAD(_Character) \
_ismbblead_l((_Character), _LocUpdate.GetLocaleT())
#define _ISMBBLEADPREFIX(_Result, _StringStart, _BytePtr) \
{ \
unsigned char *_Tmp_VAR, *_StringStart_VAR, *_BytePtr_VAR; \
\
_StringStart_VAR = (_StringStart); \
_BytePtr_VAR = (_BytePtr); \
_Tmp_VAR = _BytePtr_VAR; \
while ((_Tmp_VAR >= _StringStart_VAR) && _ISMBBLEAD(*_Tmp_VAR)) \
{ \
_Tmp_VAR--; \
} \
(_Result) = ((_BytePtr_VAR - _Tmp_VAR) & 1) != 0; \
}
#define _LOCALE_SHORTCUT_TEST \
_LocUpdate.GetLocaleT()->mbcinfo->ismbcodepage == 0
/* misc */
#define _ASSIGN_IF_NOT_NULL(_Pointer, _Value) \
if ((_Pointer) != NULL) \
{ \
*(_Pointer) = (_Value); \
}
#endif /* _INC_INTERNAL_SECURECRT */

View file

@ -0,0 +1,157 @@
//
// corecrt_internal_simd.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines internal SIMD utilities. This header may only
// be included in C++ translation units.
//
#pragma once
#include <intrin.h>
#include <isa_availability.h>
#include <stdint.h>
#if (defined _M_IX86 || defined _M_X64) && !defined(_M_HYBRID_X86_ARM64) && !defined(_M_ARM64EC)
#define _CRT_SIMD_SUPPORT_AVAILABLE
#endif
#if defined _CRT_SIMD_SUPPORT_AVAILABLE
extern "C" int __isa_available;
enum class __crt_simd_isa
{
sse2,
avx2
};
template <__crt_simd_isa Isa>
struct __crt_simd_cleanup_guard;
template <__crt_simd_isa Isa>
struct __crt_simd_pack_traits;
template <__crt_simd_isa Isa, typename Element>
struct __crt_simd_traits;
template <__crt_simd_isa Isa, typename Element>
struct __crt_simd_element_traits
: __crt_simd_pack_traits<Isa>
{
using element_type = Element;
enum : size_t
{
element_size = sizeof(element_type),
elements_per_pack = pack_size / element_size
};
};
template <>
struct __crt_simd_cleanup_guard<__crt_simd_isa::sse2>
{
// No cleanup required for SSE2 usage, however we still need to define
// the no-op destructor in order to avoid unreferened local variable
// warnings when this cleanup guard is used.
~__crt_simd_cleanup_guard() throw()
{
}
};
template <>
struct __crt_simd_pack_traits<__crt_simd_isa::sse2>
{
using pack_type = __m128i;
enum : size_t { pack_size = sizeof(pack_type) };
static __forceinline pack_type get_zero_pack() throw()
{
return _mm_setzero_si128();
}
static __forceinline int compute_byte_mask(pack_type const x) throw()
{
return _mm_movemask_epi8(x);
}
};
template <>
struct __crt_simd_traits<__crt_simd_isa::sse2, uint8_t>
: __crt_simd_element_traits<__crt_simd_isa::sse2, uint8_t>
{
static __forceinline pack_type compare_equals(pack_type const x, pack_type const y) throw()
{
return _mm_cmpeq_epi8(x, y);
}
};
template <>
struct __crt_simd_traits<__crt_simd_isa::sse2, uint16_t>
: __crt_simd_element_traits<__crt_simd_isa::sse2, uint16_t>
{
static __forceinline pack_type compare_equals(pack_type const x, pack_type const y) throw()
{
return _mm_cmpeq_epi16(x, y);
}
};
template <>
struct __crt_simd_cleanup_guard<__crt_simd_isa::avx2>
{
~__crt_simd_cleanup_guard()
{
// After executing AVX2 instructions, we must zero the upper halves
// of the YMM registers before returning. See the Intel article
// "Intel AVX State Transitions: Migrating SSE Code to AVX" for
// further details.
_mm256_zeroupper();
}
};
template <>
struct __crt_simd_pack_traits<__crt_simd_isa::avx2>
{
using pack_type = __m256i;
enum : size_t { pack_size = sizeof(pack_type) };
static __forceinline pack_type get_zero_pack() throw()
{
return _mm256_setzero_si256();
}
static __forceinline int compute_byte_mask(pack_type const x) throw()
{
return _mm256_movemask_epi8(x);
}
};
template <>
struct __crt_simd_traits<__crt_simd_isa::avx2, uint8_t>
: __crt_simd_element_traits<__crt_simd_isa::avx2, uint8_t>
{
static __forceinline pack_type compare_equals(pack_type const x, pack_type const y) throw()
{
return _mm256_cmpeq_epi8(x, y);
}
};
template <>
struct __crt_simd_traits<__crt_simd_isa::avx2, uint16_t>
: __crt_simd_element_traits<__crt_simd_isa::avx2, uint16_t>
{
static __forceinline pack_type compare_equals(pack_type const x, pack_type const y) throw()
{
return _mm256_cmpeq_epi16(x, y);
}
};
#endif // _CRT_SIMD_SUPPORT_AVAILABLE

View file

@ -0,0 +1,864 @@
//
// corecrt_internal_stdio.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines internal utilities for working with the stdio
// library.
//
#pragma once
#include <corecrt_internal.h>
#include <corecrt_internal_lowio.h>
#include <corecrt_internal_traits.h>
#include <io.h>
#include <mbstring.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(push, _CRT_PACKING)
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Stream State Flags
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
enum : long
{
// Mode bits: These bits control the stream mode. A stream may be in one
// of three modes: read mode, write mode, or update (read/write) mode. At
// least one of these bits will be set for any open stream.
//
// If the stream is open in read mode or write mode, then only the _IOREAD
// or _IOWRITE bit will be set.
//
// If the stream is open in update (read/write) mode, then the _IOUPDATE bit
// will be set. Further state must also be tracked for update mode streams.
// Read and write operations cannot be mixed willy-nilly: in most cases, a
// flush or reposition must take place in order to transition between reading
// and writing. So, for update mode streams, if the next operation must be
// a read, the _IOREAD bit is set, and if the next operation must be a write,
// the _IOWRITE bit is set.
_IOREAD = 0x0001,
_IOWRITE = 0x0002,
_IOUPDATE = 0x0004,
// Stream state bits: These bits track the state of the stream. The _IOEOF
// and _IOERROR flags track the end-of-file and error states, respectively,
// which are reported by feof() and ferror(). The _IOCTRLZ flag is when the
// last read ended because a Ctrl+Z was read; it corresponds to the lowio
// FEOFLAG state.
_IOEOF = 0x0008,
_IOERROR = 0x0010,
_IOCTRLZ = 0x0020,
// Buffering state bits: These track the buffering mode of the stream:
//
// (*) CRT: The buffer was allocated by the CRT via the usual mechanism
// (typically via __acrt_stdio_allocate_buffer_nolock, and of
// size _INTERNAL_BUFSIZ).
//
// (*) USER: The buffer was allocated by the user and was configured via
// the setvbuf() function.
//
// (*) SETVBUF: The buffer was set via the setvbuf() function. This flag
// may be combined with either the CRT or USER flag, depending
// on who owns the buffer (based on how setvbuf() was called).
//
// (*) STBUF: The buffer was set via a call to the
// __acrt_stdio_begin_temporary_buffering_nolock() function,
// which provides a temporary buffer for console I/O operations
// to improve the performance of bulk read or write operations.
//
// (*) NONE: Buffering is disabled, either because it was explicitly
// disabled or because the CRT attempted to allocate a buffer
// but allocation failed. When this flag is set, the internal
// two-byte character buffer is used.
//
// Note that these flags are related to, but distinct from, the public stdio
// buffering flags that are used with setvbuf (_IOFBF, _IOLBF, and _IONBF).
// Specifically, note that those flags are never or'ed into the flags for a
// stream.
_IOBUFFER_CRT = 0x0040,
_IOBUFFER_USER = 0x0080,
_IOBUFFER_SETVBUF = 0x0100,
_IOBUFFER_STBUF = 0x0200,
_IOBUFFER_NONE = 0x0400,
// Commit-on-flush state bit: When this flag is set, every flush operation
// on the stream also commits the file to disk.
_IOCOMMIT = 0x0800,
// String state bit: When this flag is set, it indicates that the stream is
// backed by a string, not a file. String-backed streams are not exposed to
// user code; they are created internally to support formatted I/O to string
// buffers (e.g. the sprintf and sscanf families of functions). If a stream
// is backed by a string, its lock is not initialized and no synchronization
// is required.
_IOSTRING = 0x1000,
// Allocation state bit: When this flag is set it indicates that the stream
// is currently allocated and in-use. If this flag is not set, it indicates
// that the stream is free and available for use.
_IOALLOCATED = 0x2000,
};
#ifndef _M_CEE
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal stdio functions with PTD propagation
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_Check_return_opt_
extern "C" int __cdecl _putch_nolock_internal(
_In_ int _Ch,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_opt_
extern "C" wint_t __cdecl _putwch_nolock_internal(
_In_ wchar_t _Ch,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_opt_
extern "C" wint_t __cdecl _fputwc_nolock_internal(
_In_ wchar_t _Character,
_Inout_ FILE* _Stream,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Success_(return != EOF)
_Check_return_opt_
extern "C" int __cdecl _fputc_nolock_internal(
_In_ int _Character,
_Inout_ FILE* _Stream,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_opt_
extern "C" size_t __cdecl _fwrite_nolock_internal(
_In_reads_bytes_(_ElementSize * _ElementCount) void const* _Buffer,
_In_ size_t _ElementSize,
_In_ size_t _ElementCount,
_Inout_ FILE* _Stream,
_Inout_ __crt_cached_ptd_host& _Ptd
);
_Check_return_
extern "C" __int64 __cdecl _ftelli64_nolock_internal(
_Inout_ FILE* _Stream,
_Inout_ __crt_cached_ptd_host& _Ptd
);
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal Stream Types (__crt_stdio_stream and friends)
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
struct __crt_stdio_stream_data
{
union
{
FILE _public_file;
char* _ptr;
};
char* _base;
int _cnt;
long _flags;
long _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
CRITICAL_SECTION _lock;
};
// Ensure that __crt_stdio_stream_data* and FILE* pointers are freely convertible:
static_assert(
offsetof(__crt_stdio_stream_data, _public_file) == 0,
"FILE member of __crt_stdio_stream_data is not at offset zero."
);
static_assert(
sizeof(FILE) == sizeof(void*),
"FILE structure has unexpected size."
);
class __crt_stdio_stream
{
public:
__crt_stdio_stream() throw()
: _stream(nullptr)
{
}
explicit __crt_stdio_stream(FILE* const stream) throw()
: _stream(reinterpret_cast<__crt_stdio_stream_data*>(stream))
{
}
explicit __crt_stdio_stream(__crt_stdio_stream_data* const stream) throw()
: _stream(stream)
{
}
bool valid() const throw() { return _stream != nullptr; }
FILE* public_stream() const throw() { return &_stream->_public_file; }
// Tests whether this stream is allocated. Returns true if the stream is
// currently in use; returns false if the stream is free for allocation.
bool is_in_use() const throw()
{
return (get_flags() & _IOALLOCATED) != 0;
}
// Attempts to allocate this stream for use. Returns true if this stream was
// free and has been allocated for the caller. Returns false if the stream
// was in-use and could not be allocated for the caller. If it returns true,
// the caller gains ownership of the stream and is responsible for deallocating
// it.
bool try_allocate() throw()
{
return (_InterlockedOr(&_stream->_flags, _IOALLOCATED) & _IOALLOCATED) == 0;
}
// Deallocates the stream, freeing it for use by another client. It is
// assumed that the caller owns the stream before calling this function.
void deallocate() throw()
{
// Note: We clear all flags intentionally, so that the stream object
// is "clean" the next time it is allocated.
_InterlockedExchange(&_stream->_flags, 0);
}
void lock() const throw() { _lock_file (public_stream()); }
void unlock() const throw() { _unlock_file(public_stream()); }
bool has_any_of(long const flags) const throw() { return (get_flags() & flags) != 0; }
bool has_all_of(long const flags) const throw() { return (get_flags() & flags) == flags; }
bool set_flags (long const flags) const throw() { return (_InterlockedOr(&_stream->_flags, flags) & flags) != 0; }
bool unset_flags(long const flags) const throw() { return (_InterlockedAnd(&_stream->_flags, ~flags) & flags) != 0; }
bool eof() const throw() { return has_any_of(_IOEOF); }
bool error() const throw() { return has_any_of(_IOERROR); }
bool ctrl_z() const throw() { return has_any_of(_IOCTRLZ); }
bool has_crt_buffer() const throw() { return has_any_of(_IOBUFFER_CRT); }
bool has_user_buffer() const throw() { return has_any_of(_IOBUFFER_USER); }
bool has_temporary_buffer() const throw() { return has_any_of(_IOBUFFER_STBUF); }
bool has_setvbuf_buffer() const throw() { return has_any_of(_IOBUFFER_SETVBUF); }
bool has_big_buffer() const throw() { return has_any_of(_IOBUFFER_CRT | _IOBUFFER_USER); }
bool has_any_buffer() const throw() { return has_any_of(_IOBUFFER_CRT | _IOBUFFER_USER | _IOBUFFER_NONE); }
int lowio_handle() const throw() { return __crt_interlocked_read(&_stream->_file); }
bool is_string_backed() const throw() { return (get_flags() & _IOSTRING) != 0; }
__crt_stdio_stream_data* operator->() const throw() { return _stream; }
long get_flags() const throw()
{
return __crt_interlocked_read(&_stream->_flags);
}
private:
__crt_stdio_stream_data* _stream;
};
// These cannot have C linkage because they use __crt_stdio_stream, which has
// a destructor.
__crt_stdio_stream __cdecl __acrt_stdio_allocate_stream() throw();
void __cdecl __acrt_stdio_free_stream(__crt_stdio_stream _Stream) throw();
template <typename Action>
auto __acrt_lock_stream_and_call(FILE* const stream, Action&& action) throw()
-> decltype(action())
{
return __crt_seh_guarded_call<decltype(action())>()(
[stream]() { _lock_file(stream); },
action,
[stream]() { _unlock_file(stream); });
}
/*
* Number of entries supported in the array pointed to by __piob[]. That is,
* the number of stdio-level files which may be open simultaneously. This
* is normally set to _NSTREAM_ by the stdio initialization code.
*/
extern "C" extern int _nstream;
/*
* Pointer to the array of pointers to FILE structures that are used
* to manage stdio-level files.
*/
extern "C" extern __crt_stdio_stream_data** __piob;
// __acrt_stdio_is_initialized cannot be with the rest of
// stdio initialization logic since referencing those symbols
// pulls in the stdio initializers.
inline bool __acrt_stdio_is_initialized() {
return __piob != 0;
}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Deprecated stdio functionality
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
extern "C" {
__DEFINE_CPP_OVERLOAD_STANDARD_FUNC_0_0(
_Success_(return != 0) char*, __RETURN_POLICY_SAME, _ACRTIMP, gets,
_Pre_notnull_ _Post_z_ _Out_writes_z_(((size_t)-1)), char, _Buffer
)
// string[0] must contain the maximum length of the string. The number of
// characters written is stored in string[1]. The return value is a pointer to
// string[2] on success; nullptr on failure.
__DEFINE_CPP_OVERLOAD_STANDARD_FUNC_0_0_CGETS(
_Success_(return != 0) char*, _DCRTIMP, _cgets,
_At_(_Buffer, _Pre_notnull_ _In_reads_(1))
_At_(_Buffer + 1, _Pre_notnull_ _Out_writes_(1))
_At_(_Buffer + 2, _Pre_notnull_ _Post_z_ _Out_writes_to_(_Buffer[0], _Buffer[1])),
char, _Buffer
)
__DEFINE_CPP_OVERLOAD_STANDARD_FUNC_0_0(
_Success_(return != 0)
wchar_t*, __RETURN_POLICY_SAME, _ACRTIMP, _getws,
_Pre_notnull_ _Post_z_, wchar_t, _Buffer
)
// string[0] must contain the maximum length of the string. The number of
// characters written is stored in string[1]. The return value is a pointer to
// string[2] on success; nullptr on failure.
__DEFINE_CPP_OVERLOAD_STANDARD_FUNC_0_0_CGETS(
_Post_satisfies_(return == 0 || return == _Buffer + 2)
_Success_(return != 0) wchar_t*, _DCRTIMP, _cgetws,
_At_(_Buffer, _In_reads_(1))
_At_(_Buffer + 1, _Out_writes_(1))
_At_(_Buffer + 2, _Post_z_ _Out_writes_to_(_Buffer[0], _Buffer[1])),
wchar_t, _Buffer
)
} // extern "C"
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal stdio functionality
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
extern "C" {
_Check_return_
FILE* __cdecl _openfile(
_In_z_ char const* file_name,
_In_z_ char const* mode,
_In_ int share_flag,
_Out_ FILE* stream
);
_Check_return_
FILE* __cdecl _wopenfile(
_In_z_ wchar_t const* file_name,
_In_z_ wchar_t const* mode,
_In_ int share_flag,
_Out_ FILE* stream
);
_Check_return_
int __cdecl __acrt_stdio_refill_and_read_narrow_nolock(
_Inout_ FILE* stream
);
_Check_return_
int __cdecl __acrt_stdio_refill_and_read_wide_nolock(
_Inout_ FILE* stream
);
_Check_return_opt_
int __cdecl __acrt_stdio_flush_and_write_narrow_nolock(
_In_ int c,
_Inout_ FILE* stream,
_Inout_ __crt_cached_ptd_host& ptd
);
_Check_return_opt_
int __cdecl __acrt_stdio_flush_and_write_wide_nolock(
_In_ int c,
_Inout_ FILE* stream,
_Inout_ __crt_cached_ptd_host& ptd
);
void __cdecl __acrt_stdio_allocate_buffer_nolock(
_Out_ FILE* stream
);
void __cdecl __acrt_stdio_free_buffer_nolock(
_Inout_ FILE* stream
);
bool __cdecl __acrt_stdio_begin_temporary_buffering_nolock(
_Inout_ FILE* stream
);
bool __cdecl __acrt_should_use_temporary_buffer(
_In_ FILE* stream
);
void __cdecl __acrt_stdio_end_temporary_buffering_nolock(
_In_ bool flag,
_Inout_ FILE* stream,
_Inout_ __crt_cached_ptd_host& ptd
);
int __cdecl __acrt_stdio_flush_nolock(
_Inout_ FILE* stream,
_Inout_ __crt_cached_ptd_host& ptd
);
void __cdecl __acrt_stdio_free_tmpfile_name_buffers_nolock();
#ifndef CRTDLL
extern int _cflush;
#endif
extern unsigned int _tempoff;
extern unsigned int _old_pfxlen;
} // extern "C"
class __acrt_stdio_temporary_buffering_guard
{
public:
explicit __acrt_stdio_temporary_buffering_guard(FILE* const stream, __crt_cached_ptd_host& ptd) throw()
: _stream(stream), _ptd(ptd)
{
_flag = __acrt_stdio_begin_temporary_buffering_nolock(stream);
}
__acrt_stdio_temporary_buffering_guard(__acrt_stdio_temporary_buffering_guard const&) throw() = delete;
void operator=(__acrt_stdio_temporary_buffering_guard const&) throw() = delete;
~__acrt_stdio_temporary_buffering_guard() throw()
{
__acrt_stdio_end_temporary_buffering_nolock(_flag, _stream, _ptd);
}
private:
FILE* _stream;
__crt_cached_ptd_host& _ptd;
bool _flag;
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Character Traits
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename Character>
struct __acrt_stdio_char_traits;
template <>
struct __acrt_stdio_char_traits<char> : __crt_char_traits<char>
{
static int_type const eof = EOF;
static bool validate_stream_is_ansi_if_required(FILE* const stream) throw()
{
_VALIDATE_STREAM_ANSI_RETURN(stream, EINVAL, false);
return true;
}
};
template <>
struct __acrt_stdio_char_traits<wchar_t> : __crt_char_traits<wchar_t>
{
static int_type const eof = WEOF;
static bool validate_stream_is_ansi_if_required(FILE* const stream) throw()
{
UNREFERENCED_PARAMETER(stream);
return true; // This validation is only for ANSI functions.
}
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// fopen mode string parser
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Represents a {lowio, stdio} mode pair. This is the result of parsing a
// stdio mode string using the parser, defined below.
struct __acrt_stdio_stream_mode
{
int _lowio_mode;
int _stdio_mode;
bool _success;
};
// This function and the following functions support __acrt_stdio_parse_mode.
// They handle individual parts of the parsing.
inline bool __acrt_stdio_parse_mode_plus(__acrt_stdio_stream_mode& result, bool& seen_plus) throw()
{
if (seen_plus) {
return false;
}
seen_plus = true;
if (result._lowio_mode & _O_RDWR) {
return false;
}
result._lowio_mode |= _O_RDWR;
result._lowio_mode &= ~(_O_RDONLY | _O_WRONLY);
result._stdio_mode |= _IOUPDATE;
result._stdio_mode &= ~(_IOREAD | _IOWRITE);
return true;
}
inline bool __acrt_stdio_parse_mode_b(__acrt_stdio_stream_mode& result) throw()
{
if (result._lowio_mode & (_O_TEXT | _O_BINARY)) {
return false;
}
result._lowio_mode |= _O_BINARY;
return true;
}
inline bool __acrt_stdio_parse_mode_t(__acrt_stdio_stream_mode& result) throw()
{
if (result._lowio_mode & (_O_TEXT | _O_BINARY)) {
return false;
}
result._lowio_mode |= _O_TEXT;
return true;
}
inline bool __acrt_stdio_parse_mode_c(__acrt_stdio_stream_mode& result, bool& seen_commit_mode) throw()
{
if (seen_commit_mode) {
return false;
}
seen_commit_mode = true;
result._stdio_mode |= _IOCOMMIT;
return true;
}
inline bool __acrt_stdio_parse_mode_n(__acrt_stdio_stream_mode& result, bool& seen_commit_mode) throw()
{
if (seen_commit_mode) {
return false;
}
seen_commit_mode = true;
result._stdio_mode &= ~_IOCOMMIT;
return true;
}
inline bool __acrt_stdio_parse_mode_S(__acrt_stdio_stream_mode& result, bool& seen_scan_mode) throw()
{
if (seen_scan_mode) {
return false;
}
seen_scan_mode = true;
result._lowio_mode |= _O_SEQUENTIAL;
return true;
}
inline bool __acrt_stdio_parse_mode_R(__acrt_stdio_stream_mode& result, bool& seen_scan_mode) throw()
{
if (seen_scan_mode) {
return false;
}
seen_scan_mode = true;
result._lowio_mode |= _O_RANDOM;
return true;
}
inline bool __acrt_stdio_parse_mode_T(__acrt_stdio_stream_mode& result) throw()
{
if (result._lowio_mode & _O_SHORT_LIVED) {
return false;
}
result._lowio_mode |= _O_SHORT_LIVED;
return true;
}
inline bool __acrt_stdio_parse_mode_D(__acrt_stdio_stream_mode& result) throw()
{
if (result._lowio_mode & _O_TEMPORARY) {
return false;
}
result._lowio_mode |= _O_TEMPORARY;
return true;
}
inline bool __acrt_stdio_parse_mode_N(__acrt_stdio_stream_mode& result) throw()
{
result._lowio_mode |= _O_NOINHERIT;
return true;
}
inline bool __acrt_stdio_parse_mode_x(__acrt_stdio_stream_mode& result) throw()
{
if (!(result._lowio_mode & _O_TRUNC)) {
// 'x' only permitted with 'w'
return false;
}
result._lowio_mode |= _O_EXCL;
return true;
}
// Parses a stdio mode string, returning the corresponding pair of lowio and
// stdio flags. On success, sets the success flag in the result to true; on
// failure, sets that flag to false. All failures are logic errors.
template <typename Character>
__acrt_stdio_stream_mode __cdecl __acrt_stdio_parse_mode(
Character const* const mode
) throw()
{
typedef __acrt_stdio_char_traits<Character> stdio_traits;
// Note that we value initialize the result, so the success flag is false
// by default. This ensures that any premature return will return failure.
__acrt_stdio_stream_mode result = __acrt_stdio_stream_mode();
result._stdio_mode = _commode;
// Advance past any leading spaces:
Character const* it = mode;
while (*it == ' ')
++it;
// Read the first character. It must be one of 'r', 'w' , or 'a':
switch (*it)
{
case 'r':
result._lowio_mode = _O_RDONLY;
result._stdio_mode = _IOREAD;
break;
case 'w':
result._lowio_mode = _O_WRONLY | _O_CREAT | _O_TRUNC;
result._stdio_mode = _IOWRITE;
break;
case 'a':
result._lowio_mode = _O_WRONLY | _O_CREAT | _O_APPEND;
result._stdio_mode = _IOWRITE;
break;
default:
_VALIDATE_RETURN(("Invalid file open mode", 0), EINVAL, result);
}
// Advance past the first character:
++it;
// There can be up to seven more optional mode characters:
// [1] A single '+' character
// [2] One of 't' or 'b' (indicating text or binary, respectively)
// [3] One of 'c' or 'n' (enable or disable auto-commit to disk on flush)
// [4] One of 'S' or 'R' (optimize for sequential or random access)
// [5] 'T' (indicating the file is short-lived)
// [6] 'D' (indicating the file is temporary)
// [7] 'N' (indicating the file should not be inherited by child processes)
// [8] 'x' (indicating the file must be created and it is an error if it already exists)
bool seen_commit_mode = false;
bool seen_plus = false;
bool seen_scan_mode = false;
bool seen_encoding_flag = false;
for (bool continue_loop = true; continue_loop && *it != '\0'; it += (continue_loop ? 1 : 0))
{
switch (*it)
{
case '+': continue_loop = __acrt_stdio_parse_mode_plus(result, seen_plus); break;
case 'b': continue_loop = __acrt_stdio_parse_mode_b (result); break;
case 't': continue_loop = __acrt_stdio_parse_mode_t (result); break;
case 'c': continue_loop = __acrt_stdio_parse_mode_c (result, seen_commit_mode); break;
case 'n': continue_loop = __acrt_stdio_parse_mode_n (result, seen_commit_mode); break;
case 'S': continue_loop = __acrt_stdio_parse_mode_S (result, seen_scan_mode ); break;
case 'R': continue_loop = __acrt_stdio_parse_mode_R (result, seen_scan_mode ); break;
case 'T': continue_loop = __acrt_stdio_parse_mode_T (result); break;
case 'D': continue_loop = __acrt_stdio_parse_mode_D (result); break;
case 'N': continue_loop = __acrt_stdio_parse_mode_N (result); break;
case 'x': continue_loop = __acrt_stdio_parse_mode_x (result); break;
// If we encounter any spaces, skip them:
case ' ':
break;
// If we encounter a comma, it begins the encoding specification; we
// break out of the loop immediately and parse the encoding flag next:
case ',':
seen_encoding_flag = true;
continue_loop = false;
break;
default:
_VALIDATE_RETURN(("Invalid file open mode", 0), EINVAL, result);
}
}
// Advance past the comma that terminated the loop:
if (seen_encoding_flag)
++it;
while (*it == ' ')
++it;
// If we did not encounter the encoding introducer (a comma), make sure we
// actually reached the end of the mode string. We are done:
if (!seen_encoding_flag)
{
_VALIDATE_RETURN(*it == '\0', EINVAL, result);
result._success = true;
return result;
}
// Otherwise, we saw the beginning of an encoding; parse it:
static Character const ccs[] = { 'c', 'c', 's' };
static Character const utf8_encoding[] = { 'U', 'T', 'F', '-', '8' };
static Character const utf16_encoding[] = { 'U', 'T', 'F', '-', '1', '6', 'L', 'E' };
static Character const unicode_encoding[] = { 'U', 'N', 'I', 'C', 'O', 'D', 'E' };
// Make sure it begins with "ccs" (all lowercase)...
if (stdio_traits::tcsncmp(it, ccs, _countof(ccs)) != 0)
_VALIDATE_RETURN(("Invalid file open mode", 0), EINVAL, result);
it += _countof(ccs); // Advance past the "ccs"
while (*it == ' ')
++it;
if (*it != '=')
_VALIDATE_RETURN(("Invalid file open mode", 0), EINVAL, result);
++it; // Advance past the "="
while (*it == ' ')
++it;
if (stdio_traits::tcsnicmp(it, utf8_encoding, _countof(utf8_encoding)) == 0)
{
it += _countof(utf8_encoding);
result._lowio_mode |= _O_U8TEXT;
}
else if (stdio_traits::tcsnicmp(it, utf16_encoding, _countof(utf16_encoding)) == 0)
{
it += _countof(utf16_encoding);
result._lowio_mode |= _O_U16TEXT;
}
else if (stdio_traits::tcsnicmp(it, unicode_encoding, _countof(unicode_encoding)) == 0)
{
it += _countof(unicode_encoding);
result._lowio_mode |= _O_WTEXT;
}
else
{
_VALIDATE_RETURN(("Invalid file open mode", 0), EINVAL, result);
}
// Finally, skip any trailing spaces...
while (*it == ' ')
++it;
// ...and ensure there are no characters left:
_VALIDATE_RETURN(*it == '\0', EINVAL, result);
result._success = true;
return result;
}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// __acrt_common_path_requires_backslash()
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
inline bool __cdecl __crt_stdio_path_requires_backslash(char const* const first) throw()
{
char const* const last = first + strlen(first);
if (first == last)
return false;
if (*(last - 1) == '\\')
{
return reinterpret_cast<unsigned char const*>(last - 1)
!= _mbsrchr(reinterpret_cast<unsigned char const*>(first), '\\');
}
if (*(last - 1) == '/')
return false;
return true;
}
inline bool __cdecl __crt_stdio_path_requires_backslash(wchar_t const* const first) throw()
{
wchar_t const* const last = first + wcslen(first);
if (first == last)
return false;
if (*(last - 1) == L'\\')
return false;
if (*(last - 1) == L'/')
return false;
return true;
}
// Reset the file buffer to be empty and ready for reuse
inline void __cdecl __acrt_stdio_reset_buffer(__crt_stdio_stream const stream) throw()
{
stream->_ptr = stream->_base;
stream->_cnt = 0;
}
#endif // !_M_CEE
#pragma pack(pop)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,299 @@
//
// corecrt_internal_string_templates.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines template implementations of several secure
// string functions that have identical implementations for both narrow and
// wide character strings.
//
#pragma once
#include <corecrt_internal_securecrt.h>
// _strcat_s() and _wcscat_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcscat_s(
_Inout_updates_z_(size_in_elements) Character* const destination,
size_t const size_in_elements,
_In_z_ Character const* const source
) throw()
{
_VALIDATE_STRING(destination, size_in_elements);
_VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
Character* destination_it = destination;
size_t available = size_in_elements;
while (available > 0 && *destination_it != 0)
{
++destination_it;
--available;
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
}
Character const* source_it = source;
while ((*destination_it++ = *source_it++) != 0 && --available > 0)
{
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}
// _strcpy_s() and _wcscpy_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcscpy_s(
_Out_writes_z_(size_in_elements) Character* const destination,
_In_ size_t const size_in_elements,
_In_z_ Character const* const source
) throw()
{
_VALIDATE_STRING(destination, size_in_elements);
_VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
Character* destination_it = destination;
Character const* source_it = source;
size_t available = size_in_elements;
while ((*destination_it++ = *source_it++) != 0 && --available > 0)
{
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}
// _strncat_s() and _wcsncat_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcsncat_s(
_Inout_updates_z_(size_in_elements) Character* const destination,
_In_ size_t const size_in_elements,
_In_reads_or_z_(count) Character const* const source,
_In_ size_t const count
) throw()
{
if (count == 0 && destination == nullptr && size_in_elements == 0)
{
// This case is allowed; nothing to do:
_RETURN_NO_ERROR;
}
_VALIDATE_STRING(destination, size_in_elements);
if (count != 0)
{
_VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
}
Character* destination_it = destination;
size_t available = size_in_elements;
size_t remaining = count;
while (available > 0 && *destination_it != 0)
{
++destination_it;
--available;
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
}
Character const* source_it = source;
if (count == _TRUNCATE)
{
while ((*destination_it++ = *source_it++) != 0 && --available > 0)
{
}
}
else
{
while (remaining > 0 && (*destination_it++ = *source_it++) != 0 && --available > 0)
{
remaining--;
}
if (remaining == 0)
{
*destination_it = 0;
}
}
if (available == 0)
{
if (count == _TRUNCATE)
{
destination[size_in_elements - 1] = 0;
_RETURN_TRUNCATE;
}
_RESET_STRING(destination, size_in_elements);
_RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}
// _strncpy_s() and _wcsncpy_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcsncpy_s(
_Out_writes_z_(size_in_elements) Character* const destination,
_In_ size_t const size_in_elements,
_In_reads_or_z_(count) Character const* const source,
_In_ size_t const count
) throw()
{
if (count == 0 && destination == nullptr && size_in_elements == 0)
{
// this case is allowed; nothing to do:
_RETURN_NO_ERROR;
}
_VALIDATE_STRING(destination, size_in_elements);
if (count == 0)
{
// Notice that the source string pointer can be nullptr in this case:
_RESET_STRING(destination, size_in_elements);
_RETURN_NO_ERROR;
}
_VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
Character* destination_it = destination;
Character const* source_it = source;
size_t available = size_in_elements;
size_t remaining = count;
if (count == _TRUNCATE)
{
while ((*destination_it++ = *source_it++) != 0 && --available > 0)
{
}
}
else
{
while ((*destination_it++ = *source_it++) != 0 && --available > 0 && --remaining > 0)
{
}
if (remaining == 0)
{
*destination_it = 0;
}
}
if (available == 0)
{
if (count == _TRUNCATE)
{
destination[size_in_elements - 1] = 0;
_RETURN_TRUNCATE;
}
_RESET_STRING(destination, size_in_elements);
_RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}
// _strnset_s() and _wcsnset_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcsnset_s(
_Inout_updates_z_(size_in_elements) Character* const destination,
_In_ size_t const size_in_elements,
_In_ Character const value,
_In_ size_t const count
) throw()
{
if (count == 0 && destination == nullptr && size_in_elements == 0)
{
// This case is allowed; nothing to do:
_RETURN_NO_ERROR;
}
_VALIDATE_STRING(destination, size_in_elements);
Character* destination_it = destination;
size_t available = size_in_elements;
size_t remaining = count;
while (*destination_it != 0 && remaining > 0 && --available > 0)
{
*destination_it++ = value;
--remaining;
}
if (remaining == 0)
{
// Ensure the string is null-terminated:
while (*destination_it != 0 && --available > 0)
{
++destination_it;
}
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}
// _strset_s() and _wcsset_s()
template <typename Character>
_Success_(return == 0)
static errno_t __cdecl common_tcsset_s(
_Inout_updates_z_(size_in_elements) Character* const destination,
_In_ size_t const size_in_elements,
_In_ Character const value
) throw()
{
_VALIDATE_STRING(destination, size_in_elements);
Character* destination_it = destination;
size_t available = size_in_elements;
while (*destination_it != 0 && --available > 0)
{
*destination_it++ = value;
}
if (available == 0)
{
_RESET_STRING(destination, size_in_elements);
_RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
}
_FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
_RETURN_NO_ERROR;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,216 @@
//
// corecrt_internal_time.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines internal utilities for working with the time
// library.
//
#pragma once
#include <corecrt.h>
#include <corecrt_internal.h>
#include <corecrt_internal_traits.h>
#include <io.h>
#include <sys/utime.h>
#include <time.h>
#pragma pack(push, _CRT_PACKING)
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Constants
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
#define _EPOCH_BIAS 116444736000000000i64
#define _DAY_SEC (24 * 60 * 60) // Seconds in a day
#define _YEAR_SEC (365 * _DAY_SEC) // Seconds in a year
#define _FOUR_YEAR_SEC (1461 * _DAY_SEC) // Seconds in a four-year interval
#define _BASE_YEAR 70 // The epoch year (1970)
#define _BASE_DOW 4 // The day of week of 01-Jan-70 (Thursday)
// Maximum local time adjustment (GMT + 14 Hours, DST -0 Hours)
#define _MAX_LOCAL_TIME (14 * 60 * 60)
// Minimum local time adjustment (GMT - 11 Hours, DST - 1 Hours)
#define _MIN_LOCAL_TIME (-12 * 60 * 60)
#define _TZ_STRINGS_SIZE 64
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Global Data
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
extern "C"
{
extern char const __dnames[];
extern char const __mnames[];
extern int const _days[];
extern int const _lpdays[];
}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Integer Traits
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename TimeType>
struct __crt_time_time_t_traits;
template <>
struct __crt_time_time_t_traits<__time32_t> : __crt_integer_traits<__time32_t>
{
typedef _timespec32 timespec_type;
enum : long
{
// Number of seconds from 00:00:00, 01/01/1970 UTC to 23:59:59, 01/18/2038 UTC
max_time_t = 0x7fffd27f,
};
enum : unsigned long
{
// The maximum representable year
max_year = 138, // 2038 is the maximum year
};
};
template <>
struct __crt_time_time_t_traits<__time64_t> : __crt_integer_traits<__time64_t>
{
typedef _timespec64 timespec_type;
enum : long long
{
// Number of seconds from 00:00:00, 01/01/1970 UTC to 07:59:59, 01/19/3001 UTC
// Note that the end of the epoch was intended to be 23:59:59, 01/18/3001 UTC,
// but this was mistakenly computed from a PST value (thus the 8 hour delta).
max_time_t = 0x793582affLL,
};
enum : unsigned long long
{
// The maximum representable year
max_year = 1101, // 3001 is the maximum year
};
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Combined Traits
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename TimeType, typename Character>
struct __crt_time_traits
: __crt_char_traits<Character>,
__crt_time_time_t_traits<TimeType>
{
};
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Utilities
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Union to facilitate converting from FILETIME to unsigned __int64
union __crt_filetime_union
{
unsigned __int64 _scalar;
FILETIME _filetime;
};
extern "C"
{
int __cdecl _isindst(_In_ tm* _Time);
void __cdecl __tzset();
tm* __cdecl __getgmtimebuf();
__time32_t __cdecl __loctotime32_t(int, int, int, int, int, int, int);
__time64_t __cdecl __loctotime64_t(int, int, int, int, int, int, int);
}
// Tests if the given year is a leap year. The year is not the absolute year;
// it is the number of years since 1900.
template <typename TimeType>
bool __cdecl __crt_time_is_leap_year(TimeType const yr) throw()
{
if (yr % 4 == 0 && yr % 100 != 0)
return true;
if ((yr + 1900) % 400 == 0)
return true;
return false;
}
// Computes the number of leap years that have elapsed betwwen 1970 up to, but
// not including, the specified year. The year is not the absolute year; it is
// the number of years since 1900.
template <typename TimeType>
TimeType __cdecl __crt_time_elapsed_leap_years(TimeType const yr) throw()
{
static TimeType const leap_years_between_1900_and_1970 = 17;
TimeType const elapsed_leap_years = ((yr - 1) / 4) - ((yr - 1) / 100) + ((yr + 299) / 400);
return elapsed_leap_years - leap_years_between_1900_and_1970;
}
// Tests if the given date is valid (i.e., if such a day actually existed).
inline bool __cdecl __crt_time_is_day_valid(int const yr, int const mo, int const dy) throw()
{
if (dy <= 0)
return false;
int const days_in_month = _days[mo + 1] - _days[mo];
if (dy <= days_in_month)
return true;
// Special case for February:
if (__crt_time_is_leap_year(yr) && mo == 1 && dy <= 29)
return true;
return false;
}
inline int __crt_get_2digit_year(int const year) throw()
{
return (1900 + year) % 100;
}
inline int __crt_get_century(int const year) throw()
{
return (1900 + year) / 100;
}
extern "C" _Success_(return > 0) size_t __cdecl _Wcsftime_l(
_Out_writes_z_(max_size) wchar_t* string,
_In_ size_t max_size,
_In_z_ wchar_t const* format,
_In_ tm const* timeptr,
_In_opt_ void* lc_time_arg,
_In_opt_ _locale_t locale
);
_Check_return_ _Deref_ret_z_
extern "C" wchar_t** __cdecl __wide_tzname();
#pragma pack(pop)

View file

@ -0,0 +1,276 @@
//
// corecrt_internal_traits.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This internal header defines template-based utilities for implementing sets
// of functions that are largely similar but which operate on different kinds of
// strings (narrow or wide) or different kinds of integers (32-bit or 64-bit).
// It is similar in some respects to the macro-based <tchar.h>.
//
#pragma once
#include <corecrt_internal.h>
#include <corecrt_internal_win32_buffer.h>
#include <stdio.h>
#include <string.h>
#pragma pack(push, _CRT_PACKING)
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Character Traits
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename Character>
struct __crt_char_traits;
#define _CORECRT_APPLY_TO_MAPPINGS(_APPLY) \
_APPLY(capture_argv, __acrt_capture_narrow_argv, __acrt_capture_wide_argv ) \
_APPLY(create_process, __acrt_CreateProcessA, CreateProcessW ) \
_APPLY(find_first_file_ex, __acrt_FindFirstFileExA, FindFirstFileExW ) \
_APPLY(find_next_file, __acrt_FindNextFileA, FindNextFileW ) \
_APPLY(free_environment_strings, FreeEnvironmentStringsA, FreeEnvironmentStringsW ) \
_APPLY(ftprintf, fprintf, fwprintf ) \
_APPLY(get_current_directory, __acrt_get_current_directory_narrow_acp_or_utf8, __acrt_get_current_directory_wide ) \
_APPLY(get_environment_from_os, __dcrt_get_narrow_environment_from_os, __dcrt_get_wide_environment_from_os ) \
_APPLY(get_full_path_name, __acrt_get_full_path_name_narrow_acp_or_utf8, __acrt_get_full_path_name_wide ) \
_APPLY(get_module_file_name, __acrt_GetModuleFileNameA, GetModuleFileNameW ) \
_APPLY(get_or_create_environment_nolock, __dcrt_get_or_create_narrow_environment_nolock, __dcrt_get_or_create_wide_environment_nolock ) \
_APPLY(get_temp_path, __acrt_GetTempPath2A, __acrt_GetTempPath2W ) \
_APPLY(getc_nolock, _getc_nolock, _getwc_nolock ) \
_APPLY(gettche_nolock, _getche_nolock, _getwche_nolock ) \
_APPLY(initialize_environment_nolock, _initialize_narrow_environment, _initialize_wide_environment ) \
_APPLY(istspace, isspace, iswspace ) \
_APPLY(itot_s, _itoa_s, _itow_s ) \
_APPLY(message_box, __acrt_MessageBoxA, __acrt_MessageBoxW ) \
_APPLY(open_file, _openfile, _wopenfile ) \
_APPLY(output_debug_string, __acrt_OutputDebugStringA, OutputDebugStringW ) \
_APPLY(pack_command_line_and_environment, __acrt_pack_narrow_command_line_and_environment, __acrt_pack_wide_command_line_and_environment ) \
_APPLY(puttc_nolock_internal, _fputc_nolock_internal, _fputwc_nolock_internal ) \
_APPLY(puttch_nolock_internal, _putch_nolock_internal, _putwch_nolock_internal ) \
_APPLY(set_current_directory, __acrt_SetCurrentDirectoryA, SetCurrentDirectoryW ) \
_APPLY(set_environment_variable, __acrt_SetEnvironmentVariableA, SetEnvironmentVariableW ) \
_APPLY(set_program_name, _set_pgmptr, _set_wpgmptr ) \
_APPLY(set_variable_in_environment_nolock, __dcrt_set_variable_in_narrow_environment_nolock, __dcrt_set_variable_in_wide_environment_nolock) \
_APPLY(show_message_box, __acrt_show_narrow_message_box, __acrt_show_wide_message_box ) \
_APPLY(sntprintf_s, _snprintf_s, _snwprintf_s ) \
_APPLY(taccess_s, _access_s, _waccess_s ) \
_APPLY(tasctime, asctime, _wasctime ) \
_APPLY(tasctime_s, asctime_s, _wasctime_s ) \
_APPLY(tcscat_s, strcat_s, wcscat_s ) \
_APPLY(tcschr, strchr, wcschr ) \
_APPLY(tcscmp, strcmp, wcscmp ) \
_APPLY(tcscpy_s, strcpy_s, wcscpy_s ) \
_APPLY(tcserror_s, strerror_s, _wcserror_s ) \
_APPLY(tcsicmp, _stricmp, _wcsicmp ) \
_APPLY(tcslen, strlen, wcslen ) \
_APPLY(tcsnlen_s, strnlen_s, wcsnlen_s ) \
_APPLY(tcsncat_s, strncat_s, wcsncat_s ) \
_APPLY(tcsncmp, strncmp, wcsncmp ) \
_APPLY(tcsncpy_s, strncpy_s, wcsncpy_s ) \
_APPLY(tcsnicmp, _strnicmp, _wcsnicmp ) \
_APPLY(tcsnicoll, _strnicoll, _wcsnicoll ) \
_APPLY(tcsnlen, strnlen, wcsnlen ) \
_APPLY(tcspbrk, strpbrk, wcspbrk ) \
_APPLY(tcsrchr, strrchr, wcsrchr ) \
_APPLY(tcstoull, strtoull, wcstoull ) \
_APPLY(tdupenv_s_crt, _dupenv_s_crt, _wdupenv_s_crt ) \
_APPLY(texecve, _execve, _wexecve ) \
_APPLY(tfdopen, _fdopen, _wfdopen ) \
_APPLY(tfullpath, _fullpath, _wfullpath ) \
_APPLY(tgetcwd, _getcwd, _wgetcwd ) \
_APPLY(tgetpath, __acrt_getpath, __acrt_wgetpath ) \
_APPLY(tmktemp_s, _mktemp_s, _wmktemp_s ) \
_APPLY(tsopen_nolock, _sopen_nolock, _wsopen_nolock ) \
_APPLY(tsopen_s, _sopen_s, _wsopen_s ) \
_APPLY(tspawnve, _spawnve, _wspawnve ) \
_APPLY(tspawnvpe, _spawnvpe, _wspawnvpe ) \
_APPLY(ulltot_s, _ui64toa_s, _ui64tow_s ) \
_APPLY(ultot_s, _ultoa_s, _ultow_s ) \
_APPLY(ungettc_nolock, _ungetc_nolock, _ungetwc_nolock ) \
_APPLY(ungettch_nolock, _ungetch_nolock, _ungetwch_nolock )
template <>
struct __crt_char_traits<char>
{
typedef char char_type;
typedef unsigned char unsigned_char_type;
typedef wchar_t other_char_type;
typedef int int_type;
typedef STARTUPINFOA startup_info_type;
typedef WIN32_FIND_DATAA win32_find_data_type;
#define _APPLY(name, narrow_name, wide_name) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, narrow_name)
_CORECRT_APPLY_TO_MAPPINGS(_APPLY)
#undef _APPLY
};
template <>
struct __crt_char_traits<wchar_t>
{
typedef wchar_t char_type;
typedef wchar_t unsigned_char_type;
typedef char other_char_type;
typedef wint_t int_type;
typedef STARTUPINFOW startup_info_type;
typedef WIN32_FIND_DATAW win32_find_data_type;
#define _APPLY(name, narrow_name, wide_name) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, wide_name)
_CORECRT_APPLY_TO_MAPPINGS(_APPLY)
#undef _APPLY
};
#undef _CORECRT_APPLY_TO_MAPPINGS
#define _GENERATE_TCHAR_STRING_FUNCTIONS(name, string) \
static char const* __cdecl _CRT_CONCATENATE(get_, name)(char) throw() { return string; } \
static wchar_t const* __cdecl _CRT_CONCATENATE(get_, name)(wchar_t) throw() { return _CRT_WIDE(string); } \
static size_t const _CRT_CONCATENATE(name, _length) = _countof(string) - 1; \
static size_t const _CRT_CONCATENATE(name, _count ) = _countof(string);
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Integer Traits
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
template <typename Integer>
struct __crt_integer_traits;
#define _CORECRT_APPLY_TO_MAPPINGS(_APPLY) \
_APPLY(ftell_nolock, _ftell_nolock, _ftelli64_nolock) \
_APPLY(lseek, _lseek, _lseeki64 ) \
_APPLY(lseek_nolock, _lseek_nolock, _lseeki64_nolock) \
_APPLY(futime, _futime32, _futime64 ) \
_APPLY(gmtime_s, _gmtime32_s, _gmtime64_s ) \
_APPLY(localtime_s, _localtime32_s, _localtime64_s ) \
_APPLY(loctotime, __loctotime32_t, __loctotime64_t ) \
_APPLY(time, _time32, _time64 )
template <>
struct __crt_integer_traits<long>
{
#define _APPLY(name, name_32, name_64) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, name_32)
_CORECRT_APPLY_TO_MAPPINGS(_APPLY)
#undef _APPLY
};
template <>
struct __crt_integer_traits<long long>
{
#define _APPLY(name, name_32, name_64) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, name_64)
_CORECRT_APPLY_TO_MAPPINGS(_APPLY)
#undef _APPLY
};
#undef _CORECRT_APPLY_TO_MAPPINGS
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// char <=> wchar_t conversion utilities
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Complete list of internal conversion functions (only some defined here):
// * __acrt_WideCharToMultiByte / __acrt_MultiByteToWideChar
// * Provides option compatibility to ensure we don't get ERROR_INVALID_FLAGS due to code page changes.
// * Other functions in this list use this to be implemented.
// * wcstombs / mbstowcs
// * Public conversion functions, also used internally.
// * Should try to use _l variants when possible to avoid overhead of grabbing per-thread data.
// * __acrt_mbs_to_wcs / __acrt_wcs_to_mbs
// * Should be used by default - uses wcstombs / mbstowcs.
// * Provides automatic space allocation with __crt_win32_buffer.
// * __acrt_mbs_to_wcs_cp / __acrt_wcs_to_mbs_cp
// * Should be used by default, using code page instead of _locale_t.
// * Less optimizations - can't detect "C" locale for quick conversion.
// * Provides automatic space allocation with __crt_win32_buffer.
// * Uses __acrt_WideChartoMultiByte / __acrt_MultiByteToWideChar.
// * __crt_compute_required_transform_buffer_count / __crt_transform_string
// * Used by environment initialization.
// * Only one (narrow or wide) environment may be available from the OS,
// the other needs to be cloned into the other.
//
// Places where we don't use current global locale, user-supplied locale, or ACP/UTF-8 adapter:
// CP_ACP - __acrt_GetTempPath2A (via tmpnam)
// * Documented to do so on MSDN.
// * Required by API design - static buffer returned to user
// * Therefore, characters cannot be modified according to locale.
// CP_ACP - Environment Initialization
// * This is done at startup and does not change based off of locale, so using the ACP is correct.
// GetConsoleOutputCP() - write_double_translated_ansi_nolock (via _write)
// GetConsoleCP() - _getch
// CP_UTF8 - write_text_utf8_nolock (via _write)
//
// The following functions previous to UTF-8 awareness used the ACP for char conversions.
// To avoid backwards compatibility issues, they will still use the ACP, except when the currently
// set locale is CP_UTF8.
// * _access
// * _chdir
// * _chmod
// * _exec*
// * _findfile*
// * _fullpath
// * _loaddll
// * _mkdir
// * _popen
// * _remove
// * _rename
// * _rmdir
// * _sopen
// * _spawn*
// * _stat*
// * _unlink
// * Wildcard parsing in argv with setargv.obj
// * Calls to get the current module name for debug pop-up windows and assert messages (via __acrt_GetModuleFileNameA)
// * Setting _tzname when value provided via TZ environment variable.
//
inline size_t __crt_compute_required_transform_buffer_count(
unsigned const code_page,
_In_z_ char const* const string
)
{
return static_cast<size_t>(__acrt_MultiByteToWideChar(code_page, 0, string, -1, nullptr, 0));
}
inline size_t __crt_compute_required_transform_buffer_count(
unsigned const code_page,
_In_z_ wchar_t const* const string
)
{
return static_cast<size_t>(__acrt_WideCharToMultiByte(code_page, 0, string, -1, nullptr, 0, nullptr, nullptr));
}
_Success_(return > 0 && return <= buffer_count)
inline size_t __crt_transform_string(
unsigned const code_page,
_In_z_ char const* const string,
_Out_writes_z_(buffer_count) wchar_t* const buffer,
size_t const buffer_count
)
{
int const int_count = static_cast<int>(buffer_count);
return static_cast<size_t>(__acrt_MultiByteToWideChar(code_page, 0, string, -1, buffer, int_count));
}
_Success_(return > 0 && return <= buffer_count)
inline size_t __crt_transform_string(
unsigned const code_page,
_In_z_ wchar_t const* const string,
_Out_writes_z_(buffer_count) char* const buffer,
size_t const buffer_count
)
{
int const int_count = static_cast<int>(buffer_count);
return static_cast<size_t>(__acrt_WideCharToMultiByte(code_page, 0, string, -1, buffer, int_count, nullptr, nullptr));
}
#pragma pack(pop)

View file

@ -0,0 +1,799 @@
//
// 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)

View file

@ -0,0 +1,323 @@
;***
;cruntime.inc - multi-model assembly macros for interfacing to HLLs
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; This file defines the current memory model being used.
;
;*******************************************************************************
;==============================================================================
;
;Use the following defines to control processor/segment model
;
; default is -DI86 -Dmem_S
;
;==============================================================================
;
;The following variables are defined by this file:
; cpu 86, 286, or 386
; mmodel english name of the memory model, i.e. "Medium"
; ISIZE, LSIZE, NSIZE size of ints, longs, shorts
; FLTSIZE, DBLSIZE, LDBLSIZE size of float, double, long double
;
;The following macros allow easy writing of combined 16/32 bit code:
;
; 16/32 bit registers:
; rax, rbx, rcx, rdx, expand to native registers (rax = eax or ax)
; rsi, rdi, rsp, rbp
; CBI convert byte to int (al to rax)
; Numeric type instructions:
; IWORD, LWORD, SWORD data type of int, long, short
; DFLOAT, DDOUBLE, DLDOUBLE define float, double, long double
;
;The following utility macros are provided:
; codeseg define/declare code segment
; error <msg> stop assembly with message
; display <msg> display a message, unless QUIET defined
; _if cond <instruction> assemble instruction only if cond is TRUE
; _ife cond <instruction> assemble instruction only if cond is FALSE
; _ifd symbol <instruction> assemble instruction only if symbol defined
; _ifnd symbol <instruction> assemble instruction only if symbol not defined
;
; lab LabelName assembles to "LabelName:" If DEBUG is defined
; LabelName is made public
;
; JS* (ex. JSE,JSZ,JSB ...) assemble to "je short","jz short","jb short"
;
; Cmacro look alikes
; static* Name, InitialValue, Repeat defines a static variable of type *
; global* Name, InitialValue, Repeat defines a global variable of type *
; label* Name, {PUBLIC,PASCAL,C} defines a label of type *
;
;==============================================================================
; error <msg> - Output message and generate error
error MACRO msg
if2 ;; only on pass 2 can we generate errors
%out **********************************************************
%out *** E r r o r -- msg
%out **********************************************************
.err
endif
ENDM
; display msg - Output message unless QUIET defined
display MACRO msg
ifndef QUIET ;; only when quiet flag not set
if1 ;; and on pass 1, then display message
%out msg
endif
endif
ENDM
; One line conditionals:
; here we create the capability of writing code lines like
;
; _if sizeD <push ds> as opposed to if sizeD
; push ds
; endif
_if MACRO cond,text
if cond
text
endif
ENDM
_ife MACRO cond,text
ife cond
text
endif
ENDM
_ifd MACRO cond,text
ifdef cond
text
endif
ENDM
_ifnd MACRO cond,text
ifndef cond
text
endif
ENDM
; Process processor arguments
.686
; Set memory model
.model flat, C
; Define registers:
; Instead of using the "word" registers directly, we will use a set of
; text equates. This will allow you to use the native word size instead of
; hard coded to 16 bit words. We also have some instruction equates for
; instruction with the register type hard coded in.
rax equ <eax>
rbx equ <ebx>
rcx equ <ecx>
rdx equ <edx>
rdi equ <edi>
rsi equ <esi>
rbp equ <ebp>
rsp equ <esp>
CBI equ <movsx eax, al> ; convert byte to int (al to rax)
; The next set of equates deals with the size of SHORTS, INTS, LONGS, and
; pointers.
; parameters and locals
IWORD equ <dword>
; sizes for fixing SP, stepping through tables, etc.
ISIZE equ 4
; Float/double definitions
; (currently the same for 16- and 32-bit segments)
FLTSIZE equ 4 ; float
DBLSIZE equ 8 ; double
LDBLSIZE equ 10 ; long double
DFLOAT equ <dd>
DDOUBLE equ <dq>
DLDOUBLE equ <dt>
; codeseg - Define/declare the standard code segment. Maps to the proper
; form of the .code directive.
;
; Input:
;
; Output:
; .code _TEXT ; for large code models
; .code ; for small code models
; assume cs:FLAT ; for 386
; assume ds:FLAT ; for 386
; assume es:FLAT ; for 386
; assume ss:FLAT ; for 386
;
codeseg MACRO
.code
assume ds:FLAT
assume es:FLAT
assume ss:FLAT
ENDM
; Define named constants for ISA levels.
__ISA_AVAILABLE_X86 equ 0
__ISA_AVAILABLE_SSE2 equ 1
__ISA_AVAILABLE_SSE42 equ 2
__ISA_AVAILABLE_AVX equ 3
; Define named constants for favor
__FAVOR_ATOM equ 0
__FAVOR_ENFSTRG equ 1
;***************************************************************
;*
;* Debug lab macro
;*
;***************************************************************
lab macro name
ifdef DEBUG
public pascal name ;; define label public for Symdeb
endif
name:
endm
;***************************************************************
;*
;* Conditional jump short macros
;*
;***************************************************************
irp x,<Z,NZ,E,NE,P,PE,AE,BE,G>
JS&x equ <j&x short>
endm
;***************************************************************
;*
;* Global data definition macros
;*
;* Usage:
;* globalI Name, InitialValue, Repeat
;*
;***************************************************************
MakeGlobal macro suffix, DataType ;; makes all of the global* macros
global&suffix macro name, data, rep
public name
ifb <rep>
_repeat = 1
else
_repeat = (rep)
endif
name &DataType _repeat dup( data )
endm
endm
MakeGlobal T, dt ; globalT
MakeGlobal Q, dq ; globalQ
MakeGlobal D, dd ; globalD
MakeGlobal W, dw ; globalW
MakeGlobal B, db ; globalB
;***************************************************************
;*
;* Static data definition macros
;*
;* Usage:
;* staticI Name, InitialValue, Repeat
;*
;***************************************************************
MakeStatic macro suffix, DataType ;; makes all of the static* macros
static&suffix macro name, data, rep
ifdef DEBUG
public pascal name ;; make statics public if DEBUG
endif
ifb <rep>
_repeat = 1
else
_repeat = (rep)
endif
name &DataType _repeat dup( data )
endm
endm
MakeStatic T, dt ; staticT
MakeStatic Q, dq ; staticQ
MakeStatic D, dd ; staticD
MakeStatic W, dw ; staticW
MakeStatic B, db ; staticB
;***************************************************************
;*
;* Label definition macros
;*
;* Usage:
;* labelI Name, {PUBLIC, PASCAL, C}
;*
;***************************************************************
__MakePublic macro name, option ;; decides if a label should be
ifidni <option>, <PUBLIC> ;; made public
public name
elseifidni <option>, <PASCAL>
public pascal name
elseifidni <option>, <C>
public C name
elseifb <option>
ifdef DEBUG
public pascal name ;; make public if DEBUG
endif
endif
endm
MakeLabel macro suffix, LabelType ;; makes all of the label* macros
%@CatStr(<label>,<suffix>) macro name, option
__MakePublic <name>,<option>
name label &LabelType
endm
endm
MakeLabel T, tbyte ; make labelT
MakeLabel Q, qword ; make labelQ
MakeLabel D, dword ; make labelD
MakeLabel W, word ; make labelW
MakeLabel B, byte ; make labelB
MakeLabel NP, near ; make labelNP

2043
sdk/lib/ucrt/inc/ksamd64.inc Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
include kxamd64.inc

1002
sdk/lib/ucrt/inc/kxamd64.inc Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
include macamd64.inc

View file

@ -0,0 +1,685 @@
;++
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;
; Module:
;
; macamd64.w
;
; Astract:
;
; Contains AMD64 public architecture constants and assembly macros.
;
; Author:
;--
;++
;
; push_reg <reg>
;
; Macro Description:
;
; This macro emits a single-byte push <reg> instruction in a
; nested prologue, as well as the associated unwind code.
;
; Arguments:
;
; reg - supplies the integer register to push
;
;--
push_reg macro Reg
push Reg
.pushreg Reg
endm
;++
;
; rex_push_reg <reg>
;
; Macro Description:
;
; This macro emits a single-byte push <reg> instruction in a
; nested prologue, as well as the associated unwind code.
;
; This differs from push_reg only in that a redundant rex prefix
; is added. rex_push_reg must be used in lieu of push_reg when it
; appears as the first instruction in a function, as the calling
; standard dictates that functions must not begin with a single
; byte instruction.
;
; Arguments:
;
; reg - supplies the integer register to push
;
;--
rex_push_reg macro Reg
db 048h
push Reg
.pushreg Reg
endm
;++
;
; push_eflags
;
; Macro Description:
;
; This macro emits a single-byte pushfq instruction in a
; nested prologue, as well as the associated unwind code.
;
; Arguments:
;
; none
;
;--
push_eflags macro
pushfq
.allocstack 8
endm
;++
;
; rex_push_eflags
;
; Macro Description:
;
; This macro emits a single-byte pushfq instruction in a
; nested prologue, as well as the associated unwind code.
;
; This differs from push_eflags only in that a redundant rex prefix
; is added. rex_push_eflags must be used in lieu of push_eflags when it
; appears as the first instruction in a function, as the calling
; standard dictates that functions must not begin with a single
; byte instruction.
;
; Arguments:
;
; none
;
;--
rex_push_eflags macro
db 048h
pushfq
.allocstack 8
endm
;++
;
; rex_jmp_reg <reg>
;
; Macro Description:
;
; This macro emits a jmp <reg> instruction in a nested epilogue.
;
; This differs from jmp reg only in that a redundant rex prefix
; is added. rex_jmp_reg must be be used in lieu of jmp when it
; appears as a tail call terminating an epilogue of a function,
; as the calling dictates that functions that exit an epilogue
; with a jmp reg must include a redundant rex prefix to signify
; the presence of a tail call epilogue to the unwinder.
;
; Arguments:
;
; reg - supplies the integer register to jump to.
;
;--
rex_jmp_reg macro Reg
rexw jmp Reg
endm
;++
;
; ret_zero
;
; Macro Description:
;
; This macro emits a three byte return instruction.
;
; This differs from the typical ret in that it adds additional padding bytes
; that prevent branch misprediction problems when the ret is the target of
; a (un)conditional branch, or is immediately preceded by a conditional branch.
;
; Arguments:
;
; none
;
;--
ret_zero macro
ret
endm
;++
;
; alloc_stack <Size>
;
; Macro Description:
;
; This macro emits an opcode to subtract <Size> from rsp, as well
; as the associated unwind code.
;
; Arguments:
;
; Size - The number of bytes to subtract from rsp.
;
;--
alloc_stack macro Size
sub rsp, Size
.allocstack Size
endm
;++
;
; save_reg <Reg>, <Offset>
;
; Macro Description:
;
; This macro emits an opcode to save the non-volatile 64-bit general purpose
; register indicated by <Reg> at offset <Offset> relative to the current
; position of the stack pointer. It also generates the associated unwind
; code.
;
; Arguments:
;
; Reg - Supplies the integer register to save
;
; Offset - Supplies the offset relative to the current position of the stack
; pointer.
;
;--
save_reg macro Reg, Offset
mov Offset[rsp], Reg
.savereg Reg, Offset
endm
;++
;
; save_xmm128 <Reg>, <Offset>
;
; Macro Description:
;
; This macro emits an opcode to save the 128-bit non-volatile xmm register
; indicated by <Reg> at offset <Offset> relative to the current position
; of the stack pointer. It also generates the associated unwind code.
;
; Arguments:
;
; Reg - Supplies the xmm register register to save
;
; Offset - Supplies the offset relative to the current position of the stack
; pointer.
;
;--
save_xmm128 macro Reg, Offset
movaps Offset[rsp], Reg
.savexmm128 Reg, Offset
endm
;++
;
; push_frame
;
; Macro Description:
;
; This macro emits unwind data indicating that a machine frame has been
; pushed on the stack (usually by the CPU in response to a trap or fault).
;
; Arguments:
;
; None.
;
;--
push_frame macro Code
.pushframe Code
endm
;++
;
; set_frame <Reg>, <Offset>
;
; Macro Description:
;
; This macro emits an opcode and unwind data establishing the use of <Reg>
; as the current stack frame pointer.
;
; Arguments:
;
; Reg - Supplies the integer register to use as the current stack frame
; pointer.
;
; Offset - Supplies the optional offset of the frame pointer relative to
; the stack frame. In stack frames greater than 080h bytes,
; a non-zero offset can help reduce the size of subsequent opcodes
; that access portions of the stack frame by facilitating the use of
; positive and negative single-byte displacements.
;
; If not supplied, no offset is assumed.
;
;--
set_frame macro Reg, Offset
if Offset
lea Reg, Offset[rsp]
else
mov Reg, rsp
endif
.setframe Reg, Offset
endm
;++
;
; END_PROLOGUE
;
; Macro Description:
;
; This macro marks the end of the prologue. This must appear after all
; of the prologue directives in a nested function.
;
; Arguments:
;
; None.
;
;--
END_PROLOGUE macro
.endprolog
endm
;++
;
; Macro Description:
;
; This macro marks the beginning of a function epilogue. It may appear
; one or more times within a function body. The epilogue ends at the
; next control transfer instruction.
;
; Arguments:
;
; None.
;
;--
BEGIN_EPILOGUE macro
.beginepilog
endm
;++
;
; LEAF_ENTRY <Name>, <Section>, <NoPad>
;
; Macro Description:
;
; This macro indicates the beginning of a leaf function.
;
; A leaf function is one that DOES NOT:
;
; - manipulate non-volatile registers
; - manipulate the stack pointer
; - call other functions
; - reference an exception handler
; - contain a prologue
; - have any unwind data associated with it
;
; Arguments:
;
; Name - Supplies the name of the function
;
; Section - Supplies the name of the section within which the function
; is to appear
;
; NoPad - If present, indicates that the function should not be prefixed
; with 6 bytes of padding. This is for internal use only - the
; calling standard dictates that functions (nested and leaf) must
; be prefixed with padding.
;
;--
LEAF_ENTRY macro Name, Section, NoPad
Section segment para 'CODE'
ifb <NoPad>
db 6 dup (0cch)
endif
align 16
public Name
Name proc frame
END_PROLOGUE
endm
;++
;
; LEAF_ENTRY_ARG1 <Name>, <Section>, <Arg1>, <NoPad>
;
; Macro Description:
;
; Indicates the beginning of a leaf function, as LEAF_ENTRY above,
; and declares one input parameter so that debug info will be
; generated for it. The other forms, LEAF_ENTRY_ARG2 and LEAF_ENTRY_ARG3,
; are similar.
;
;--
LEAF_ENTRY_ARG1 macro Name, Section, Arg1, NoPad
Section segment para 'CODE'
ifb <NoPad>
db 6 dup (0cch)
endif
align 16
public Name
Name proc frame
END_PROLOGUE
endm
;++
;
; LEAF_ENTRY_ARG2 <Name>, <Section>, <Arg1>, <Arg2>, <NoPad>
;
; Macro Description:
;
; As LEAF_ENTRY_ARG1 above, marks the entry to a leaf function
; and defines 2 input parameters.
;
;--
LEAF_ENTRY_ARG2 macro Name, Section, Arg1, Arg2, NoPad
Section segment para 'CODE'
ifb <NoPad>
db 6 dup (0cch)
endif
align 16
public Name
Name proc frame
END_PROLOGUE
endm
;++
;
; LEAF_ENTRY_ARG3 <Name>, <Section>, <Arg1>, <Arg2>, <Arg3>, <NoPad>
;
; Macro Description:
;
; As LEAF_ENTRY_ARG1 above, marks the entry to a leaf function
; and defines 3 input parameters.
;
;--
LEAF_ENTRY_ARG3 macro Name, Section, Arg1, Arg2, Arg3, NoPad
Section segment para 'CODE'
ifb <NoPad>
db 6 dup (0cch)
endif
align 16
public Name
Name proc frame
END_PROLOGUE
endm
;++
;
; LEAF_END <Name>, <Section>
;
; Macro Description:
;
; This macro indicates the end of a leaf function. It must be paired
; with a LEAF_ENTRY macro that includes matching Name and Section
; parameters.
;
; Arguments:
;
; Name - Supplies the name of the function. Must match that supplied to
; the corresponding LEAF_ENTRY macro.
;
; Section - Supplies the name of the section within which the function
; is to appear. Must match that supplied to the corresponding
; LEAF_ENTRY macro.
;
;--
LEAF_END macro Name, section
Name endp
Section ends
endm
;++
;
; NESTED_ENTRY <Name>, <Section>, <Handler>, <NoPad>
;
; Macro Description:
;
; This macro indicates the beginning of a nested function.
;
; A nested function is one that does any of the following:
;
; - manipulates non-volatile registers
; - manipulates the stack pointer
; - references an exception handler
; - calls other functions
;
; A nested function must include a prologue with unwind data.
;
; Arguments:
;
; Name - Supplies the name of the function.
;
; Section - Supplies the name of the section within which the function
; is to appear.
;
; Handler - Supplies the name of the handler for exceptions raised
; within the scope of this function.
;
; NoPad - If present, indicates that the function should not be prefixed
; with 6 bytes of padding. This is for internal use only - the
; calling standard dictates that functions (nested and leaf) must
; be prefixed with padding.
;
;--
NESTED_ENTRY macro Name, Section, Handler, NoPad
ifdef _CurrentSection_
ifdif <Section>, _CurrentSection_
.err <NESTED_ENTRY invoked for different sections within same module>
endif
endif
_CurrentSection_ EQU <Section>
Section segment para 'CODE'
ifb <NoPad>
db 6 dup (0cch)
endif
align 16
public Name
ifb <Handler>
Name proc frame
else
Name proc frame:Handler
endif
endm
;++
;
; NESTED_END <Name>, <Section>
;
; Macro Description:
;
; This macro indicates the end of a nested function. It must be paired
; with a NESTED_ENTRY macro that includes matching Name and Section
; parameters.
;
; Arguments:
;
; Name - Supplies the name of the function. Must match that supplied to
; the corresponding NESTED_ENTRY macro.
;
; Section - Supplies the name of the section within which the function
; is to appear. Must match that supplied to the corresponding
; NESTED_ENTRY macro.
;
;--
NESTED_END macro Name, section
Name endp
Section ends
endm
;++
;
; ALTERNATE_ENTRY <Name>
;
; Macro Description:
;
; This macro indicates an alternate entry point in a function, or
; a synonymous name for an existing function.
;
; Arguments:
;
; Name - Supplies the name of the alternate entry point.
;
;--
ALTERNATE_ENTRY macro Name
Name:
endm
;++
;
; Yield
;
; Macro Description:
;
; This macro generates a yield instruction, interpreted by SMT processors
; as an indication of a stall or idle condition.
;
; Arguments:
;
; None.
;
;--
Yield macro
pause ; yield execution on SMT processors
endm
;++
;
; RetpolineIgnore
;
; Macro Description:
;
; This macro generates a retpoline ignore directive which informs tools that
; retpoline instrumentation is not required.
;
; Arguments:
;
; None.
;
;--
RetpolineIgnore macro
ifdef _RETPOLINE
.retpolineignore ; mark branch as retpoline-ignored
endif
endm