#include "file_backend.hpp" #include #include #include 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() { memory_owned = false; ptr = NULL; len = 0; } 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; } 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; memory_owned = true; } void MemFile::close() { if (memory_owned) 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; }