mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-09-30 18:58:08 +03:00
521 lines
14 KiB
C++
521 lines
14 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include <thread>
|
|
#include "../KKdLib/io/file_stream.hpp"
|
|
#include "../KKdLib/hash.hpp"
|
|
#include "file_handler.hpp"
|
|
#include "data.hpp"
|
|
#include <sys/stat.h>
|
|
|
|
struct farc_read_handler {
|
|
std::string file_path;
|
|
bool cache;
|
|
farc* farc;
|
|
|
|
farc_read_handler();
|
|
~farc_read_handler();
|
|
|
|
size_t get_file_size(std::string& file);
|
|
bool read(std::string& file_path, bool cache);
|
|
bool read_data(void* data, size_t size, std::string& file);
|
|
};
|
|
|
|
struct file_handler_storage {
|
|
std::list<file_handler*> list;
|
|
farc_read_handler* farc_read_handler;
|
|
std::deque<file_handler*> deque;
|
|
std::mutex farc_mtx;
|
|
std::thread* thread;
|
|
std::mutex mtx;
|
|
std::condition_variable cnd;
|
|
bool exit;
|
|
bool field_61;
|
|
int32_t field_64;
|
|
bool read_in_thread;
|
|
bool field_69;
|
|
int32_t field_6C;
|
|
int32_t field_70;
|
|
int32_t field_74;
|
|
|
|
file_handler_storage();
|
|
~file_handler_storage();
|
|
};
|
|
|
|
file_handler_storage* file_handler_storage_data;
|
|
|
|
static bool file_handler_load_file(void* data, const char* dir, const char* file, uint32_t hash);
|
|
static bool file_handler_load_farc_file(void* data, const char* dir, const char* file, uint32_t hash);
|
|
static void file_handler_storage_ctrl_list();
|
|
static void file_handler_storage_thread_ctrl();
|
|
|
|
file_handler::file_handler() : count(), not_ready(true),
|
|
reading(), cache(), callback(), size(), data(), ds() {
|
|
|
|
}
|
|
|
|
file_handler::~file_handler() {
|
|
if (data) {
|
|
free(data);
|
|
data = 0;
|
|
}
|
|
}
|
|
|
|
void file_handler::call_callback(int32_t index) {
|
|
if (index >= 2)
|
|
return;
|
|
|
|
const void* data = 0;
|
|
size_t size = 0;
|
|
void(*callback_func)(void*, const void*, size_t) = 0;
|
|
void* callback_data = 0;
|
|
bool ready = false;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
data = this->data;
|
|
size = this->size;
|
|
callback_func = this->callback[index].func;
|
|
callback_data = this->callback[index].data;
|
|
ready = this->callback[index].ready;
|
|
this->callback[index].ready = true;
|
|
}
|
|
|
|
if (!ready && callback_func)
|
|
callback_func(callback_data, data, size);
|
|
}
|
|
|
|
void file_handler::set_file(const char* file) {
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
this->file.assign(file);
|
|
}
|
|
|
|
void file_handler::set_farc_file(const char* farc_file, bool cache) {
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
this->farc_file.assign(farc_file);
|
|
this->cache = cache;
|
|
}
|
|
|
|
void file_handler::set_dir(const char* dir) {
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
this->dir.assign(dir);
|
|
}
|
|
|
|
void file_handler::set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func, void* data) {
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
if (index < 2) {
|
|
callback[index].func = func;
|
|
callback[index].data = data;
|
|
callback[index].ready = false;
|
|
}
|
|
}
|
|
|
|
void file_handler::free_data_lock() {
|
|
bool free_fhndl = false;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(mtx);
|
|
if (count <= 0)
|
|
return;
|
|
|
|
free_fhndl = --count == 0;
|
|
}
|
|
|
|
if (free_fhndl)
|
|
delete this;
|
|
}
|
|
|
|
farc_read_handler::farc_read_handler() : cache(), farc() {
|
|
|
|
}
|
|
|
|
farc_read_handler::~farc_read_handler() {
|
|
delete farc;
|
|
}
|
|
|
|
size_t farc_read_handler::get_file_size(std::string& file) {
|
|
if (farc)
|
|
return farc->get_file_size(file.c_str());
|
|
return 0;
|
|
}
|
|
|
|
bool farc_read_handler::read(std::string& file_path, bool cache) {
|
|
if (farc) {
|
|
if (this->file_path == file_path && this->cache == cache)
|
|
return true;
|
|
|
|
delete farc;
|
|
farc = 0;
|
|
}
|
|
|
|
this->file_path = file_path;
|
|
this->cache = cache;
|
|
|
|
struct stat st;
|
|
if (!stat(this->file_path.c_str(), &st) && st.st_size) {
|
|
size_t size = st.st_size;
|
|
farc = new ::farc;
|
|
if (farc) {
|
|
farc->read(this->file_path.c_str(), this->cache, false);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool farc_read_handler::read_data(void* data, size_t size, std::string& file) {
|
|
if (farc) {
|
|
farc_file* ff = farc->read_file(file.c_str());
|
|
if (ff) {
|
|
memcpy(data, ff->data, min_def(size, ff->size));
|
|
if (!cache && ff->data) {
|
|
free(ff->data);
|
|
ff->data = 0;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
file_handler_storage::file_handler_storage() : farc_read_handler(), thread(), cnd(), exit(),
|
|
field_61(), field_64(), read_in_thread(), field_69(), field_6C(), field_70(), field_74() {
|
|
|
|
}
|
|
|
|
file_handler_storage::~file_handler_storage() {
|
|
delete farc_read_handler;
|
|
}
|
|
|
|
void file_handler_storage_init() {
|
|
file_handler_storage_data = new file_handler_storage;
|
|
file_handler_storage_data->thread = new std::thread(file_handler_storage_thread_ctrl);
|
|
if (file_handler_storage_data->thread) {
|
|
SetThreadDescription((HANDLE)file_handler_storage_data->thread->native_handle(), L"File Thread");
|
|
//file_handler_storage_data->thread->detach();
|
|
}
|
|
}
|
|
|
|
void file_handler_storage_ctrl() {
|
|
file_handler_storage_ctrl_list();
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(file_handler_storage_data->mtx);
|
|
std::list<file_handler*>& list = file_handler_storage_data->list;
|
|
std::deque<file_handler*>& deque = file_handler_storage_data->deque;
|
|
if (!deque.size()) {
|
|
for (file_handler*& i : list)
|
|
if (i->not_ready && !i->reading) {
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(i->mtx);
|
|
i->count++;
|
|
}
|
|
deque.push_back(i);
|
|
}
|
|
|
|
if (deque.size())
|
|
file_handler_storage_data->cnd.notify_all();
|
|
}
|
|
}
|
|
}
|
|
|
|
void file_handler_storage_free() {
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(file_handler_storage_data->mtx);
|
|
file_handler_storage_data->exit = true;
|
|
file_handler_storage_data->cnd.notify_one();
|
|
}
|
|
|
|
file_handler_storage_data->thread->join();
|
|
delete file_handler_storage_data->thread;
|
|
file_handler_storage_data->thread = 0;
|
|
delete file_handler_storage_data;
|
|
}
|
|
|
|
static bool file_handler_load_file(void* data, const char* dir, const char* file, uint32_t hash) {
|
|
std::string file_path = dir;
|
|
file_path += file;
|
|
|
|
struct stat st;
|
|
if (stat(file_path.c_str(), &st) || !st.st_size)
|
|
return false;
|
|
|
|
file_handler* fhndl = (file_handler*)data;
|
|
fhndl->size = st.st_size;
|
|
fhndl->data = malloc(st.st_size);
|
|
if (!fhndl->data)
|
|
return false;
|
|
|
|
file_stream s;
|
|
s.open(file_path.c_str(), "rb");
|
|
bool ret = s.check_not_null() && s.read(fhndl->data, fhndl->size);
|
|
if (!ret && fhndl->data) {
|
|
free(fhndl->data);
|
|
fhndl->data = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static bool file_handler_load_farc_file(void* data, const char* dir, const char* file, uint32_t hash) {
|
|
std::string file_path = dir;
|
|
file_path += file;
|
|
|
|
file_handler* fhndl = (file_handler*)data;
|
|
|
|
std::unique_lock<std::mutex> u_lock(file_handler_storage_data->farc_mtx);
|
|
bool cache = fhndl->cache;
|
|
|
|
farc_read_handler* farc_read_hndl = file_handler_storage_data->farc_read_handler;
|
|
if (farc_read_hndl && farc_read_hndl->file_path != file_path) {
|
|
delete file_handler_storage_data->farc_read_handler;
|
|
file_handler_storage_data->farc_read_handler = 0;
|
|
}
|
|
|
|
if (!file_handler_storage_data->farc_read_handler)
|
|
file_handler_storage_data->farc_read_handler = new farc_read_handler;
|
|
|
|
farc_read_hndl = file_handler_storage_data->farc_read_handler;
|
|
if (farc_read_hndl && farc_read_hndl->read(file_path, cache)) {
|
|
fhndl->size = farc_read_hndl->get_file_size(fhndl->file);
|
|
if (!fhndl->size)
|
|
fhndl->size = 1;
|
|
|
|
fhndl->data = malloc(fhndl->size);
|
|
if (fhndl->data && farc_read_hndl->read_data(fhndl->data, fhndl->size, fhndl->file))
|
|
return true;
|
|
}
|
|
|
|
if (fhndl->data) {
|
|
free(fhndl->data);
|
|
fhndl->data = 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void file_handler_storage_ctrl_list() {
|
|
std::list<file_handler*>& list = file_handler_storage_data->list;
|
|
for (std::list<file_handler*>::iterator i = list.begin(); i != list.end();) {
|
|
file_handler* pfhndl = *i;
|
|
if (pfhndl->count == 1) {
|
|
pfhndl->free_data_lock();
|
|
i = list.erase(i);
|
|
}
|
|
else {
|
|
if (!pfhndl->not_ready && !pfhndl->callback[0].ready)
|
|
pfhndl->call_callback(0);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void file_handler_storage_thread_ctrl() {
|
|
std::unique_lock<std::mutex> u_lock(file_handler_storage_data->mtx);
|
|
while (!file_handler_storage_data->exit) {
|
|
file_handler_storage_data->cnd.wait(u_lock);
|
|
if (file_handler_storage_data->exit)
|
|
break;
|
|
|
|
for (file_handler*& i : file_handler_storage_data->deque) {
|
|
if (i->not_ready) {
|
|
std::unique_lock<std::mutex> u_lock(i->mtx);
|
|
i->reading = true;
|
|
if (i->not_ready) {
|
|
if (i->farc_file.size())
|
|
i->not_ready = !((data_struct*)i->ds)->load_file(i,
|
|
i->dir.c_str(), i->farc_file.c_str(), file_handler_load_farc_file);
|
|
else
|
|
i->not_ready = !((data_struct*)i->ds)->load_file(i,
|
|
i->dir.c_str(), i->file.c_str(), file_handler_load_file);
|
|
}
|
|
i->reading = false;
|
|
}
|
|
i->free_data_lock();
|
|
}
|
|
file_handler_storage_data->deque.clear();
|
|
}
|
|
file_handler_storage_data->exit = false;
|
|
}
|
|
|
|
p_file_handler::p_file_handler() {
|
|
ptr = 0;
|
|
}
|
|
|
|
p_file_handler::~p_file_handler() {
|
|
if (ptr) {
|
|
if (check_not_ready())
|
|
call_free_callback();
|
|
else
|
|
free_data();
|
|
}
|
|
}
|
|
|
|
void p_file_handler::call_free_callback() {
|
|
if (ptr)
|
|
ptr->call_callback(1);
|
|
free_data();
|
|
}
|
|
|
|
bool p_file_handler::check_not_ready() {
|
|
if (!ptr)
|
|
return false;
|
|
else if (ptr->not_ready)
|
|
return true;
|
|
else
|
|
return !ptr->callback[0].ready;
|
|
}
|
|
|
|
void p_file_handler::free_data() {
|
|
if (!ptr)
|
|
return;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
for (int32_t i = 0; i < 2; i++)
|
|
ptr->callback[i] = {};
|
|
}
|
|
|
|
ptr->free_data_lock();
|
|
ptr = 0;
|
|
}
|
|
|
|
const void* p_file_handler::get_data() {
|
|
if (!ptr || ptr->not_ready)
|
|
return 0;
|
|
return ptr->data;
|
|
}
|
|
|
|
ssize_t p_file_handler::get_size() {
|
|
if (!ptr || ptr->not_ready || ptr->size < 0)
|
|
return 0;
|
|
return ptr->size;
|
|
}
|
|
|
|
bool p_file_handler::read_file(void* data, const char* path) {
|
|
const char* t = strrchr(path, '/');
|
|
if (t) {
|
|
std::string dir = std::string(path, t - path + 1);
|
|
return read_file(data, dir.c_str(), 0, t + 1, false);
|
|
}
|
|
|
|
t = strrchr(path, '\\');
|
|
if (t) {
|
|
std::string dir = std::string(path, t - path + 1);
|
|
return read_file(data, dir.c_str(), 0, t + 1, false);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool p_file_handler::read_file(void* data, const char* dir,
|
|
const char* farc_file, const char* file, bool cache) {
|
|
if (!dir || !file)
|
|
return false;
|
|
|
|
if (ptr) {
|
|
if (ptr->not_ready)
|
|
return false;
|
|
free_data();
|
|
}
|
|
|
|
if (!((data_struct*)data)->check_file_exists(dir, farc_file ? farc_file : file))
|
|
return false;
|
|
|
|
ptr = new file_handler;
|
|
if (!ptr)
|
|
return false;
|
|
|
|
ptr->ds = data;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
ptr->count++;
|
|
}
|
|
|
|
ptr->set_dir(dir);
|
|
if (farc_file)
|
|
ptr->set_farc_file(farc_file, cache);
|
|
ptr->set_file(file);
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
ptr->count++;
|
|
}
|
|
|
|
file_handler_storage_data->list.push_back(ptr);
|
|
return true;
|
|
}
|
|
|
|
bool p_file_handler::read_file(void* data, const char* dir, const char* file) {
|
|
return read_file(data, dir, 0, file, false);
|
|
}
|
|
|
|
bool p_file_handler::read_file(void* data, const char* dir, uint32_t hash, const char* ext) {
|
|
if (!dir || !hash || hash == hash_murmurhash_empty)
|
|
return false;
|
|
|
|
if (ptr) {
|
|
if (ptr->not_ready)
|
|
return false;
|
|
free_data();
|
|
}
|
|
|
|
std::string file;
|
|
if (!((data_struct*)data)->get_file(dir, hash, ext, file))
|
|
return false;
|
|
|
|
ptr = new file_handler;
|
|
if (!ptr)
|
|
return false;
|
|
|
|
ptr->ds = data;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
ptr->count++;
|
|
}
|
|
|
|
ptr->set_dir(dir);
|
|
ptr->set_file(file.c_str());
|
|
|
|
{
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
ptr->count++;
|
|
}
|
|
|
|
file_handler_storage_data->list.push_back(ptr);
|
|
return true;
|
|
}
|
|
|
|
void p_file_handler::read_now() {
|
|
while (check_not_ready()) {
|
|
if (file_handler_storage_data->read_in_thread)
|
|
break;
|
|
|
|
if (ptr) {
|
|
std::unique_lock<std::mutex> u_lock(ptr->mtx);
|
|
ptr->reading = true;
|
|
if (ptr->not_ready) {
|
|
bool ret;
|
|
if (ptr->farc_file.size())
|
|
ret = ((data_struct*)ptr->ds)->load_file(
|
|
ptr, ptr->dir.c_str(), ptr->farc_file.c_str(), file_handler_load_farc_file);
|
|
else
|
|
ret = ((data_struct*)ptr->ds)->load_file(
|
|
ptr, ptr->dir.c_str(), ptr->file.c_str(), file_handler_load_file);
|
|
|
|
if (ret)
|
|
ptr->not_ready = false;
|
|
}
|
|
ptr->reading = false;
|
|
}
|
|
|
|
file_handler_storage_ctrl_list();
|
|
}
|
|
}
|
|
|
|
void p_file_handler::set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func, void* data) {
|
|
if (ptr)
|
|
ptr->set_callback_data(index, func, data);
|
|
}
|