looper/file_backend.cpp

226 lines
6.2 KiB
C++

#include "file_backend.hpp"
#include <filesystem>
#include <string.h>
File::File() {
}
size_t File::get_len() {
return len;
}
CFile::CFile() : File() {
}
void CFile::open(const char *fname) {
name = fname;
file = fopen(fname, "rb");
if (file == NULL) {
throw NotFoundException(fname);
}
fseek(file, 0, SEEK_END);
len = ftell(file);
fseek(file, 0, SEEK_SET);
}
void CFile::close() {
if (file == NULL) return;
fclose(file);
file = NULL;
}
size_t CFile::read(void *ptr, size_t size, size_t len) {
if (file == NULL) return 0;
return fread(ptr, size, len, file);
}
void CFile::seek(int64_t pos, SeekType seek_type) {
int whence;
switch (seek_type) {
case SeekType::SET: {
whence = SEEK_SET;
if (pos < 0) throw std::exception();
} break;
case SeekType::CUR: {
whence = SEEK_CUR;
if (get_pos() + pos < 0) throw std::exception();
} break;
case SeekType::END: {
whence = SEEK_END;
if (((int64_t)get_len()) + pos < 0) throw std::exception();
} break;
}
if (file == NULL) throw std::exception();
fseek(file, pos, whence);
}
int64_t CFile::get_pos() {
if (file == NULL) return 0;
return ftell(file);
}
bool CFile::is_open() {
return file != NULL;
}
MemFile::MemFile() {
ptr = NULL;
len = 0;
}
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;
}
void MemFile::close() {
free(this->ptr);
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;
}
size_t rwops_read(SDL_RWops *rwops, void *ptr, size_t size, size_t maxnum) {
File *file = (File*)rwops->hidden.unknown.data1;
int64_t oldpos = file->get_pos();
try {
return file->read(ptr, size, maxnum);
} catch (std::exception) {
return (file->get_pos() - oldpos) / size;
}
}
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;
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();
}
Sint64 rwops_size(SDL_RWops *rwops) {
FILE_TYPE *file = (FILE_TYPE*)rwops->hidden.unknown.data1;
return (Sint64)file->get_len();
}
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);
return file->read(dst, 1, length);
}
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) {
auto output = new FILE_TYPE();
output->open(name);
return output;
}