mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-07 17:11:09 -10:00
* Use custom file IO callbacks for libraries: libzip, 7zip, libchdr, and stb_image. * Add file IO indirection. * Add libretro VFS implementation. --------- Co-authored-by: Clownacy <[email protected]>
194 lines
5.0 KiB
C++
194 lines
5.0 KiB
C++
/*
|
|
This file is part of Flycast.
|
|
|
|
Flycast is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Flycast is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "storage.h"
|
|
|
|
#include <file/file_path.h>
|
|
|
|
struct retro_vfs_interface* hostfs::LibretroStorage::vfs_interface = nullptr;
|
|
|
|
bool hostfs::LibretroStorage::isFileWriteable(const std::string& path)
|
|
{
|
|
// Not ideal; would be nicer if the VFS API gave us a direct way of checking this.
|
|
RFILE* file = filestream_open(path.c_str(), RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING, RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
|
|
|
if (file == nullptr)
|
|
return false;
|
|
|
|
filestream_close(file);
|
|
return true;
|
|
}
|
|
|
|
hostfs::FileInfo hostfs::LibretroStorage::makeFileInfo(std::string name, std::string path)
|
|
{
|
|
const bool is_directory = path_is_directory(path.c_str());
|
|
const size_t size = path_get_size(path.c_str());
|
|
const bool is_writeable = isFileWriteable(path);
|
|
|
|
return {std::move(name), std::move(path), is_directory, size, is_writeable};
|
|
}
|
|
|
|
void hostfs::LibretroStorage::initialise(retro_environment_t environ_cb)
|
|
{
|
|
retro_vfs_interface_info vfs_interface_info;
|
|
vfs_interface_info.required_interface_version = 3; // We really want those directory functions.
|
|
|
|
if (!environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_interface_info))
|
|
return;
|
|
|
|
vfs_interface = vfs_interface_info.iface;
|
|
|
|
filestream_vfs_init(&vfs_interface_info);
|
|
path_vfs_init(&vfs_interface_info);
|
|
}
|
|
|
|
bool hostfs::LibretroStorage::isKnownPath(const std::string& path)
|
|
{
|
|
return filestream_exists(path.c_str());
|
|
}
|
|
|
|
std::vector<hostfs::FileInfo> hostfs::LibretroStorage::listContent(const std::string& path)
|
|
{
|
|
std::vector<FileInfo> list;
|
|
|
|
struct retro_vfs_dir_handle* dir = vfs_interface->opendir(path.c_str(), true);
|
|
|
|
if (dir == nullptr)
|
|
return list;
|
|
|
|
while (vfs_interface->readdir(dir))
|
|
{
|
|
const auto entry_name = vfs_interface->dirent_get_name(dir);
|
|
const auto entry_path = path + PATH_DEFAULT_SLASH_C() + entry_name;
|
|
|
|
list.emplace_back(makeFileInfo(entry_name, entry_path));
|
|
}
|
|
|
|
vfs_interface->closedir(dir);
|
|
|
|
return list;
|
|
}
|
|
|
|
hostfs::File *hostfs::LibretroStorage::openFile(const std::string& path, const std::string& mode)
|
|
{
|
|
bool extended = false;
|
|
bool append = false;
|
|
unsigned int mode_bitfield = 0;
|
|
|
|
for (char character : mode)
|
|
{
|
|
switch (character)
|
|
{
|
|
case 'R':
|
|
case 'r':
|
|
if (mode_bitfield != 0)
|
|
return nullptr;
|
|
|
|
mode_bitfield = RETRO_VFS_FILE_ACCESS_READ;
|
|
break;
|
|
|
|
case 'W':
|
|
case 'w':
|
|
if (mode_bitfield != 0)
|
|
return nullptr;
|
|
|
|
mode_bitfield = RETRO_VFS_FILE_ACCESS_WRITE;
|
|
break;
|
|
|
|
case 'A':
|
|
case 'a':
|
|
if (mode_bitfield != 0)
|
|
return nullptr;
|
|
|
|
mode_bitfield = RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
|
|
append = true;
|
|
break;
|
|
|
|
case '+':
|
|
extended = true;
|
|
break;
|
|
|
|
case 'B':
|
|
case 'b':
|
|
case 'T':
|
|
case 't':
|
|
// Binary mode unfortunately just gets assumed by default...
|
|
// TODO: Do any of Flycast's text parsers require text mode?
|
|
break;
|
|
|
|
default:
|
|
// Unrecognised character.
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (mode_bitfield == 0)
|
|
return nullptr;
|
|
|
|
if (extended)
|
|
mode_bitfield = RETRO_VFS_FILE_ACCESS_READ_WRITE;
|
|
|
|
RFILE *rfile = filestream_open(path.c_str(), mode_bitfield, RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
|
|
|
if (rfile == nullptr)
|
|
return nullptr;
|
|
|
|
auto file = new LibretroFile(rfile);
|
|
|
|
if (append)
|
|
file->seek(0, SEEK_END);
|
|
|
|
return file;
|
|
}
|
|
|
|
std::string hostfs::LibretroStorage::getParentPath(const std::string& path)
|
|
{
|
|
std::string parent_path = path;
|
|
|
|
parent_path.resize(path_parent_dir(parent_path.data(), parent_path.size()));
|
|
|
|
return parent_path;
|
|
}
|
|
|
|
std::string hostfs::LibretroStorage::getSubPath(const std::string& reference, const std::string& relative)
|
|
{
|
|
return reference + PATH_DEFAULT_SLASH_C() + relative;
|
|
}
|
|
|
|
hostfs::FileInfo hostfs::LibretroStorage::getFileInfo(const std::string& path)
|
|
{
|
|
return makeFileInfo(path_basename(path.c_str()), path);
|
|
}
|
|
|
|
bool hostfs::LibretroStorage::exists(const std::string& path)
|
|
{
|
|
return filestream_exists(path.c_str());
|
|
}
|
|
|
|
bool hostfs::LibretroStorage::addStorage(bool isDirectory, bool writeAccess, const std::string& description,
|
|
void (*callback)(bool cancelled, std::string selectedPath), const std::string& mimeType)
|
|
{
|
|
// TODO: Should this do anything?
|
|
return false;
|
|
}
|
|
|
|
hostfs::CustomStorage& hostfs::customStorage()
|
|
{
|
|
static LibretroStorage storage;
|
|
|
|
return storage;
|
|
}
|