mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-10 18:35:47 -04:00
Android: Allow opening/getting files relative to downloads directory
This commit is contained in:
@ -2,6 +2,7 @@
|
||||
#include "assert.h"
|
||||
#include "file_system.h"
|
||||
#include "log.h"
|
||||
#include "string_util.h"
|
||||
#include <array>
|
||||
Log_SetChannel(CDImage);
|
||||
|
||||
@ -17,45 +18,50 @@ u32 CDImage::GetBytesPerSector(TrackMode mode)
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::Open(const char* filename, Common::Error* error)
|
||||
{
|
||||
const char* extension = std::strrchr(filename, '.');
|
||||
const char* extension;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::string filename_display_name(FileSystem::GetDisplayNameFromPath(filename));
|
||||
if (filename_display_name.empty())
|
||||
filename_display_name = filename;
|
||||
|
||||
extension = std::strrchr(filename_display_name.c_str(), '.');
|
||||
#else
|
||||
extension = std::strrchr(filename, '.');
|
||||
#endif
|
||||
|
||||
if (!extension)
|
||||
{
|
||||
Log_ErrorPrintf("Invalid filename: '%s'", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CASE_COMPARE _stricmp
|
||||
#else
|
||||
#define CASE_COMPARE strcasecmp
|
||||
#endif
|
||||
|
||||
if (CASE_COMPARE(extension, ".cue") == 0)
|
||||
if (StringUtil::Strcasecmp(extension, ".cue") == 0)
|
||||
{
|
||||
return OpenCueSheetImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".bin") == 0 || CASE_COMPARE(extension, ".img") == 0 ||
|
||||
CASE_COMPARE(extension, ".iso") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".bin") == 0 || StringUtil::Strcasecmp(extension, ".img") == 0 ||
|
||||
StringUtil::Strcasecmp(extension, ".iso") == 0)
|
||||
{
|
||||
return OpenBinImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".chd") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".chd") == 0)
|
||||
{
|
||||
return OpenCHDImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".ecm") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".ecm") == 0)
|
||||
{
|
||||
return OpenEcmImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".mds") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".mds") == 0)
|
||||
{
|
||||
return OpenMdsImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".pbp") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".pbp") == 0)
|
||||
{
|
||||
return OpenPBPImage(filename, error);
|
||||
}
|
||||
else if (CASE_COMPARE(extension, ".m3u") == 0)
|
||||
else if (StringUtil::Strcasecmp(extension, ".m3u") == 0)
|
||||
{
|
||||
return OpenM3uImage(filename, error);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ bool CDImageBin::Open(const char* filename, Common::Error* error)
|
||||
|
||||
AddLeadOutIndex();
|
||||
|
||||
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());
|
||||
m_sbi.LoadSBIFromImagePath(filename);
|
||||
|
||||
return Seek(1, Position{0, 0, 0});
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
||||
m_lba_count = disc_lba;
|
||||
AddLeadOutIndex();
|
||||
|
||||
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());
|
||||
m_sbi.LoadSBIFromImagePath(filename);
|
||||
|
||||
return Seek(1, Position{0, 0, 0});
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
||||
m_lba_count = disc_lba;
|
||||
AddLeadOutIndex();
|
||||
|
||||
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());
|
||||
m_sbi.LoadSBIFromImagePath(filename);
|
||||
|
||||
return Seek(1, Position{0, 0, 0});
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
||||
|
||||
AddLeadOutIndex();
|
||||
|
||||
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());
|
||||
m_sbi.LoadSBIFromImagePath(filename);
|
||||
|
||||
m_chunk_buffer.reserve(RAW_SECTOR_SIZE * 2);
|
||||
return Seek(1, Position{0, 0, 0});
|
||||
|
@ -250,7 +250,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
||||
m_lba_count = m_tracks.back().start_lba + m_tracks.back().length;
|
||||
AddLeadOutIndex();
|
||||
|
||||
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());
|
||||
m_sbi.LoadSBIFromImagePath(filename);
|
||||
|
||||
return Seek(1, Position{0, 0, 0});
|
||||
}
|
||||
|
@ -673,8 +673,8 @@ bool CDImagePBP::OpenDisc(u32 index, Common::Error* error)
|
||||
|
||||
if (m_disc_offsets.size() > 1)
|
||||
{
|
||||
std::string sbi_path =
|
||||
FileSystem::StripExtension(m_filename) + StringUtil::StdStringFromFormat("_%u.sbi", index + 1);
|
||||
std::string sbi_path(FileSystem::StripExtension(m_filename));
|
||||
sbi_path += TinyString::FromFormat("_%u.sbi", index + 1);
|
||||
m_sbi.LoadSBI(sbi_path.c_str());
|
||||
}
|
||||
else
|
||||
|
@ -83,6 +83,11 @@ bool CDSubChannelReplacement::LoadSBI(const char* path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDSubChannelReplacement::LoadSBIFromImagePath(const char* image_path)
|
||||
{
|
||||
return LoadSBI(FileSystem::ReplaceExtension(image_path, "sbi").c_str());
|
||||
}
|
||||
|
||||
void CDSubChannelReplacement::AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq)
|
||||
{
|
||||
auto iter = m_replacement_subq.find(lba);
|
||||
|
@ -14,6 +14,7 @@ public:
|
||||
u32 GetReplacementSectorCount() const { return static_cast<u32>(m_replacement_subq.size()); }
|
||||
|
||||
bool LoadSBI(const char* path);
|
||||
bool LoadSBIFromImagePath(const char* image_path);
|
||||
|
||||
/// Adds a sector to the replacement map.
|
||||
void AddReplacementSubChannelQ(u32 lba, const CDImage::SubChannelQ& subq);
|
||||
|
@ -51,6 +51,8 @@ static jfieldID s_android_FileHelper_FindResult_relativeName;
|
||||
static jfieldID s_android_FileHelper_FindResult_size;
|
||||
static jfieldID s_android_FileHelper_FindResult_modifiedTime;
|
||||
static jfieldID s_android_FileHelper_FindResult_flags;
|
||||
static jmethodID s_android_FileHelper_getDisplayName;
|
||||
static jmethodID s_android_FileHelper_getRelativePathForURIPath;
|
||||
|
||||
// helper for retrieving the current per-thread jni environment
|
||||
static JNIEnv* GetJNIEnv()
|
||||
@ -89,6 +91,8 @@ void SetAndroidFileHelper(void* jvm, void* env, void* object)
|
||||
|
||||
jenv->DeleteGlobalRef(s_android_FileHelper_object);
|
||||
jenv->DeleteGlobalRef(s_android_FileHelper_class);
|
||||
s_android_FileHelper_getRelativePathForURIPath = {};
|
||||
s_android_FileHelper_getDisplayName = {};
|
||||
s_android_FileHelper_openURIAsFileDescriptor = {};
|
||||
s_android_FileHelper_FindFiles = {};
|
||||
s_android_FileHelper_object = {};
|
||||
@ -114,7 +118,13 @@ void SetAndroidFileHelper(void* jvm, void* env, void* object)
|
||||
s_android_FileHelper_FindFiles =
|
||||
jenv->GetMethodID(s_android_FileHelper_class, "findFiles",
|
||||
"(Ljava/lang/String;I)[Lcom/github/stenzek/duckstation/FileHelper$FindResult;");
|
||||
Assert(s_android_FileHelper_openURIAsFileDescriptor && s_android_FileHelper_FindFiles);
|
||||
s_android_FileHelper_getDisplayName =
|
||||
jenv->GetMethodID(s_android_FileHelper_class, "getDisplayNameForURIPath", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
s_android_FileHelper_getRelativePathForURIPath =
|
||||
jenv->GetMethodID(s_android_FileHelper_class, "getRelativePathForURIPath",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
||||
Assert(s_android_FileHelper_openURIAsFileDescriptor && s_android_FileHelper_FindFiles &&
|
||||
s_android_FileHelper_getDisplayName && s_android_FileHelper_getRelativePathForURIPath);
|
||||
|
||||
jclass fr_class = jenv->FindClass("com/github/stenzek/duckstation/FileHelper$FindResult");
|
||||
Assert(fr_class);
|
||||
@ -279,6 +289,68 @@ static bool FindUriFiles(const char* path, const char* pattern, u32 flags, FindR
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetDisplayNameForUriPath(const char* path, std::string* result)
|
||||
{
|
||||
if (!s_android_FileHelper_object)
|
||||
return false;
|
||||
|
||||
JNIEnv* env = GetJNIEnv();
|
||||
|
||||
jstring path_jstr = env->NewStringUTF(path);
|
||||
jstring result_jstr = static_cast<jstring>(
|
||||
env->CallObjectMethod(s_android_FileHelper_object, s_android_FileHelper_getDisplayName, path_jstr));
|
||||
env->DeleteLocalRef(path_jstr);
|
||||
if (!result_jstr)
|
||||
return false;
|
||||
|
||||
const char* result_name = env->GetStringUTFChars(result_jstr, nullptr);
|
||||
if (result_name)
|
||||
{
|
||||
Log_DevPrintf("GetDisplayNameForUriPath(\"%s\") -> \"%s\"", path, result_name);
|
||||
result->assign(result_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
result->clear();
|
||||
}
|
||||
|
||||
env->ReleaseStringUTFChars(result_jstr, result_name);
|
||||
env->DeleteLocalRef(result_jstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetRelativePathForUriPath(const char* path, const char* filename, std::string* result)
|
||||
{
|
||||
if (!s_android_FileHelper_object)
|
||||
return false;
|
||||
|
||||
JNIEnv* env = GetJNIEnv();
|
||||
|
||||
jstring path_jstr = env->NewStringUTF(path);
|
||||
jstring filename_jstr = env->NewStringUTF(filename);
|
||||
jstring result_jstr = static_cast<jstring>(env->CallObjectMethod(
|
||||
s_android_FileHelper_object, s_android_FileHelper_getRelativePathForURIPath, path_jstr, filename_jstr));
|
||||
env->DeleteLocalRef(filename_jstr);
|
||||
env->DeleteLocalRef(path_jstr);
|
||||
if (!result_jstr)
|
||||
return false;
|
||||
|
||||
const char* result_name = env->GetStringUTFChars(result_jstr, nullptr);
|
||||
if (result_name)
|
||||
{
|
||||
Log_DevPrintf("GetRelativePathForUriPath(\"%s\", \"%s\") -> \"%s\"", path, filename, result_name);
|
||||
result->assign(result_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
result->clear();
|
||||
}
|
||||
|
||||
env->ReleaseStringUTFChars(result_jstr, result_name);
|
||||
env->DeleteLocalRef(result_jstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // __ANDROID__
|
||||
|
||||
ChangeNotifier::ChangeNotifier(const String& directoryPath, bool recursiveWatch)
|
||||
@ -510,17 +582,33 @@ bool IsAbsolutePath(const std::string_view& path)
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string StripExtension(const std::string_view& path)
|
||||
std::string_view StripExtension(const std::string_view& path)
|
||||
{
|
||||
std::string_view::size_type pos = path.rfind('.');
|
||||
if (pos == std::string::npos)
|
||||
return std::string(path);
|
||||
return path;
|
||||
|
||||
return std::string(path, 0, pos);
|
||||
return path.substr(0, pos);
|
||||
}
|
||||
|
||||
std::string ReplaceExtension(const std::string_view& path, const std::string_view& new_extension)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
// This is more complex on android because the path may not contain the actual filename.
|
||||
if (IsUriPath(path))
|
||||
{
|
||||
std::string display_name(GetDisplayNameFromPath(path));
|
||||
std::string_view::size_type pos = display_name.rfind('.');
|
||||
if (pos == std::string::npos)
|
||||
return std::string(path);
|
||||
|
||||
display_name.erase(pos + 1);
|
||||
display_name.append(new_extension);
|
||||
|
||||
return BuildRelativePath(path, display_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string_view::size_type pos = path.rfind('.');
|
||||
if (pos == std::string::npos)
|
||||
return std::string(path);
|
||||
@ -572,6 +660,28 @@ static std::string_view::size_type GetLastSeperatorPosition(const std::string_vi
|
||||
return last_separator;
|
||||
}
|
||||
|
||||
std::string GetDisplayNameFromPath(const std::string_view& path)
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
std::string result;
|
||||
|
||||
if (IsUriPath(path))
|
||||
{
|
||||
std::string temp(path);
|
||||
if (!GetDisplayNameForUriPath(temp.c_str(), &result))
|
||||
result = std::move(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = path;
|
||||
}
|
||||
|
||||
return result;
|
||||
#else
|
||||
return std::string(GetFileNameFromPath(path));
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string_view GetPathDirectory(const std::string_view& path)
|
||||
{
|
||||
std::string::size_type pos = GetLastSeperatorPosition(path, false);
|
||||
@ -583,7 +693,7 @@ std::string_view GetPathDirectory(const std::string_view& path)
|
||||
|
||||
std::string_view GetFileNameFromPath(const std::string_view& path)
|
||||
{
|
||||
std::string::size_type pos = GetLastSeperatorPosition(path, true);
|
||||
std::string_view::size_type pos = GetLastSeperatorPosition(path, true);
|
||||
if (pos == std::string_view::npos)
|
||||
return path;
|
||||
|
||||
@ -630,6 +740,15 @@ std::vector<std::string> GetRootDirectoryList()
|
||||
std::string BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename)
|
||||
{
|
||||
std::string new_string;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (IsUriPath(filename) &&
|
||||
GetRelativePathForUriPath(std::string(filename).c_str(), std::string(new_filename).c_str(), &new_string))
|
||||
{
|
||||
return new_string;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string_view::size_type pos = GetLastSeperatorPosition(filename, true);
|
||||
if (pos != std::string_view::npos)
|
||||
new_string.assign(filename, 0, pos);
|
||||
|
@ -145,11 +145,15 @@ void SanitizeFileName(std::string& Destination, bool StripSlashes = true);
|
||||
bool IsAbsolutePath(const std::string_view& path);
|
||||
|
||||
/// Removes the extension of a filename.
|
||||
std::string StripExtension(const std::string_view& path);
|
||||
std::string_view StripExtension(const std::string_view& path);
|
||||
|
||||
/// Replaces the extension of a filename with another.
|
||||
std::string ReplaceExtension(const std::string_view& path, const std::string_view& new_extension);
|
||||
|
||||
/// Returns the display name of a filename. Usually this is the same as the path, except on Android
|
||||
/// where it resolves a content URI to its name.
|
||||
std::string GetDisplayNameFromPath(const std::string_view& path);
|
||||
|
||||
/// Returns the directory component of a filename.
|
||||
std::string_view GetPathDirectory(const std::string_view& path);
|
||||
|
||||
|
@ -33,8 +33,7 @@ HostInterface::HostInterface()
|
||||
g_host_interface = this;
|
||||
|
||||
// we can get the program directory at construction time
|
||||
const std::string program_path = FileSystem::GetProgramPath();
|
||||
m_program_directory = FileSystem::GetPathDirectory(program_path.c_str());
|
||||
m_program_directory = FileSystem::GetPathDirectory(FileSystem::GetProgramPath());
|
||||
}
|
||||
|
||||
HostInterface::~HostInterface()
|
||||
@ -896,8 +895,7 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
|
||||
|
||||
void HostInterface::SetUserDirectoryToProgramDirectory()
|
||||
{
|
||||
const std::string program_path(FileSystem::GetProgramPath());
|
||||
const std::string program_directory(FileSystem::GetPathDirectory(program_path.c_str()));
|
||||
const std::string program_directory(FileSystem::GetProgramPath());
|
||||
m_user_directory = program_directory;
|
||||
}
|
||||
|
||||
|
@ -2914,7 +2914,7 @@ void CommonHostInterface::GetGameInfo(const char* path, CDImage* image, std::str
|
||||
}
|
||||
else
|
||||
{
|
||||
*title = FileSystem::GetFileTitleFromPath(path);
|
||||
*title = FileSystem::GetFileTitleFromPath(std::string(path));
|
||||
if (image)
|
||||
*code = System::GetGameCodeForImage(image, true);
|
||||
}
|
||||
|
@ -662,7 +662,7 @@ static void DoChangeDiscFromFile()
|
||||
};
|
||||
|
||||
OpenFileSelector(ICON_FA_COMPACT_DISC " Select Disc Image", false, std::move(callback), GetDiscImageFilters(),
|
||||
std::string(FileSystem::GetPathDirectory(System::GetMediaFileName().c_str())));
|
||||
std::string(FileSystem::GetPathDirectory(System::GetMediaFileName())));
|
||||
}
|
||||
|
||||
static void DoChangeDisc()
|
||||
@ -1076,7 +1076,7 @@ static bool SettingInfoButton(const SettingInfo& si, const char* section)
|
||||
CloseFileSelector();
|
||||
};
|
||||
OpenFileSelector(si.visible_name, false, std::move(callback), ImGuiFullscreen::FileSelectorFilters(),
|
||||
std::string(FileSystem::GetPathDirectory(value.c_str())));
|
||||
std::string(FileSystem::GetPathDirectory(std::move(value))));
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -2372,7 +2372,7 @@ void DrawQuickMenu(MainWindowType type)
|
||||
SmallString subtitle;
|
||||
if (!code.empty())
|
||||
subtitle.Format("%s - ", code.c_str());
|
||||
subtitle.AppendString(FileSystem::GetFileNameFromPath(System::GetRunningPath().c_str()));
|
||||
subtitle.AppendString(FileSystem::GetFileNameFromPath(System::GetRunningPath()));
|
||||
|
||||
const ImVec2 title_size(
|
||||
g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f, title.c_str()));
|
||||
@ -2805,7 +2805,7 @@ void DrawGameListWindow()
|
||||
else
|
||||
summary.Format("%s - %s - ", entry->code.c_str(), Settings::GetDiscRegionName(entry->region));
|
||||
|
||||
summary.AppendString(FileSystem::GetFileNameFromPath(entry->path.c_str()));
|
||||
summary.AppendString(FileSystem::GetFileNameFromPath(entry->path));
|
||||
|
||||
ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
|
@ -487,11 +487,8 @@ void GameList::ScanDirectory(const char* path, bool recursive, ProgressCallback*
|
||||
if (AddFileFromCache(ffd.FileName, modified_time))
|
||||
continue;
|
||||
|
||||
const std::string_view file_part(FileSystem::GetFileNameFromPath(ffd.FileName));
|
||||
if (!file_part.empty())
|
||||
progress->SetFormattedStatusText("Scanning '%*s'...", static_cast<int>(file_part.size()), file_part.data());
|
||||
|
||||
// ownership of fp is transferred
|
||||
progress->SetFormattedStatusText("Scanning '%s'...", FileSystem::GetDisplayNameFromPath(ffd.FileName).c_str());
|
||||
ScanFile(std::move(ffd.FileName), modified_time);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user