mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 22:55:41 +00:00
[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:
parent
f1b60c66f0
commit
04e0dc4a7a
568 changed files with 115483 additions and 0 deletions
2119
sdk/lib/ucrt/inc/corecrt_internal.h
Normal file
2119
sdk/lib/ucrt/inc/corecrt_internal.h
Normal file
File diff suppressed because it is too large
Load diff
931
sdk/lib/ucrt/inc/corecrt_internal_big_integer.h
Normal file
931
sdk/lib/ucrt/inc/corecrt_internal_big_integer.h
Normal 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
|
220
sdk/lib/ucrt/inc/corecrt_internal_fltintrn.h
Normal file
220
sdk/lib/ucrt/inc/corecrt_internal_fltintrn.h
Normal 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
|
328
sdk/lib/ucrt/inc/corecrt_internal_lowio.h
Normal file
328
sdk/lib/ucrt/inc/corecrt_internal_lowio.h
Normal 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
|
152
sdk/lib/ucrt/inc/corecrt_internal_mbstring.h
Normal file
152
sdk/lib/ucrt/inc/corecrt_internal_mbstring.h
Normal 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);
|
||||
}
|
569
sdk/lib/ucrt/inc/corecrt_internal_ptd_propagation.h
Normal file
569
sdk/lib/ucrt/inc/corecrt_internal_ptd_propagation.h
Normal 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
|
130
sdk/lib/ucrt/inc/corecrt_internal_securecrt.h
Normal file
130
sdk/lib/ucrt/inc/corecrt_internal_securecrt.h
Normal 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 */
|
157
sdk/lib/ucrt/inc/corecrt_internal_simd.h
Normal file
157
sdk/lib/ucrt/inc/corecrt_internal_simd.h
Normal 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
|
864
sdk/lib/ucrt/inc/corecrt_internal_stdio.h
Normal file
864
sdk/lib/ucrt/inc/corecrt_internal_stdio.h
Normal 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)
|
1613
sdk/lib/ucrt/inc/corecrt_internal_stdio_input.h
Normal file
1613
sdk/lib/ucrt/inc/corecrt_internal_stdio_input.h
Normal file
File diff suppressed because it is too large
Load diff
2809
sdk/lib/ucrt/inc/corecrt_internal_stdio_output.h
Normal file
2809
sdk/lib/ucrt/inc/corecrt_internal_stdio_output.h
Normal file
File diff suppressed because it is too large
Load diff
299
sdk/lib/ucrt/inc/corecrt_internal_string_templates.h
Normal file
299
sdk/lib/ucrt/inc/corecrt_internal_string_templates.h
Normal 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;
|
||||
}
|
2046
sdk/lib/ucrt/inc/corecrt_internal_strtox.h
Normal file
2046
sdk/lib/ucrt/inc/corecrt_internal_strtox.h
Normal file
File diff suppressed because it is too large
Load diff
216
sdk/lib/ucrt/inc/corecrt_internal_time.h
Normal file
216
sdk/lib/ucrt/inc/corecrt_internal_time.h
Normal 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)
|
276
sdk/lib/ucrt/inc/corecrt_internal_traits.h
Normal file
276
sdk/lib/ucrt/inc/corecrt_internal_traits.h
Normal 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)
|
799
sdk/lib/ucrt/inc/corecrt_internal_win32_buffer.h
Normal file
799
sdk/lib/ucrt/inc/corecrt_internal_win32_buffer.h
Normal 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)
|
323
sdk/lib/ucrt/inc/i386/cruntime.inc
Normal file
323
sdk/lib/ucrt/inc/i386/cruntime.inc
Normal 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
2043
sdk/lib/ucrt/inc/ksamd64.inc
Normal file
File diff suppressed because it is too large
Load diff
1
sdk/lib/ucrt/inc/ksamd64_stub.inc
Normal file
1
sdk/lib/ucrt/inc/ksamd64_stub.inc
Normal file
|
@ -0,0 +1 @@
|
|||
include kxamd64.inc
|
1002
sdk/lib/ucrt/inc/kxamd64.inc
Normal file
1002
sdk/lib/ucrt/inc/kxamd64.inc
Normal file
File diff suppressed because it is too large
Load diff
1
sdk/lib/ucrt/inc/kxamd64_stub.inc
Normal file
1
sdk/lib/ucrt/inc/kxamd64_stub.inc
Normal file
|
@ -0,0 +1 @@
|
|||
include macamd64.inc
|
685
sdk/lib/ucrt/inc/macamd64.inc
Normal file
685
sdk/lib/ucrt/inc/macamd64.inc
Normal 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
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue