Use VFiles for all file operations
@@ -3,6 +3,7 @@
#include "gba.h" #include "util/memory.h" +#include "util/vfile.h" #include <errno.h> #include <fcntl.h>@@ -16,7 +17,7 @@ savedata->type = SAVEDATA_NONE;
savedata->data = 0; savedata->command = EEPROM_COMMAND_NULL; savedata->flashState = FLASH_STATE_RAW; - savedata->fd = -1; + savedata->vf = 0; savedata->filename = filename; }@@ -29,24 +30,42 @@ savedata->type = type;
} void GBASavedataDeinit(struct GBASavedata* savedata) { - switch (savedata->type) { - case SAVEDATA_SRAM: - mappedMemoryFree(savedata->data, SIZE_CART_SRAM); - break; - case SAVEDATA_FLASH512: - mappedMemoryFree(savedata->data, SIZE_CART_FLASH512); - break; - case SAVEDATA_FLASH1M: - mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M); - break; - case SAVEDATA_EEPROM: - mappedMemoryFree(savedata->data, SIZE_CART_EEPROM); - break; - default: - break; - } - if (savedata->fd >= 0) { - close(savedata->fd); + if (savedata->vf) { + switch (savedata->type) { + case SAVEDATA_SRAM: + savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM); + break; + case SAVEDATA_FLASH512: + savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512); + break; + case SAVEDATA_FLASH1M: + savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M); + break; + case SAVEDATA_EEPROM: + savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM); + break; + case SAVEDATA_NONE: + break; + } + savedata->vf->close(savedata->vf); + savedata->vf = 0; + } else { + switch (savedata->type) { + case SAVEDATA_SRAM: + mappedMemoryFree(savedata->data, SIZE_CART_SRAM); + break; + case SAVEDATA_FLASH512: + mappedMemoryFree(savedata->data, SIZE_CART_FLASH512); + break; + case SAVEDATA_FLASH1M: + mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M); + break; + case SAVEDATA_EEPROM: + mappedMemoryFree(savedata->data, SIZE_CART_EEPROM); + break; + case SAVEDATA_NONE: + break; + } } savedata->type = SAVEDATA_NONE; }@@ -59,18 +78,18 @@ if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); return; } - savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); + savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT); off_t end; - if (savedata->fd < 0) { + if (!savedata->vf) { GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M); } else { - end = lseek(savedata->fd, 0, SEEK_END); + end = savedata->vf->seek(savedata->vf, 0, SEEK_END); if (end < SIZE_CART_FLASH512) { - ftruncate(savedata->fd, SIZE_CART_FLASH1M); + savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M); } - savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_FLASH1M, MEMORY_WRITE); + savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MEMORY_WRITE); } savedata->currentBank = savedata->data;@@ -86,18 +105,18 @@ } else {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); return; } - savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); + savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT); off_t end; - if (savedata->fd < 0) { + if (!savedata->vf) { GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM); } else { - end = lseek(savedata->fd, 0, SEEK_END); + end = savedata->vf->seek(savedata->vf, 0, SEEK_END); if (end < SIZE_CART_EEPROM) { - ftruncate(savedata->fd, SIZE_CART_EEPROM); + savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM); } - savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_EEPROM, MEMORY_WRITE); + savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, MEMORY_WRITE); } if (end < SIZE_CART_EEPROM) { memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);@@ -111,18 +130,18 @@ } else {
GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); return; } - savedata->fd = open(savedata->filename, O_RDWR | O_CREAT, 0666); + savedata->vf = VFileOpen(savedata->filename, O_RDWR | O_CREAT); off_t end; - if (savedata->fd < 0) { + if (!savedata->vf) { GBALog(0, GBA_LOG_ERROR, "Cannot open savedata file %s (errno: %d)", savedata->filename, errno); end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_SRAM); } else { - end = lseek(savedata->fd, 0, SEEK_END); + end = savedata->vf->seek(savedata->vf, 0, SEEK_END); if (end < SIZE_CART_SRAM) { - ftruncate(savedata->fd, SIZE_CART_SRAM); + savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM); } - savedata->data = fileMemoryMap(savedata->fd, SIZE_CART_SRAM, MEMORY_WRITE); + savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, MEMORY_WRITE); } if (end < SIZE_CART_SRAM) {@@ -299,7 +318,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
savedata->currentBank = &savedata->data[bank << 16]; if (bank > 0) { savedata->type = SAVEDATA_FLASH1M; - ftruncate(savedata->fd, SIZE_CART_FLASH1M); + savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M); } }
@@ -3,6 +3,8 @@ #define GBA_SAVEDATA_H
#include "common.h" +struct VFile; + enum SavedataType { SAVEDATA_NONE = 0, SAVEDATA_SRAM,@@ -55,7 +57,7 @@ enum SavedataType type;
uint8_t* data; const char* filename; enum SavedataCommand command; - int fd; + struct VFile* vf; int readBitsRemaining; int readAddress;
@@ -5,6 +5,7 @@ #include "gba-io.h"
#include "gba-thread.h" #include "util/memory.h" +#include "util/vfile.h" #include <fcntl.h>@@ -62,43 +63,47 @@ GBAVideoDeserialize(&gba->video, state);
GBAAudioDeserialize(&gba->audio, state); } -static int _getStateFd(struct GBA* gba, int slot) { +static struct VFile* _getStateVf(struct GBA* gba, int slot) { char path[PATH_MAX]; path[PATH_MAX - 1] = '\0'; snprintf(path, PATH_MAX - 1, "%s.ss%d", gba->activeFile, slot); - int fd = open(path, O_CREAT | O_RDWR, 0777); - if (fd >= 0) { - ftruncate(fd, sizeof(struct GBASerializedState)); + struct VFile* vf = VFileOpen(path, O_CREAT | O_RDWR); + if (vf) { + vf->truncate(vf, sizeof(struct GBASerializedState)); } - return fd; + return vf; } bool GBASaveState(struct GBA* gba, int slot) { - int fd = _getStateFd(gba, slot); - if (fd < 0) { + struct VFile* vf = _getStateVf(gba, slot); + if (!vf) { return false; } - struct GBASerializedState* state = GBAMapState(fd); + struct GBASerializedState* state = GBAMapState(vf); GBASerialize(gba, state); - GBADeallocateState(state); - close(fd); + GBAUnmapState(vf, state); + vf->close(vf); return true; } bool GBALoadState(struct GBA* gba, int slot) { - int fd = _getStateFd(gba, slot); - if (fd < 0) { + struct VFile* vf = _getStateVf(gba, slot); + if (!vf) { return false; } - struct GBASerializedState* state = GBAMapState(fd); + struct GBASerializedState* state = GBAMapState(vf); GBADeserialize(gba, state); - GBADeallocateState(state); - close(fd); + GBAUnmapState(vf, state); + vf->close(vf); return true; } -struct GBASerializedState* GBAMapState(int fd) { - return fileMemoryMap(fd, sizeof(struct GBASerializedState), MEMORY_WRITE); +struct GBASerializedState* GBAMapState(struct VFile* vf) { + return vf->map(vf, sizeof(struct GBASerializedState), MEMORY_WRITE); +} + +void GBAUnmapState(struct VFile* vf, struct GBASerializedState* state) { + vf->unmap(vf, state, sizeof(struct GBASerializedState)); } struct GBASerializedState* GBAAllocateState(void) {
@@ -225,13 +225,17 @@ uint8_t iwram[SIZE_WORKING_IRAM];
uint8_t wram[SIZE_WORKING_RAM]; }; +struct VFile; + void GBASerialize(struct GBA* gba, struct GBASerializedState* state); void GBADeserialize(struct GBA* gba, struct GBASerializedState* state); bool GBASaveState(struct GBA* gba, int slot); bool GBALoadState(struct GBA* gba, int slot); -struct GBASerializedState* GBAMapState(int fd); +struct GBASerializedState* GBAMapState(struct VFile* vf); +void GBAUnmapState(struct VFile* vf, struct GBASerializedState* state); + struct GBASerializedState* GBAAllocateState(void); void GBADeallocateState(struct GBASerializedState* state);
@@ -89,7 +89,7 @@ if (threadContext->renderer) {
GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); } - if (threadContext->fd >= 0) { + if (threadContext->fd) { if (threadContext->fname) { char* dotPoint = strrchr(threadContext->fname, '.'); if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) {@@ -111,11 +111,11 @@ }
} gba.savefile = savedata; GBALoadROM(&gba, threadContext->fd, threadContext->fname); - if (threadContext->biosFd >= 0) { + if (threadContext->biosFd) { GBALoadBIOS(&gba, threadContext->biosFd); } - if (threadContext->patchFd >= 0 && loadPatch(VFileFromFD(threadContext->patchFd), &patch)) { + if (threadContext->patchFd && loadPatch(threadContext->patchFd, &patch)) { GBAApplyPatch(&gba, &patch); } }@@ -191,10 +191,10 @@ return 0;
} void GBAMapOptionsToContext(struct StartupOptions* opts, struct GBAThread* threadContext) { - threadContext->fd = opts->fd; + threadContext->fd = VFileFromFD(opts->fd); threadContext->fname = opts->fname; - threadContext->biosFd = opts->biosFd; - threadContext->patchFd = opts->patchFd; + threadContext->biosFd = VFileFromFD(opts->biosFd); + threadContext->patchFd = VFileFromFD(opts->patchFd); threadContext->frameskip = opts->frameskip; threadContext->logLevel = opts->logLevel; threadContext->rewindBufferCapacity = opts->rewindBufferCapacity;
@@ -47,9 +47,9 @@ // Input
struct GBAVideoRenderer* renderer; struct GBASIODriverSet sioDrivers; struct ARMDebugger* debugger; - int fd; - int biosFd; - int patchFd; + struct VFile* fd; + struct VFile* biosFd; + struct VFile* patchFd; const char* fname; int activeKeys; int frameskip;
@@ -7,8 +7,7 @@ #include "gba-thread.h"
#include "util/memory.h" #include "util/patch.h" - -#include <sys/stat.h> +#include "util/vfile.h" const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;@@ -134,6 +133,9 @@ gba->keySource = 0;
gba->rotationSource = 0; gba->rumble = 0; + gba->romVf = 0; + gba->biosVf = 0; + gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL; gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);@@ -143,7 +145,15 @@ void GBADestroy(struct GBA* gba) {
if (gba->pristineRom == gba->memory.rom) { gba->memory.rom = 0; } - mappedMemoryFree(gba->pristineRom, gba->pristineRomSize); + + if (gba->romVf) { + gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); + } + + if (gba->biosVf) { + gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS); + } + GBAMemoryDeinit(gba); GBAVideoDeinit(&gba->video); GBAAudioDeinit(&gba->audio);@@ -363,13 +373,13 @@ void GBADetachDebugger(struct GBA* gba) {
gba->debugger = 0; } -void GBALoadROM(struct GBA* gba, int fd, const char* fname) { - struct stat info; - gba->pristineRom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ); +void GBALoadROM(struct GBA* gba, struct VFile* vf, const char* fname) { + gba->romVf = vf; + gba->pristineRomSize = vf->seek(vf, 0, SEEK_END); + vf->seek(vf, 0, SEEK_SET); + gba->pristineRom = vf->map(vf, SIZE_CART0, MEMORY_READ); gba->memory.rom = gba->pristineRom; gba->activeFile = fname; - fstat(fd, &info); - gba->pristineRomSize = info.st_size; gba->memory.romSize = gba->pristineRomSize; if (gba->savefile) { GBASavedataInit(&gba->memory.savedata, gba->savefile);@@ -379,8 +389,9 @@ _checkOverrides(gba, ((struct GBACartridge*) gba->memory.rom)->id);
// TODO: error check } -void GBALoadBIOS(struct GBA* gba, int fd) { - gba->memory.bios = fileMemoryMap(fd, SIZE_BIOS, MEMORY_READ); +void GBALoadBIOS(struct GBA* gba, struct VFile* vf) { + gba->biosVf = vf; + gba->memory.bios = vf->map(vf, SIZE_BIOS, MEMORY_READ); gba->memory.fullBios = 1; uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);
@@ -60,9 +60,10 @@ GBA_KEY_L = 9,
GBA_KEY_NONE = -1 }; -struct GBARotationSource; struct GBA; +struct GBARotationSource; struct Patch; +struct VFile; typedef void (*GBALogHandler)(struct GBA*, enum GBALogLevel, const char* format, va_list args);@@ -99,6 +100,8 @@ struct GBARotationSource* rotationSource;
struct GBARumble* rumble; void* pristineRom; size_t pristineRomSize; + struct VFile* romVf; + struct VFile* biosVf; const char* activeFile; const char* savefile;@@ -141,8 +144,8 @@
void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger); void GBADetachDebugger(struct GBA* gba); -void GBALoadROM(struct GBA* gba, int fd, const char* fname); -void GBALoadBIOS(struct GBA* gba, int fd); +void GBALoadROM(struct GBA* gba, struct VFile* vf, const char* fname); +void GBALoadBIOS(struct GBA* gba, struct VFile* vf); void GBAApplyPatch(struct GBA* gba, struct Patch* patch); __attribute__((format (printf, 3, 4)))
@@ -5,13 +5,6 @@
void* anonymousMemoryMap(size_t size) { return mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); } -void* fileMemoryMap(int fd, size_t size, int flags) { - int mmapFlags = MAP_PRIVATE; - if (flags & MEMORY_WRITE) { - mmapFlags = MAP_SHARED; - } - return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, fd, 0); -} void mappedMemoryFree(void* memory, size_t size) { munmap(memory, size);
@@ -8,23 +8,6 @@ HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size & 0xFFFFFFFF, 0);
return MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, size); } -void* fileMemoryMap(int fd, size_t size, int flags) { - int createFlags = PAGE_READONLY; - int mapFiles = FILE_MAP_READ; - if (flags & MEMORY_WRITE) { - createFlags = PAGE_READWRITE; - mapFiles = FILE_MAP_WRITE; - } - size_t location = lseek(fd, 0, SEEK_CUR); - size_t fileSize = lseek(fd, 0, SEEK_END); - lseek(fd, location, SEEK_SET); - if (size > fileSize) { - size = fileSize; - } - HANDLE hMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0); - return MapViewOfFile(hMap, mapFiles, 0, 0, size); -} - void mappedMemoryFree(void* memory, size_t size) { // TODO fill in }
@@ -7,7 +7,6 @@ #define MEMORY_READ 1
#define MEMORY_WRITE 2 void* anonymousMemoryMap(size_t size); -void* fileMemoryMap(int fd, size_t size, int flags); void mappedMemoryFree(void* memory, size_t size); #endif
@@ -2,9 +2,19 @@ #include "util/vfile.h"
#include <fcntl.h> +#ifndef _WIN32 +#include <sys/mman.h> +#else +#include <io.h> +#include <Windows.h> +#endif + struct VFileFD { struct VFile d; int fd; +#ifdef _WIN32 + HANDLE hMap; +#endif }; static bool _vfdClose(struct VFile* vf);@@ -12,9 +22,12 @@ static size_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size); static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size); static size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size); +static void* _vfdMap(struct VFile* vf, size_t size, int flags); +static void _vfdUnmap(struct VFile* vf, void* memory, size_t size); +static void _vfdTruncate(struct VFile* vf, size_t size); struct VFile* VFileOpen(const char* path, int flags) { - int fd = open(path, flags); + int fd = open(path, flags, 0666); return VFileFromFD(fd); }@@ -34,6 +47,9 @@ vfd->d.seek = _vfdSeek;
vfd->d.read = _vfdRead; vfd->d.readline = _vfdReadline; vfd->d.write = _vfdWrite; + vfd->d.map = _vfdMap; + vfd->d.unmap = _vfdUnmap; + vfd->d.truncate = _vfdTruncate; return &vfd->d; }@@ -74,3 +90,50 @@ size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size) {
struct VFileFD* vfd = (struct VFileFD*) vf; return write(vfd->fd, buffer, size); } + +#ifndef _WIN32 +static void* _vfdMap(struct VFile* vf, size_t size, int flags) { + struct VFileFD* vfd = (struct VFileFD*) vf; + int mmapFlags = MAP_PRIVATE; + if (flags & MEMORY_WRITE) { + mmapFlags = MAP_SHARED; + } + return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0); +} + +static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) { + UNUSED(vf); + munmap(memory, size); +} +#else +static void* _vfdMap(struct VFile* vf, size_t size, int flags) { + struct VFileFD* vfd = (struct VFileFD*) vf; + int createFlags = PAGE_READONLY; + int mapFiles = FILE_MAP_READ; + if (flags & MEMORY_WRITE) { + createFlags = PAGE_READWRITE; + mapFiles = FILE_MAP_WRITE; + } + size_t location = lseek(vfd->fd, 0, SEEK_CUR); + size_t fileSize = lseek(vfd->fd, 0, SEEK_END); + lseek(vfd->fd, location, SEEK_SET); + if (size > fileSize) { + size = fileSize; + } + vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0); + return MapViewOfFile(hMap, mapFiles, 0, 0, size); +} + +static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) { + UNUSED(size); + struct VFileFD* vfd = (struct VFileFD*) vf; + UnmapViewOfFile(memory); + CloseHandle(vfd->hMap); + vfd->hMap = 0; +} +#endif + +static void _vfdTruncate(struct VFile* vf, size_t size) { + struct VFileFD* vfd = (struct VFileFD*) vf; + ftruncate(vfd->fd, size); +}
@@ -3,12 +3,17 @@ #define VFILE_H
#include "common.h" +#include "memory.h" + struct VFile { bool (*close)(struct VFile* vf); size_t (*seek)(struct VFile* vf, off_t offset, int whence); size_t (*read)(struct VFile* vf, void* buffer, size_t size); size_t (*readline)(struct VFile* vf, char* buffer, size_t size); size_t (*write)(struct VFile* vf, void* buffer, size_t size); + void* (*map)(struct VFile* vf, size_t size, int flags); + void (*unmap)(struct VFile* vf, void* memory, size_t size); + void (*truncate)(struct VFile* vf, size_t size); }; struct VFile* VFileOpen(const char* path, int flags);