mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +00:00
Common/FileSystem: Add BuildRelativePath() function
This commit is contained in:
parent
1b16662f17
commit
e1578be20f
|
@ -72,9 +72,6 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the directory of the filename
|
|
||||||
std::string basepath(FileSystem::GetPathDirectory(filename));
|
|
||||||
basepath += "/";
|
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
|
|
||||||
u32 disc_lba = 0;
|
u32 disc_lba = 0;
|
||||||
|
@ -106,7 +103,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
||||||
}
|
}
|
||||||
if (track_file_index == m_files.size())
|
if (track_file_index == m_files.size())
|
||||||
{
|
{
|
||||||
const std::string track_full_filename(basepath + track_filename);
|
const std::string track_full_filename(FileSystem::BuildRelativePath(m_filename, track_filename));
|
||||||
std::FILE* track_fp = FileSystem::OpenCFile(track_full_filename.c_str(), "rb");
|
std::FILE* track_fp = FileSystem::OpenCFile(track_full_filename.c_str(), "rb");
|
||||||
if (!track_fp && track_file_index == 0)
|
if (!track_fp && track_file_index == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cd_image.h"
|
#include "cd_image.h"
|
||||||
#include "cd_subchannel_replacement.h"
|
#include "cd_subchannel_replacement.h"
|
||||||
|
#include "error.h"
|
||||||
#include "file_system.h"
|
#include "file_system.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fstream>
|
#include <sstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
Log_SetChannel(CDImageMemory);
|
Log_SetChannel(CDImageMemory);
|
||||||
|
|
||||||
|
@ -48,13 +49,19 @@ CDImageM3u::~CDImageM3u() = default;
|
||||||
|
|
||||||
bool CDImageM3u::Open(const char* path, Common::Error* error)
|
bool CDImageM3u::Open(const char* path, Common::Error* error)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(path);
|
std::FILE* fp = FileSystem::OpenCFile(path, "rb");
|
||||||
if (!ifs.is_open())
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::optional<std::string> cue_file(FileSystem::ReadFileToString(fp));
|
||||||
|
std::fclose(fp);
|
||||||
|
if (!cue_file.has_value() || cue_file->empty())
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to open %s", path);
|
error->SetMessage("Failed to read cue sheet");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::istringstream ifs(cue_file.value());
|
||||||
m_filename = path;
|
m_filename = path;
|
||||||
|
|
||||||
std::vector<std::string> entries;
|
std::vector<std::string> entries;
|
||||||
|
@ -79,14 +86,12 @@ bool CDImageM3u::Open(const char* path, Common::Error* error)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Entry entry;
|
Entry entry;
|
||||||
entry.filename.assign(line.begin() + start_offset, line.begin() + end_offset + 1);
|
std::string entry_filename(line.begin() + start_offset, line.begin() + end_offset + 1);
|
||||||
entry.title = FileSystem::GetFileTitleFromPath(entry.filename);
|
entry.title = FileSystem::GetFileTitleFromPath(entry_filename);
|
||||||
if (!FileSystem::IsAbsolutePath(entry.filename))
|
if (!FileSystem::IsAbsolutePath(entry_filename))
|
||||||
{
|
entry.filename = FileSystem::BuildRelativePath(path, entry_filename);
|
||||||
SmallString absolute_path;
|
else
|
||||||
FileSystem::BuildPathRelativeToFile(absolute_path, path, entry.filename.c_str());
|
entry.filename = std::move(entry_filename);
|
||||||
entry.filename = absolute_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log_DevPrintf("Read path from m3u: '%s'", entry.filename.c_str());
|
Log_DevPrintf("Read path from m3u: '%s'", entry.filename.c_str());
|
||||||
m_entries.push_back(std::move(entry));
|
m_entries.push_back(std::move(entry));
|
||||||
|
|
|
@ -283,13 +283,29 @@ std::string ReplaceExtension(const std::string_view& path, const std::string_vie
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string_view::size_type GetLastSeperatorPosition(const std::string_view& filename, bool include_separator)
|
||||||
|
{
|
||||||
|
std::string_view::size_type last_separator = filename.rfind('/');
|
||||||
|
if (include_separator && last_separator != std::string_view::npos)
|
||||||
|
last_separator++;
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
std::string_view::size_type other_last_separator = filename.rfind('\\');
|
||||||
|
if (other_last_separator != std::string_view::npos)
|
||||||
|
{
|
||||||
|
if (include_separator)
|
||||||
|
other_last_separator++;
|
||||||
|
if (last_separator == std::string_view::npos || other_last_separator > last_separator)
|
||||||
|
last_separator = other_last_separator;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return last_separator;
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view GetPathDirectory(const std::string_view& path)
|
std::string_view GetPathDirectory(const std::string_view& path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
std::string::size_type pos = GetLastSeperatorPosition(path, false);
|
||||||
std::string::size_type pos = path.find_last_of("/\\");
|
|
||||||
#else
|
|
||||||
std::string::size_type pos = path.find_last_of("/");
|
|
||||||
#endif
|
|
||||||
if (pos == std::string_view::npos)
|
if (pos == std::string_view::npos)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -298,15 +314,11 @@ std::string_view GetPathDirectory(const std::string_view& path)
|
||||||
|
|
||||||
std::string_view GetFileNameFromPath(const std::string_view& path)
|
std::string_view GetFileNameFromPath(const std::string_view& path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
std::string::size_type pos = GetLastSeperatorPosition(path, true);
|
||||||
std::string::size_type pos = path.find_last_of("/\\");
|
|
||||||
#else
|
|
||||||
std::string::size_type pos = path.find_last_of("/");
|
|
||||||
#endif
|
|
||||||
if (pos == std::string_view::npos)
|
if (pos == std::string_view::npos)
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
return path.substr(pos + 1);
|
return path.substr(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view GetFileTitleFromPath(const std::string_view& path)
|
std::string_view GetFileTitleFromPath(const std::string_view& path)
|
||||||
|
@ -346,108 +358,14 @@ std::vector<std::string> GetRootDirectoryList()
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildPathRelativeToFile(char* Destination, u32 cbDestination, const char* CurrentFileName, const char* NewFileName,
|
std::string BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename)
|
||||||
bool OSPath /* = true */, bool Canonicalize /* = true */)
|
|
||||||
{
|
{
|
||||||
s32 i;
|
std::string new_string;
|
||||||
u32 currentPos = 0;
|
std::string_view::size_type pos = GetLastSeperatorPosition(filename, true);
|
||||||
DebugAssert(Destination != nullptr && cbDestination > 0 && CurrentFileName != nullptr && NewFileName != nullptr);
|
if (pos != std::string_view::npos)
|
||||||
|
new_string.assign(filename, 0, pos);
|
||||||
// clone to a local buffer if the same pointer
|
new_string.append(new_filename);
|
||||||
std::string pathClone;
|
return new_string;
|
||||||
if (Destination == CurrentFileName)
|
|
||||||
{
|
|
||||||
pathClone = CurrentFileName;
|
|
||||||
CurrentFileName = pathClone.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// search for a / or \, copy everything up to and including it to the destination
|
|
||||||
i = (s32)std::strlen(CurrentFileName);
|
|
||||||
for (; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (CurrentFileName[i] == '/' || CurrentFileName[i] == '\\')
|
|
||||||
{
|
|
||||||
// cap to destination length
|
|
||||||
u32 copyLen;
|
|
||||||
if (NewFileName[0] != '\0')
|
|
||||||
copyLen = std::min((u32)(i + 1), cbDestination);
|
|
||||||
else
|
|
||||||
copyLen = std::min((u32)i, cbDestination);
|
|
||||||
|
|
||||||
if (copyLen > 0)
|
|
||||||
{
|
|
||||||
std::memcpy(Destination, CurrentFileName, copyLen);
|
|
||||||
if (copyLen == cbDestination)
|
|
||||||
Destination[cbDestination - 1] = '\0';
|
|
||||||
|
|
||||||
currentPos = copyLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the new parts in
|
|
||||||
if (currentPos < cbDestination && NewFileName[0] != '\0')
|
|
||||||
StringUtil::Strlcpy(Destination + currentPos, NewFileName, cbDestination - currentPos);
|
|
||||||
|
|
||||||
// canonicalize it
|
|
||||||
if (Canonicalize)
|
|
||||||
CanonicalizePath(Destination, cbDestination, Destination, OSPath);
|
|
||||||
else if (OSPath)
|
|
||||||
BuildOSPath(Destination, cbDestination, Destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildPathRelativeToFile(String& Destination, const char* CurrentFileName, const char* NewFileName,
|
|
||||||
bool OSPath /* = true */, bool Canonicalize /* = true */)
|
|
||||||
{
|
|
||||||
s32 i;
|
|
||||||
DebugAssert(CurrentFileName != nullptr && NewFileName != nullptr);
|
|
||||||
|
|
||||||
// get curfile length
|
|
||||||
u32 curFileLength = static_cast<u32>(std::strlen(CurrentFileName));
|
|
||||||
|
|
||||||
// clone to a local buffer if the same pointer
|
|
||||||
if (Destination.GetWriteableCharArray() == CurrentFileName)
|
|
||||||
{
|
|
||||||
char* pathClone = (char*)alloca(curFileLength + 1);
|
|
||||||
StringUtil::Strlcpy(pathClone, CurrentFileName, curFileLength + 1);
|
|
||||||
CurrentFileName = pathClone;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search for a / or \\, copy everything up to and including it to the destination
|
|
||||||
Destination.Clear();
|
|
||||||
i = (s32)curFileLength;
|
|
||||||
for (; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (CurrentFileName[i] == '/' || CurrentFileName[i] == '\\')
|
|
||||||
{
|
|
||||||
if (NewFileName[0] != '\0')
|
|
||||||
Destination.AppendSubString(CurrentFileName, 0, i + 1);
|
|
||||||
else
|
|
||||||
Destination.AppendSubString(CurrentFileName, 0, i);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the new parts in
|
|
||||||
if (NewFileName[0] != '\0')
|
|
||||||
Destination.AppendString(NewFileName);
|
|
||||||
|
|
||||||
// canonicalize it
|
|
||||||
if (Canonicalize)
|
|
||||||
CanonicalizePath(Destination, Destination.GetCharArray(), OSPath);
|
|
||||||
else if (OSPath)
|
|
||||||
BuildOSPath(Destination, Destination.GetCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
String BuildPathRelativeToFile(const char* CurrentFileName, const char* NewFileName, bool OSPath /*= true*/,
|
|
||||||
bool Canonicalize /*= true*/)
|
|
||||||
{
|
|
||||||
String ret;
|
|
||||||
BuildPathRelativeToFile(ret, CurrentFileName, NewFileName, OSPath, Canonicalize);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 Flags)
|
std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 Flags)
|
||||||
|
|
|
@ -126,13 +126,8 @@ void BuildOSPath(char* Destination, u32 cbDestination, const char* Path);
|
||||||
void BuildOSPath(String& Destination, const char* Path);
|
void BuildOSPath(String& Destination, const char* Path);
|
||||||
void BuildOSPath(String& Destination);
|
void BuildOSPath(String& Destination);
|
||||||
|
|
||||||
// builds a path relative to the specified file, optionally canonicalizing it
|
// builds a path relative to the specified file
|
||||||
void BuildPathRelativeToFile(char* Destination, u32 cbDestination, const char* CurrentFileName, const char* NewFileName,
|
std::string BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename);
|
||||||
bool OSPath = true, bool Canonicalize = true);
|
|
||||||
void BuildPathRelativeToFile(String& Destination, const char* CurrentFileName, const char* NewFileName,
|
|
||||||
bool OSPath = true, bool Canonicalize = true);
|
|
||||||
String BuildPathRelativeToFile(const char* CurrentFileName, const char* NewFileName, bool OSPath = true,
|
|
||||||
bool Canonicalize = true);
|
|
||||||
|
|
||||||
// sanitizes a filename for use in a filesystem.
|
// sanitizes a filename for use in a filesystem.
|
||||||
void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes = true);
|
void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes = true);
|
||||||
|
|
|
@ -162,14 +162,6 @@ bool File::Load(const char* path)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetLibraryPSFPath(const char* main_path, const char* lib_path)
|
|
||||||
{
|
|
||||||
std::string path(FileSystem::GetPathDirectory(main_path));
|
|
||||||
path += FS_OSPATH_SEPARATOR_CHARACTER;
|
|
||||||
path += lib_path;
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0)
|
static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0)
|
||||||
{
|
{
|
||||||
// don't recurse past 10 levels just in case of broken files
|
// don't recurse past 10 levels just in case of broken files
|
||||||
|
@ -190,7 +182,7 @@ static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0)
|
||||||
std::optional<std::string> lib_name(file.GetTagString("_lib"));
|
std::optional<std::string> lib_name(file.GetTagString("_lib"));
|
||||||
if (lib_name.has_value())
|
if (lib_name.has_value())
|
||||||
{
|
{
|
||||||
const std::string lib_path(GetLibraryPSFPath(path, lib_name->c_str()));
|
const std::string lib_path(FileSystem::BuildRelativePath(path, lib_name.value()));
|
||||||
Log_InfoPrintf("Loading main parent PSF '%s'", lib_path.c_str());
|
Log_InfoPrintf("Loading main parent PSF '%s'", lib_path.c_str());
|
||||||
|
|
||||||
// We should use the initial SP/PC from the **first** parent lib.
|
// We should use the initial SP/PC from the **first** parent lib.
|
||||||
|
@ -222,7 +214,7 @@ static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0)
|
||||||
if (!lib_name.has_value())
|
if (!lib_name.has_value())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const std::string lib_path(GetLibraryPSFPath(path, lib_name->c_str()));
|
const std::string lib_path(FileSystem::BuildRelativePath(path, lib_name.value()));
|
||||||
Log_InfoPrintf("Loading parent PSF '%s'", lib_path.c_str());
|
Log_InfoPrintf("Loading parent PSF '%s'", lib_path.c_str());
|
||||||
if (!LoadLibraryPSF(lib_path.c_str(), false, depth + 1))
|
if (!LoadLibraryPSF(lib_path.c_str(), false, depth + 1))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue