mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Update SAF handling
This commit is contained in:
@@ -215,14 +215,13 @@ void fscDeviceRedirect_map();
|
||||
void fscDeviceRedirect_add(std::string_view virtualSourcePath, size_t fileSize, const fs::path& targetFilePath, sint32 priority);
|
||||
|
||||
#if __ANDROID__
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
bool FSCDeviceAndroidSAF_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority);
|
||||
#endif // __ANDROID__
|
||||
|
||||
inline bool FSCDeviceHost_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(std::string(hostTargetPath)))
|
||||
if (FilesystemAndroid::IsContentUri(std::string(hostTargetPath)))
|
||||
return FSCDeviceAndroidSAF_Mount(mountPath, hostTargetPath, priority);
|
||||
else
|
||||
#endif // __ANDROID__
|
||||
|
||||
@@ -5,231 +5,229 @@
|
||||
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "Common/FileStream.h"
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
#include "Common/android/FilesystemAndroid.h"
|
||||
|
||||
FSCVirtualFile_AndroidSAF::~FSCVirtualFile_AndroidSAF()
|
||||
{
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
delete m_fs;
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
delete m_fs;
|
||||
}
|
||||
|
||||
sint32 FSCVirtualFile_AndroidSAF::fscGetType()
|
||||
{
|
||||
return m_type;
|
||||
return m_type;
|
||||
}
|
||||
|
||||
uint32 FSCVirtualFile_AndroidSAF::fscDeviceAndroidSAFFSFile_getFileSize()
|
||||
{
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
{
|
||||
if (m_fileSize > 0xFFFFFFFFULL)
|
||||
cemu_assert_suspicious(); // files larger than 4GB are not supported by Wii U filesystem
|
||||
return (uint32)m_fileSize;
|
||||
}
|
||||
return 0;
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
{
|
||||
if (m_fileSize > 0xFFFFFFFFULL)
|
||||
cemu_assert_suspicious(); // files larger than 4GB are not supported by Wii U filesystem
|
||||
return (uint32)m_fileSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 FSCVirtualFile_AndroidSAF::fscQueryValueU64(uint32 id)
|
||||
{
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
{
|
||||
if (id == FSC_QUERY_SIZE)
|
||||
return fscDeviceAndroidSAFFSFile_getFileSize();
|
||||
else if (id == FSC_QUERY_WRITEABLE)
|
||||
return m_isWritable;
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
else if (m_type == FSC_TYPE_DIRECTORY)
|
||||
{
|
||||
if (id == FSC_QUERY_SIZE)
|
||||
return fscDeviceAndroidSAFFSFile_getFileSize();
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
cemu_assert_unimplemented();
|
||||
return 0;
|
||||
if (m_type == FSC_TYPE_FILE)
|
||||
{
|
||||
if (id == FSC_QUERY_SIZE)
|
||||
return fscDeviceAndroidSAFFSFile_getFileSize();
|
||||
else if (id == FSC_QUERY_WRITEABLE)
|
||||
return m_isWritable;
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
else if (m_type == FSC_TYPE_DIRECTORY)
|
||||
{
|
||||
if (id == FSC_QUERY_SIZE)
|
||||
return fscDeviceAndroidSAFFSFile_getFileSize();
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
cemu_assert_unimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 FSCVirtualFile_AndroidSAF::fscWriteData(void* buffer, uint32 size)
|
||||
{
|
||||
throw std::logic_error("write not supported with SAF");
|
||||
return 0;
|
||||
throw std::logic_error("write not supported with SAF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 FSCVirtualFile_AndroidSAF::fscReadData(void* buffer, uint32 size)
|
||||
{
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
if (size >= (2UL * 1024UL * 1024UL * 1024UL))
|
||||
{
|
||||
cemu_assert_suspicious();
|
||||
return 0;
|
||||
}
|
||||
uint32 bytesLeft = (uint32)(m_fileSize - m_seek);
|
||||
bytesLeft = std::min(bytesLeft, 0x7FFFFFFFu);
|
||||
sint32 bytesToRead = std::min(bytesLeft, size);
|
||||
uint32 bytesRead = m_fs->readData(buffer, bytesToRead);
|
||||
m_seek += bytesRead;
|
||||
return bytesRead;
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
if (size >= (2UL * 1024UL * 1024UL * 1024UL))
|
||||
{
|
||||
cemu_assert_suspicious();
|
||||
return 0;
|
||||
}
|
||||
uint32 bytesLeft = (uint32)(m_fileSize - m_seek);
|
||||
bytesLeft = std::min(bytesLeft, 0x7FFFFFFFu);
|
||||
sint32 bytesToRead = std::min(bytesLeft, size);
|
||||
uint32 bytesRead = m_fs->readData(buffer, bytesToRead);
|
||||
m_seek += bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void FSCVirtualFile_AndroidSAF::fscSetSeek(uint64 seek)
|
||||
{
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return;
|
||||
this->m_seek = seek;
|
||||
cemu_assert_debug(seek <= m_fileSize);
|
||||
m_fs->SetPosition(seek);
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return;
|
||||
this->m_seek = seek;
|
||||
cemu_assert_debug(seek <= m_fileSize);
|
||||
m_fs->SetPosition(seek);
|
||||
}
|
||||
|
||||
uint64 FSCVirtualFile_AndroidSAF::fscGetSeek()
|
||||
{
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
return m_seek;
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return 0;
|
||||
return m_seek;
|
||||
}
|
||||
|
||||
void FSCVirtualFile_AndroidSAF::fscSetFileLength(uint64 endOffset)
|
||||
{
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return;
|
||||
m_fs->SetPosition(endOffset);
|
||||
bool r = m_fs->SetEndOfFile();
|
||||
m_seek = std::min(m_seek, endOffset);
|
||||
m_fileSize = m_seek;
|
||||
m_fs->SetPosition(m_seek);
|
||||
if (!r)
|
||||
cemuLog_log(LogType::Force, "fscSetFileLength: Failed to set size to 0x{:x}", endOffset);
|
||||
if (m_type != FSC_TYPE_FILE)
|
||||
return;
|
||||
m_fs->SetPosition(endOffset);
|
||||
bool r = m_fs->SetEndOfFile();
|
||||
m_seek = std::min(m_seek, endOffset);
|
||||
m_fileSize = m_seek;
|
||||
m_fs->SetPosition(m_seek);
|
||||
if (!r)
|
||||
cemuLog_log(LogType::Force, "fscSetFileLength: Failed to set size to 0x{:x}", endOffset);
|
||||
}
|
||||
|
||||
bool FSCVirtualFile_AndroidSAF::fscDirNext(FSCDirEntry* dirEntry)
|
||||
{
|
||||
if (m_type != FSC_TYPE_DIRECTORY)
|
||||
return false;
|
||||
if (m_type != FSC_TYPE_DIRECTORY)
|
||||
return false;
|
||||
|
||||
if (!m_files)
|
||||
{
|
||||
// init iterator on first iteration attempt
|
||||
m_files = std::make_unique<std::vector<fs::path>>(FilesystemAndroid::listFiles(*m_path));
|
||||
m_filesIterator = m_files->begin();
|
||||
if (!m_files)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to iterate directory: {}", _pathToUtf8(*m_path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_filesIterator == m_files->end())
|
||||
return false;
|
||||
if (!m_files)
|
||||
{
|
||||
// init iterator on first iteration attempt
|
||||
m_files = std::make_unique<std::vector<fs::path>>(FilesystemAndroid::ListFiles(*m_path));
|
||||
m_filesIterator = m_files->begin();
|
||||
if (!m_files)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to iterate directory: {}", _pathToUtf8(*m_path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_filesIterator == m_files->end())
|
||||
return false;
|
||||
|
||||
const fs::path& file = *m_filesIterator;
|
||||
const fs::path& file = *m_filesIterator;
|
||||
|
||||
std::string fileName = file.filename().generic_string();
|
||||
if (fileName.size() >= sizeof(dirEntry->path) - 1)
|
||||
fileName.resize(sizeof(dirEntry->path) - 1);
|
||||
strncpy(dirEntry->path, fileName.data(), sizeof(dirEntry->path));
|
||||
if (FilesystemAndroid::isDirectory(file))
|
||||
{
|
||||
dirEntry->isDirectory = true;
|
||||
dirEntry->isFile = false;
|
||||
dirEntry->fileSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirEntry->isDirectory = false;
|
||||
dirEntry->isFile = true;
|
||||
dirEntry->fileSize = 0;
|
||||
auto fs = FileStream::openFile2(file);
|
||||
if (fs)
|
||||
{
|
||||
dirEntry->fileSize = fs->GetSize();
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
m_filesIterator++;
|
||||
return true;
|
||||
std::string fileName = file.filename().generic_string();
|
||||
if (fileName.size() >= sizeof(dirEntry->path) - 1)
|
||||
fileName.resize(sizeof(dirEntry->path) - 1);
|
||||
strncpy(dirEntry->path, fileName.data(), sizeof(dirEntry->path));
|
||||
if (FilesystemAndroid::IsDirectory(file))
|
||||
{
|
||||
dirEntry->isDirectory = true;
|
||||
dirEntry->isFile = false;
|
||||
dirEntry->fileSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirEntry->isDirectory = false;
|
||||
dirEntry->isFile = true;
|
||||
dirEntry->fileSize = 0;
|
||||
auto fs = FileStream::openFile2(file);
|
||||
if (fs)
|
||||
{
|
||||
dirEntry->fileSize = fs->GetSize();
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
m_filesIterator++;
|
||||
return true;
|
||||
}
|
||||
|
||||
FSCVirtualFile* FSCVirtualFile_AndroidSAF::OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus)
|
||||
{
|
||||
if (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && !HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||
cemu_assert_debug(false); // not allowed. At least one of both flags must be set
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION) ||
|
||||
HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALLOW_CREATE) ||
|
||||
HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE))
|
||||
throw std::logic_error("writing and creating a file is not supported with SAF");
|
||||
// attempt to open as file
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))
|
||||
{
|
||||
FileStream* fs = FileStream::openFile2(path);
|
||||
if (fs)
|
||||
{
|
||||
FSCVirtualFile_AndroidSAF* vf = new FSCVirtualFile_AndroidSAF(FSC_TYPE_FILE);
|
||||
vf->m_fs = fs;
|
||||
vf->m_isWritable = false;
|
||||
vf->m_fileSize = fs->GetSize();
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
return vf;
|
||||
}
|
||||
}
|
||||
if (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && !HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||
cemu_assert_debug(false); // not allowed. At least one of both flags must be set
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION) ||
|
||||
HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALLOW_CREATE) ||
|
||||
HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE))
|
||||
throw std::logic_error("writing and creating a file is not supported with SAF");
|
||||
// attempt to open as file
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))
|
||||
{
|
||||
FileStream* fs = FileStream::openFile2(path);
|
||||
if (fs)
|
||||
{
|
||||
FSCVirtualFile_AndroidSAF* vf = new FSCVirtualFile_AndroidSAF(FSC_TYPE_FILE);
|
||||
vf->m_fs = fs;
|
||||
vf->m_isWritable = false;
|
||||
vf->m_fileSize = fs->GetSize();
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
return vf;
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to open as directory
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||
{
|
||||
bool isExistingDir = FilesystemAndroid::exists(path);
|
||||
if (isExistingDir)
|
||||
{
|
||||
FSCVirtualFile_AndroidSAF* vf = new FSCVirtualFile_AndroidSAF(FSC_TYPE_DIRECTORY);
|
||||
vf->m_path.reset(new std::filesystem::path(path));
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
return vf;
|
||||
}
|
||||
}
|
||||
fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
return nullptr;
|
||||
// attempt to open as directory
|
||||
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||
{
|
||||
bool isExistingDir = FilesystemAndroid::Exists(path);
|
||||
if (isExistingDir)
|
||||
{
|
||||
FSCVirtualFile_AndroidSAF* vf = new FSCVirtualFile_AndroidSAF(FSC_TYPE_DIRECTORY);
|
||||
vf->m_path.reset(new std::filesystem::path(path));
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
return vf;
|
||||
}
|
||||
}
|
||||
fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Device implementation */
|
||||
|
||||
class fscDeviceAndroidSAFFSC : public fscDeviceC
|
||||
{
|
||||
public:
|
||||
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
*fscStatus = FSC_STATUS_OK;
|
||||
FSCVirtualFile* vf = FSCVirtualFile_AndroidSAF::OpenFile(_utf8ToPath(path), accessFlags, *fscStatus);
|
||||
cemu_assert_debug((bool)vf == (*fscStatus == FSC_STATUS_OK));
|
||||
return vf;
|
||||
}
|
||||
public:
|
||||
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
*fscStatus = FSC_STATUS_OK;
|
||||
FSCVirtualFile* vf = FSCVirtualFile_AndroidSAF::OpenFile(_utf8ToPath(path), accessFlags, *fscStatus);
|
||||
cemu_assert_debug((bool)vf == (*fscStatus == FSC_STATUS_OK));
|
||||
return vf;
|
||||
}
|
||||
|
||||
bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::logic_error("creating a directory is not supported with SAF");
|
||||
bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::runtime_error("creating a directory is not supported with SAF");
|
||||
}
|
||||
|
||||
bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::runtime_error("removing a file or dir is not supported with SAF");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::logic_error("removing a file or dir is not supported with SAF");
|
||||
return false;
|
||||
}
|
||||
bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::runtime_error("renaming not supported with SAF");
|
||||
}
|
||||
|
||||
bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus) override
|
||||
{
|
||||
throw std::logic_error("renaming not supported with SAF");
|
||||
return false;
|
||||
}
|
||||
|
||||
// singleton
|
||||
public:
|
||||
static fscDeviceAndroidSAFFSC& instance()
|
||||
{
|
||||
static fscDeviceAndroidSAFFSC _instance;
|
||||
return _instance;
|
||||
}
|
||||
// singleton
|
||||
public:
|
||||
static fscDeviceAndroidSAFFSC& instance()
|
||||
{
|
||||
static fscDeviceAndroidSAFFSC _instance;
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
bool FSCDeviceAndroidSAF_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority)
|
||||
{
|
||||
return fsc_mount(mountPath, hostTargetPath, &fscDeviceAndroidSAFFSC::instance(), nullptr, priority) == FSC_STATUS_OK;
|
||||
return fsc_mount(mountPath, hostTargetPath, &fscDeviceAndroidSAFFSC::instance(), nullptr, priority) == FSC_STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,12 @@
|
||||
#include "pugixml.hpp"
|
||||
#include "Common/FileStream.h"
|
||||
|
||||
#if __ANDROID__
|
||||
#include "Common/unix/ContentUriStream.h"
|
||||
#endif // __ANDROID__
|
||||
|
||||
#include <zarchive/zarchivereader.h>
|
||||
#include "util/IniParser/IniParser.h"
|
||||
#include "util/crypto/crc32.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "util/helpers/ZArchiveHelpers.h"
|
||||
|
||||
// detect format by reading file header/footer
|
||||
CafeTitleFileType DetermineCafeSystemFileType(fs::path filePath)
|
||||
@@ -225,13 +222,8 @@ bool TitleInfo::DetectFormat(const fs::path& path, fs::path& pathOut, TitleDataF
|
||||
pathOut = path;
|
||||
// a Wii U archive file can contain multiple titles but TitleInfo only maps to one
|
||||
// we use the first base title that we find. This is the most intuitive behavior when someone launches "game.wua"
|
||||
ZArchiveReader* zar = nullptr;
|
||||
#if __ANDROID__
|
||||
if(FilesystemAndroid::isContentUri(path))
|
||||
zar = ZArchiveReader::OpenFromStream(std::make_unique<ContentUriStream>(path));
|
||||
else
|
||||
#endif // __ANDROID__
|
||||
zar = ZArchiveReader::OpenFromFile(path);
|
||||
ZArchiveReader* zar = ZArchiveHelpers::OpenReader(path);
|
||||
|
||||
if (!zar)
|
||||
return false;
|
||||
ZArchiveNodeHandle rootDir = zar->LookUp("", false, true);
|
||||
@@ -366,13 +358,8 @@ ZArchiveReader* _ZArchivePool_AcquireInstance(const fs::path& path)
|
||||
}
|
||||
_lock.unlock();
|
||||
// opening wua files can be expensive, so we do it outside of the lock
|
||||
ZArchiveReader* zar = nullptr;
|
||||
#if __ANDROID__
|
||||
if(FilesystemAndroid::isContentUri(path))
|
||||
zar = ZArchiveReader::OpenFromStream(std::make_unique<ContentUriStream>(path));
|
||||
else
|
||||
#endif // __ANDROID__
|
||||
zar = ZArchiveReader::OpenFromFile(path);
|
||||
ZArchiveReader* zar = ZArchiveHelpers::OpenReader(path);
|
||||
|
||||
if (!zar)
|
||||
return nullptr;
|
||||
_lock.lock();
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
#include "Common/FileStream.h"
|
||||
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "util/helpers/ZArchiveHelpers.h"
|
||||
|
||||
#if __ANDROID__
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
#include "Common/unix/ContentUriStream.h"
|
||||
#endif // __ANDROID__
|
||||
|
||||
#include <zarchive/zarchivereader.h>
|
||||
|
||||
@@ -221,13 +218,8 @@ void CafeTitleList::AddTitleFromPath(fs::path path)
|
||||
{
|
||||
if (path.has_extension() && boost::iequals(_pathToUtf8(path.extension()), ".wua"))
|
||||
{
|
||||
ZArchiveReader* zar = nullptr;
|
||||
#if __ANDROID__
|
||||
if(FilesystemAndroid::isContentUri(path))
|
||||
zar = ZArchiveReader::OpenFromStream(std::make_unique<ContentUriStream>(path));
|
||||
else
|
||||
#endif // __ANDROID__
|
||||
zar = ZArchiveReader::OpenFromFile(path);
|
||||
ZArchiveReader* zar = ZArchiveHelpers::OpenReader(path);
|
||||
|
||||
if (!zar)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Found {} but it is not a valid Wii U archive file", _pathToUtf8(path));
|
||||
@@ -374,23 +366,23 @@ void CafeTitleList::ScanGamePath(const fs::path& path)
|
||||
hasMetaFolder = true;
|
||||
};
|
||||
#if __ANDROID__
|
||||
if(FilesystemAndroid::isContentUri(path))
|
||||
if (FilesystemAndroid::IsContentUri(path))
|
||||
{
|
||||
for(auto&& file:FilesystemAndroid::listFiles(path))
|
||||
for (auto&& file : FilesystemAndroid::ListFiles(path))
|
||||
{
|
||||
if(FilesystemAndroid::isFile(file))
|
||||
{
|
||||
filesInDirectory.emplace_back(file);
|
||||
}
|
||||
else if(FilesystemAndroid::isDirectory(file))
|
||||
if (FilesystemAndroid::IsDirectory(file))
|
||||
{
|
||||
dirsInDirectory.emplace_back(file);
|
||||
|
||||
checkForTitleFolders(_pathToUtf8(file.filename()));
|
||||
}
|
||||
else
|
||||
{
|
||||
filesInDirectory.emplace_back(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
#endif // __ANDROID__
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
@@ -56,11 +56,11 @@ endif()
|
||||
|
||||
if(ANDROID)
|
||||
target_sources(CemuCommon PRIVATE
|
||||
unix/ContentUriStream.h
|
||||
unix/FilesystemAndroid.cpp
|
||||
unix/FilesystemAndroid.h
|
||||
unix/FileStream_contentUri.cpp
|
||||
unix/FileStream_contentUri.h
|
||||
android/FdStream.h
|
||||
android/FileStream_saf.cpp
|
||||
android/FileStream_saf.h
|
||||
android/FilesystemAndroid.cpp
|
||||
android/FilesystemAndroid.h
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
+87
-86
@@ -3,153 +3,154 @@
|
||||
#if BOOST_OS_UNIX
|
||||
|
||||
#if __ANDROID__
|
||||
#include "Common/unix/FileStream_contentUri.h"
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
#endif // __ANDROID__
|
||||
#include "Common/android/FileStream_saf.h"
|
||||
#include "Common/android/FilesystemAndroid.h"
|
||||
#endif // __ANDROID__
|
||||
|
||||
#include "Common/unix/FileStream_unix.h"
|
||||
|
||||
FileStream* FileStream::openFile(std::string_view path)
|
||||
{
|
||||
return openFile2(path, false);
|
||||
return openFile2(path, false);
|
||||
}
|
||||
|
||||
FileStream* FileStream::openFile(const wchar_t* path, bool allowWrite)
|
||||
{
|
||||
return openFile2(path, allowWrite);
|
||||
return openFile2(path, allowWrite);
|
||||
}
|
||||
|
||||
FileStream* FileStream::openFile2(const fs::path& path, bool allowWrite)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(path))
|
||||
{
|
||||
if (allowWrite || FilesystemAndroid::isDirectory(path))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FileStreamContentUri* fs = new FileStreamContentUri(path);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
FileStreamUnix* fs = new FileStreamUnix(path, true, allowWrite);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
if (FilesystemAndroid::IsContentUri(path))
|
||||
{
|
||||
if (allowWrite || FilesystemAndroid::IsDirectory(path))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto fs = new FileStreamSAF(path);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
|
||||
FileStreamUnix* fs = new FileStreamUnix(path, true, allowWrite);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile(const wchar_t* path)
|
||||
{
|
||||
return createFile2(path);
|
||||
return createFile2(path);
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile(std::string_view path)
|
||||
{
|
||||
return createFile2(path);
|
||||
return createFile2(path);
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile2(const fs::path& path)
|
||||
{
|
||||
FileStreamUnix* fs = new FileStreamUnix(path, false, false);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
FileStreamUnix* fs = new FileStreamUnix(path, false, false);
|
||||
if (fs->m_isValid)
|
||||
return fs;
|
||||
delete fs;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8>> FileStream::LoadIntoMemory(const fs::path& path)
|
||||
{
|
||||
FileStream* fs = openFile2(path);
|
||||
if (!fs)
|
||||
return std::nullopt;
|
||||
uint64 fileSize = fs->GetSize();
|
||||
if (fileSize > 0xFFFFFFFFull)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<std::vector<uint8>> v(fileSize);
|
||||
if (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
delete fs;
|
||||
return v;
|
||||
FileStream* fs = openFile2(path);
|
||||
if (!fs)
|
||||
return std::nullopt;
|
||||
uint64 fileSize = fs->GetSize();
|
||||
if (fileSize > 0xFFFFFFFFull)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<std::vector<uint8>> v(fileSize);
|
||||
if (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
delete fs;
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif // BOOST_OS_UNIX
|
||||
#endif // BOOST_OS_UNIX
|
||||
|
||||
#ifdef _WIN32
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
#include "Common/windows/FileStream_win32.h"
|
||||
|
||||
FileStream* FileStream::openFile(std::string_view path)
|
||||
{
|
||||
HANDLE hFile = CreateFileW(boost::nowide::widen(path.data(), path.size()).c_str(), FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
HANDLE hFile = CreateFileW(boost::nowide::widen(path.data(), path.size()).c_str(), FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
}
|
||||
|
||||
FileStream* FileStream::openFile(const wchar_t* path, bool allowWrite)
|
||||
{
|
||||
HANDLE hFile = CreateFileW(path, allowWrite ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE) : FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
HANDLE hFile = CreateFileW(path, allowWrite ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE) : FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
}
|
||||
|
||||
FileStream* FileStream::openFile2(const fs::path& path, bool allowWrite)
|
||||
{
|
||||
return openFile(path.generic_wstring().c_str(), allowWrite);
|
||||
return openFile(path.generic_wstring().c_str(), allowWrite);
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile(const wchar_t* path)
|
||||
{
|
||||
HANDLE hFile = CreateFileW(path, FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
HANDLE hFile = CreateFileW(path, FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile(std::string_view path)
|
||||
{
|
||||
auto w = boost::nowide::widen(path.data(), path.size());
|
||||
HANDLE hFile = CreateFileW(w.c_str(), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
auto w = boost::nowide::widen(path.data(), path.size());
|
||||
HANDLE hFile = CreateFileW(w.c_str(), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return nullptr;
|
||||
return new FileStreamWin32(hFile);
|
||||
}
|
||||
|
||||
FileStream* FileStream::createFile2(const fs::path& path)
|
||||
{
|
||||
return createFile(path.generic_wstring().c_str());
|
||||
return createFile(path.generic_wstring().c_str());
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8>> FileStream::LoadIntoMemory(const fs::path& path)
|
||||
{
|
||||
FileStream* fs = openFile2(path);
|
||||
if (!fs)
|
||||
return std::nullopt;
|
||||
uint64 fileSize = fs->GetSize();
|
||||
if (fileSize > 0xFFFFFFFFull)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<std::vector<uint8>> v(fileSize);
|
||||
if (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
delete fs;
|
||||
return v;
|
||||
FileStream* fs = openFile2(path);
|
||||
if (!fs)
|
||||
return std::nullopt;
|
||||
uint64 fileSize = fs->GetSize();
|
||||
if (fileSize > 0xFFFFFFFFull)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<std::vector<uint8>> v(fileSize);
|
||||
if (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)
|
||||
{
|
||||
delete fs;
|
||||
return std::nullopt;
|
||||
}
|
||||
delete fs;
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // BOOST_OS_WINDOWS
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
|
||||
class FdStream : private boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source>, public std::istream
|
||||
{
|
||||
public:
|
||||
explicit FdStream(int fd)
|
||||
: boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source>(fd, boost::iostreams::close_handle), std::istream(this) {}
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
return component()->is_open();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "FileStream_saf.h"
|
||||
#include "FilesystemAndroid.h"
|
||||
|
||||
void FileStreamSAF::SetPosition(uint64 pos)
|
||||
{
|
||||
if (!m_isValid)
|
||||
return;
|
||||
m_stream.seekg((std::streampos)pos);
|
||||
}
|
||||
|
||||
uint64 FileStreamSAF::GetSize()
|
||||
{
|
||||
cemu_assert(m_isValid);
|
||||
auto currentPos = m_stream.tellg();
|
||||
m_stream.seekg(0, std::ios::end);
|
||||
auto fileSize = m_stream.tellg();
|
||||
m_stream.seekg(currentPos, std::ios::beg);
|
||||
uint64 fs = (uint64)fileSize;
|
||||
return fs;
|
||||
}
|
||||
|
||||
bool FileStreamSAF::SetEndOfFile()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileStreamSAF::extract(std::vector<uint8>& data)
|
||||
{
|
||||
if (!m_isValid)
|
||||
return;
|
||||
uint64 fileSize = GetSize();
|
||||
SetPosition(0);
|
||||
data.resize(fileSize);
|
||||
readData(data.data(), fileSize);
|
||||
}
|
||||
|
||||
uint32 FileStreamSAF::readData(void* data, uint32 length)
|
||||
{
|
||||
m_stream.read((char*)data, length);
|
||||
size_t bytesRead = m_stream.gcount();
|
||||
return (uint32)bytesRead;
|
||||
}
|
||||
|
||||
bool FileStreamSAF::readU64(uint64& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint64)) == sizeof(uint64);
|
||||
}
|
||||
|
||||
bool FileStreamSAF::readU32(uint32& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint32)) == sizeof(uint32);
|
||||
}
|
||||
|
||||
bool FileStreamSAF::readU8(uint8& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint8)) == sizeof(uint8);
|
||||
}
|
||||
|
||||
bool FileStreamSAF::readLine(std::string& line)
|
||||
{
|
||||
line.clear();
|
||||
uint8 c;
|
||||
bool isEOF = true;
|
||||
while (readU8(c))
|
||||
{
|
||||
isEOF = false;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
if (c == '\n')
|
||||
break;
|
||||
line.push_back((char)c);
|
||||
}
|
||||
return !isEOF;
|
||||
}
|
||||
|
||||
sint32 FileStreamSAF::writeData(const void* data, sint32 length)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeU64(uint64 v)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeU32(uint32 v)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeU8(uint8 v)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeStringFmt(const char* format, ...)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeString(const char* str)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamSAF::writeLine(const char* str)
|
||||
{
|
||||
throw std::runtime_error("write operation not supported");
|
||||
}
|
||||
|
||||
FileStreamSAF::FileStreamSAF(const fs::path& uri) : m_stream(FilesystemAndroid::OpenContentUri(uri))
|
||||
{
|
||||
m_isValid = m_stream.IsValid();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/FileStream.h"
|
||||
|
||||
#include "FdStream.h"
|
||||
|
||||
class FileStreamSAF : public FileStream
|
||||
{
|
||||
public:
|
||||
// size and seek
|
||||
void SetPosition(uint64 pos) override;
|
||||
|
||||
uint64 GetSize() override;
|
||||
bool SetEndOfFile() override;
|
||||
void extract(std::vector<uint8>& data) override;
|
||||
|
||||
// reading
|
||||
uint32 readData(void* data, uint32 length) override;
|
||||
bool readU64(uint64& v) override;
|
||||
bool readU32(uint32& v) override;
|
||||
bool readU8(uint8& v) override;
|
||||
bool readLine(std::string& line) override;
|
||||
|
||||
// writing (not supported)
|
||||
sint32 writeData(const void* data, sint32 length) override;
|
||||
void writeU64(uint64 v) override;
|
||||
void writeU32(uint32 v) override;
|
||||
void writeU8(uint8 v) override;
|
||||
void writeStringFmt(const char* format, ...) override;
|
||||
void writeString(const char* str) override;
|
||||
void writeLine(const char* str) override;
|
||||
|
||||
private:
|
||||
friend class FileStream;
|
||||
FileStreamSAF(const fs::path& uri);
|
||||
FdStream m_stream;
|
||||
bool m_isValid = false;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "FilesystemAndroid.h"
|
||||
|
||||
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
|
||||
using namespace boost::iostreams;
|
||||
|
||||
namespace FilesystemAndroid
|
||||
{
|
||||
std::shared_ptr<FilesystemCallbacks> g_filesystemCallbacks = nullptr;
|
||||
|
||||
void SetFilesystemCallbacks(const std::shared_ptr<FilesystemCallbacks> &filesystemCallbacks)
|
||||
{
|
||||
g_filesystemCallbacks = filesystemCallbacks;
|
||||
}
|
||||
|
||||
int OpenContentUri(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->OpenContentUri(uri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<fs::path> ListFiles(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->ListFiles(uri);
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IsDirectory(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->IsDirectory(uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsFile(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->IsFile(uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Exists(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->Exists(uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsContentUri(const std::string &uri)
|
||||
{
|
||||
static constexpr auto content = "content://";
|
||||
return uri.starts_with(content);
|
||||
}
|
||||
|
||||
} // namespace FilesystemAndroid
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
namespace FilesystemAndroid
|
||||
{
|
||||
class FilesystemCallbacks
|
||||
{
|
||||
public:
|
||||
virtual int OpenContentUri(const fs::path &uri) = 0;
|
||||
virtual std::vector<fs::path> ListFiles(const fs::path &uri) = 0;
|
||||
virtual bool IsDirectory(const fs::path &uri) = 0;
|
||||
virtual bool IsFile(const fs::path &uri) = 0;
|
||||
virtual bool Exists(const fs::path &uri) = 0;
|
||||
};
|
||||
|
||||
void SetFilesystemCallbacks(const std::shared_ptr<FilesystemCallbacks> &filesystemCallbacks);
|
||||
|
||||
int OpenContentUri(const fs::path &uri);
|
||||
|
||||
std::vector<fs::path> ListFiles(const fs::path &uri);
|
||||
|
||||
bool IsDirectory(const fs::path &uri);
|
||||
|
||||
bool IsFile(const fs::path &uri);
|
||||
|
||||
bool Exists(const fs::path& uri);
|
||||
|
||||
bool IsContentUri(const std::string &uri);
|
||||
|
||||
} // namespace FilesystemAndroid
|
||||
+13
-13
@@ -85,7 +85,7 @@
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
#if __ANDROID__
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
#include "Common/android/FilesystemAndroid.h"
|
||||
#endif // __ANDROID
|
||||
|
||||
namespace cemu
|
||||
@@ -95,48 +95,48 @@ namespace fs
|
||||
inline bool is_directory(const std::filesystem::path& p)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::isDirectory(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::IsDirectory(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::is_directory(p);
|
||||
}
|
||||
inline bool is_directory(const std::filesystem::path& p, std::error_code& ec)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::isDirectory(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::IsDirectory(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::is_directory(p, ec);
|
||||
}
|
||||
inline bool is_file(const std::filesystem::path& p)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::isFile(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::IsFile(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::is_regular_file(p);
|
||||
}
|
||||
inline bool is_file(const std::filesystem::path& p, std::error_code& ec)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::isFile(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::IsFile(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::is_regular_file(p, ec);
|
||||
}
|
||||
inline bool exists(const std::filesystem::path& p)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::exists(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::Exists(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::exists(p);
|
||||
}
|
||||
inline bool exists(const std::filesystem::path& p, std::error_code& ec)
|
||||
{
|
||||
#if __ANDROID__
|
||||
if (FilesystemAndroid::isContentUri(p))
|
||||
return FilesystemAndroid::exists(p);
|
||||
if (FilesystemAndroid::IsContentUri(p))
|
||||
return FilesystemAndroid::Exists(p);
|
||||
#endif // __ANDROID__
|
||||
return std::filesystem::exists(p, ec);
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
|
||||
class ContentUriStream : public boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source>, public std::istream
|
||||
{
|
||||
public:
|
||||
explicit ContentUriStream(const std::filesystem::path& path)
|
||||
: boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source>(FilesystemAndroid::openContentUri(path), boost::iostreams::close_handle), std::istream(this) {}
|
||||
|
||||
bool is_open()
|
||||
{
|
||||
return component()->is_open();
|
||||
}
|
||||
};
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "FileStream_contentUri.h"
|
||||
|
||||
#include "unix/ContentUriStream.h"
|
||||
|
||||
void ThrowWriteNotSupportedError()
|
||||
{
|
||||
throw std::logic_error("write operation not supported");
|
||||
}
|
||||
|
||||
void FileStreamContentUri::SetPosition(uint64 pos)
|
||||
{
|
||||
if (!m_isValid)
|
||||
return;
|
||||
m_contentUriStream.seekg((std::streampos)pos);
|
||||
}
|
||||
|
||||
uint64 FileStreamContentUri::GetSize()
|
||||
{
|
||||
cemu_assert(m_isValid);
|
||||
auto currentPos = m_contentUriStream.tellg();
|
||||
m_contentUriStream.seekg(0, std::ios::end);
|
||||
auto fileSize = m_contentUriStream.tellg();
|
||||
m_contentUriStream.seekg(currentPos, std::ios::beg);
|
||||
uint64 fs = (uint64)fileSize;
|
||||
return fs;
|
||||
}
|
||||
|
||||
bool FileStreamContentUri::SetEndOfFile()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileStreamContentUri::extract(std::vector<uint8>& data)
|
||||
{
|
||||
if (!m_isValid)
|
||||
return;
|
||||
uint64 fileSize = GetSize();
|
||||
SetPosition(0);
|
||||
data.resize(fileSize);
|
||||
readData(data.data(), fileSize);
|
||||
}
|
||||
|
||||
uint32 FileStreamContentUri::readData(void* data, uint32 length)
|
||||
{
|
||||
m_contentUriStream.read((char*)data, length);
|
||||
size_t bytesRead = m_contentUriStream.gcount();
|
||||
return (uint32)bytesRead;
|
||||
}
|
||||
|
||||
bool FileStreamContentUri::readU64(uint64& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint64)) == sizeof(uint64);
|
||||
}
|
||||
|
||||
bool FileStreamContentUri::readU32(uint32& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint32)) == sizeof(uint32);
|
||||
}
|
||||
|
||||
bool FileStreamContentUri::readU8(uint8& v)
|
||||
{
|
||||
return readData(&v, sizeof(uint8)) == sizeof(uint8);
|
||||
}
|
||||
|
||||
bool FileStreamContentUri::readLine(std::string& line)
|
||||
{
|
||||
line.clear();
|
||||
uint8 c;
|
||||
bool isEOF = true;
|
||||
while (readU8(c))
|
||||
{
|
||||
isEOF = false;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
if (c == '\n')
|
||||
break;
|
||||
line.push_back((char)c);
|
||||
}
|
||||
return !isEOF;
|
||||
}
|
||||
|
||||
sint32 FileStreamContentUri::writeData(const void* data, sint32 length)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeU64(uint64 v)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeU32(uint32 v)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeU8(uint8 v)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeStringFmt(const char* format, ...)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeString(const char* str)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
void FileStreamContentUri::writeLine(const char* str)
|
||||
{
|
||||
ThrowWriteNotSupportedError();
|
||||
}
|
||||
|
||||
FileStreamContentUri::FileStreamContentUri(const std::string& uri)
|
||||
: m_contentUriStream(uri)
|
||||
{
|
||||
m_isValid = m_contentUriStream.is_open();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/FileStream.h"
|
||||
#include "Common/unix/ContentUriStream.h"
|
||||
|
||||
class FileStreamContentUri : public FileStream
|
||||
{
|
||||
public:
|
||||
// size and seek
|
||||
void SetPosition(uint64 pos) override;
|
||||
|
||||
uint64 GetSize() override;
|
||||
bool SetEndOfFile() override;
|
||||
void extract(std::vector<uint8>& data) override;
|
||||
|
||||
// reading
|
||||
uint32 readData(void* data, uint32 length) override;
|
||||
bool readU64(uint64& v) override;
|
||||
bool readU32(uint32& v) override;
|
||||
bool readU8(uint8& v) override;
|
||||
bool readLine(std::string& line) override;
|
||||
|
||||
// writing (not supported)
|
||||
sint32 writeData(const void* data, sint32 length) override;
|
||||
void writeU64(uint64 v) override;
|
||||
void writeU32(uint32 v) override;
|
||||
void writeU8(uint8 v) override;
|
||||
void writeStringFmt(const char* format, ...) override;
|
||||
void writeString(const char* str) override;
|
||||
void writeLine(const char* str) override;
|
||||
|
||||
private:
|
||||
friend class FileStream;
|
||||
FileStreamContentUri(const std::string& uri);
|
||||
ContentUriStream m_contentUriStream;
|
||||
bool m_isValid = false;
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "FilesystemAndroid.h"
|
||||
|
||||
namespace FilesystemAndroid
|
||||
{
|
||||
std::shared_ptr<FilesystemCallbacks> g_filesystemCallbacks = nullptr;
|
||||
|
||||
void setFilesystemCallbacks(const std::shared_ptr<FilesystemCallbacks> &filesystemCallbacks)
|
||||
{
|
||||
g_filesystemCallbacks = filesystemCallbacks;
|
||||
}
|
||||
|
||||
int openContentUri(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->openContentUri(uri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<fs::path> listFiles(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->listFiles(uri);
|
||||
return {};
|
||||
}
|
||||
bool isDirectory(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->isDirectory(uri);
|
||||
return false;
|
||||
}
|
||||
bool isFile(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->isFile(uri);
|
||||
return false;
|
||||
}
|
||||
bool exists(const fs::path &uri)
|
||||
{
|
||||
if (g_filesystemCallbacks)
|
||||
return g_filesystemCallbacks->exists(uri);
|
||||
return false;
|
||||
}
|
||||
bool isContentUri(const std::string &uri)
|
||||
{
|
||||
static constexpr auto content = "content://";
|
||||
return uri.starts_with(content);
|
||||
}
|
||||
} // namespace FilesystemAndroid
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace FilesystemAndroid
|
||||
{
|
||||
class FilesystemCallbacks
|
||||
{
|
||||
public:
|
||||
virtual int openContentUri(const std::filesystem::path &uri) = 0;
|
||||
virtual std::vector<std::filesystem::path> listFiles(const std::filesystem::path &uri) = 0;
|
||||
virtual bool isDirectory(const std::filesystem::path &uri) = 0;
|
||||
virtual bool isFile(const std::filesystem::path &uri) = 0;
|
||||
virtual bool exists(const std::filesystem::path &uri) = 0;
|
||||
};
|
||||
|
||||
void setFilesystemCallbacks(const std::shared_ptr<FilesystemCallbacks> &filesystemCallbacks);
|
||||
|
||||
int openContentUri(const std::filesystem::path &uri);
|
||||
|
||||
std::vector<std::filesystem::path> listFiles(const std::filesystem::path &uri);
|
||||
|
||||
bool isDirectory(const std::filesystem::path &uri);
|
||||
|
||||
bool isFile(const std::filesystem::path &uri);
|
||||
|
||||
bool exists(const std::filesystem::path& uri);
|
||||
|
||||
bool isContentUri(const std::string &uri);
|
||||
|
||||
} // namespace FilesystemAndroid
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "JNIUtils.h"
|
||||
#include "Common/unix/FilesystemAndroid.h"
|
||||
#include "Common/android/FilesystemAndroid.h"
|
||||
|
||||
class AndroidFilesystemCallbacks : public FilesystemAndroid::FilesystemCallbacks {
|
||||
jmethodID m_openContentUriMid;
|
||||
@@ -11,7 +11,7 @@ class AndroidFilesystemCallbacks : public FilesystemAndroid::FilesystemCallbacks
|
||||
jmethodID m_existsMid;
|
||||
JNIUtils::Scopedjclass m_fileUtilClass;
|
||||
|
||||
bool callBooleanFunction(const std::filesystem::path& uri, jmethodID methodId)
|
||||
bool CallBooleanFunction(const std::filesystem::path& uri, jmethodID methodId)
|
||||
{
|
||||
bool result = false;
|
||||
JNIUtils::fiberSafeJNICall([&](JNIEnv* env) {
|
||||
@@ -34,7 +34,7 @@ class AndroidFilesystemCallbacks : public FilesystemAndroid::FilesystemCallbacks
|
||||
m_existsMid = env->GetStaticMethodID(*m_fileUtilClass, "exists", "(Ljava/lang/String;)Z");
|
||||
}
|
||||
|
||||
int openContentUri(const std::filesystem::path& uri) override
|
||||
int OpenContentUri(const std::filesystem::path& uri) override
|
||||
{
|
||||
int fd = -1;
|
||||
JNIUtils::fiberSafeJNICall([&](JNIEnv* env) {
|
||||
@@ -45,7 +45,7 @@ class AndroidFilesystemCallbacks : public FilesystemAndroid::FilesystemCallbacks
|
||||
return fd;
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> listFiles(const std::filesystem::path& uri) override
|
||||
std::vector<std::filesystem::path> ListFiles(const std::filesystem::path& uri) override
|
||||
{
|
||||
std::vector<std::filesystem::path> paths;
|
||||
JNIUtils::fiberSafeJNICall([&](JNIEnv* env) {
|
||||
@@ -65,18 +65,18 @@ class AndroidFilesystemCallbacks : public FilesystemAndroid::FilesystemCallbacks
|
||||
return paths;
|
||||
}
|
||||
|
||||
bool isDirectory(const std::filesystem::path& uri) override
|
||||
bool IsDirectory(const std::filesystem::path& uri) override
|
||||
{
|
||||
return callBooleanFunction(uri, m_isDirectoryMid);
|
||||
return CallBooleanFunction(uri, m_isDirectoryMid);
|
||||
}
|
||||
|
||||
bool isFile(const std::filesystem::path& uri) override
|
||||
bool IsFile(const std::filesystem::path& uri) override
|
||||
{
|
||||
return callBooleanFunction(uri, m_isFileMid);
|
||||
return CallBooleanFunction(uri, m_isFileMid);
|
||||
}
|
||||
|
||||
bool exists(const std::filesystem::path& uri) override
|
||||
bool Exists(const std::filesystem::path& uri) override
|
||||
{
|
||||
return callBooleanFunction(uri, m_existsMid);
|
||||
return CallBooleanFunction(uri, m_existsMid);
|
||||
}
|
||||
};
|
||||
@@ -161,7 +161,7 @@ Java_info_cemu_cemu_nativeinterface_NativeEmulation_setReplaceTVWithPadView([[ma
|
||||
extern "C" [[maybe_unused]] JNIEXPORT void JNICALL
|
||||
Java_info_cemu_cemu_nativeinterface_NativeEmulation_initializeEmulation([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz)
|
||||
{
|
||||
FilesystemAndroid::setFilesystemCallbacks(std::make_shared<AndroidFilesystemCallbacks>());
|
||||
FilesystemAndroid::SetFilesystemCallbacks(std::make_shared<AndroidFilesystemCallbacks>());
|
||||
GetConfigHandle().SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
|
||||
NativeEmulation::createCemuDirectories();
|
||||
NetworkConfig::LoadOnce();
|
||||
|
||||
@@ -37,6 +37,7 @@ add_library(CemuUtil
|
||||
helpers/StringParser.h
|
||||
helpers/SystemException.h
|
||||
helpers/TempState.h
|
||||
helpers/ZArchiveHelpers.h
|
||||
highresolutiontimer/HighResolutionTimer.cpp
|
||||
highresolutiontimer/HighResolutionTimer.h
|
||||
ImageWriter/bmp.h
|
||||
@@ -99,6 +100,7 @@ endif()
|
||||
target_link_libraries(CemuUtil PRIVATE
|
||||
CemuCommon
|
||||
CemuConfig
|
||||
ZArchive::zarchive
|
||||
Boost::headers
|
||||
Boost::nowide
|
||||
OpenSSL::Crypto
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user