Reactos
at master 445 lines 14 kB view raw
1// 2// output.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// The standard _output functions, which perform formatted output to a stream. 7// 8#include <corecrt_internal_stdio_output.h> 9 10 11 12using namespace __crt_stdio_output; 13 14 15// Enclaves do not have a file system, but they do allow in-memory operations 16// from stdio. 17#ifndef _UCRT_ENCLAVE_BUILD 18 19template <template <typename, typename> class Base, typename Character> 20static int __cdecl common_vfprintf( 21 unsigned __int64 const options, 22 FILE* const stream, 23 Character const* const format, 24 __crt_cached_ptd_host& ptd, 25 va_list const arglist 26 ) throw() 27{ 28 typedef output_processor< 29 Character, 30 stream_output_adapter<Character>, 31 Base<Character, stream_output_adapter<Character>> 32 > processor_type; 33 34 _UCRT_VALIDATE_RETURN(ptd, stream != nullptr, EINVAL, -1); 35 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1); 36 37 return __acrt_lock_stream_and_call(stream, [&]() -> int 38 { 39 __acrt_stdio_temporary_buffering_guard const buffering(stream, ptd); 40 41 processor_type processor( 42 stream_output_adapter<Character>(stream), 43 options, 44 format, 45 ptd, 46 arglist); 47 48 return processor.process(); 49 }); 50} 51 52extern "C" int __cdecl __stdio_common_vfprintf( 53 unsigned __int64 const options, 54 FILE* const stream, 55 char const* const format, 56 _locale_t const locale, 57 va_list const arglist 58 ) 59{ 60 __crt_cached_ptd_host ptd(locale); 61 return common_vfprintf<standard_base>(options, stream, format, ptd, arglist); 62} 63 64extern "C" int __cdecl __stdio_common_vfwprintf( 65 unsigned __int64 const options, 66 FILE* const stream, 67 wchar_t const* const format, 68 _locale_t const locale, 69 va_list const arglist 70 ) 71{ 72 __crt_cached_ptd_host ptd(locale); 73 return common_vfprintf<standard_base>(options, stream, format, ptd, arglist); 74} 75 76extern "C" int __cdecl __stdio_common_vfprintf_s( 77 unsigned __int64 const options, 78 FILE* const stream, 79 char const* const format, 80 _locale_t const locale, 81 va_list const arglist 82 ) 83{ 84 __crt_cached_ptd_host ptd(locale); 85 return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist); 86} 87 88extern "C" int __cdecl __stdio_common_vfwprintf_s( 89 unsigned __int64 const options, 90 FILE* const stream, 91 wchar_t const* const format, 92 _locale_t const locale, 93 va_list const arglist 94 ) 95{ 96 __crt_cached_ptd_host ptd(locale); 97 return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist); 98} 99 100extern "C" int __cdecl __stdio_common_vfprintf_p( 101 unsigned __int64 const options, 102 FILE* const stream, 103 char const* const format, 104 _locale_t const locale, 105 va_list const arglist 106 ) 107{ 108 __crt_cached_ptd_host ptd(locale); 109 return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist); 110} 111 112extern "C" int __cdecl __stdio_common_vfwprintf_p( 113 unsigned __int64 const options, 114 FILE* const stream, 115 wchar_t const* const format, 116 _locale_t const locale, 117 va_list const arglist 118 ) 119{ 120 __crt_cached_ptd_host ptd(locale); 121 return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist); 122} 123 124#endif /* _UCRT_ENCLAVE_BUILD */ 125 126 127template <template <typename, typename> class Base, typename Character> 128_Success_(return >= 0) 129static int __cdecl common_vsprintf( 130 unsigned __int64 const options, 131 _Out_writes_z_(buffer_count) Character* const buffer, 132 size_t const buffer_count, 133 Character const* const format, 134 __crt_cached_ptd_host& ptd, 135 va_list const arglist 136 ) throw() 137{ 138 typedef __acrt_stdio_char_traits<Character> char_traits; 139 140 typedef output_processor< 141 Character, 142 string_output_adapter<Character>, 143 Base<Character, string_output_adapter<Character>> 144 > processor_type; 145 146 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1); 147 _UCRT_VALIDATE_RETURN(ptd, buffer_count == 0 || buffer != nullptr, EINVAL, -1); 148 149 string_output_adapter_context<Character> context{}; 150 context._buffer = buffer; 151 context._buffer_count = buffer_count; 152 context._buffer_used = 0; 153 154 // For the C Standard snprintf functions, we continue formatting even after 155 // the buffer is full so that we can return the number of characters that 156 // are required to complete the format operation. For all other sprintf 157 // functions that have a buffer count, if no buffer was provided then we 158 // do the same. 159 context._continue_count = 160 (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR) != 0 || 161 buffer == nullptr; 162 163 processor_type processor( 164 string_output_adapter<Character>(&context), 165 options, 166 format, 167 ptd, 168 arglist); 169 170 int const result = processor.process(); 171 172 if (buffer == nullptr) 173 { 174 return result; 175 } 176 177 // Otherwise, we formatted data into the buffer and need to terminate it: 178 if (options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION) 179 { 180 if (buffer_count == 0 && result != 0) 181 { 182 return -1; 183 } 184 else if (context._buffer_used != buffer_count) 185 { 186 buffer[context._buffer_used] = '\0'; 187 } 188 else if (result >= 0 && static_cast<size_t>(result) > buffer_count) 189 { 190 return -1; 191 } 192 } 193 else if (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR) 194 { 195 if (buffer_count == 0) 196 { 197 // No-op 198 } 199 else if (result < 0) 200 { 201 buffer[0] = '\0'; 202 } 203 else if (context._buffer_used == buffer_count) 204 { 205 buffer[buffer_count - 1] = '\0'; 206 } 207 else 208 { 209 buffer[context._buffer_used] = '\0'; 210 } 211 } 212 else 213 { 214 if (buffer_count == 0) 215 { 216 return -1; 217 } 218 else if (context._buffer_used == buffer_count) 219 { 220 buffer[buffer_count - 1] = '\0'; 221 return -2; 222 } 223 else 224 { 225 buffer[context._buffer_used] = '\0'; 226 } 227 } 228 229#pragma warning(suppress:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 needs work 230 return result; 231} 232 233extern "C" int __cdecl __stdio_common_vsprintf( 234 unsigned __int64 const options, 235 char* const buffer, 236 size_t const buffer_count, 237 char const* const format, 238 _locale_t const locale, 239 va_list const arglist 240 ) 241{ 242 __crt_cached_ptd_host ptd(locale); 243 return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist); 244} 245 246extern "C" int __cdecl __stdio_common_vswprintf( 247 unsigned __int64 const options, 248 wchar_t* const buffer, 249 size_t const buffer_count, 250 wchar_t const* const format, 251 _locale_t const locale, 252 va_list const arglist 253 ) 254{ 255 __crt_cached_ptd_host ptd(locale); 256 return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist); 257} 258 259template <typename Character> 260_Success_(return >= 0) 261static int __cdecl common_vsprintf_s( 262 unsigned __int64 const options, 263 _Out_writes_z_(buffer_count) Character* const buffer, 264 size_t const buffer_count, 265 Character const* const format, 266 __crt_cached_ptd_host& ptd, 267 va_list const arglist 268 ) throw() 269{ 270 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1); 271 _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1); 272 273 int const result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist); 274 if (result < 0) 275 { 276 buffer[0] = 0; 277 _SECURECRT__FILL_STRING(buffer, buffer_count, 1); 278 } 279 280 if (result == -2) 281 { 282 _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1); 283 } 284 else if (result >= 0) 285 { 286 _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1); 287 } 288 289 return result; 290} 291 292extern "C" int __cdecl __stdio_common_vsprintf_s( 293 unsigned __int64 const options, 294 char* const buffer, 295 size_t const buffer_count, 296 char const* const format, 297 _locale_t const locale, 298 va_list const arglist 299 ) 300{ 301 __crt_cached_ptd_host ptd(locale); 302 return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist); 303} 304 305extern "C" int __cdecl __stdio_common_vswprintf_s( 306 unsigned __int64 const options, 307 wchar_t* const buffer, 308 size_t const buffer_count, 309 wchar_t const* const format, 310 _locale_t const locale, 311 va_list const arglist 312 ) 313{ 314 __crt_cached_ptd_host ptd(locale); 315 return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist); 316} 317 318template <typename Character> 319_Success_(return >= 0) 320static int __cdecl common_vsnprintf_s( 321 unsigned __int64 const options, 322 _Out_writes_z_(buffer_count) Character* const buffer, 323 size_t const buffer_count, 324 size_t const max_count, 325 Character const* const format, 326 __crt_cached_ptd_host& ptd, 327 va_list const arglist 328 ) throw() 329{ 330 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1); 331 332 if (max_count == 0 && buffer == nullptr && buffer_count == 0) 333 return 0; // No work to do 334 335 _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1); 336 337 int result = -1; 338 { 339 auto errno_restore_point = ptd.get_errno().create_guard(); 340 errno_restore_point.disable(); 341 342 if (buffer_count > max_count) 343 { 344 result = common_vsprintf<format_validation_base>(options, buffer, max_count + 1, format, ptd, arglist); 345 346 if (result == -2) 347 { 348 // The string has been truncated; return -1: 349 _SECURECRT__FILL_STRING(buffer, buffer_count, max_count + 1); 350 if (ptd.get_errno().check(ERANGE)) 351 { 352 errno_restore_point.enable(); 353 } 354 355 return -1; 356 } 357 } 358 else 359 { 360 result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist); 361 buffer[buffer_count - 1] = 0; 362 363 // We allow truncation if count == _TRUNCATE 364 if (result == -2 && max_count == _TRUNCATE) 365 { 366 if (ptd.get_errno().check(ERANGE)) 367 { 368 errno_restore_point.enable(); 369 } 370 371 return -1; 372 } 373 } 374 } 375 376 if (result < 0) 377 { 378 buffer[0] = 0; 379 _SECURECRT__FILL_STRING(buffer, buffer_count, 1); 380 if (result == -2) 381 { 382 _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1); 383 } 384 385 return -1; 386 } 387 388 _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1); 389 390 return result < 0 ? -1 : result; 391} 392 393extern "C" int __cdecl __stdio_common_vsnprintf_s( 394 unsigned __int64 const options, 395 char* const buffer, 396 size_t const buffer_count, 397 size_t const max_count, 398 char const* const format, 399 _locale_t const locale, 400 va_list const arglist 401 ) 402{ 403 __crt_cached_ptd_host ptd(locale); 404 return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist); 405} 406 407extern "C" int __cdecl __stdio_common_vsnwprintf_s( 408 unsigned __int64 const options, 409 wchar_t* const buffer, 410 size_t const buffer_count, 411 size_t const max_count, 412 wchar_t const* const format, 413 _locale_t const locale, 414 va_list const arglist 415 ) 416{ 417 __crt_cached_ptd_host ptd(locale); 418 return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist); 419} 420 421extern "C" int __cdecl __stdio_common_vsprintf_p( 422 unsigned __int64 const options, 423 char* const buffer, 424 size_t const buffer_count, 425 char const* const format, 426 _locale_t const locale, 427 va_list const arglist 428 ) 429{ 430 __crt_cached_ptd_host ptd(locale); 431 return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist); 432} 433 434extern "C" int __cdecl __stdio_common_vswprintf_p( 435 unsigned __int64 const options, 436 wchar_t* const buffer, 437 size_t const buffer_count, 438 wchar_t const* const format, 439 _locale_t const locale, 440 va_list const arglist 441 ) 442{ 443 __crt_cached_ptd_host ptd(locale); 444 return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist); 445}