mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
160 lines
3.8 KiB
C
160 lines
3.8 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* PURPOSE: CRT: implementation of __[w]splitpath[_s]
|
|
* PROGRAMMERS: Timo Kreuzer
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
#include <tchar.h>
|
|
#include <mbctype.h>
|
|
|
|
#if IS_SECAPI
|
|
#define _FAILURE -1
|
|
#define _SUCCESS 0
|
|
|
|
_Check_return_wat_
|
|
_CRTIMP_ALTERNATIVE
|
|
errno_t
|
|
__cdecl
|
|
_tsplitpath_x(
|
|
_In_z_ const _TCHAR* path,
|
|
_Out_writes_opt_z_(drive_size) _TCHAR* drive,
|
|
_In_ size_t drive_size,
|
|
_Out_writes_opt_z_(dir_size) _TCHAR* dir,
|
|
_In_ size_t dir_size,
|
|
_Out_writes_opt_z_(fname_size) _TCHAR* fname,
|
|
_In_ size_t fname_size,
|
|
_Out_writes_opt_z_(ext_size) _TCHAR* ext,
|
|
_In_ size_t ext_size)
|
|
#else
|
|
#define _FAILURE
|
|
#define _SUCCESS
|
|
|
|
_CRT_INSECURE_DEPRECATE(_splitpath_s)
|
|
_CRTIMP
|
|
void
|
|
__cdecl
|
|
_tsplitpath_x(
|
|
_In_z_ const _TCHAR* path,
|
|
_Pre_maybenull_ _Post_z_ _TCHAR* drive,
|
|
_Pre_maybenull_ _Post_z_ _TCHAR* dir,
|
|
_Pre_maybenull_ _Post_z_ _TCHAR* fname,
|
|
_Pre_maybenull_ _Post_z_ _TCHAR* ext)
|
|
#endif
|
|
{
|
|
const _TCHAR *src, *dir_start, *file_start = 0, *ext_start = 0;
|
|
size_t count;
|
|
#if !IS_SECAPI
|
|
const size_t drive_size = INT_MAX, dir_size = INT_MAX,
|
|
fname_size = INT_MAX, ext_size = INT_MAX;
|
|
#endif
|
|
|
|
#if IS_SECAPI
|
|
/* Validate parameters */
|
|
if (MSVCRT_CHECK_PMT((path == NULL) ||
|
|
((drive != NULL) && (drive_size == 0)) ||
|
|
((dir != NULL) && (dir_size == 0)) ||
|
|
((fname != NULL) && (fname_size == 0)) ||
|
|
((ext != NULL) && (ext_size == 0))))
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
/* Truncate all output strings */
|
|
if (drive) drive[0] = '\0';
|
|
if (dir) dir[0] = '\0';
|
|
if (fname) fname[0] = '\0';
|
|
if (ext) ext[0] = '\0';
|
|
|
|
#if WINVER >= 0x600
|
|
/* Check parameter */
|
|
if (!path)
|
|
{
|
|
#ifndef _LIBCNT_
|
|
_set_errno(EINVAL);
|
|
#endif
|
|
return _FAILURE;
|
|
}
|
|
#endif
|
|
|
|
_Analysis_assume_(path != 0);
|
|
|
|
#if WINVER == 0x600
|
|
/* Skip '\\?\' prefix */
|
|
if ((path[0] == '\\') && (path[1] == '\\') &&
|
|
(path[2] == '?') && (path[3] == '\\')) path += 4;
|
|
#endif
|
|
|
|
if (path[0] == '\0') return _FAILURE;
|
|
|
|
/* Check if we have a drive letter (only 1 char supported) */
|
|
if (path[1] == ':')
|
|
{
|
|
if (drive && (drive_size >= 3))
|
|
{
|
|
drive[0] = path[0];
|
|
drive[1] = ':';
|
|
drive[2] = '\0';
|
|
}
|
|
path += 2;
|
|
}
|
|
|
|
/* Scan the rest of the string */
|
|
dir_start = path;
|
|
while (*path != '\0')
|
|
{
|
|
#if !defined(_UNICODE) && !defined(_LIBCNT_)
|
|
/* Check for multibyte lead bytes */
|
|
if (_ismbblead((unsigned char)*path))
|
|
{
|
|
/* Check for unexpected end of string */
|
|
if (path[1] == 0) break;
|
|
|
|
/* Skip the lead byte and the following byte */
|
|
path += 2;
|
|
continue;
|
|
}
|
|
#endif
|
|
/* Remember last path separator and last dot */
|
|
if ((*path == '\\') || (*path == '/')) file_start = path + 1;
|
|
if (*path == '.') ext_start = path;
|
|
path++;
|
|
}
|
|
|
|
/* Check if we got a file name / extension */
|
|
if (!file_start)
|
|
file_start = dir_start;
|
|
if (!ext_start || (ext_start < file_start))
|
|
ext_start = path;
|
|
|
|
if (dir)
|
|
{
|
|
src = dir_start;
|
|
count = dir_size - 1;
|
|
while ((src < file_start) && count--) *dir++ = *src++;
|
|
*dir = '\0';
|
|
}
|
|
|
|
if (fname)
|
|
{
|
|
src = file_start;
|
|
count = fname_size - 1;
|
|
while (src < ext_start && count--) *fname++ = *src++;
|
|
*fname = '\0';
|
|
}
|
|
|
|
if (ext)
|
|
{
|
|
src = ext_start;
|
|
count = ext_size - 1;
|
|
while (*src != '\0' && count--) *ext++ = *src++;
|
|
*ext = '\0';
|
|
}
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|