9#include <initializer_list>
20namespace fs = std::filesystem;
23 fs::path ToFsPath(
const DotNetDupe::System::String& sPath) {
31 DotNetDupe::System::String FromFsPath(
const fs::path& path) {
35 return DotNetDupe::System::String(path.string().c_str());
49 auto sTempFilePath = sFilePath;
50 if (sFilePath [0] ==
'.')
51 sTempFilePath = sFilePath.
Remove(0);
54 fs::path path = ToFsPath(sTempFilePath);
60 return FromFsPath(path);
66 fs::path rootPath = ToFsPath(indexedList [0]);
67 if (!rootPath.has_root_directory())
68 return indexedList [0];
72 for (
auto sPath : sPaths) {
73 sCombinedPath.
Append(sPath);
74 sCombinedPath.
Append(
static_cast<char>(fs::path::preferred_separator));
81 if (sFilePath.
IsEmpty())
return false;
82 char chLastChar = sFilePath[sFilePath.
GetLength() - 1];
84 return chLastChar ==
'\\' || chLastChar ==
'/';
89 return fs::exists(ToFsPath(sFilePath));
98 fs::path path = ToFsPath(sFilePath);
99 return FromFsPath(path.parent_path());
107 fs::path path = ToFsPath(sFilePath);
108 return FromFsPath(path.filename());
117 fs::path path = ToFsPath(sFilePath);
118 return FromFsPath(path.extension());
127 fs::path path = ToFsPath(sFilePath);
128 return FromFsPath(path.stem());
137 return FromFsPath(fs::absolute(ToFsPath(sPath)));
142 static const std::vector<char> tempInvalidChars = {
143 '"',
'<',
'>',
'|',
'\0',
144 '\x01',
'\x02',
'\x03',
'\x04',
'\x05',
'\x06',
'\x07',
'\x08',
'\x09',
'\x0A',
'\x0B',
'\x0C',
'\x0D',
'\x0E',
'\x0F',
145 '\x10',
'\x11',
'\x12',
'\x13',
'\x14',
'\x15',
'\x16',
'\x17',
'\x18',
'\x19',
'\x1A',
'\x1B',
'\x1C',
'\x1D',
'\x1E',
'\x1F',
146 ':',
'*',
'?',
'\\',
'/' };
147 Array<char> invalidChars((
int)tempInvalidChars.size());
148 for (
int iIndex = 0; iIndex < (int)tempInvalidChars.size(); iIndex++) invalidChars[iIndex] = tempInvalidChars[iIndex];
154 static const std::vector<char> tempInvalidChars = {
156 '\x01',
'\x02',
'\x03',
'\x04',
'\x05',
'\x06',
'\x07',
'\x08',
'\x09',
'\x0A',
'\x0B',
'\x0C',
'\x0D',
'\x0E',
'\x0F',
157 '\x10',
'\x11',
'\x12',
'\x13',
'\x14',
'\x15',
'\x16',
'\x17',
'\x18',
'\x19',
'\x1A',
'\x1B',
'\x1C',
'\x1D',
'\x1E',
'\x1F' };
158 Array<char> invalidChars((
int)tempInvalidChars.size());
159 for (
int iIndex = 0; iIndex < (int)tempInvalidChars.size(); iIndex++) invalidChars[iIndex] = tempInvalidChars[iIndex];
166 const char chChars[] =
"abcdefghijklmnopqrstuvwxyz0123456789";
167 const int nCharsLen =
sizeof(chChars) /
sizeof(
char) - 1;
169 std::random_device rd;
170 std::mt19937 generator(rd());
171 std::uniform_int_distribution<> distribution(0, nCharsLen - 1);
173 char chRandomString[13];
175 for (
int iIndex = 0; iIndex < 8; ++iIndex) {
176 chRandomString[iIndex] = chChars[distribution(generator)];
178 chRandomString[8] =
'.';
179 for (
int iIndex = 0; iIndex < 3; ++iIndex) {
180 chRandomString[9 + iIndex] = chChars[distribution(generator)];
182 chRandomString[12] =
'\0';
184 return String(chRandomString);
199 int iIdx = sPath.
IndexOf(
"\\", 2,
false);
202 iIdx = sPath.
IndexOf(
"\\", iIdx + 1,
false);
210 fs::path p = ToFsPath(sPath);
211 return FromFsPath(p.root_path());
216 const fs::path fsRelativeTo = ToFsPath(
GetFullPath(sRelativeTo));
217 const fs::path fsPath = ToFsPath(
GetFullPath(sPath));
220 if (fsRelativeTo.root_name() != fsPath.root_name()) {
225 return FromFsPath(fs::relative(fsPath, fsRelativeTo));
230 std::random_device rd;
231 std::mt19937 generator(rd());
232 std::uniform_int_distribution<int> dist(0, 35);
233 const char alphabet[] =
"abcdefghijklmnopqrstuvwxyz0123456789";
234 for (
int i = 0; i < 100; ++i) {
236 for (
int j = 0; j < 8; ++j) name[j] = alphabet[dist(generator)];
238 fs::path fp = ToFsPath(sTempDir) / (
String(name) +
".tmp").GetRawString();
239 if (!fs::exists(fp)) {
240 std::ofstream ofs(fp);
241 if (ofs)
return FromFsPath(fp);
244 throw IOException(
"Could not create a unique temporary file.");
255 wchar_t buffer [MAX_PATH];
256 ::GetTempPathW(MAX_PATH, buffer);
261 const char* pTmpDir = getenv(
"TMPDIR");
270 if (sPath.
IsEmpty())
return false;
272 if (sFilenameStr.
IsEmpty() || sFilenameStr ==
"." || sFilenameStr ==
"..")
return false;
273 std::string sFilename((
const char*)sFilenameStr);
274 auto nDotPos = sFilename.rfind(
'.');
275 return (nDotPos != std::string::npos && nDotPos != sFilename.length() - 1);
280 if (sPath.
IsEmpty())
return false;
282 return ToFsPath(sPath).is_absolute();
287 if (sPath.
IsEmpty())
return false;
290 if (sPath[0] ==
'\\' || sPath[0] ==
'/')
return true;
291 if (nLen >= 2 && sPath[1] ==
':' && std::isalpha(
static_cast<unsigned char>(sPath[0]))) {
292 return (nLen >= 3 && (sPath[2] ==
'\\' || sPath[2] ==
'/'));
300 if (
TryJoin(sPaths, sResult))
return sResult;
307 for (
const auto& sPath : sPaths) {
308 for (
auto ch : invalidPathChars) {
309 if (sPath.
Contains(ch))
return false;
322 char chLast = sJoined[sJoined.
GetLength() - 1];
323 if (chLast !=
'\\' && chLast !=
'/') sJoined.
Append(
static_cast<char>(fs::path::preferred_separator));
324 if (sPath[0] ==
'\\' || sPath[0] ==
'/') {
340 sResult = sJoinedPath;
346 if (sPath.
IsEmpty())
return sPath;
350 char chLastChar = sPath[sPath.
GetLength() - 1];
351 if (chLastChar ==
'\\' || chLastChar ==
'/') {
359 return static_cast<char>(fs::path::preferred_separator);
364 return (fs::path::preferred_separator ==
'/') ?
'\\' :
'/';
The exception that is thrown when an I/O error occurs.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
IOException()
Initializes a new instance of the IOException class with a default message.
static bool Exists(const String &sFilePath)
Determines whether the given path refers to an existing file or directory on disk.
static String ChangeExtension(const String &sFilePath, const String &sExtension)
Changes the extension of a path string.
static String GetRelativePath(const String &sRelativeTo, const String &sPath)
Returns a relative path from one path to another.
static bool EndsInDirectorySeparator(const String &sFilePath)
Returns a value that indicates whether the specified path ends in a directory separator.
static char GetDirectorySeparatorChar()
Provides a platform-specific character used to separate directory levels in a path.
static Array< char > GetInvalidPathChars()
Gets an array of characters that cannot be present in path names.
static bool TryJoin(const std::initializer_list< String > sPaths, String &sResult)
Attempts to concatenate an array of paths into a single path.
static String GetExtension(const String &sFilePath)
Returns the extension of the specified path string.
static String GetRandomFileName()
Returns a random folder name or file name.
static String TrimEndingDirectorySeparator(const String &sPath)
Trims one trailing directory separator beyond the root of the specified path.
static String GetTempPath()
Returns the path of the current user's temporary folder.
static String GetFullPath(const String &sPath)
Returns the absolute path for the specified path string.
static String Combine(const std::initializer_list< String > sPaths)
Combines an array of strings into a path.
static String GetDirectoryName(const String &sFilePath)
Returns the directory information for the specified path string.
static char GetPathSeparator()
A platform-specific separator character used to separate path strings in environment variables.
static String GetPathRoot(const String &sPath)
Gets the root directory information from the path contained in the specified string.
static char GetAltDirectorySeparatorChar()
Provides a platform-specific alternate character used to separate directory levels.
static Array< char > GetInvalidFileNameChars()
Gets an array of characters that cannot be present in file names.
static String Join(const std::initializer_list< String > sPaths)
Concatenates an array of paths into a single path.
static char GetVolumeSeparatorChar()
Provides a platform-specific volume separator character.
static String GetTempFileName()
Creates a uniquely named, zero-byte temporary file on disk and returns the full path of that file.
static bool IsPathFullyQualified(const String &sPath)
Returns a value that indicates whether the specified path is fully qualified.
static String GetFileName(const String &sFilePath)
Returns the file name and extension of the specified path string.
static bool IsPathRooted(const String &sPath)
Returns a value that indicates whether the specified path string contains a root.
static bool HasExtension(const String &sPath)
Determines whether a path includes a file name extension.
static String GetFileNameWithoutExtension(const String &sFilePath)
Returns the file name of the specified path string without the extension.
static std::wstring Utf8ToWChar(const char *pUtf8Str)
static std::string WCharToUtf8(const wchar_t *pWStr)
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
String Substring(int iStartIndex) const
bool StartsWith(const String &sPrefix) const
String Remove(int iStartIndex) const
bool EndsWith(char ch, bool bIgnoreCase) const
String()
Initializes a new instance of the String class to an empty string.
String & Append(const char ch)
int IndexOf(const String &sSubstring) const
const char * GetRawString() const
bool Contains(char ch) const
static bool ValidatePathChars(const std::initializer_list< String > &sPaths)
static String GenerateRandomTempFileName(const String &sTempDir)
static void AppendPathSegment(String &sJoined, const String &sPath)
std::string WCharToUtf8(const wchar_t *pWStr)
_init_list_with_indexer(const std::initializer_list< T > &_list)
Constructs a wrapper over the provided initializer list.