Reactos
at master 205 lines 6.3 kB view raw
1// 2// makepath.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines the makepath family of functions, which compose a path string. 7// 8#include <corecrt_internal_securecrt.h> 9#include <mbstring.h> 10#include <stdlib.h> 11 12 13 14static char const* previous_character(char const* const first, char const* const current) throw() 15{ 16 return reinterpret_cast<char const*>(_mbsdec( 17 reinterpret_cast<unsigned char const*>(first), 18 reinterpret_cast<unsigned char const*>(current))); 19} 20 21static wchar_t const* previous_character(wchar_t const*, wchar_t const* const current) throw() 22{ 23 return current - 1; 24} 25 26 27 28template <typename Character> 29static errno_t __cdecl cleanup_after_error( 30 _Out_writes_z_(count) Character* const buffer, 31 size_t const count) throw() 32{ 33 // This is referenced only in the Debug CRT build 34 UNREFERENCED_PARAMETER(count); 35 36 _RESET_STRING(buffer, count); 37 _RETURN_BUFFER_TOO_SMALL(buffer, count); 38 return EINVAL; // This is unreachable 39} 40 41 42 43// These functions compose a path string from its component parts. They 44// concatenate the drive, directory, file_name, and extension into the provided 45// result_buffer. For the functions that do not have a buffer count parameter, 46// the buffer is assumed to be large enough to hold however many characters are 47// required. 48// 49// The drive may or may not contain a ':'. The directory may or may not contain 50// a leading or trailing '/' or '\'. The extension may or may not contain a 51// leading '.'. 52template <typename Character> 53static errno_t __cdecl common_makepath_s( 54 _Out_writes_z_(result_count) Character* const result_buffer, 55 _In_ size_t const result_count, 56 _In_opt_z_ Character const* const drive, 57 _In_opt_z_ Character const* const directory, 58 _In_opt_z_ Character const* const file_name, 59 _In_opt_z_ Character const* const extension 60 ) throw() 61{ 62 _VALIDATE_STRING(result_buffer, result_count); 63 64 Character* result_it = result_buffer; 65 66 // For the non-secure makepath functions, result_count is _CRT_UNBOUNDED_BUFFER_SIZE. 67 // In this case, we do not want to perform arithmetic with the result_count. Instead, 68 // we set the result_end to nullptr: result_it will never be a null pointer, 69 // and when we need to perform arithmetic with result_end we can check it for 70 // null first. 71 Character* const result_end = result_count != _CRT_UNBOUNDED_BUFFER_SIZE 72 ? result_buffer + result_count 73 : nullptr; 74 75 CRT_WARNING_DISABLE_PUSH(26015, "Silence prefast about overflow - covered by result_end for secure callers") 76 77 // Copy the drive: 78 if (drive && drive[0] != '\0') 79 { 80 if (result_end != nullptr && result_end - result_it < 2) 81 return cleanup_after_error(result_buffer, result_count); 82 83 *result_it++ = *drive; 84 *result_it++ = ':'; 85 } 86 87 // Copy the directory: 88 if (directory && directory[0] != '\0') 89 { 90 Character const* source_it = directory; 91 while (*source_it != '\0') 92 { 93 if ((result_end != nullptr) && (result_it >= result_end)) 94 return cleanup_after_error(result_buffer, result_count); 95 96 *result_it++ = *source_it++; 97 } 98 99 // Write a trailing backslash if there isn't one: 100 source_it = previous_character(directory, source_it); 101 if (*source_it != '/' && *source_it != '\\') 102 { 103 if ((result_end != nullptr) && (result_it >= result_end)) 104 return cleanup_after_error(result_buffer, result_count); 105 106 *result_it++ = '\\'; 107 } 108 } 109 110 // Copy the file name: 111 if (file_name) 112 { 113 Character const* source_it = file_name; 114 while (*source_it != '\0') 115 { 116 if ((result_end != nullptr) && (result_it >= result_end)) 117 return cleanup_after_error(result_buffer, result_count); 118 119 *result_it++ = *source_it++; 120 } 121 } 122 123 // Copy the extension: 124 if (extension) 125 { 126 // Add a '.' if one is required: 127 if (extension[0] != '\0' && extension[0] != '.') 128 { 129 if ((result_end != nullptr) && (result_it >= result_end)) 130 return cleanup_after_error(result_buffer, result_count); 131 132 *result_it++ = '.'; 133 } 134 135 Character const* source_it = extension; 136 while (*source_it != '\0') 137 { 138 if ((result_end != nullptr) && (result_it >= result_end)) 139 return cleanup_after_error(result_buffer, result_count); 140 141 *result_it++ = *source_it++; 142 } 143 } 144 145 // Copy the null terminator: 146 if ((result_end != nullptr) && (result_it >= result_end)) 147 return cleanup_after_error(result_buffer, result_count); 148 149 *result_it++ = '\0'; 150 151 CRT_WARNING_POP 152 153 _FILL_STRING(result_buffer, result_count, result_it - result_buffer); 154 return 0; 155} 156 157 158 159extern "C" void __cdecl _makepath( 160 char* const result_buffer, 161 char const* const drive, 162 char const* const directory, 163 char const* const file_name, 164 char const* const extension 165 ) 166{ 167 _makepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension); 168} 169 170extern "C" void __cdecl _wmakepath( 171 wchar_t* const result_buffer, 172 wchar_t const* const drive, 173 wchar_t const* const directory, 174 wchar_t const* const file_name, 175 wchar_t const* const extension 176 ) 177{ 178 _wmakepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension); 179} 180 181 182 183extern "C" errno_t __cdecl _makepath_s( 184 char* const result_buffer, 185 size_t const result_count, 186 char const* const drive, 187 char const* const directory, 188 char const* const file_name, 189 char const* const extension 190 ) 191{ 192 return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension); 193} 194 195extern "C" errno_t __cdecl _wmakepath_s( 196 wchar_t* const result_buffer, 197 size_t const result_count, 198 wchar_t const* const drive, 199 wchar_t const* const directory, 200 wchar_t const* const file_name, 201 wchar_t const* const extension 202 ) 203{ 204 return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension); 205}