MushMachine/framework/filesystem/src/mm/fs_const_archiver.cpp

250 lines
5.5 KiB
C++

#include "./fs_const_archiver.hpp"
#include <cstring>
#include <mm/logger.hpp>
#define LOG_CRIT(...) __LOG_CRIT( "Filesystem", __VA_ARGS__)
#define LOG_ERROR(...) __LOG_ERROR("Filesystem", __VA_ARGS__)
#define LOG_WARN(...) __LOG_WARN( "Filesystem", __VA_ARGS__)
#define LOG_INFO(...) __LOG_INFO( "Filesystem", __VA_ARGS__)
#define LOG_DEBUG(...) __LOG_DEBUG("Filesystem", __VA_ARGS__)
#define LOG_TRACE(...) __LOG_TRACE("Filesystem", __VA_ARGS__)
namespace MM {
std::unordered_map<std::string, std::pair<uint8_t*, size_t>> FSConstArchiver::_storage {};
void* FSConstArchiver::PH_openArchive(PHYSFS_Io* io, const char* name, int forWrite, int* claimed) {
(void)io;
(void)name;
// TODO: test name
if (forWrite) {
//PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
*claimed = 0;
return nullptr;
}
*claimed = 1;
return (void*)1; // non zero
}
PHYSFS_EnumerateCallbackResult FSConstArchiver::PH_enumerate(void* opaque, const char* dirname, PHYSFS_EnumerateCallback cb, const char* origdir, void* callbackdata) {
(void)opaque;
(void)dirname;
(void)cb;
(void)origdir;
(void)callbackdata;
// "files" just not enumeratable
//return PHYSFS_ENUM_STOP;
return PHYSFS_ENUM_OK;
}
PHYSFS_Io* FSConstArchiver::PH_openRead(void* opaque, const char* fnm) {
(void)opaque;
if (!_storage.count(fnm)) {
PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
return nullptr;
}
return createIO(fnm);
}
PHYSFS_Io* FSConstArchiver::PH_openWrite(void* opaque, const char* filename) {
(void)opaque;
(void)filename;
return nullptr;
}
PHYSFS_Io* FSConstArchiver::PH_openAppend(void* opaque, const char* filename) {
(void)opaque;
(void)filename;
return nullptr;
}
int FSConstArchiver::PH_remove(void* opaque, const char* filename) {
(void)opaque;
(void)filename;
// TODO: support this?
PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
return 0;
}
int FSConstArchiver::PH_mkdir(void* opaque, const char* filename) {
(void)opaque;
(void)filename;
PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
return 0;
}
int FSConstArchiver::PH_stat(void* opaque, const char* fn, PHYSFS_Stat* stat) {
(void)opaque;
if (pathIsDir(fn)) {
stat->filesize = 0;
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
} else if (_storage.count(fn)) {
stat->filesize = _storage[fn].second;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
} else {
return 0;
}
stat->accesstime = -1;
stat->createtime = -1;
stat->modtime = -1;
stat->readonly = 1;
return 1;
}
void FSConstArchiver::PH_closeArchive(void* opaque) {
(void)opaque;
}
PHYSFS_Io* FSConstArchiver::createIO(const char* filename, PHYSFS_uint64 pos) {
if (!_storage.count(filename)) {
//LOGCA(std::string("error: path '") + filename + "' alredy used!");
LOG_ERROR("path '{}' already used!", filename);
return nullptr;
}
//LOGCA(std::string("###creating io for ") + filename);
LOG_TRACE("creating io for {}", filename);
struct io_internal {
std::string filename;
PHYSFS_uint64 pos = 0;
uint8_t* data = nullptr;
size_t data_size = 0;
};
auto new_io = new PHYSFS_Io;
new_io->version = 0;
new_io->write = nullptr;
new_io->flush = nullptr;
new_io->opaque = new io_internal{
filename,
pos,
_storage[filename].first,
_storage[filename].second
};
new_io->destroy = [](PHYSFS_Io* io) {
delete (io_internal*)io->opaque;
delete io;
};
new_io->tell = [](PHYSFS_Io* io) -> PHYSFS_sint64 { return ((io_internal*)io->opaque)->pos; };
new_io->seek = [](PHYSFS_Io* io, PHYSFS_uint64 offset) -> int {
auto* inter = (io_internal*)io->opaque;
if (offset > inter->data_size)
return 0; // error, past end
inter->pos = offset;
return 1;
};
new_io->length = [](PHYSFS_Io* io) -> PHYSFS_sint64 { return ((io_internal*)io->opaque)->data_size; };
new_io->duplicate = [](PHYSFS_Io* io) -> PHYSFS_Io* {
if (!io)
return nullptr;
auto* inter = (io_internal*)io->opaque;
auto* dup = createIO(inter->filename.c_str(), inter->pos);
return dup;
};
new_io->read = [](PHYSFS_Io* io, void* buf, PHYSFS_uint64 len) -> PHYSFS_sint64 {
if (!io)
return -1;
auto* inter = (io_internal*)io->opaque;
if (inter->data_size == inter->pos)
return 0; // EOF
PHYSFS_sint64 bytes_to_read = 0;
if (inter->pos + len >= inter->data_size) {
bytes_to_read = inter->data_size - inter->pos; // remaining data
} else {
bytes_to_read = len;
}
memcpy(buf, inter->data + inter->pos, bytes_to_read);
inter->pos += bytes_to_read;
return bytes_to_read;
};
return new_io;
}
bool FSConstArchiver::pathIsDir(const char* path) {
// TODO: fix leading '/'
std::string_view pstr {path};
//for (auto&[str, data] : _storage) {
for (auto& it : _storage) {
// stats_with c++20 <.<
if (it.first.compare(0, pstr.size(), pstr) == 0 && it.first.size() != pstr.size()) {
return true;
}
}
return false;
}
const PHYSFS_Archiver* FSConstArchiver::getArchiverStruct(void) {
static const PHYSFS_Archiver a {
0, // version
{ // info
"MEM", // ext
"in const memory 'archiver'", // desc
"Green", // author
"", // url
0 // sym
},
&PH_openArchive,
&PH_enumerate,
&PH_openRead,
&PH_openWrite,
&PH_openAppend,
&PH_remove,
&PH_mkdir,
&PH_stat,
&PH_closeArchive
};
return &a;
}
void FSConstArchiver::addFile(const char* path, uint8_t* data, size_t data_size) {
if (!path)
return;
// remove leading / es
while (path[0] == '/') {
path++;
if (path[0] == '\0')
return;
}
if (_storage.count(path)) {
//LOGCA(std::string("error: '") + path + "' already in path");
LOG_TRACE("'{}' already in path, overriding...", path);
}
_storage[path] = {data, data_size};
}
} // MM