Bundle libOpenMPT as a dynamic framework, which should be safe once again, now that there is only one version to bundle. Also, now it is using the versions of libvorbisfile and libmpg123 that are bundled with the player, instead of compiling minimp3 and stbvorbis. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
872 lines
19 KiB
C++
872 lines
19 KiB
C++
/*
|
|
* mptPathString.cpp
|
|
* -----------------
|
|
* Purpose: Wrapper class around the platform-native representation of path names. Should be the only type that is used to store path names.
|
|
* Notes : Currently none.
|
|
* Authors: OpenMPT Devs
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "mptPathString.h"
|
|
|
|
#include "mpt/uuid/uuid.hpp"
|
|
|
|
#include "misc_util.h"
|
|
|
|
#include "mptRandom.h"
|
|
|
|
#if MPT_OS_WINDOWS
|
|
#include <windows.h>
|
|
#if defined(MODPLUG_TRACKER)
|
|
#include <shlwapi.h>
|
|
#endif
|
|
#include <tchar.h>
|
|
#endif
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
#if MPT_OS_WINDOWS
|
|
|
|
namespace mpt
|
|
{
|
|
|
|
|
|
RawPathString PathString::AsNativePrefixed() const
|
|
{
|
|
#if MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)
|
|
// For WinRT on Windows 8, there is no official wy to determine an absolute path.
|
|
return path;
|
|
#else
|
|
if(path.length() < MAX_PATH || path.substr(0, 4) == PL_("\\\\?\\"))
|
|
{
|
|
// Path is short enough or already in prefixed form
|
|
return path;
|
|
}
|
|
const RawPathString absPath = mpt::GetAbsolutePath(*this).AsNative();
|
|
if(absPath.substr(0, 2) == PL_("\\\\"))
|
|
{
|
|
// Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar
|
|
return PL_("\\\\?\\UNC") + absPath.substr(1);
|
|
} else
|
|
{
|
|
// Regular file: C:\foo.bar -> \\?\C:\foo.bar
|
|
return PL_("\\\\?\\") + absPath;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
#if !MPT_OS_WINDOWS_WINRT
|
|
|
|
int PathString::CompareNoCase(const PathString & a, const PathString & b)
|
|
{
|
|
return lstrcmpi(a.path.c_str(), b.path.c_str());
|
|
}
|
|
|
|
#endif // !MPT_OS_WINDOWS_WINRT
|
|
|
|
|
|
// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
|
|
// Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH
|
|
// and unlimited versions are only available on Windows 8 and later.
|
|
// Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes.
|
|
PathString PathString::Simplify() const
|
|
{
|
|
if(path.empty())
|
|
return PathString();
|
|
|
|
std::vector<RawPathString> components;
|
|
RawPathString root;
|
|
RawPathString::size_type startPos = 0;
|
|
if(path.size() >= 2 && path[1] == PC_(':'))
|
|
{
|
|
// Drive letter
|
|
root = path.substr(0, 2) + PC_('\\');
|
|
startPos = 2;
|
|
} else if(path.substr(0, 2) == PL_("\\\\"))
|
|
{
|
|
// Network share
|
|
root = PL_("\\\\");
|
|
startPos = 2;
|
|
} else if(path.substr(0, 2) == PL_(".\\") || path.substr(0, 2) == PL_("./"))
|
|
{
|
|
// Special case for relative paths
|
|
root = PL_(".\\");
|
|
startPos = 2;
|
|
} else if(path.size() >= 1 && (path[0] == PC_('\\') || path[0] == PC_('/')))
|
|
{
|
|
// Special case for relative paths
|
|
root = PL_("\\");
|
|
startPos = 1;
|
|
}
|
|
|
|
while(startPos < path.size())
|
|
{
|
|
auto pos = path.find_first_of(PL_("\\/"), startPos);
|
|
if(pos == RawPathString::npos)
|
|
pos = path.size();
|
|
mpt::RawPathString dir = path.substr(startPos, pos - startPos);
|
|
if(dir == PL_(".."))
|
|
{
|
|
// Go back one directory
|
|
if(!components.empty())
|
|
{
|
|
components.pop_back();
|
|
}
|
|
} else if(dir == PL_("."))
|
|
{
|
|
// nop
|
|
} else if(!dir.empty())
|
|
{
|
|
components.push_back(std::move(dir));
|
|
}
|
|
startPos = pos + 1;
|
|
}
|
|
|
|
RawPathString result = root;
|
|
result.reserve(path.size());
|
|
for(const auto &component : components)
|
|
{
|
|
result += component + PL_("\\");
|
|
}
|
|
if(!components.empty())
|
|
result.pop_back();
|
|
return mpt::PathString(result);
|
|
}
|
|
|
|
} // namespace mpt
|
|
|
|
#endif // MPT_OS_WINDOWS
|
|
|
|
|
|
namespace mpt
|
|
{
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
|
|
|
void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const
|
|
{
|
|
// We cannot use CRT splitpath here, because:
|
|
// * limited to _MAX_PATH or similar
|
|
// * no support for UNC paths
|
|
// * no support for \\?\ prefixed paths
|
|
|
|
if(drive) *drive = mpt::PathString();
|
|
if(dir) *dir = mpt::PathString();
|
|
if(fname) *fname = mpt::PathString();
|
|
if(ext) *ext = mpt::PathString();
|
|
|
|
mpt::RawPathString p = path;
|
|
|
|
// remove \\?\\ prefix
|
|
if(p.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
|
{
|
|
p = PL_("\\\\") + p.substr(8);
|
|
} else if(p.substr(0, 4) == PL_("\\\\?\\"))
|
|
{
|
|
p = p.substr(4);
|
|
}
|
|
|
|
if (p.length() >= 2 && (
|
|
p.substr(0, 2) == PL_("\\\\")
|
|
|| p.substr(0, 2) == PL_("\\/")
|
|
|| p.substr(0, 2) == PL_("/\\")
|
|
|| p.substr(0, 2) == PL_("//")
|
|
))
|
|
{ // UNC
|
|
mpt::RawPathString::size_type first_slash = p.substr(2).find_first_of(PL_("\\/"));
|
|
if(first_slash != mpt::RawPathString::npos)
|
|
{
|
|
mpt::RawPathString::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(PL_("\\/"));
|
|
if(second_slash != mpt::RawPathString::npos)
|
|
{
|
|
if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2 + first_slash + 1 + second_slash));
|
|
p = p.substr(2 + first_slash + 1 + second_slash);
|
|
} else
|
|
{
|
|
if(drive) *drive = mpt::PathString::FromNative(p);
|
|
p = mpt::RawPathString();
|
|
}
|
|
} else
|
|
{
|
|
if(drive) *drive = mpt::PathString::FromNative(p);
|
|
p = mpt::RawPathString();
|
|
}
|
|
} else
|
|
{ // local
|
|
if(p.length() >= 2 && (p[1] == PC_(':')))
|
|
{
|
|
if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2));
|
|
p = p.substr(2);
|
|
} else
|
|
{
|
|
if(drive) *drive = mpt::PathString();
|
|
}
|
|
}
|
|
mpt::RawPathString::size_type last_slash = p.find_last_of(PL_("\\/"));
|
|
if(last_slash != mpt::RawPathString::npos)
|
|
{
|
|
if(dir) *dir = mpt::PathString::FromNative(p.substr(0, last_slash + 1));
|
|
p = p.substr(last_slash + 1);
|
|
} else
|
|
{
|
|
if(dir) *dir = mpt::PathString();
|
|
}
|
|
mpt::RawPathString::size_type last_dot = p.find_last_of(PL_("."));
|
|
if(last_dot == mpt::RawPathString::npos)
|
|
{
|
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
|
if(ext) *ext = mpt::PathString();
|
|
} else if(last_dot == 0)
|
|
{
|
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
|
if(ext) *ext = mpt::PathString();
|
|
} else if(p == PL_(".") || p == PL_(".."))
|
|
{
|
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
|
if(ext) *ext = mpt::PathString();
|
|
} else
|
|
{
|
|
if(fname) *fname = mpt::PathString::FromNative(p.substr(0, last_dot));
|
|
if(ext) *ext = mpt::PathString::FromNative(p.substr(last_dot));
|
|
}
|
|
|
|
}
|
|
|
|
PathString PathString::GetDrive() const
|
|
{
|
|
PathString drive;
|
|
SplitPath(&drive, nullptr, nullptr, nullptr);
|
|
return drive;
|
|
}
|
|
PathString PathString::GetDir() const
|
|
{
|
|
PathString dir;
|
|
SplitPath(nullptr, &dir, nullptr, nullptr);
|
|
return dir;
|
|
}
|
|
PathString PathString::GetPath() const
|
|
{
|
|
PathString drive, dir;
|
|
SplitPath(&drive, &dir, nullptr, nullptr);
|
|
return drive + dir;
|
|
}
|
|
PathString PathString::GetFileName() const
|
|
{
|
|
PathString fname;
|
|
SplitPath(nullptr, nullptr, &fname, nullptr);
|
|
return fname;
|
|
}
|
|
PathString PathString::GetFileExt() const
|
|
{
|
|
PathString ext;
|
|
SplitPath(nullptr, nullptr, nullptr, &ext);
|
|
return ext;
|
|
}
|
|
PathString PathString::GetFullFileName() const
|
|
{
|
|
PathString name, ext;
|
|
SplitPath(nullptr, nullptr, &name, &ext);
|
|
return name + ext;
|
|
}
|
|
|
|
|
|
bool PathString::IsDirectory() const
|
|
{
|
|
// Using PathIsDirectoryW here instead would increase libopenmpt dependencies by shlwapi.dll.
|
|
// GetFileAttributesW also does the job just fine.
|
|
#if MPT_OS_WINDOWS_WINRT
|
|
WIN32_FILE_ATTRIBUTE_DATA data = {};
|
|
if(::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
DWORD dwAttrib = data.dwFileAttributes;
|
|
#else // !MPT_OS_WINDOWS_WINRT
|
|
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
|
#endif // MPT_OS_WINDOWS_WINRT
|
|
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
|
|
bool PathString::IsFile() const
|
|
{
|
|
#if MPT_OS_WINDOWS_WINRT
|
|
WIN32_FILE_ATTRIBUTE_DATA data = {};
|
|
if (::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
DWORD dwAttrib = data.dwFileAttributes;
|
|
#else // !MPT_OS_WINDOWS_WINRT
|
|
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
|
#endif // MPT_OS_WINDOWS_WINRT
|
|
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
|
|
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
|
|
|
bool PathString::FileOrDirectoryExists() const
|
|
{
|
|
return ::PathFileExists(path.c_str()) != FALSE;
|
|
}
|
|
|
|
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
|
|
|
PathString PathString::ReplaceExt(const mpt::PathString &newExt) const
|
|
{
|
|
return GetDrive() + GetDir() + GetFileName() + newExt;
|
|
}
|
|
|
|
|
|
PathString PathString::SanitizeComponent() const
|
|
{
|
|
PathString result = *this;
|
|
SanitizeFilename(result);
|
|
return result;
|
|
}
|
|
|
|
|
|
// Convert an absolute path to a path that's relative to "&relativeTo".
|
|
PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) const
|
|
{
|
|
mpt::PathString result = *this;
|
|
if(path.empty())
|
|
{
|
|
return result;
|
|
}
|
|
if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), relativeTo.AsNative().length()))
|
|
{
|
|
// Path is OpenMPT's directory or a sub directory ("C:\OpenMPT\Somepath" => ".\Somepath")
|
|
result = P_(".\\"); // ".\"
|
|
result += mpt::PathString::FromNative(AsNative().substr(relativeTo.AsNative().length()));
|
|
} else if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), 2))
|
|
{
|
|
// Path is on the same drive as OpenMPT ("C:\Somepath" => "\Somepath")
|
|
result = mpt::PathString::FromNative(AsNative().substr(2));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
// Convert a path that is relative to "&relativeTo" to an absolute path.
|
|
PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) const
|
|
{
|
|
mpt::PathString result = *this;
|
|
if(path.empty())
|
|
{
|
|
return result;
|
|
}
|
|
if(path.length() >= 2 && path[0] == PC_('\\') && path[1] != PC_('\\'))
|
|
{
|
|
// Path is on the same drive as OpenMPT ("\Somepath\" => "C:\Somepath\"), but ignore network paths starting with "\\"
|
|
result = mpt::PathString::FromNative(relativeTo.AsNative().substr(0, 2));
|
|
result += mpt::PathString(path);
|
|
} else if(path.length() >= 2 && path.substr(0, 2) == PL_(".\\"))
|
|
{
|
|
// Path is OpenMPT's directory or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\")
|
|
result = relativeTo; // "C:\OpenMPT\"
|
|
result += mpt::PathString::FromNative(AsNative().substr(2));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
|
|
|
|
|
bool PathString::IsPathSeparator(RawPathString::value_type c)
|
|
{
|
|
#if MPT_OS_WINDOWS
|
|
return (c == PC_('\\')) || (c == PC_('/'));
|
|
#else
|
|
return c == PC_('/');
|
|
#endif
|
|
}
|
|
|
|
RawPathString::value_type PathString::GetDefaultPathSeparator()
|
|
{
|
|
#if MPT_OS_WINDOWS
|
|
return PC_('\\');
|
|
#else
|
|
return PC_('/');
|
|
#endif
|
|
}
|
|
|
|
|
|
} // namespace mpt
|
|
|
|
|
|
namespace mpt
|
|
{
|
|
|
|
bool PathIsAbsolute(const mpt::PathString &path) {
|
|
mpt::RawPathString rawpath = path.AsNative();
|
|
#if MPT_OS_WINDOWS
|
|
if(rawpath.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
|
{
|
|
return true;
|
|
}
|
|
if(rawpath.substr(0, 4) == PL_("\\\\?\\"))
|
|
{
|
|
return true;
|
|
}
|
|
if(rawpath.substr(0, 2) == PL_("\\\\"))
|
|
{
|
|
return true; // UNC
|
|
}
|
|
if(rawpath.substr(0, 2) == PL_("//"))
|
|
{
|
|
return true; // UNC
|
|
}
|
|
return (rawpath.length()) >= 3 && (rawpath[1] == ':') && mpt::PathString::IsPathSeparator(rawpath[2]);
|
|
#else
|
|
return (rawpath.length() >= 1) && mpt::PathString::IsPathSeparator(rawpath[0]);
|
|
#endif
|
|
}
|
|
|
|
|
|
#if MPT_OS_WINDOWS
|
|
|
|
#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00))
|
|
|
|
mpt::PathString GetAbsolutePath(const mpt::PathString &path)
|
|
{
|
|
DWORD size = GetFullPathName(path.AsNative().c_str(), 0, nullptr, nullptr);
|
|
if(size == 0)
|
|
{
|
|
return path;
|
|
}
|
|
std::vector<TCHAR> fullPathName(size, TEXT('\0'));
|
|
if(GetFullPathName(path.AsNative().c_str(), size, fullPathName.data(), nullptr) == 0)
|
|
{
|
|
return path;
|
|
}
|
|
return mpt::PathString::FromNative(fullPathName.data());
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef MODPLUG_TRACKER
|
|
|
|
bool DeleteWholeDirectoryTree(mpt::PathString path)
|
|
{
|
|
if(path.AsNative().empty())
|
|
{
|
|
return false;
|
|
}
|
|
if(PathIsRelative(path.AsNative().c_str()) == TRUE)
|
|
{
|
|
return false;
|
|
}
|
|
if(!path.FileOrDirectoryExists())
|
|
{
|
|
return true;
|
|
}
|
|
if(!path.IsDirectory())
|
|
{
|
|
return false;
|
|
}
|
|
path.EnsureTrailingSlash();
|
|
HANDLE hFind = NULL;
|
|
WIN32_FIND_DATA wfd = {};
|
|
hFind = FindFirstFile((path + P_("*.*")).AsNative().c_str(), &wfd);
|
|
if(hFind != NULL && hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName);
|
|
if(filename != P_(".") && filename != P_(".."))
|
|
{
|
|
filename = path + filename;
|
|
if(filename.IsDirectory())
|
|
{
|
|
if(!DeleteWholeDirectoryTree(filename))
|
|
{
|
|
return false;
|
|
}
|
|
} else if(filename.IsFile())
|
|
{
|
|
if(DeleteFile(filename.AsNative().c_str()) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} while(FindNextFile(hFind, &wfd));
|
|
FindClose(hFind);
|
|
}
|
|
if(RemoveDirectory(path.AsNative().c_str()) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif // MODPLUG_TRACKER
|
|
|
|
#endif // MPT_OS_WINDOWS
|
|
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
|
|
|
mpt::PathString GetExecutablePath()
|
|
{
|
|
std::vector<TCHAR> exeFileName(MAX_PATH);
|
|
while(GetModuleFileName(0, exeFileName.data(), mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
|
|
{
|
|
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
return mpt::PathString();
|
|
}
|
|
exeFileName.resize(exeFileName.size() * 2);
|
|
}
|
|
return mpt::GetAbsolutePath(mpt::PathString::FromNative(exeFileName.data()).GetPath());
|
|
}
|
|
|
|
|
|
#if !MPT_OS_WINDOWS_WINRT
|
|
|
|
mpt::PathString GetSystemPath()
|
|
{
|
|
DWORD size = GetSystemDirectory(nullptr, 0);
|
|
std::vector<TCHAR> path(size + 1);
|
|
if(!GetSystemDirectory(path.data(), size + 1))
|
|
{
|
|
return mpt::PathString();
|
|
}
|
|
return mpt::PathString::FromNative(path.data()) + P_("\\");
|
|
}
|
|
|
|
#endif // !MPT_OS_WINDOWS_WINRT
|
|
|
|
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
|
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
|
|
|
mpt::PathString GetTempDirectory()
|
|
{
|
|
DWORD size = GetTempPath(0, nullptr);
|
|
if(size)
|
|
{
|
|
std::vector<TCHAR> tempPath(size + 1);
|
|
if(GetTempPath(size + 1, tempPath.data()))
|
|
{
|
|
return mpt::PathString::FromNative(tempPath.data());
|
|
}
|
|
}
|
|
// use exe directory as fallback
|
|
return mpt::GetExecutablePath();
|
|
}
|
|
|
|
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix, const mpt::PathString &fileNameExtension)
|
|
{
|
|
mpt::PathString filename = mpt::GetTempDirectory();
|
|
filename += (!fileNamePrefix.empty() ? fileNamePrefix + P_("_") : mpt::PathString());
|
|
filename += mpt::PathString::FromUnicode(mpt::UUID::GenerateLocalUseOnly(mpt::global_prng()).ToUString());
|
|
filename += (!fileNameExtension.empty() ? P_(".") + fileNameExtension : mpt::PathString());
|
|
return filename;
|
|
}
|
|
|
|
TempFileGuard::TempFileGuard(const mpt::PathString &filename)
|
|
: filename(filename)
|
|
{
|
|
return;
|
|
}
|
|
|
|
mpt::PathString TempFileGuard::GetFilename() const
|
|
{
|
|
return filename;
|
|
}
|
|
|
|
TempFileGuard::~TempFileGuard()
|
|
{
|
|
if(!filename.empty())
|
|
{
|
|
DeleteFile(filename.AsNative().c_str());
|
|
}
|
|
}
|
|
|
|
|
|
TempDirGuard::TempDirGuard(const mpt::PathString &dirname_)
|
|
: dirname(dirname_.WithTrailingSlash())
|
|
{
|
|
if(dirname.empty())
|
|
{
|
|
return;
|
|
}
|
|
if(::CreateDirectory(dirname.AsNative().c_str(), NULL) == 0)
|
|
{ // fail
|
|
dirname = mpt::PathString();
|
|
}
|
|
}
|
|
|
|
mpt::PathString TempDirGuard::GetDirname() const
|
|
{
|
|
return dirname;
|
|
}
|
|
|
|
TempDirGuard::~TempDirGuard()
|
|
{
|
|
if(!dirname.empty())
|
|
{
|
|
DeleteWholeDirectoryTree(dirname);
|
|
}
|
|
}
|
|
|
|
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
|
|
|
} // namespace mpt
|
|
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER)
|
|
|
|
static inline char SanitizeFilenameChar(char c)
|
|
{
|
|
if( c == '\\' ||
|
|
c == '\"' ||
|
|
c == '/' ||
|
|
c == ':' ||
|
|
c == '?' ||
|
|
c == '<' ||
|
|
c == '>' ||
|
|
c == '|' ||
|
|
c == '*')
|
|
{
|
|
c = '_';
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static inline wchar_t SanitizeFilenameChar(wchar_t c)
|
|
{
|
|
if( c == L'\\' ||
|
|
c == L'\"' ||
|
|
c == L'/' ||
|
|
c == L':' ||
|
|
c == L'?' ||
|
|
c == L'<' ||
|
|
c == L'>' ||
|
|
c == L'|' ||
|
|
c == L'*')
|
|
{
|
|
c = L'_';
|
|
}
|
|
return c;
|
|
}
|
|
|
|
#if MPT_CXX_AT_LEAST(20)
|
|
static inline char8_t SanitizeFilenameChar(char8_t c)
|
|
{
|
|
if( c == u8'\\' ||
|
|
c == u8'\"' ||
|
|
c == u8'/' ||
|
|
c == u8':' ||
|
|
c == u8'?' ||
|
|
c == u8'<' ||
|
|
c == u8'>' ||
|
|
c == u8'|' ||
|
|
c == u8'*')
|
|
{
|
|
c = u8'_';
|
|
}
|
|
return c;
|
|
}
|
|
#endif
|
|
|
|
void SanitizeFilename(mpt::PathString &filename)
|
|
{
|
|
mpt::RawPathString tmp = filename.AsNative();
|
|
for(auto &c : tmp)
|
|
{
|
|
c = SanitizeFilenameChar(c);
|
|
}
|
|
filename = mpt::PathString::FromNative(tmp);
|
|
}
|
|
|
|
void SanitizeFilename(char *beg, char *end)
|
|
{
|
|
for(char *it = beg; it != end; ++it)
|
|
{
|
|
*it = SanitizeFilenameChar(*it);
|
|
}
|
|
}
|
|
|
|
void SanitizeFilename(wchar_t *beg, wchar_t *end)
|
|
{
|
|
for(wchar_t *it = beg; it != end; ++it)
|
|
{
|
|
*it = SanitizeFilenameChar(*it);
|
|
}
|
|
}
|
|
|
|
void SanitizeFilename(std::string &str)
|
|
{
|
|
for(size_t i = 0; i < str.length(); i++)
|
|
{
|
|
str[i] = SanitizeFilenameChar(str[i]);
|
|
}
|
|
}
|
|
|
|
void SanitizeFilename(std::wstring &str)
|
|
{
|
|
for(size_t i = 0; i < str.length(); i++)
|
|
{
|
|
str[i] = SanitizeFilenameChar(str[i]);
|
|
}
|
|
}
|
|
|
|
#if MPT_USTRING_MODE_UTF8
|
|
void SanitizeFilename(mpt::u8string &str)
|
|
{
|
|
for(size_t i = 0; i < str.length(); i++)
|
|
{
|
|
str[i] = SanitizeFilenameChar(str[i]);
|
|
}
|
|
}
|
|
#endif // MPT_USTRING_MODE_UTF8
|
|
|
|
#if defined(MPT_WITH_MFC)
|
|
void SanitizeFilename(CString &str)
|
|
{
|
|
for(int i = 0; i < str.GetLength(); i++)
|
|
{
|
|
str.SetAt(i, SanitizeFilenameChar(str.GetAt(i)));
|
|
}
|
|
}
|
|
#endif // MPT_WITH_MFC
|
|
|
|
#endif // MODPLUG_TRACKER
|
|
|
|
|
|
#if defined(MODPLUG_TRACKER)
|
|
|
|
|
|
mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
|
|
{
|
|
mpt::PathString filter;
|
|
if(GetShortName().empty() || GetExtensions().empty())
|
|
{
|
|
return filter;
|
|
}
|
|
if(!GetDescription().empty())
|
|
{
|
|
filter += mpt::PathString::FromUnicode(GetDescription());
|
|
} else
|
|
{
|
|
filter += mpt::PathString::FromUnicode(GetShortName());
|
|
}
|
|
const auto extensions = GetExtensions();
|
|
if(format[FileTypeFormatShowExtensions])
|
|
{
|
|
filter += P_(" (");
|
|
bool first = true;
|
|
for(const auto &ext : extensions)
|
|
{
|
|
if(first)
|
|
{
|
|
first = false;
|
|
} else
|
|
{
|
|
filter += P_(",");
|
|
}
|
|
filter += P_("*.");
|
|
filter += ext;
|
|
}
|
|
filter += P_(")");
|
|
}
|
|
filter += P_("|");
|
|
{
|
|
bool first = true;
|
|
for(const auto &ext : extensions)
|
|
{
|
|
if(first)
|
|
{
|
|
first = false;
|
|
} else
|
|
{
|
|
filter += P_(";");
|
|
}
|
|
filter += P_("*.");
|
|
filter += ext;
|
|
}
|
|
}
|
|
filter += P_("|");
|
|
return filter;
|
|
}
|
|
|
|
|
|
mpt::PathString FileType::AsFilterOnlyString() const
|
|
{
|
|
mpt::PathString filter;
|
|
const auto extensions = GetExtensions();
|
|
{
|
|
bool first = true;
|
|
for(const auto &ext : extensions)
|
|
{
|
|
if(first)
|
|
{
|
|
first = false;
|
|
} else
|
|
{
|
|
filter += P_(";");
|
|
}
|
|
filter += P_("*.");
|
|
filter += ext;
|
|
}
|
|
}
|
|
return filter;
|
|
}
|
|
|
|
|
|
mpt::PathString ToFilterString(const FileType &fileType, FlagSet<FileTypeFormat> format)
|
|
{
|
|
return fileType.AsFilterString(format);
|
|
}
|
|
|
|
|
|
mpt::PathString ToFilterString(const std::vector<FileType> &fileTypes, FlagSet<FileTypeFormat> format)
|
|
{
|
|
mpt::PathString filter;
|
|
for(const auto &type : fileTypes)
|
|
{
|
|
filter += type.AsFilterString(format);
|
|
}
|
|
return filter;
|
|
}
|
|
|
|
|
|
mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty)
|
|
{
|
|
mpt::PathString filter = fileType.AsFilterOnlyString();
|
|
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
|
}
|
|
|
|
|
|
mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool prependSemicolonWhenNotEmpty)
|
|
{
|
|
mpt::PathString filter;
|
|
for(const auto &type : fileTypes)
|
|
{
|
|
filter += type.AsFilterOnlyString();
|
|
}
|
|
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
|
}
|
|
|
|
|
|
#endif // MODPLUG_TRACKER
|
|
|
|
|
|
|
|
OPENMPT_NAMESPACE_END
|