all repos — mgba @ c14da05d8dca225010677643c32fea5c0ac8517a

mGBA Game Boy Advance Emulator

src/util/vfs/vfs-file.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "util/vfs.h"
  7
  8#include "util/memory.h"
  9
 10#include <errno.h>
 11#include <stdio.h>
 12
 13struct VFileFILE {
 14	struct VFile d;
 15	FILE* file;
 16	bool writable;
 17};
 18
 19static bool _vffClose(struct VFile* vf);
 20static off_t _vffSeek(struct VFile* vf, off_t offset, int whence);
 21static ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size);
 22static ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size);
 23static void* _vffMap(struct VFile* vf, size_t size, int flags);
 24static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
 25static void _vffTruncate(struct VFile* vf, size_t size);
 26static ssize_t _vffSize(struct VFile* vf);
 27static bool _vffSync(struct VFile* vf, const void* buffer, size_t size);
 28
 29struct VFile* VFileFOpen(const char* path, const char* mode) {
 30	if (!path && !mode) {
 31		return 0;
 32	}
 33	FILE* file = fopen(path, mode);
 34	if (!file && errno == ENOENT && strcmp(mode, "r+b") == 0) {
 35		file = fopen(path, "w+b");
 36	}
 37	return VFileFromFILE(file);
 38}
 39
 40struct VFile* VFileFromFILE(FILE* file) {
 41	if (!file) {
 42		return 0;
 43	}
 44
 45	struct VFileFILE* vff = malloc(sizeof(struct VFileFILE));
 46	if (!vff) {
 47		return 0;
 48	}
 49
 50	vff->file = file;
 51	vff->writable = false;
 52	vff->d.close = _vffClose;
 53	vff->d.seek = _vffSeek;
 54	vff->d.read = _vffRead;
 55	vff->d.readline = VFileReadline;
 56	vff->d.write = _vffWrite;
 57	vff->d.map = _vffMap;
 58	vff->d.unmap = _vffUnmap;
 59	vff->d.truncate = _vffTruncate;
 60	vff->d.size = _vffSize;
 61	vff->d.sync = _vffSync;
 62
 63	return &vff->d;
 64}
 65
 66bool _vffClose(struct VFile* vf) {
 67	struct VFileFILE* vff = (struct VFileFILE*) vf;
 68	if (fclose(vff->file) < 0) {
 69		return false;
 70	}
 71	free(vff);
 72	return true;
 73}
 74
 75off_t _vffSeek(struct VFile* vf, off_t offset, int whence) {
 76	struct VFileFILE* vff = (struct VFileFILE*) vf;
 77	return fseek(vff->file, offset, whence);
 78}
 79
 80ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) {
 81	struct VFileFILE* vff = (struct VFileFILE*) vf;
 82	return fread(buffer, size, 1, vff->file);
 83}
 84
 85ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size) {
 86	struct VFileFILE* vff = (struct VFileFILE*) vf;
 87	return fwrite(buffer, size, 1, vff->file);
 88}
 89
 90static void* _vffMap(struct VFile* vf, size_t size, int flags) {
 91	struct VFileFILE* vff = (struct VFileFILE*) vf;
 92	if (flags & MAP_WRITE) {
 93		vff->writable = true;
 94	}
 95	void* mem = anonymousMemoryMap(size);
 96	if (!mem) {
 97		return 0;
 98	}
 99	long pos = ftell(vff->file);
100	fseek(vff->file, 0, SEEK_SET);
101	fread(mem, size, 1, vff->file);
102	fseek(vff->file, pos, SEEK_SET);
103	return mem;
104}
105
106static void _vffUnmap(struct VFile* vf, void* memory, size_t size) {
107	struct VFileFILE* vff = (struct VFileFILE*) vf;
108	if (vff->writable) {
109		long pos = ftell(vff->file);
110		fseek(vff->file, 0, SEEK_SET);
111		fwrite(memory, size, 1, vff->file);
112		fseek(vff->file, pos, SEEK_SET);
113	}
114	mappedMemoryFree(memory, size);
115}
116
117static void _vffTruncate(struct VFile* vf, size_t size) {
118	struct VFileFILE* vff = (struct VFileFILE*) vf;
119	long pos = ftell(vff->file);
120	fseek(vff->file, 0, SEEK_END);
121	ssize_t realSize = ftell(vff->file);
122	if (realSize < 0) {
123		return;
124	}
125	while (size > (size_t) realSize) {
126		static const char zeros[128] = "";
127		size_t diff = size - realSize;
128		if (diff > sizeof(zeros)) {
129			diff = sizeof(zeros);
130		}
131		fwrite(zeros, diff, 1, vff->file);
132		realSize += diff;
133	}
134	fseek(vff->file, pos, SEEK_SET);
135}
136
137static ssize_t _vffSize(struct VFile* vf) {
138	struct VFileFILE* vff = (struct VFileFILE*) vf;
139	long pos = ftell(vff->file);
140	fseek(vff->file, 0, SEEK_END);
141	ssize_t size = ftell(vff->file);
142	fseek(vff->file, pos, SEEK_SET);
143	return size;
144}
145
146static bool _vffSync(struct VFile* vf, const void* buffer, size_t size) {
147	struct VFileFILE* vff = (struct VFileFILE*) vf;
148	if (buffer && size) {
149		long pos = ftell(vff->file);
150		fseek(vff->file, 0, SEEK_SET);
151		fwrite(buffer, size, 1, vff->file);
152		fseek(vff->file, pos, SEEK_SET);
153	}
154	return fflush(vff->file) == 0;
155}