2022-05-21 19:58:09 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Path.h"
|
|
|
|
|
|
|
|
namespace IO
|
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::ChangeExtension(const String& FilePath, const String& Extension)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
String Base;
|
2022-05-21 19:58:09 +02:00
|
|
|
for (int32_t i = FilePath.Length(); --i >= 0;)
|
|
|
|
{
|
|
|
|
auto& Ch = FilePath[i];
|
|
|
|
if (Ch == '.')
|
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
Base = FilePath.SubString(0, i);
|
2022-05-21 19:58:09 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore the separators, we made it too far
|
|
|
|
if (Ch == DirectorySeparatorChar || Ch == AltDirectorySeparatorChar || Ch == VolumeSeparatorChar)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Base.Length() > 0)
|
|
|
|
{
|
|
|
|
if (Extension.Length() == 0 || Extension[0] != '.')
|
|
|
|
{
|
|
|
|
Base += ".";
|
|
|
|
Base += Extension;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Base += Extension;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Base;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetDirectoryName(const String& Path)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
// Cache the full length and root length
|
|
|
|
int32_t cLength = (int32_t)Path.Length();
|
|
|
|
int32_t rLength = (cLength > 2 && Path[1] == VolumeSeparatorChar && (Path[2] == DirectorySeparatorChar || Path[2] == AltDirectorySeparatorChar)) ? 3 : 0;
|
|
|
|
|
|
|
|
if (cLength > rLength)
|
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
// Iterate while not modifying the String for performance
|
2022-05-21 19:58:09 +02:00
|
|
|
while (cLength > rLength && Path[--cLength] != DirectorySeparatorChar && Path[cLength] != AltDirectorySeparatorChar);
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
return Path.SubString(0, cLength);
|
2022-05-21 19:58:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetExtension(const String& FilePath)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
// Cache full length
|
|
|
|
int32_t cLength = (int32_t)FilePath.Length();
|
|
|
|
|
|
|
|
for (int32_t i = cLength; --i >= 0;)
|
|
|
|
{
|
|
|
|
auto& Ch = FilePath[i];
|
|
|
|
if (Ch == '.')
|
|
|
|
{
|
|
|
|
if (i != cLength - 1)
|
2022-05-21 21:51:35 +02:00
|
|
|
return FilePath.SubString(i, cLength - i);
|
2022-05-21 19:58:09 +02:00
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we found one of these, we made it too far
|
|
|
|
if (Ch == DirectorySeparatorChar || Ch == AltDirectorySeparatorChar || Ch == VolumeSeparatorChar)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetFileName(const String& FilePath)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
int32_t cLength = (int32_t)FilePath.Length();
|
|
|
|
for (int32_t i = cLength; --i >= 0;)
|
|
|
|
{
|
|
|
|
auto& Ch = FilePath[i];
|
|
|
|
|
|
|
|
if (Ch == DirectorySeparatorChar || Ch == AltDirectorySeparatorChar || Ch == VolumeSeparatorChar)
|
2022-05-21 21:51:35 +02:00
|
|
|
return FilePath.SubString(i + 1, cLength - i - 1);
|
2022-05-21 19:58:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return FilePath;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetFileNameWithoutExtension(const String& FilePath)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto fPath = Path::GetFileName(FilePath);
|
|
|
|
auto fExt = fPath.LastIndexOf('.');
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
if (fExt != String::InvalidPosition)
|
|
|
|
return fPath.SubString(0, fExt);
|
2022-05-21 19:58:09 +02:00
|
|
|
else
|
|
|
|
return fPath;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetPathRoot(const String& Path)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
return Path.SubString(0, Path::GetRootLength(Path));
|
2022-05-21 19:58:09 +02:00
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetTempPath()
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
char Buffer[MAX_PATH + 1]{};
|
|
|
|
GetTempPathA(MAX_PATH, Buffer);
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::GetTempFileName()
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto BasePath = Path::GetTempPath();
|
|
|
|
|
|
|
|
char Buffer[MAX_PATH + 1]{};
|
|
|
|
GetTempFileNameA((const char*)BasePath, "tmp", 0, (char*)Buffer);
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
bool Path::HasExtension(const String& FilePath)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto cLength = FilePath.Length();
|
|
|
|
|
|
|
|
for (int32_t i = cLength; --i >= 0;)
|
|
|
|
{
|
|
|
|
auto& Ch = FilePath[i];
|
|
|
|
if (Ch == '.')
|
|
|
|
{
|
|
|
|
if (i != cLength - 1)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we found one of these, we made it too far
|
|
|
|
if (Ch == DirectorySeparatorChar || Ch == AltDirectorySeparatorChar || Ch == VolumeSeparatorChar)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
bool Path::IsPathRooted(const String& Path)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto cLength = Path.Length();
|
|
|
|
if ((cLength >= 1 && (Path[0] == DirectorySeparatorChar || Path[0] == AltDirectorySeparatorChar)) || (cLength >= 2 && Path[1] == VolumeSeparatorChar))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String Path::Combine(const String& Path1, const String& Path2)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
if (Path2.Length() == 0)
|
|
|
|
return Path1;
|
|
|
|
if (Path1.Length() == 0)
|
|
|
|
return Path2;
|
|
|
|
|
|
|
|
if (Path::IsPathRooted(Path2))
|
|
|
|
return Path2;
|
|
|
|
|
|
|
|
auto& Ch = Path1[Path1.Length() - 1];
|
|
|
|
if (Ch != DirectorySeparatorChar && Ch != AltDirectorySeparatorChar && Ch != VolumeSeparatorChar)
|
|
|
|
return Path1 + DirectorySeparatorChar + Path2;
|
|
|
|
|
|
|
|
return Path1 + Path2;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
uint32_t Path::GetRootLength(const String& Path)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
int32_t i = 0, cLength = Path.Length();
|
|
|
|
|
|
|
|
auto IsDirectorySeparator = [](char Ch) -> bool
|
|
|
|
{
|
|
|
|
return (Ch == DirectorySeparatorChar || Ch == AltDirectorySeparatorChar);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (cLength >= 1 && IsDirectorySeparator(Path[0]))
|
|
|
|
{
|
|
|
|
// Handles UNC paths and currrent drive root paths
|
|
|
|
i = 1;
|
|
|
|
if (cLength >= 2 && IsDirectorySeparator(Path[1]))
|
|
|
|
{
|
|
|
|
i = 2;
|
|
|
|
int32_t nIter = 2;
|
|
|
|
|
|
|
|
while (i < cLength && !IsDirectorySeparator(Path[i]) || --nIter > 0)
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cLength >= 2 && Path[1] == VolumeSeparatorChar)
|
|
|
|
{
|
|
|
|
// Handles C:\Windows
|
|
|
|
i = 2;
|
|
|
|
if (cLength >= 3 && IsDirectorySeparator(Path[2]))
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|