all repos — mgba @ f1f55cea475b2e75c188d657bfb846f8ddf7fc5b

mGBA Game Boy Advance Emulator

src/util/vfile.c (view raw)

  1#include "util/vfile.h"
  2
  3#include <fcntl.h>
  4
  5#ifndef _WIN32
  6#include <sys/mman.h>
  7#else
  8#include <io.h>
  9#include <Windows.h>
 10#endif
 11
 12struct VFileFD {
 13	struct VFile d;
 14	int fd;
 15#ifdef _WIN32
 16	HANDLE hMap;
 17#endif
 18};
 19
 20static bool _vfdClose(struct VFile* vf);
 21static size_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
 22static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
 23static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
 24static size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size);
 25static void* _vfdMap(struct VFile* vf, size_t size, int flags);
 26static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
 27static void _vfdTruncate(struct VFile* vf, size_t size);
 28
 29struct VFile* VFileOpen(const char* path, int flags) {
 30	int fd = open(path, flags, 0666);
 31	return VFileFromFD(fd);
 32}
 33
 34struct VFile* VFileFromFD(int fd) {
 35	if (fd < 0) {
 36		return 0;
 37	}
 38
 39	struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
 40	if (!vfd) {
 41		return 0;
 42	}
 43
 44	vfd->fd = fd;
 45	vfd->d.close = _vfdClose;
 46	vfd->d.seek = _vfdSeek;
 47	vfd->d.read = _vfdRead;
 48	vfd->d.readline = _vfdReadline;
 49	vfd->d.write = _vfdWrite;
 50	vfd->d.map = _vfdMap;
 51	vfd->d.unmap = _vfdUnmap;
 52	vfd->d.truncate = _vfdTruncate;
 53
 54	return &vfd->d;
 55}
 56
 57bool _vfdClose(struct VFile* vf) {
 58	struct VFileFD* vfd = (struct VFileFD*) vf;
 59	if (close(vfd->fd) < 0) {
 60		return false;
 61	}
 62	free(vfd);
 63	return true;
 64}
 65
 66size_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
 67	struct VFileFD* vfd = (struct VFileFD*) vf;
 68	return lseek(vfd->fd, offset, whence);
 69}
 70
 71size_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
 72	struct VFileFD* vfd = (struct VFileFD*) vf;
 73	return read(vfd->fd, buffer, size);
 74}
 75
 76size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
 77	struct VFileFD* vfd = (struct VFileFD*) vf;
 78	size_t bytesRead = 0;
 79	while (bytesRead < size - 1) {
 80		size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
 81		bytesRead += newRead;
 82		if (!newRead || buffer[bytesRead] == '\n') {
 83			break;
 84		}
 85	}
 86	return buffer[bytesRead] = '\0';
 87}
 88
 89size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size) {
 90	struct VFileFD* vfd = (struct VFileFD*) vf;
 91	return write(vfd->fd, buffer, size);
 92}
 93
 94#ifndef _WIN32
 95static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
 96	struct VFileFD* vfd = (struct VFileFD*) vf;
 97	int mmapFlags = MAP_PRIVATE;
 98	if (flags & MEMORY_WRITE) {
 99		mmapFlags = MAP_SHARED;
100	}
101	return mmap(0, size, PROT_READ | PROT_WRITE, mmapFlags, vfd->fd, 0);
102}
103
104static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
105	UNUSED(vf);
106	munmap(memory, size);
107}
108#else
109static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
110	struct VFileFD* vfd = (struct VFileFD*) vf;
111	int createFlags = PAGE_READONLY;
112	int mapFiles = FILE_MAP_READ;
113	if (flags & MEMORY_WRITE) {
114		createFlags = PAGE_READWRITE;
115		mapFiles = FILE_MAP_WRITE;
116	}
117	size_t location = lseek(vfd->fd, 0, SEEK_CUR);
118	size_t fileSize = lseek(vfd->fd, 0, SEEK_END);
119	lseek(vfd->fd, location, SEEK_SET);
120	if (size > fileSize) {
121		size = fileSize;
122	}
123	vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
124	return MapViewOfFile(hMap, mapFiles, 0, 0, size);
125}
126
127static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
128	UNUSED(size);
129	struct VFileFD* vfd = (struct VFileFD*) vf;
130	UnmapViewOfFile(memory);
131	CloseHandle(vfd->hMap);
132	vfd->hMap = 0;
133}
134#endif
135
136static void _vfdTruncate(struct VFile* vf, size_t size) {
137	struct VFileFD* vfd = (struct VFileFD*) vf;
138	ftruncate(vfd->fd, size);
139}