mirror of
https://github.com/google/leveldb.git
synced 2025-03-14 09:50:07 +08:00
135 lines
3.5 KiB
C++
135 lines
3.5 KiB
C++
#include "leveldb/db_path.h"
|
|
|
|
namespace leveldb {
|
|
namespace path {
|
|
|
|
#ifdef LEVELDB_PLATFORM_WINDOWS
|
|
|
|
const char* kExtendedPathPrefix = "\\\\?\\";
|
|
const char* kUncExtendedPathPrefix = "\\\\?\\UNC\\";
|
|
|
|
bool IsValidDriveChar(const char c) {
|
|
const char drive_char = std::toupper(c);
|
|
return drive_char >= 'A' && drive_char <= 'Z';
|
|
}
|
|
|
|
#elif LEVELDB_PLATFORM_POSIX
|
|
|
|
#endif
|
|
|
|
bool IsDirectorySeparator(const char c) {
|
|
return (c == kDirectorySeparator || c == kAltDirecttorySeparator);
|
|
}
|
|
|
|
const std::string& GetRootDirectory(const std::string& path) {
|
|
return path.substr(0, RootLength(path));
|
|
}
|
|
|
|
bool IsAbsolute(const std::string& path) {
|
|
#ifdef LEVELDB_PLATFORM_WINDOWS
|
|
return path.size() >= 3 && IsValidDriveChar(path[0]) &&
|
|
path[1] == kVolumeSeparatorChar;
|
|
#endif
|
|
}
|
|
|
|
bool IsRelative(const std::string& path) {
|
|
if (path.size() < 2) {
|
|
return true;
|
|
}
|
|
|
|
if (IsDirectorySeparator(path[0])) {
|
|
if (path[1] != '?') {
|
|
return !IsDirectorySeparator(path[1]);
|
|
}
|
|
return false;
|
|
}
|
|
if (path.size() >= 3 && path[1] == kVolumeSeparatorChar &&
|
|
IsDirectorySeparator(path[2])) {
|
|
#ifdef LEVELDB_PLATFORM_WINDOWS
|
|
return IsValidDriveChar(path[0]);
|
|
#elif LEVELDB_PLATFORM_POSIX
|
|
|
|
#endif
|
|
}
|
|
return true;
|
|
}
|
|
|
|
size_t RootLength(const std::string& path) {
|
|
size_t path_length = path.size();
|
|
size_t root_length = 0;
|
|
size_t volume_separator_length = 2;
|
|
size_t unc_root_length = 2;
|
|
|
|
bool extended_syntax = StartsWith(path, std::string(kExtendedPathPrefix));
|
|
bool extended_unc_syntax = StartsWith(path, std::string(kUncExtendedPathPrefix));
|
|
|
|
if (extended_syntax) {
|
|
if (extended_unc_syntax) {
|
|
unc_root_length = std::strlen(kUncExtendedPathPrefix);
|
|
} else {
|
|
volume_separator_length += std::strlen(kExtendedPathPrefix);
|
|
}
|
|
}
|
|
|
|
if ((!extended_syntax || extended_unc_syntax) && path_length != 0 &&
|
|
IsDirectorySeparator(path[0])) {
|
|
root_length = 1;
|
|
|
|
if (extended_unc_syntax ||
|
|
(path_length > 1 && IsDirectorySeparator(path[1]))) {
|
|
root_length = unc_root_length;
|
|
int n = 2; // maximum separators to skip
|
|
while (root_length < path_length &&
|
|
(!IsDirectorySeparator(path[root_length]) || --n > 0)) {
|
|
++root_length;
|
|
}
|
|
}
|
|
} else if (path_length >= volume_separator_length &&
|
|
path[volume_separator_length - 1] == kVolumeSeparatorChar) {
|
|
root_length = volume_separator_length;
|
|
if (path_length >= volume_separator_length &&
|
|
IsDirectorySeparator(path[volume_separator_length])) {
|
|
++root_length;
|
|
}
|
|
}
|
|
|
|
return root_length;
|
|
}
|
|
|
|
bool StartsWith(const std::string& path, const std::string& search,
|
|
bool ignore_case) {
|
|
if (search.size() > path.size()) {
|
|
return false;
|
|
}
|
|
if (ignore_case) {
|
|
auto ignore_case_cmp_func = [](char a, char b) {
|
|
return std::tolower(a) == std::tolower(b);
|
|
};
|
|
return std::equal(search.begin(), search.end(), path.begin(),
|
|
ignore_case_cmp_func);
|
|
}
|
|
return std::equal(search.begin(), search.end(), path.begin());
|
|
}
|
|
|
|
std::string Normalize(const std::string& path) {
|
|
std::string out;
|
|
auto path_it = path.begin();
|
|
|
|
for (const char c : path) {
|
|
if (!IsDirectorySeparator(c)) {
|
|
out += c;
|
|
path_it++;
|
|
} else if (path_it == path.begin() ||
|
|
!IsDirectorySeparator(*std::prev(path_it))) {
|
|
out += kDirectorySeparator;
|
|
path_it++;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
} // namespace path
|
|
} // namespace leveldb
|