all repos — mgba @ 5c1988c48a34923fb9918970d95213b6f8a68ba4

mGBA Game Boy Advance Emulator

Util: VFile using FILE* backing
Jeffrey Pfau jeffrey@endrift.com
Mon, 15 Jun 2015 01:05:45 -0700
commit

5c1988c48a34923fb9918970d95213b6f8a68ba4

parent

bbc63a23924d7f24b162f9e94b1a5b07b1514baf

2 files changed, 134 insertions(+), 0 deletions(-)

jump to
M src/util/vfs.hsrc/util/vfs.h

@@ -53,8 +53,10 @@ struct VFile* (*openFile)(struct VDir* vd, const char* name, int mode);

}; struct VFile* VFileOpen(const char* path, int flags); +struct VFile* VFileFOpen(const char* path, const char* mode); struct VFile* VFileFromFD(int fd); struct VFile* VFileFromMemory(void* mem, size_t size); +struct VFile* VFileFromFILE(FILE* file); struct VDir* VDirOpen(const char* path);
A src/util/vfs/vfs-file.c

@@ -0,0 +1,132 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/vfs.h" + +#include "util/memory.h" + +#include <stdio.h> + +struct VFileFILE { + struct VFile d; + FILE* file; +}; + +static bool _vffClose(struct VFile* vf); +static off_t _vffSeek(struct VFile* vf, off_t offset, int whence); +static ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size); +static ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size); +static void* _vffMap(struct VFile* vf, size_t size, int flags); +static void _vffUnmap(struct VFile* vf, void* memory, size_t size); +static void _vffTruncate(struct VFile* vf, size_t size); +static ssize_t _vffSize(struct VFile* vf); + +struct VFile* VFileFOpen(const char* path, const char* mode) { + if (!path && !mode) { + return 0; + } + FILE* file = fopen(path, mode); + return VFileFromFILE(file); +} + +struct VFile* VFileFromFILE(FILE* file) { + if (!file) { + return 0; + } + + struct VFileFILE* vff = malloc(sizeof(struct VFileFILE)); + if (!vff) { + return 0; + } + + vff->file = file; + vff->d.close = _vffClose; + vff->d.seek = _vffSeek; + vff->d.read = _vffRead; + vff->d.readline = VFileReadline; + vff->d.write = _vffWrite; + vff->d.map = _vffMap; + vff->d.unmap = _vffUnmap; + vff->d.truncate = _vffTruncate; + vff->d.size = _vffSize; + + return &vff->d; +} + +bool _vffClose(struct VFile* vf) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + if (fclose(vff->file) < 0) { + return false; + } + free(vff); + return true; +} + +off_t _vffSeek(struct VFile* vf, off_t offset, int whence) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + return fseek(vff->file, offset, whence); +} + +ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + return fread(buffer, size, 1, vff->file); +} + +ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + return fwrite(buffer, size, 1, vff->file); +} + +static void* _vffMap(struct VFile* vf, size_t size, int flags) { + UNUSED(flags); + struct VFileFILE* vff = (struct VFileFILE*) vf; + void* mem = anonymousMemoryMap(size); + if (!mem) { + return 0; + } + long pos = ftell(vff->file); + fseek(vff->file, 0, SEEK_SET); + fread(mem, size, 1, vff->file); + fseek(vff->file, pos, SEEK_SET); + return mem; +} + +static void _vffUnmap(struct VFile* vf, void* memory, size_t size) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + long pos = ftell(vff->file); + fseek(vff->file, 0, SEEK_SET); + fwrite(memory, size, 1, vff->file); + fseek(vff->file, pos, SEEK_SET); + mappedMemoryFree(memory, size); +} + +static void _vffTruncate(struct VFile* vf, size_t size) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + long pos = ftell(vff->file); + fseek(vff->file, 0, SEEK_END); + ssize_t realSize = ftell(vff->file); + if (realSize < 0) { + return; + } + while (size > (size_t) realSize) { + static const char zeros[128] = ""; + size_t diff = size - realSize; + if (diff > sizeof(zeros)) { + diff = sizeof(zeros); + } + fwrite(zeros, diff, 1, vff->file); + realSize += diff; + } + fseek(vff->file, pos, SEEK_SET); +} + +static ssize_t _vffSize(struct VFile* vf) { + struct VFileFILE* vff = (struct VFileFILE*) vf; + long pos = ftell(vff->file); + fseek(vff->file, 0, SEEK_END); + ssize_t size = ftell(vff->file); + fseek(vff->file, pos, SEEK_SET); + return size; +}