From b8903f21e80847f0176c964718bb78500fd0d40b Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Fri, 29 Aug 2025 20:28:55 +0300 Subject: [PATCH] Update SAF handling --- src/Cafe/Filesystem/fsc.h | 3 +- src/Cafe/Filesystem/fscDeviceAndroidSAF.cpp | 330 +++++++++--------- src/Cafe/TitleList/TitleInfo.cpp | 23 +- src/Cafe/TitleList/TitleList.cpp | 30 +- src/Common/CMakeLists.txt | 10 +- src/Common/FileStream.cpp | 173 ++++----- src/Common/android/FdStream.h | 16 + src/Common/android/FileStream_saf.cpp | 114 ++++++ src/Common/android/FileStream_saf.h | 38 ++ src/Common/android/FilesystemAndroid.cpp | 58 +++ src/Common/android/FilesystemAndroid.h | 29 ++ src/Common/precompiled.h | 26 +- src/Common/unix/ContentUriStream.h | 18 - src/Common/unix/FileStream_contentUri.cpp | 122 ------- src/Common/unix/FileStream_contentUri.h | 37 -- src/Common/unix/FilesystemAndroid.cpp | 48 --- src/Common/unix/FilesystemAndroid.h | 29 -- .../src/main/cpp/AndroidFilesystemCallbacks.h | 20 +- .../app/src/main/cpp/NativeEmulation.cpp | 2 +- src/util/CMakeLists.txt | 2 + src/util/helpers/ZArchiveHelpers.h | 28 ++ 21 files changed, 582 insertions(+), 574 deletions(-) create mode 100644 src/Common/android/FdStream.h create mode 100644 src/Common/android/FileStream_saf.cpp create mode 100644 src/Common/android/FileStream_saf.h create mode 100644 src/Common/android/FilesystemAndroid.cpp create mode 100644 src/Common/android/FilesystemAndroid.h delete mode 100644 src/Common/unix/ContentUriStream.h delete mode 100644 src/Common/unix/FileStream_contentUri.cpp delete mode 100644 src/Common/unix/FileStream_contentUri.h delete mode 100644 src/Common/unix/FilesystemAndroid.cpp delete mode 100644 src/Common/unix/FilesystemAndroid.h create mode 100644 src/util/helpers/ZArchiveHelpers.h diff --git a/src/Cafe/Filesystem/fsc.h b/src/Cafe/Filesystem/fsc.h index 5c272d86..feb6fa73 100644 --- a/src/Cafe/Filesystem/fsc.h +++ b/src/Cafe/Filesystem/fsc.h @@ -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__ diff --git a/src/Cafe/Filesystem/fscDeviceAndroidSAF.cpp b/src/Cafe/Filesystem/fscDeviceAndroidSAF.cpp index b063dd3b..11f2a97e 100644 --- a/src/Cafe/Filesystem/fscDeviceAndroidSAF.cpp +++ b/src/Cafe/Filesystem/fscDeviceAndroidSAF.cpp @@ -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>(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>(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; } diff --git a/src/Cafe/TitleList/TitleInfo.cpp b/src/Cafe/TitleList/TitleInfo.cpp index c3e1db05..528b5f63 100644 --- a/src/Cafe/TitleList/TitleInfo.cpp +++ b/src/Cafe/TitleList/TitleInfo.cpp @@ -5,15 +5,12 @@ #include "pugixml.hpp" #include "Common/FileStream.h" -#if __ANDROID__ -#include "Common/unix/ContentUriStream.h" -#endif // __ANDROID__ - #include #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(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(path)); - else -#endif // __ANDROID__ - zar = ZArchiveReader::OpenFromFile(path); + ZArchiveReader* zar = ZArchiveHelpers::OpenReader(path); + if (!zar) return nullptr; _lock.lock(); diff --git a/src/Cafe/TitleList/TitleList.cpp b/src/Cafe/TitleList/TitleList.cpp index e4da9db1..4bd259bc 100644 --- a/src/Cafe/TitleList/TitleList.cpp +++ b/src/Cafe/TitleList/TitleList.cpp @@ -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 @@ -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(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; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index 6cf8d9f4..b58a03bf 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -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() diff --git a/src/Common/FileStream.cpp b/src/Common/FileStream.cpp index b227b10b..b03a5743 100644 --- a/src/Common/FileStream.cpp +++ b/src/Common/FileStream.cpp @@ -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> 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> 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> 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> 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> 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> v(fileSize); + if (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize) + { + delete fs; + return std::nullopt; + } + delete fs; + return v; } -#endif // _WIN32 \ No newline at end of file +#endif // BOOST_OS_WINDOWS \ No newline at end of file diff --git a/src/Common/android/FdStream.h b/src/Common/android/FdStream.h new file mode 100644 index 00000000..7f4b69ce --- /dev/null +++ b/src/Common/android/FdStream.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +class FdStream : private boost::iostreams::stream_buffer, public std::istream +{ + public: + explicit FdStream(int fd) + : boost::iostreams::stream_buffer(fd, boost::iostreams::close_handle), std::istream(this) {} + + bool IsValid() + { + return component()->is_open(); + } +}; diff --git a/src/Common/android/FileStream_saf.cpp b/src/Common/android/FileStream_saf.cpp new file mode 100644 index 00000000..6dfea219 --- /dev/null +++ b/src/Common/android/FileStream_saf.cpp @@ -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& 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(); +} diff --git a/src/Common/android/FileStream_saf.h b/src/Common/android/FileStream_saf.h new file mode 100644 index 00000000..18345c99 --- /dev/null +++ b/src/Common/android/FileStream_saf.h @@ -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& 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; +}; diff --git a/src/Common/android/FilesystemAndroid.cpp b/src/Common/android/FilesystemAndroid.cpp new file mode 100644 index 00000000..dd150fad --- /dev/null +++ b/src/Common/android/FilesystemAndroid.cpp @@ -0,0 +1,58 @@ +#include "FilesystemAndroid.h" + +#include +#include + +using namespace boost::iostreams; + +namespace FilesystemAndroid +{ +std::shared_ptr g_filesystemCallbacks = nullptr; + +void SetFilesystemCallbacks(const std::shared_ptr &filesystemCallbacks) +{ + g_filesystemCallbacks = filesystemCallbacks; +} + +int OpenContentUri(const fs::path &uri) +{ + if (g_filesystemCallbacks) + return g_filesystemCallbacks->OpenContentUri(uri); + return -1; +} + +std::vector 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 \ No newline at end of file diff --git a/src/Common/android/FilesystemAndroid.h b/src/Common/android/FilesystemAndroid.h new file mode 100644 index 00000000..e9f4bd43 --- /dev/null +++ b/src/Common/android/FilesystemAndroid.h @@ -0,0 +1,29 @@ +#pragma once + +namespace FilesystemAndroid +{ +class FilesystemCallbacks +{ + public: + virtual int OpenContentUri(const fs::path &uri) = 0; + virtual std::vector 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); + +int OpenContentUri(const fs::path &uri); + +std::vector 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 diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index c00a866a..5e795fa8 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -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); } diff --git a/src/Common/unix/ContentUriStream.h b/src/Common/unix/ContentUriStream.h deleted file mode 100644 index 1ee648f1..00000000 --- a/src/Common/unix/ContentUriStream.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include - -#include "Common/unix/FilesystemAndroid.h" - -class ContentUriStream : public boost::iostreams::stream_buffer, public std::istream -{ - public: - explicit ContentUriStream(const std::filesystem::path& path) - : boost::iostreams::stream_buffer(FilesystemAndroid::openContentUri(path), boost::iostreams::close_handle), std::istream(this) {} - - bool is_open() - { - return component()->is_open(); - } -}; \ No newline at end of file diff --git a/src/Common/unix/FileStream_contentUri.cpp b/src/Common/unix/FileStream_contentUri.cpp deleted file mode 100644 index e4448710..00000000 --- a/src/Common/unix/FileStream_contentUri.cpp +++ /dev/null @@ -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& 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(); -} diff --git a/src/Common/unix/FileStream_contentUri.h b/src/Common/unix/FileStream_contentUri.h deleted file mode 100644 index 5dbad151..00000000 --- a/src/Common/unix/FileStream_contentUri.h +++ /dev/null @@ -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& 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; -}; diff --git a/src/Common/unix/FilesystemAndroid.cpp b/src/Common/unix/FilesystemAndroid.cpp deleted file mode 100644 index f072d4c0..00000000 --- a/src/Common/unix/FilesystemAndroid.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "FilesystemAndroid.h" - -namespace FilesystemAndroid -{ -std::shared_ptr g_filesystemCallbacks = nullptr; - -void setFilesystemCallbacks(const std::shared_ptr &filesystemCallbacks) -{ - g_filesystemCallbacks = filesystemCallbacks; -} - -int openContentUri(const fs::path &uri) -{ - if (g_filesystemCallbacks) - return g_filesystemCallbacks->openContentUri(uri); - return -1; -} - -std::vector 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 \ No newline at end of file diff --git a/src/Common/unix/FilesystemAndroid.h b/src/Common/unix/FilesystemAndroid.h deleted file mode 100644 index b67c5be0..00000000 --- a/src/Common/unix/FilesystemAndroid.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -namespace FilesystemAndroid -{ -class FilesystemCallbacks -{ - public: - virtual int openContentUri(const std::filesystem::path &uri) = 0; - virtual std::vector 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); - -int openContentUri(const std::filesystem::path &uri); - -std::vector 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 diff --git a/src/android/app/src/main/cpp/AndroidFilesystemCallbacks.h b/src/android/app/src/main/cpp/AndroidFilesystemCallbacks.h index a54a8561..5ef29109 100644 --- a/src/android/app/src/main/cpp/AndroidFilesystemCallbacks.h +++ b/src/android/app/src/main/cpp/AndroidFilesystemCallbacks.h @@ -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 listFiles(const std::filesystem::path& uri) override + std::vector ListFiles(const std::filesystem::path& uri) override { std::vector 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); } }; \ No newline at end of file diff --git a/src/android/app/src/main/cpp/NativeEmulation.cpp b/src/android/app/src/main/cpp/NativeEmulation.cpp index 5c9c7a91..db83f94a 100644 --- a/src/android/app/src/main/cpp/NativeEmulation.cpp +++ b/src/android/app/src/main/cpp/NativeEmulation.cpp @@ -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()); + FilesystemAndroid::SetFilesystemCallbacks(std::make_shared()); GetConfigHandle().SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring()); NativeEmulation::createCemuDirectories(); NetworkConfig::LoadOnce(); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 8a31fff4..1bf7a8d3 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -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 diff --git a/src/util/helpers/ZArchiveHelpers.h b/src/util/helpers/ZArchiveHelpers.h new file mode 100644 index 00000000..b8b70f13 --- /dev/null +++ b/src/util/helpers/ZArchiveHelpers.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#if __ANDROID__ +#include "Common/android/FilesystemAndroid.h" +#include "Common/android/FdStream.h" +#endif // __ANDROID__ + +namespace ZArchiveHelpers +{ + inline ZArchiveReader* OpenReader(const fs::path& path) + { +#if __ANDROID__ + if (FilesystemAndroid::IsContentUri(path)) + { + int fd = FilesystemAndroid::OpenContentUri(path); + + if (fd == -1) + return nullptr; + + return ZArchiveReader::OpenFromStream(std::make_unique(fd)); + } +#endif // __ANDROID__ + + return ZArchiveReader::OpenFromFile(path); + } +} // namespace ZArchiveHelpers