1 // 2 // _ctype.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Functions for converting integers to strings. 7 // 8 #include <corecrt_internal.h> 9 #include <corecrt_internal_securecrt.h> 10 #include <limits.h> 11 #include <stdlib.h> 12 13 #pragma warning(disable:__WARNING_NOT_SATISFIED) // 28020 Prefast thinks that 18446744073709551615 < 1. 14 #pragma warning(disable:__WARNING_RANGE_PRECONDITION_VIOLATION) // 26060 Prefast thinks that 18446744073709551615 < 1. 15 16 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 17 // 18 // Common Conversion Implementation 19 // 20 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 21 namespace 22 { 23 template <typename T> struct make_signed; 24 template <> struct make_signed<unsigned long> { typedef long type; }; 25 template <> struct make_signed<unsigned __int64> { typedef __int64 type; }; 26 } 27 28 29 30 template <typename UnsignedInteger, typename Character> 31 _Success_(return == 0) 32 static errno_t __cdecl common_xtox( 33 UnsignedInteger const original_value, 34 _Out_writes_z_(buffer_count) Character* const buffer, 35 _When_(is_negative == true, _In_range_(>=, 2)) _In_range_(>=, 1) 36 size_t const buffer_count, 37 unsigned const radix, 38 bool const is_negative 39 ) throw() 40 { 41 // OACR isn't able to track that p stays within the bounds of [buffer, buffer + buffer_count) so manually verified and disabled warning 42 #pragma warning(push) 43 #pragma warning(disable:26014) 44 Character* p = buffer; // pointer to traverse the string 45 size_t length = 0; // current length of string 46 47 UnsignedInteger remaining_value = original_value;; 48 49 if (is_negative) 50 { 51 *p++ = '-'; 52 ++length; 53 54 remaining_value = static_cast<UnsignedInteger>( 55 -static_cast<typename make_signed<UnsignedInteger>::type>(remaining_value) 56 ); 57 } 58 59 Character* first_digit = p; 60 61 do 62 { 63 unsigned const digit = static_cast<unsigned>(remaining_value % radix); 64 remaining_value /= radix; 65 66 // Convert to ASCII and store: 67 if (digit > 9) 68 { 69 *p++ = static_cast<Character>(digit - 10 + 'a'); 70 } 71 else 72 { 73 *p++ = static_cast<Character>(digit + '0'); 74 } 75 76 ++length; 77 } 78 while (remaining_value > 0 && length < buffer_count); 79 80 if (length >= buffer_count) 81 { 82 buffer[0] = '\0'; 83 _VALIDATE_RETURN_ERRCODE(length < buffer_count, ERANGE); 84 } 85 86 // We now have the digits of the number in the buffer, but in reverse order. 87 // Reverse the order, but first terminate the string: 88 *p-- = '\0'; 89 90 do 91 { 92 Character const t = *p; 93 *p = *first_digit; 94 *first_digit = t; 95 --p; 96 ++first_digit; 97 } 98 while (first_digit < p); 99 100 return 0; 101 #pragma warning(pop) 102 } 103 104 template <typename UnsignedInteger, typename Character> 105 _Success_(return == 0) 106 static errno_t __cdecl common_xtox_s( 107 UnsignedInteger const value, 108 _Out_writes_z_(buffer_count) Character* const buffer, 109 size_t const buffer_count, 110 unsigned const radix, 111 bool const is_negative 112 ) throw() 113 { 114 _VALIDATE_RETURN_ERRCODE(buffer != nullptr, EINVAL); 115 _VALIDATE_RETURN_ERRCODE(buffer_count > 0, EINVAL); 116 _RESET_STRING(buffer, buffer_count); 117 _VALIDATE_RETURN_ERRCODE(buffer_count > static_cast<size_t>(is_negative ? 2 : 1), ERANGE); 118 _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL); 119 120 return common_xtox(value, buffer, buffer_count, radix, is_negative); 121 } 122 123 124 125 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 126 // 127 // 32-bit Integers => Narrow Strings 128 // 129 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 130 extern "C" errno_t __cdecl _itoa_s( 131 int const value, 132 char* const buffer, 133 size_t const buffer_count, 134 int const radix 135 ) 136 { 137 bool const is_negative = radix == 10 && value < 0; 138 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative); 139 } 140 141 extern "C" errno_t __cdecl _ltoa_s( 142 long const value, 143 char* const buffer, 144 size_t const buffer_count, 145 int const radix 146 ) 147 { 148 bool const is_negative = radix == 10 && value < 0; 149 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative); 150 } 151 152 extern "C" errno_t __cdecl _ultoa_s( 153 unsigned long const value, 154 char* const buffer, 155 size_t const buffer_count, 156 int const radix 157 ) 158 { 159 return common_xtox_s(value, buffer, buffer_count, radix, false); 160 } 161 162 163 164 extern "C" char* __cdecl _itoa( 165 int const value, 166 char* const buffer, 167 int const radix 168 ) 169 { 170 bool const is_negative = radix == 10 && value < 0; 171 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 172 return buffer; 173 } 174 175 extern "C" char* __cdecl _ltoa( 176 long const value, 177 char* const buffer, 178 int const radix 179 ) 180 { 181 bool const is_negative = radix == 10 && value < 0; 182 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 183 return buffer; 184 } 185 186 extern "C" char* __cdecl _ultoa( 187 unsigned long const value, 188 char* const buffer, 189 int const radix 190 ) 191 { 192 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false); 193 return buffer; 194 } 195 196 197 198 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 199 // 200 // 64-bit Integers => Narrow Strings 201 // 202 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 203 extern "C" errno_t __cdecl _i64toa_s( 204 __int64 const value, 205 char* const buffer, 206 size_t const buffer_count, 207 int const radix 208 ) 209 { 210 bool const is_negative = radix == 10 && value < 0; 211 return common_xtox_s(static_cast<unsigned __int64>(value), buffer, buffer_count, radix, is_negative); 212 } 213 214 extern "C" errno_t __cdecl _ui64toa_s( 215 unsigned __int64 const value, 216 char* const buffer, 217 size_t const buffer_count, 218 int const radix 219 ) 220 { 221 return common_xtox_s(value, buffer, buffer_count, radix, false); 222 } 223 224 225 226 extern "C" char* __cdecl _i64toa( 227 __int64 const value, 228 char* const buffer, 229 int const radix 230 ) 231 { 232 bool const is_negative = radix == 10 && value < 0; 233 common_xtox(static_cast<unsigned __int64>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 234 return buffer; 235 } 236 237 extern "C" char* __cdecl _ui64toa( 238 unsigned __int64 const value, 239 char* const buffer, 240 int const radix 241 ) 242 { 243 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false); 244 return buffer; 245 } 246 247 248 249 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 250 // 251 // 32-bit Integers => Wide Strings 252 // 253 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 254 extern "C" errno_t __cdecl _itow_s( 255 int const value, 256 wchar_t* const buffer, 257 size_t const buffer_count, 258 int const radix 259 ) 260 { 261 bool const is_negative = radix == 10 && value < 0; 262 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative); 263 } 264 265 extern "C" errno_t __cdecl _ltow_s( 266 long const value, 267 wchar_t* const buffer, 268 size_t const buffer_count, 269 int const radix 270 ) 271 { 272 bool const is_negative = radix == 10 && value < 0; 273 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative); 274 } 275 276 extern "C" errno_t __cdecl _ultow_s( 277 unsigned long const value, 278 wchar_t* const buffer, 279 size_t const buffer_count, 280 int const radix 281 ) 282 { 283 return common_xtox_s(value, buffer, buffer_count, radix, false); 284 } 285 286 287 288 extern "C" wchar_t* __cdecl _itow( 289 int const value, 290 wchar_t* const buffer, 291 int const radix 292 ) 293 { 294 bool const is_negative = radix == 10 && value < 0; 295 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 296 return buffer; 297 } 298 299 extern "C" wchar_t* __cdecl _ltow( 300 long const value, 301 wchar_t* const buffer, 302 int const radix 303 ) 304 { 305 bool const is_negative = radix == 10 && value < 0; 306 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 307 return buffer; 308 } 309 310 extern "C" wchar_t* __cdecl _ultow( 311 unsigned long const value, 312 wchar_t* const buffer, 313 int const radix 314 ) 315 { 316 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false); 317 return buffer; 318 } 319 320 321 322 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 323 // 324 // 64-bit Integers => Wide Strings 325 // 326 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 327 extern "C" errno_t __cdecl _i64tow_s( 328 __int64 const value, 329 wchar_t* const buffer, 330 size_t const buffer_count, 331 int const radix 332 ) 333 { 334 bool const is_negative = radix == 10 && value < 0; 335 return common_xtox_s(static_cast<unsigned __int64>(value), buffer, buffer_count, radix, is_negative); 336 } 337 338 extern "C" errno_t __cdecl _ui64tow_s( 339 unsigned __int64 const value, 340 wchar_t* const buffer, 341 size_t const buffer_count, 342 int const radix 343 ) 344 { 345 return common_xtox_s(value, buffer, buffer_count, radix, false); 346 } 347 348 349 350 extern "C" wchar_t* __cdecl _i64tow( 351 __int64 const value, 352 wchar_t* const buffer, 353 int const radix 354 ) 355 { 356 bool const is_negative = radix == 10 && value < 0; 357 common_xtox(static_cast<unsigned __int64>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative); 358 return buffer; 359 } 360 361 extern "C" wchar_t* __cdecl _ui64tow( 362 unsigned __int64 const value, 363 wchar_t* const buffer, 364 int const radix 365 ) 366 { 367 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false); 368 return buffer; 369 } 370