1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * PURPOSE: CRT: implementation of __[w]splitpath[_s] 5 * PROGRAMMERS: Timo Kreuzer 6 */ 7 8 #include <precomp.h> 9 #include <tchar.h> 10 #include <mbctype.h> 11 12 #if IS_SECAPI 13 #define _FAILURE -1 14 #define _SUCCESS 0 15 16 _Check_return_wat_ 17 _CRTIMP_ALTERNATIVE 18 errno_t 19 __cdecl 20 _tsplitpath_x( 21 _In_z_ const _TCHAR* path, 22 _Out_writes_opt_z_(drive_size) _TCHAR* drive, 23 _In_ size_t drive_size, 24 _Out_writes_opt_z_(dir_size) _TCHAR* dir, 25 _In_ size_t dir_size, 26 _Out_writes_opt_z_(fname_size) _TCHAR* fname, 27 _In_ size_t fname_size, 28 _Out_writes_opt_z_(ext_size) _TCHAR* ext, 29 _In_ size_t ext_size) 30 #else 31 #define _FAILURE 32 #define _SUCCESS 33 34 _CRT_INSECURE_DEPRECATE(_splitpath_s) 35 _CRTIMP 36 void 37 __cdecl 38 _tsplitpath_x( 39 _In_z_ const _TCHAR* path, 40 _Pre_maybenull_ _Post_z_ _TCHAR* drive, 41 _Pre_maybenull_ _Post_z_ _TCHAR* dir, 42 _Pre_maybenull_ _Post_z_ _TCHAR* fname, 43 _Pre_maybenull_ _Post_z_ _TCHAR* ext) 44 #endif 45 { 46 const _TCHAR *src, *dir_start, *file_start = 0, *ext_start = 0; 47 size_t count; 48 #if !IS_SECAPI 49 const size_t drive_size = INT_MAX, dir_size = INT_MAX, 50 fname_size = INT_MAX, ext_size = INT_MAX; 51 #endif 52 53 #if IS_SECAPI 54 /* Validate parameters */ 55 if (MSVCRT_CHECK_PMT((path == NULL) || 56 ((drive != NULL) && (drive_size == 0)) || 57 ((dir != NULL) && (dir_size == 0)) || 58 ((fname != NULL) && (fname_size == 0)) || 59 ((ext != NULL) && (ext_size == 0)))) 60 { 61 errno = EINVAL; 62 return -1; 63 } 64 #endif 65 66 /* Truncate all output strings */ 67 if (drive) drive[0] = '\0'; 68 if (dir) dir[0] = '\0'; 69 if (fname) fname[0] = '\0'; 70 if (ext) ext[0] = '\0'; 71 72 #if WINVER >= 0x600 73 /* Check parameter */ 74 if (!path) 75 { 76 #ifndef _LIBCNT_ 77 _set_errno(EINVAL); 78 #endif 79 return _FAILURE; 80 } 81 #endif 82 83 _Analysis_assume_(path != 0); 84 85 #if WINVER == 0x600 86 /* Skip '\\?\' prefix */ 87 if ((path[0] == '\\') && (path[1] == '\\') && 88 (path[2] == '?') && (path[3] == '\\')) path += 4; 89 #endif 90 91 if (path[0] == '\0') return _FAILURE; 92 93 /* Check if we have a drive letter (only 1 char supported) */ 94 if (path[1] == ':') 95 { 96 if (drive && (drive_size >= 3)) 97 { 98 drive[0] = path[0]; 99 drive[1] = ':'; 100 drive[2] = '\0'; 101 } 102 path += 2; 103 } 104 105 /* Scan the rest of the string */ 106 dir_start = path; 107 while (*path != '\0') 108 { 109 #if !defined(_UNICODE) && !defined(_LIBCNT_) 110 /* Check for multibyte lead bytes */ 111 if (_ismbblead((unsigned char)*path)) 112 { 113 /* Check for unexpected end of string */ 114 if (path[1] == 0) break; 115 116 /* Skip the lead byte and the following byte */ 117 path += 2; 118 continue; 119 } 120 #endif 121 /* Remember last path separator and last dot */ 122 if ((*path == '\\') || (*path == '/')) file_start = path + 1; 123 if (*path == '.') ext_start = path; 124 path++; 125 } 126 127 /* Check if we got a file name / extension */ 128 if (!file_start) 129 file_start = dir_start; 130 if (!ext_start || (ext_start < file_start)) 131 ext_start = path; 132 133 if (dir) 134 { 135 src = dir_start; 136 count = dir_size - 1; 137 while ((src < file_start) && count--) *dir++ = *src++; 138 *dir = '\0'; 139 } 140 141 if (fname) 142 { 143 src = file_start; 144 count = fname_size - 1; 145 while (src < ext_start && count--) *fname++ = *src++; 146 *fname = '\0'; 147 } 148 149 if (ext) 150 { 151 src = ext_start; 152 count = ext_size - 1; 153 while (*src != '\0' && count--) *ext++ = *src++; 154 *ext = '\0'; 155 } 156 157 return _SUCCESS; 158 } 159 160