📄 filesystem_traits.hpp
字号:
{
return false;
}
static bool_type is_readonly(fstat_data_type const* stat_data)
{
return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
}
#ifdef STLSOFT_CF_64BIT_INT_SUPPORT
static ws_uint64_t get_file_size(file_handle_type h)
{
DWORD dwHigh;
DWORD dwLow = ::GetFileSize(h, &dwHigh);
if( 0xFFFFFFFF == dwLow &&
ERROR_SUCCESS != ::GetLastError())
{
dwHigh = 0xFFFFFFFF;
}
return (static_cast<ws_uint64_t>(dwHigh) << 32) | dwLow;
}
#endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
};
STLSOFT_TEMPLATE_SPECIALISATION
struct filesystem_traits<ws_char_a_t>
: public system_traits<ws_char_a_t>
{
public:
typedef ws_char_a_t char_type;
typedef ws_size_t size_type;
typedef ws_ptrdiff_t difference_type;
typedef WIN32_FIND_DATAA find_data_type;
typedef WIN32_FIND_DATAA stat_data_type;
typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
typedef filesystem_traits<char_type> class_type;
typedef ws_int_t int_type;
typedef ws_bool_t bool_type;
typedef HANDLE file_handle_type;
typedef HINSTANCE module_type;
typedef DWORD error_type;
private:
#if !defined(STLSOFT_COMPILER_IS_MSVC) || \
_MSC_VER >= 1200
typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_type_;
#endif /* compiler */
public:
enum
{
maxPathLength = 1 + _MAX_PATH //!< The maximum length of a path for the current file system
};
public:
static char_type *ensure_dir_end(char_type *dir)
{
WINSTL_ASSERT(NULL != dir);
char_type *end = str_end(dir);
if( dir < end &&
!is_path_name_separator(*(end - 1)))
{
*end = path_name_separator();
*(end + 1) = '\0';
}
return dir;
}
static char_type *remove_dir_end(char_type *dir)
{
WINSTL_ASSERT(NULL != dir);
// Don't trim drive roots ...
if( isalpha(dir[0]) &&
':' == dir[1] &&
is_path_name_separator(dir[2]) &&
'\0' == dir[3])
{
return dir;
}
// ... or UNC roots
if( '\\' == dir[0] &&
'\\' == dir[1] &&
'\0' == dir[3])
{
return dir;
}
char_type *end = str_end(dir);
if( dir < end &&
is_path_name_separator(*(end - 1)))
{
*(end - 1) = '\0';
}
return dir;
}
static bool_type has_dir_end(char_type const* dir)
{
WINSTL_ASSERT(NULL != dir);
size_type len = str_len(dir);
return (0 < len) && is_path_name_separator(dir[len - 1]);
}
static bool_type is_dots(char_type const* dir)
{
WINSTL_ASSERT(NULL != dir);
return dir[0] == '.' &&
( dir[1] == '\0' ||
( dir[1] == '.' &&
dir[2] == '\0'));
}
static bool_type is_path_rooted(char_type const* path)
{
WINSTL_ASSERT(NULL != path);
return is_path_name_separator(*path) || is_path_absolute(path);
}
static bool_type is_path_absolute(char_type const* path)
{
WINSTL_ASSERT(NULL != path);
size_type len = str_len(path);
return is_path_UNC(path) ||
( (2 < len) &&
(':' == path[1]) &&
is_path_name_separator(path[2]));
}
static bool_type is_path_UNC(char_type const* path)
{
WINSTL_ASSERT(NULL != path);
return ('\\' == path[0] && '\\' == path[1]);
}
private:
static bool_type is_root_drive_(char_type const* path)
{
if( isalpha(path[0]) &&
':' == path[1] &&
is_path_name_separator(path[2]) &&
'\0' == path[3])
{
return true;
}
return false;
}
static bool_type is_root_UNC_(char_type const* path)
{
if(is_path_UNC(path))
{
char_type const* sep = str_pbrk(path + 2, "\\/");
if( NULL == sep ||
'\0' == sep[1])
{
return true;
}
}
return false;
}
static bool_type is_root_directory_(char_type const* path)
{
if( is_path_name_separator(path[0]) &&
'\0' == path[1])
{
return true;
}
return false;
}
public:
static bool_type is_root_designator(char_type const* path)
{
WINSTL_ASSERT(NULL != path);
return is_root_directory_(path) || is_root_drive_(path) || is_root_UNC_(path);
}
static bool_type is_path_name_separator(char_type ch)
{
return '\\' == ch || '/' == ch;
}
static char_type path_separator()
{
return ';';
}
static char_type path_name_separator()
{
return '\\';
}
static char_type const* pattern_all()
{
return "*.*";
}
static size_type path_max()
{
return 1 + _MAX_PATH;
}
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
_MSC_VER < 1200
static ws_dword_t get_full_path_name(char_type const* fileName, ws_dword_t cchBuffer, char_type* buffer, char_type **ppFile)
{
WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same, so it's not a good idea to do this for ANSI compilation", fileName != buffer);
if('"' == *fileName)
{
// This can only work if ...
const size_type len = class_type::str_len(fileName);
char_type const* const closing = class_type::str_chr(fileName + 1, '"');
// ... 1. the only other double quote is at the end of the string, and ...
if( NULL != closing &&
closing - fileName == static_cast<ws_ptrdiff_t>(len - 1))
{
ws_dword_t res = class_type::get_full_path_name(fileName + 1, cchBuffer, buffer, ppFile);
// ... 2. the front-quote skipped string can be converted, and ...
if( 0 != res &&
res < cchBuffer)
{
WINSTL_ASSERT('\0' == buffer[res]);
char_type *const closing2 = class_type::str_chr(buffer, '"');
// ... 3. the front-quote skipped converted string contains a single trailing quote
if( NULL != closing2 &&
closing2 - buffer == static_cast<ws_ptrdiff_t>(res - 1))
{
buffer[res-- - 1] = '\0';
return res;
}
}
}
}
return ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
}
#else /* ? compiler */
private:
static size_type get_full_path_name_impl2(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type **ppFile)
{
size_type r = ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
if( 0 != r &&
NULL != buffer &&
r > cchBuffer)
{
buffer_type_ buffer_(1 + r);
if(0 == buffer_.size())
{
*ppFile = NULL;
return 0;
}
else
{
char_type *pFile2;
size_type r2 = get_full_path_name_impl2(fileName, len, &buffer_[0], buffer_.size(), &pFile2);
if(0 == r2)
{
return 0;
}
else
{
if(r2 > cchBuffer)
{
r2 = cchBuffer;
}
str_n_copy(&buffer[0], &buffer_[0], r2);
if( NULL != pFile2 &&
r2 == (r - 1) &&
static_cast<size_type>(pFile2 - &buffer_[0]) < r2)
{
*ppFile = &buffer[0] + (pFile2 - &buffer_[0]);
}
else
{
*ppFile = NULL;
}
return r2;
}
}
}
else
{
return r;
}
}
static size_type get_full_path_name_impl(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type **ppFile)
{
WINSTL_ASSERT(len > 0);
if('\0' != fileName[len])
{
buffer_type_ fileName_(1 + (len - 1));
// May be being compiled absent exception support, so need to check the
// file path buffers. (This _could_ be done with a compile-time #ifdef,
// but it's best not, since some translators support exceptions but yet
// don't throw on mem exhaustion, and in any case a user could change
// ::new)
if(0 == fileName_.size())
{
set_last_error(ERROR_OUTOFMEMORY);
return 0;
}
else
{
fileName_[len] = '\0';
return get_full_path_name_impl( str_n_copy(&fileName_[0], fileName, len)
, len
, buffer
, cchBuffer
, ppFile);
}
}
else
{
return get_full_path_name_impl2(fileName, len, buffer, cchBuffer, ppFile);
}
}
public:
static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type **ppFile)
{
WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same, so it's not a good idea to do this for ANSI compilation", fileName != buffer);
size_type n = 0;
const size_type len = class_type::str_len(fileName);
if(NULL != class_type::str_pbrk(fileName, "<>|*?"))
{
::SetLastError(ERROR_INVALID_NAME);
return 0;
}
if('"' == *fileName)
{
// This can only work if:
//
// - the only other double-quote is at the end of the string
// - the unquoted form successfully converts
char_type const* const closing = class_type::str_chr(fileName + 1, '"');
if( NULL == closing ||
static_cast<size_type>(closing - fileName) != len - 1)
{
set_last_error(ERROR_INVALID_DATA);
}
else
{
size_type r;
if(NULL == buffer)
{
r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
if(0 != r)
{
n = 2 + r;
}
}
else if(cchBuffer == 0)
{
n = 0;
*ppFile = NULL;
}
else if(cchBuffer == 1)
{
// Have to check it's valid
r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
if(0 != r)
{
buffer[0] = '"';
n = 1;
*ppFile = NULL;
}
}
else
{
r = get_full_path_name_impl(fileName + 1, len - 2, buffer + 1, cchBuffer - 1, ppFile);
if(0 != r)
{
// Write the first quote character into the buffer
buffer[0] = '"';
if(r + 1 < cchBuffer)
{
// There's enough space for the result and the closing quote
buffer[r + 1] = '"';
if(r + 2 < cchBuffer)
{
// There's enough space for the result and the closing quote and the nul-terminator
buffer[r + 2] = '\0';
n = r + 2;
}
else
{
n = r + 2;
}
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -