xref: /reactos/sdk/lib/crt/string/_tsplitpath_x.h (revision b36d9bd9)
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