2024-08-08 13:12:37 -07:00
|
|
|
#include "file_backend.hpp"
|
|
|
|
#include <filesystem>
|
|
|
|
#include <string.h>
|
2024-12-21 14:23:00 -08:00
|
|
|
#include <cassert>
|
2024-08-08 13:12:37 -07:00
|
|
|
|
2024-09-28 10:31:06 -07:00
|
|
|
File::File() {
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
size_t File::get_len() {
|
|
|
|
return len;
|
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
CFile::CFile() : File() {
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void CFile::open(const char *fname) {
|
|
|
|
name = fname;
|
|
|
|
file = fopen(fname, "rb");
|
|
|
|
if (file == NULL) {
|
2024-09-29 15:28:08 -07:00
|
|
|
throw NotFoundException(fname);
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
len = ftell(file);
|
|
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
}
|
|
|
|
void CFile::close() {
|
|
|
|
if (file == NULL) return;
|
|
|
|
fclose(file);
|
|
|
|
file = NULL;
|
|
|
|
}
|
2024-09-16 15:05:53 -07:00
|
|
|
size_t CFile::read(void *ptr, size_t size, size_t len) {
|
2024-08-08 13:12:37 -07:00
|
|
|
if (file == NULL) return 0;
|
2024-09-16 15:05:53 -07:00
|
|
|
return fread(ptr, size, len, file);
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
void CFile::seek(int64_t pos, SeekType seek_type) {
|
2024-08-08 13:12:37 -07:00
|
|
|
int whence;
|
|
|
|
switch (seek_type) {
|
|
|
|
case SeekType::SET: {
|
|
|
|
whence = SEEK_SET;
|
2024-09-28 10:31:06 -07:00
|
|
|
if (pos < 0) throw std::exception();
|
2024-08-08 13:12:37 -07:00
|
|
|
} break;
|
|
|
|
case SeekType::CUR: {
|
|
|
|
whence = SEEK_CUR;
|
2024-09-28 10:31:06 -07:00
|
|
|
if (get_pos() + pos < 0) throw std::exception();
|
2024-08-08 13:12:37 -07:00
|
|
|
} break;
|
|
|
|
case SeekType::END: {
|
|
|
|
whence = SEEK_END;
|
2024-09-28 10:31:06 -07:00
|
|
|
if (((int64_t)get_len()) + pos < 0) throw std::exception();
|
2024-08-08 13:12:37 -07:00
|
|
|
} break;
|
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
if (file == NULL) throw std::exception();
|
2024-08-08 13:12:37 -07:00
|
|
|
fseek(file, pos, whence);
|
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
int64_t CFile::get_pos() {
|
2024-08-08 13:12:37 -07:00
|
|
|
if (file == NULL) return 0;
|
|
|
|
return ftell(file);
|
|
|
|
}
|
|
|
|
bool CFile::is_open() {
|
|
|
|
return file != NULL;
|
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
MemFile::MemFile() {
|
2024-12-21 14:23:00 -08:00
|
|
|
memory_owned = false;
|
2024-09-28 10:31:06 -07:00
|
|
|
ptr = NULL;
|
|
|
|
len = 0;
|
|
|
|
}
|
2024-12-21 14:23:00 -08:00
|
|
|
void MemFile::open_memory(void *ptr, size_t len, const char *name) {
|
|
|
|
assert(name != NULL);
|
|
|
|
this->name = strdup(name);
|
|
|
|
this->ptr = ptr;
|
|
|
|
this->len = len;
|
|
|
|
this->pos = 0;
|
|
|
|
memory_owned = false;
|
|
|
|
}
|
2024-09-28 10:31:06 -07:00
|
|
|
void MemFile::open(const char *path) {
|
|
|
|
CFile file;
|
|
|
|
file.open(path);
|
|
|
|
this->name = strdup(file.name);
|
|
|
|
this->ptr = malloc(file.get_len());
|
|
|
|
this->len = file.read(this->ptr, 1, file.get_len());
|
|
|
|
file.close();
|
|
|
|
this->pos = 0;
|
2024-12-21 14:23:00 -08:00
|
|
|
memory_owned = true;
|
2024-09-28 10:31:06 -07:00
|
|
|
}
|
|
|
|
void MemFile::close() {
|
2024-12-21 14:23:00 -08:00
|
|
|
if (memory_owned) free(this->ptr);
|
2024-09-28 10:31:06 -07:00
|
|
|
free((void*)this->name);
|
|
|
|
this->ptr = NULL;
|
|
|
|
this->name = NULL;
|
|
|
|
this->len = 0;
|
|
|
|
this->pos = 0;
|
|
|
|
}
|
|
|
|
size_t MemFile::read(void *ptr, size_t size, size_t len) {
|
|
|
|
if (this->ptr == NULL) {
|
|
|
|
ERROR.writeln("Attempt to read invalid memfile");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (size == 0) return 0;
|
|
|
|
if (len == 0) return 0;
|
|
|
|
uint8_t *ptr8 = (uint8_t*)ptr;
|
|
|
|
uint8_t *myptr8 = (uint8_t*)this->ptr;
|
|
|
|
size_t i;
|
|
|
|
size_t maxbytes = size * len;
|
|
|
|
size_t validbytes = std::min(maxbytes, (size_t)std::max((int64_t)this->len - (int64_t)this->pos, (int64_t)0));
|
|
|
|
size_t remainder = maxbytes - validbytes;
|
|
|
|
memcpy(ptr8, myptr8 + this->pos, validbytes);
|
|
|
|
if (this->pos < this->len) {
|
|
|
|
if (remainder > 0) {
|
|
|
|
seek(0, SeekType::END);
|
|
|
|
} else {
|
|
|
|
seek(maxbytes, SeekType::CUR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return validbytes / size;
|
|
|
|
}
|
|
|
|
int64_t MemFile::get_pos() {
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
bool MemFile::is_open() {
|
|
|
|
return ptr != NULL;
|
|
|
|
}
|
|
|
|
size_t MemFile::get_len() {
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
void MemFile::seek(int64_t pos, SeekType seek_type) {
|
|
|
|
int64_t new_pos = this->pos;
|
|
|
|
switch (seek_type) {
|
|
|
|
case SeekType::CUR: {
|
|
|
|
new_pos += pos;
|
|
|
|
} break;
|
|
|
|
case SeekType::END: {
|
|
|
|
new_pos = this->len + pos;
|
|
|
|
} break;
|
|
|
|
case SeekType::SET: {
|
|
|
|
new_pos = pos;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
if (new_pos < 0) throw std::exception();
|
|
|
|
this->pos = new_pos;
|
|
|
|
}
|
|
|
|
|
2024-08-08 13:12:37 -07:00
|
|
|
size_t rwops_read(SDL_RWops *rwops, void *ptr, size_t size, size_t maxnum) {
|
|
|
|
File *file = (File*)rwops->hidden.unknown.data1;
|
2024-09-28 10:31:06 -07:00
|
|
|
int64_t oldpos = file->get_pos();
|
|
|
|
try {
|
|
|
|
return file->read(ptr, size, maxnum);
|
|
|
|
} catch (std::exception) {
|
|
|
|
return (file->get_pos() - oldpos) / size;
|
|
|
|
}
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
int rwops_close(SDL_RWops *rwops) {
|
|
|
|
File *file = (File*)rwops->hidden.unknown.data1;
|
|
|
|
file->close();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Sint64 rwops_seek(SDL_RWops *rwops, Sint64 offset, int whence) {
|
|
|
|
SeekType type;
|
|
|
|
switch (whence) {
|
|
|
|
case RW_SEEK_CUR: {
|
|
|
|
type = SeekType::CUR;
|
|
|
|
} break;
|
|
|
|
case RW_SEEK_SET: {
|
|
|
|
type = SeekType::SET;
|
|
|
|
} break;
|
|
|
|
case RW_SEEK_END: {
|
|
|
|
type = SeekType::END;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
File *file = (File*)rwops->hidden.unknown.data1;
|
2024-09-28 10:31:06 -07:00
|
|
|
if (type == SeekType::CUR && offset == 0) return file->get_pos();
|
|
|
|
try {
|
|
|
|
file->seek((int64_t)offset, type);
|
|
|
|
} catch (std::exception) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return (Sint64)file->get_pos();
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
Sint64 rwops_size(SDL_RWops *rwops) {
|
|
|
|
FILE_TYPE *file = (FILE_TYPE*)rwops->hidden.unknown.data1;
|
2024-09-28 10:31:06 -07:00
|
|
|
return (Sint64)file->get_len();
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
SDL_RWops *get_sdl_file(File *file) {
|
|
|
|
SDL_RWops *rwops = new SDL_RWops();
|
|
|
|
rwops->read = &rwops_read;
|
|
|
|
rwops->close = &rwops_close;
|
|
|
|
rwops->write = NULL;
|
|
|
|
rwops->seek = &rwops_seek;
|
|
|
|
rwops->size = &rwops_size;
|
|
|
|
rwops->type = SDL_RWOPS_UNKNOWN;
|
|
|
|
rwops->hidden.unknown.data1 = file;
|
|
|
|
return rwops;
|
|
|
|
}
|
|
|
|
struct file_streamfile {
|
|
|
|
STREAMFILE vt;
|
|
|
|
File *file;
|
|
|
|
};
|
|
|
|
static file_streamfile *sf_open(file_streamfile *sf, const char *const filename, size_t buf_size) {
|
|
|
|
sf->file->open(filename);
|
|
|
|
return sf;
|
|
|
|
}
|
|
|
|
static size_t sf_read(file_streamfile *sf, uint8_t *dst, offv_t offset, size_t length) {
|
|
|
|
File *file = sf->file;
|
|
|
|
file->seek(offset, SeekType::SET);
|
2024-09-16 15:05:53 -07:00
|
|
|
return file->read(dst, 1, length);
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|
|
|
|
static size_t sf_size(file_streamfile *sf) {
|
|
|
|
File *file = sf->file;
|
|
|
|
return file->get_len();
|
|
|
|
}
|
|
|
|
static void sf_close(file_streamfile *sf) {
|
|
|
|
File *file = sf->file;
|
|
|
|
file->close();
|
|
|
|
}
|
|
|
|
static void sf_get_name(file_streamfile *sf, char *name, size_t name_size) {
|
|
|
|
File *file = sf->file;
|
|
|
|
int copy_size = strlen(file->name) + 1;
|
|
|
|
if (copy_size > name_size) copy_size = name_size;
|
|
|
|
memcpy(name, file->name, copy_size);
|
|
|
|
name[copy_size - 1] = '\0';
|
|
|
|
}
|
|
|
|
static offv_t sf_get_offset(file_streamfile *sf) {
|
|
|
|
return (offv_t)sf->file->get_pos();
|
|
|
|
}
|
|
|
|
STREAMFILE *get_sf_from_file(File *file) {
|
|
|
|
file_streamfile *sf = new file_streamfile();
|
|
|
|
sf->vt.read = (size_t(*)(STREAMFILE*, uint8_t*, offv_t, size_t))(void*)sf_read;
|
|
|
|
sf->vt.get_size = (size_t(*)(STREAMFILE*))(void*)(sf_size);
|
|
|
|
sf->vt.get_offset = (offv_t(*)(STREAMFILE*))(void*)(sf_get_offset);
|
|
|
|
sf->vt.get_name = (void(*)(STREAMFILE*,char*,size_t))(void*)(sf_get_name);
|
|
|
|
sf->vt.open = (STREAMFILE*(*)(STREAMFILE*,const char *const, size_t))(sf_open);
|
|
|
|
sf->vt.close = (void(*)(STREAMFILE*))(void*)(sf_close);
|
|
|
|
sf->vt.stream_index = 0;
|
|
|
|
sf->file = file;
|
|
|
|
return &sf->vt;
|
|
|
|
}
|
|
|
|
File *open_file(const char *name) {
|
2024-09-28 10:31:06 -07:00
|
|
|
auto output = new FILE_TYPE();
|
|
|
|
output->open(name);
|
|
|
|
return output;
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|