1 //
2 // corecrt_internal_win32_buffer.h
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // This internal header defines template-based utilities for handling call-twice
7 // Win32 APIs, where you first call the Win32 API with null or a fixed sized buffer,
8 // and if there is not enough space, allocate a dynamically sized buffer.
9 #pragma once
10 #include <corecrt_internal.h>
11
12 #pragma pack(push, _CRT_PACKING)
13
14 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15 //
16 // __crt_win32_buffer_debug_info
17 //
18 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19 // This is a class that can be used to describe the block_use, file_name, line_number
20 // debug data that is sometimes shuffled around between function calls.
21
22 class __crt_win32_buffer_debug_info
23 {
24 #ifndef _DEBUG
25 public:
__crt_win32_buffer_debug_info(int,char const *,int)26 __crt_win32_buffer_debug_info(int, char const *, int)
27 {
28 }
29 #else /* ^^^^ Release ^^^^ / vvvv Debug vvvv */
30 public:
31 __crt_win32_buffer_debug_info(
32 int const initial_block_use,
33 char const * const initial_file_name,
34 int const initial_line_number
35 )
36 : _block_use(initial_block_use),
37 _file_name(initial_file_name),
38 _line_number(initial_line_number)
39 {
40 }
41
42 int block_use() const
43 {
44 return _block_use;
45 }
46
47 char const * file_name() const
48 {
49 return _file_name;
50 }
51
52 int line_number() const
53 {
54 return _line_number;
55 }
56
57 private:
58 int _block_use;
59 char const * _file_name;
60 int _line_number;
61 #endif /* _DEBUG */
62 };
63
64 class __crt_win32_buffer_empty_debug_info
65 {
66 };
67
68 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 //
70 // __crt_win32_buffer resize policies
71 //
72 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 // These classes are used to describe the different resize policies that a
74 // __crt_win32_buffer can have.
75
76 struct __crt_win32_buffer_internal_dynamic_resizing
77 {
78 using debug_info_type = __crt_win32_buffer_empty_debug_info;
79
80 _Check_return_
allocate__crt_win32_buffer_internal_dynamic_resizing81 static errno_t allocate(void ** const address, size_t const size, debug_info_type const&)
82 {
83 void * const ret = _malloc_crt(size);
84 *address = ret;
85 if (ret == nullptr) {
86 return ENOMEM;
87 }
88 return 0;
89 }
90
deallocate__crt_win32_buffer_internal_dynamic_resizing91 static void deallocate(void * const ptr, debug_info_type const&)
92 {
93 _free_crt(ptr);
94 }
95 };
96
97 struct __crt_win32_buffer_public_dynamic_resizing
98 {
99 using debug_info_type = __crt_win32_buffer_debug_info;
100
101 _Check_return_
allocate__crt_win32_buffer_public_dynamic_resizing102 static errno_t allocate(void ** const address, size_t const size, debug_info_type const& debug_info)
103 {
104 UNREFERENCED_PARAMETER(debug_info); // only used in debug mode
105 void * const ret = _malloc_dbg(
106 size,
107 debug_info.block_use(),
108 debug_info.file_name(),
109 debug_info.line_number()
110 );
111 *address = ret;
112 if (ret == nullptr) {
113 return ENOMEM;
114 }
115 return 0;
116 }
117
deallocate__crt_win32_buffer_public_dynamic_resizing118 static void deallocate(void * const ptr, debug_info_type const& debug_info)
119 {
120 UNREFERENCED_PARAMETER(debug_info); // only used in debug mode
121 _free_dbg(ptr, debug_info.block_use());
122 }
123 };
124
125 struct __crt_win32_buffer_no_resizing
126 {
127 using debug_info_type = __crt_win32_buffer_empty_debug_info;
128
129 _Check_return_
allocate__crt_win32_buffer_no_resizing130 static errno_t allocate(void ** const, size_t const, debug_info_type const&)
131 {
132 errno = ERANGE; // buffer not large enough
133 return ERANGE;
134 }
135
deallocate__crt_win32_buffer_no_resizing136 static void deallocate(void * const, debug_info_type const&)
137 {
138 }
139 };
140
141 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142 //
143 // __crt_win32_buffer, __crt_internal_win32_buffer
144 // __crt_public_win32_buffer, __crt_no_alloc_win32_buffer
145 //
146 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147 // Class and typedefs for buffers that support calling a win32 function and automatically
148 // resizing if needed.
149
150 template <typename Character, typename ResizePolicy>
151 class __crt_win32_buffer : private ResizePolicy::debug_info_type
152 { // Buffer type to enable Win32 call-twice-if-not-enough-space APIs.
153 // Using this type allows us to use a local buffer if possible and allocate if needed.
154 public:
155 using char_type = Character;
156 using debug_info_type = typename ResizePolicy::debug_info_type;
157
__crt_win32_buffer()158 __crt_win32_buffer()
159 : debug_info_type(),
160 _initial_string(nullptr),
161 _initial_capacity(0),
162 _string(nullptr),
163 _capacity(0),
164 _size(0),
165 _is_dynamic(false)
166
167 {
168 }
169
__crt_win32_buffer(debug_info_type const & debug_info)170 explicit __crt_win32_buffer(debug_info_type const& debug_info)
171 : debug_info_type(debug_info),
172 _initial_string(nullptr),
173 _initial_capacity(0),
174 _string(nullptr),
175 _capacity(0),
176 _size(0),
177 _is_dynamic(false)
178
179 {
180 }
181
182 template <size_t N>
__crt_win32_buffer(Character (& buffer)[N])183 __crt_win32_buffer(Character (&buffer)[N])
184 : debug_info_type(),
185 _initial_string(buffer),
186 _initial_capacity(N),
187 _string(buffer),
188 _capacity(N),
189 _size(0),
190 _is_dynamic(false)
191 {
192 }
193
194 template <size_t N>
__crt_win32_buffer(Character (& buffer)[N],debug_info_type const & debug_info)195 __crt_win32_buffer(Character (&buffer)[N], debug_info_type const& debug_info)
196 : debug_info_type(debug_info),
197 _initial_string(buffer),
198 _initial_capacity(N),
199 _string(buffer),
200 _capacity(N),
201 _size(0),
202 _is_dynamic(false)
203 {
204 }
205
__crt_win32_buffer(Character * const buffer,size_t const buffer_capacity)206 __crt_win32_buffer(
207 Character * const buffer,
208 size_t const buffer_capacity
209 )
210 : debug_info_type(),
211 _initial_string(buffer),
212 _initial_capacity(buffer_capacity),
213 _string(buffer),
214 _capacity(buffer_capacity),
215 _size(0),
216 _is_dynamic(false)
217 {
218 }
219
__crt_win32_buffer(Character * const buffer,size_t const buffer_capacity,debug_info_type const & debug_info)220 __crt_win32_buffer(
221 Character * const buffer,
222 size_t const buffer_capacity,
223 debug_info_type const& debug_info
224 )
225 : debug_info_type(debug_info),
226 _initial_string(buffer),
227 _initial_capacity(buffer_capacity),
228 _string(buffer),
229 _capacity(buffer_capacity),
230 _size(0),
231 _is_dynamic(false)
232 {
233 }
234
~__crt_win32_buffer()235 ~__crt_win32_buffer()
236 {
237 _deallocate();
238 }
239
240 __crt_win32_buffer(__crt_win32_buffer const&) = delete;
241 __crt_win32_buffer& operator=(__crt_win32_buffer const&) = delete;
242
243 __crt_win32_buffer(__crt_win32_buffer&&) = delete;
244 __crt_win32_buffer& operator=(__crt_win32_buffer&&) = delete;
245
data()246 char_type * data()
247 {
248 return _string;
249 }
250
data()251 char_type const * data() const
252 {
253 return _string;
254 }
255
size()256 size_t size() const
257 {
258 return _size;
259 }
260
size(size_t new_size)261 void size(size_t new_size)
262 {
263 _size = new_size;
264 }
265
capacity()266 size_t capacity() const
267 {
268 return _capacity;
269 }
270
reset()271 void reset()
272 {
273 _deallocate();
274 _reset_no_dealloc();
275 }
276
detach()277 char_type * detach()
278 {
279 if (_string == nullptr || _size == 0) {
280 return nullptr;
281 }
282
283 char_type * return_val{};
284
285 if (!_is_dynamic && _size > 0) {
286 // This pointer needs to live longer than the stack buffer
287 // Allocate + Copy
288 ResizePolicy::allocate(
289 reinterpret_cast<void **>(&return_val),
290 _size * sizeof(Character),
291 debug_info()
292 );
293 memcpy_s(return_val, _size, _string, _capacity);
294 } else {
295 return_val = _string;
296 }
297
298 _reset_no_dealloc();
299 return return_val;
300 }
301
302 template <typename Win32Function>
call_win32_function(Win32Function const & win32_function)303 errno_t call_win32_function(Win32Function const& win32_function)
304 { // Suitable for more Win32 calls, where a size is returned
305 // if there is not enough space.
306
307 size_t const required_size = win32_function(_string, static_cast<DWORD>(_capacity));
308 if (required_size == 0) {
309 __acrt_errno_map_os_error(GetLastError());
310 return errno;
311 }
312
313 if (required_size <= _capacity) {
314 // Had enough space, data was written, save size and return
315 _size = required_size;
316 return 0;
317 }
318
319 size_t const required_size_plus_null_terminator = required_size + 1;
320
321 errno_t const alloc_err = allocate(required_size_plus_null_terminator);
322 if (alloc_err)
323 {
324 return alloc_err;
325 }
326
327 // Upon success, return value is number of characters written, minus the null terminator.
328 size_t const required_size2 = win32_function(_string, static_cast<DWORD>(_capacity));
329 if (required_size2 == 0) {
330 __acrt_errno_map_os_error(GetLastError());
331 return errno;
332 }
333
334 // Capacity should be large enough at this point.
335 _size = required_size2;
336 return 0;
337 }
338
debug_info()339 debug_info_type const& debug_info() const
340 {
341 return static_cast<debug_info_type const&>(*this);
342 }
343
allocate(size_t requested_size)344 errno_t allocate(size_t requested_size)
345 {
346 _deallocate();
347
348 errno_t err = ResizePolicy::allocate(
349 reinterpret_cast<void **>(&_string),
350 requested_size * sizeof(Character),
351 debug_info()
352 );
353
354 if (err) {
355 _is_dynamic = false;
356 _capacity = 0;
357 return err;
358 }
359
360 _is_dynamic = true;
361 _capacity = requested_size;
362 return 0;
363 }
364
set_to_nullptr()365 void set_to_nullptr()
366 {
367 _deallocate();
368
369 _string = nullptr;
370 _capacity = 0;
371 _size = 0;
372 }
373
374 private:
_reset_no_dealloc()375 void _reset_no_dealloc()
376 {
377 _string = _initial_string;
378 _capacity = _initial_capacity;
379 _size = 0;
380 }
381
_deallocate()382 void _deallocate()
383 {
384 if (_is_dynamic) {
385 ResizePolicy::deallocate(_string, debug_info());
386 _is_dynamic = false;
387 }
388 }
389
390 char_type * const _initial_string;
391 size_t _initial_capacity;
392 char_type * _string;
393 size_t _capacity;
394 size_t _size;
395 bool _is_dynamic;
396 };
397
398 template <typename Character>
399 using __crt_internal_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_internal_dynamic_resizing>;
400
401 template <typename Character>
402 using __crt_public_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_public_dynamic_resizing>;
403
404 template <typename Character>
405 using __crt_no_alloc_win32_buffer = __crt_win32_buffer<Character, __crt_win32_buffer_no_resizing>;
406
407 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 //
409 // UTF-8 or ACP Helper
410 //
411 // Some POSIX functions have historically used the ACP for doing narrow->wide
412 // conversions. In order to support UTF-8 with these functions, they've been
413 // modified so that they use CP_UTF8 when current locale is UTF-8, but the ACP
414 // otherwise in order to preserve backwards compatibility.
415 //
416 // These POSIX functions can call __acrt_get_utf8_acp_compatibility_codepage to grab
417 // the code page they should use for their conversions.
418 //
419 // The Win32 ANSI "*A" APIs also use this to preserve their behavior as using the ACP, unless
420 // the current locale is set to UTF-8.
421 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
__acrt_get_utf8_acp_compatibility_codepage()422 inline unsigned int __acrt_get_utf8_acp_compatibility_codepage()
423 {
424 _LocaleUpdate locale_update(nullptr);
425 unsigned int const current_code_page = locale_update.GetLocaleT()->locinfo->_public._locale_lc_codepage;
426
427 if (current_code_page == CP_UTF8) {
428 return CP_UTF8;
429 }
430
431 bool const use_oem_code_page = !__acrt_AreFileApisANSI();
432
433 if (use_oem_code_page) {
434 return CP_OEMCP;
435 }
436
437 return CP_ACP;
438 }
439
440 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
441 //
442 // Win32 APIs using __crt_win32_buffer
443 //
444 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
445 // See complete list of internal conversion functions in corecrt_internal_traits.h
446
447 template <typename FromChar, typename ToChar, typename CvtFunction, typename ResizePolicy>
__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)448 errno_t __acrt_convert_wcs_mbs(
449 FromChar const * const null_terminated_input_string,
450 __crt_win32_buffer<ToChar, ResizePolicy>& win32_buffer,
451 CvtFunction const& cvt_func,
452 _locale_t locale
453 )
454 {
455 // Common code path for conversions using mbstowcs and wcstombs.
456 if (null_terminated_input_string == nullptr) {
457 win32_buffer.set_to_nullptr();
458 return 0;
459 }
460
461 // No empty string special case - mbstowcs/wcstombs handles them.
462 size_t const required_size = cvt_func(nullptr, null_terminated_input_string, 0, locale);
463
464 if (required_size == static_cast<size_t>(-1)) {
465 return errno;
466 }
467
468 size_t const required_size_plus_null_terminator = required_size + 1;
469
470 if (required_size_plus_null_terminator > win32_buffer.capacity()) {
471 errno_t const alloc_err = win32_buffer.allocate(required_size_plus_null_terminator);
472 if (alloc_err != 0) {
473 return alloc_err;
474 }
475 }
476
477 size_t const chars_converted = cvt_func(win32_buffer.data(), null_terminated_input_string, win32_buffer.capacity(), locale);
478 if (chars_converted == static_cast<size_t>(-1) || chars_converted == win32_buffer.capacity()) {
479 // check for error or if output is not null terminated
480 return errno;
481 }
482
483 win32_buffer.size(chars_converted);
484 return 0;
485 }
486
487 template <typename FromChar, typename ToChar, typename CvtFunction, typename ResizePolicy>
__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)488 errno_t __acrt_convert_wcs_mbs_cp(
489 FromChar const * const null_terminated_input_string,
490 __crt_win32_buffer<ToChar, ResizePolicy>& win32_buffer,
491 CvtFunction const& cvt_func,
492 unsigned int const code_page
493 )
494 {
495 // Common code path for conversions using MultiByteToWideChar and WideCharToMultiByte with null terminated inputs.
496 if (null_terminated_input_string == nullptr) {
497 win32_buffer.set_to_nullptr();
498 return 0;
499 }
500
501 // Special Case: Empty strings are not valid input to MultiByteToWideChar/WideCharToMultiByte
502 if (null_terminated_input_string[0] == '\0') {
503 if (win32_buffer.capacity() == 0) {
504 errno_t alloc_err = win32_buffer.allocate(1);
505 if (alloc_err != 0) {
506 return alloc_err;
507 }
508 }
509
510 win32_buffer.data()[0] = '\0';
511 win32_buffer.size(0);
512 return 0;
513 }
514
515 size_t const required_size_plus_null_terminator = cvt_func(
516 code_page,
517 null_terminated_input_string,
518 nullptr,
519 0
520 );
521
522 if (required_size_plus_null_terminator == 0) {
523 __acrt_errno_map_os_error(::GetLastError());
524 return errno;
525 }
526
527 if (required_size_plus_null_terminator > win32_buffer.capacity()) {
528 errno_t alloc_err = win32_buffer.allocate(required_size_plus_null_terminator);
529 if (alloc_err != 0) {
530 return alloc_err;
531 }
532 }
533
534 size_t const chars_converted_plus_null_terminator = cvt_func(
535 code_page,
536 null_terminated_input_string,
537 win32_buffer.data(),
538 win32_buffer.capacity()
539 );
540
541 if (chars_converted_plus_null_terminator == 0) {
542 __acrt_errno_map_os_error(::GetLastError());
543 return errno;
544 }
545
546 win32_buffer.size(chars_converted_plus_null_terminator - 1); // size does not include the null terminator
547 return 0;
548 }
549
550 template <typename ResizePolicy>
551 errno_t __acrt_wcs_to_mbs(
552 wchar_t const * const null_terminated_input_string,
553 __crt_win32_buffer<char, ResizePolicy>& win32_buffer,
554 _locale_t locale = nullptr
555 )
556 {
557 _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
558 return __acrt_convert_wcs_mbs(
559 null_terminated_input_string,
560 win32_buffer,
561 _wcstombs_l,
562 locale
563 );
564 _END_SECURE_CRT_DEPRECATION_DISABLE
565 }
566
567 template <typename ResizePolicy>
__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)568 errno_t __acrt_wcs_to_mbs_cp(
569 wchar_t const * const null_terminated_input_string,
570 __crt_win32_buffer<char, ResizePolicy>& win32_buffer,
571 unsigned int const code_page
572 )
573 {
574 auto const wcs_to_mbs = [](
575 unsigned int const code_page,
576 wchar_t const * const null_terminated_input_string,
577 char * const buffer,
578 size_t const buffer_size)
579 {
580 // Return value includes null terminator.
581 return __acrt_WideCharToMultiByte(
582 code_page,
583 0,
584 null_terminated_input_string,
585 -1,
586 buffer,
587 static_cast<int>(buffer_size),
588 nullptr,
589 nullptr
590 );
591 };
592
593 return __acrt_convert_wcs_mbs_cp(
594 null_terminated_input_string,
595 win32_buffer,
596 wcs_to_mbs,
597 code_page
598 );
599 }
600
601 template <typename ResizePolicy>
602 errno_t __acrt_mbs_to_wcs(
603 char const * const null_terminated_input_string,
604 __crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer,
605 _locale_t locale = nullptr
606 )
607 {
608 _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
609 return __acrt_convert_wcs_mbs(
610 null_terminated_input_string,
611 win32_buffer,
612 _mbstowcs_l,
613 locale
614 );
615 _END_SECURE_CRT_DEPRECATION_DISABLE
616 }
617
618 template <typename ResizePolicy>
__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)619 errno_t __acrt_mbs_to_wcs_cp(
620 char const * const null_terminated_input_string,
621 __crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer,
622 unsigned int const code_page
623 )
624 {
625 auto const mbs_to_wcs = [](
626 unsigned int const code_page,
627 char const * const null_terminated_input_string,
628 wchar_t * const buffer,
629 size_t const buffer_size)
630 {
631 // Return value includes null terminator.
632 return __acrt_MultiByteToWideChar(
633 code_page,
634 MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
635 null_terminated_input_string,
636 -1,
637 buffer,
638 static_cast<int>(buffer_size)
639 );
640 };
641
642 return __acrt_convert_wcs_mbs_cp(
643 null_terminated_input_string,
644 win32_buffer,
645 mbs_to_wcs,
646 code_page
647 );
648 }
649
650 // Array overloads are useful for __try contexts where objects with unwind semantics cannot be used.
651 template <size_t N>
652 size_t __acrt_wcs_to_mbs_array(
653 wchar_t const * const null_terminated_input_string,
654 char (&buffer)[N],
655 _locale_t locale = nullptr
656 )
657 {
658 __crt_no_alloc_win32_buffer<char> win32_buffer(buffer);
659 if (__acrt_wcs_to_mbs(null_terminated_input_string, win32_buffer, locale) != 0) {
660 return 0;
661 }
662
663 return win32_buffer.size();
664 }
665
666 template <size_t N>
__acrt_wcs_to_mbs_cp_array(wchar_t const * const null_terminated_input_string,char (& buffer)[N],unsigned int const code_page)667 size_t __acrt_wcs_to_mbs_cp_array(
668 wchar_t const * const null_terminated_input_string,
669 char (&buffer)[N],
670 unsigned int const code_page
671 )
672 {
673 __crt_no_alloc_win32_buffer<char> win32_buffer(buffer);
674 if (__acrt_wcs_to_mbs_cp(null_terminated_input_string, win32_buffer, code_page) != 0) {
675 return 0;
676 }
677
678 return win32_buffer.size();
679 }
680
681 template <size_t N>
682 size_t __acrt_mbs_to_wcs_array(
683 char const * const null_terminated_input_string,
684 wchar_t (&buffer)[N],
685 _locale_t locale = nullptr
686 )
687 {
688 __crt_no_alloc_win32_buffer<wchar_t> win32_buffer(buffer);
689 if (__acrt_mbs_to_wcs(null_terminated_input_string, win32_buffer, locale) != 0) {
690 return 0;
691 }
692
693 return win32_buffer.size();
694 }
695
696 template <size_t N>
__acrt_mbs_to_wcs_cp_array(char const * const null_terminated_input_string,wchar_t (& buffer)[N],unsigned int const code_page)697 size_t __acrt_mbs_to_wcs_cp_array(
698 char const * const null_terminated_input_string,
699 wchar_t (&buffer)[N],
700 unsigned int const code_page
701 )
702 {
703 __crt_no_alloc_win32_buffer<wchar_t> win32_buffer(buffer);
704 if (__acrt_mbs_to_wcs_cp(null_terminated_input_string, win32_buffer, code_page) != 0) {
705 return 0;
706 }
707
708 return win32_buffer.size();
709 }
710
711 template <typename ResizePolicy>
__acrt_get_current_directory_wide(__crt_win32_buffer<wchar_t,ResizePolicy> & win32_buffer)712 errno_t __acrt_get_current_directory_wide(
713 __crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer
714 )
715 {
716 return win32_buffer.call_win32_function([](wchar_t * buffer, DWORD buffer_length)
717 {
718 return ::GetCurrentDirectoryW(buffer_length, buffer);
719 });
720 }
721
722 template <typename ResizePolicy>
__acrt_get_current_directory_narrow_acp_or_utf8(__crt_win32_buffer<char,ResizePolicy> & win32_buffer)723 errno_t __acrt_get_current_directory_narrow_acp_or_utf8(
724 __crt_win32_buffer<char, ResizePolicy>& win32_buffer
725 )
726 {
727 wchar_t default_buffer_space[_MAX_PATH];
728 __crt_internal_win32_buffer<wchar_t> wide_buffer(default_buffer_space);
729
730 errno_t const err = __acrt_get_current_directory_wide(wide_buffer);
731
732 if (err != 0) {
733 return err;
734 }
735
736 return __acrt_wcs_to_mbs_cp(
737 wide_buffer.data(),
738 win32_buffer,
739 __acrt_get_utf8_acp_compatibility_codepage()
740 );
741 }
742
743 template <typename ResizePolicy>
__acrt_get_full_path_name_wide(wchar_t const * const lpFileName,__crt_win32_buffer<wchar_t,ResizePolicy> & win32_buffer)744 errno_t __acrt_get_full_path_name_wide(
745 wchar_t const * const lpFileName,
746 __crt_win32_buffer<wchar_t, ResizePolicy>& win32_buffer
747 )
748 {
749 return win32_buffer.call_win32_function([lpFileName](wchar_t * buffer, DWORD buffer_length)
750 {
751 return ::GetFullPathNameW(
752 lpFileName,
753 buffer_length,
754 buffer,
755 nullptr
756 );
757 });
758 }
759
760 template <typename ResizePolicy>
__acrt_get_full_path_name_narrow_acp_or_utf8(char const * const lpFileName,__crt_win32_buffer<char,ResizePolicy> & win32_buffer)761 errno_t __acrt_get_full_path_name_narrow_acp_or_utf8(
762 char const * const lpFileName,
763 __crt_win32_buffer<char, ResizePolicy>& win32_buffer
764 )
765 {
766 wchar_t default_buffer_space[_MAX_PATH];
767 __crt_internal_win32_buffer<wchar_t> wide_buffer(default_buffer_space);
768
769 wchar_t default_file_name_space[_MAX_PATH];
770 __crt_internal_win32_buffer<wchar_t> wide_file_name(default_file_name_space);
771
772 unsigned int const code_page = __acrt_get_utf8_acp_compatibility_codepage();
773
774 errno_t const cvt_err = __acrt_mbs_to_wcs_cp(
775 lpFileName,
776 wide_file_name,
777 code_page
778 );
779
780 if (cvt_err != 0)
781 {
782 return cvt_err;
783 }
784
785 errno_t const err = __acrt_get_full_path_name_wide(wide_file_name.data(), wide_buffer);
786
787 if (err != 0)
788 {
789 return err;
790 }
791
792 return __acrt_wcs_to_mbs_cp(
793 wide_buffer.data(),
794 win32_buffer,
795 code_page
796 );
797 }
798
799 #pragma pack(pop)
800