all repos — mgba @ 697b550b375fb5df76f4bdb2ff2f6437858eca26

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};
 17
 18static bool _vffClose(struct VFile* vf);
 19static off_t _vffSeek(struct VFile* vf, off_t offset, int whence);
 20static ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size);
 21static ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size);
 22static void* _vffMap(struct VFile* vf, size_t size, int flags);
 23static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
 24static void _vffTruncate(struct VFile* vf, size_t size);
 25static ssize_t _vffSize(struct VFile* vf);
 26
 27struct VFile* VFileFOpen(const char* path, const char* mode) {
 28	if (!path && !mode) {
 29		return 0;
 30	}
 31	FILE* file = fopen(path, mode);
 32	if (!file && errno == ENOENT && strcmp(mode, "r+b") == 0) {
 33		file = fopen(path, "w+b");
 34	}
 35	return VFileFromFILE(file);
 36}
 37
 38struct VFile* VFileFromFILE(FILE* file) {
 39	if (!file) {
 40		return 0;
 41	}
 42
 43	struct VFileFILE* vff = malloc(sizeof(struct VFileFILE));
 44	if (!vff) {
 45		return 0;
 46	}
 47
 48	vff->file = file;
 49	vff->d.close = _vffClose;
 50	vff->d.seek = _vffSeek;
 51	vff->d.read = _vffRead;
 52	vff->d.readline = VFileReadline;
 53	vff->d.write = _vffWrite;
 54	vff->d.map = _vffMap;
 55	vff->d.unmap = _vffUnmap;
 56	vff->d.truncate = _vffTruncate;
 57	vff->d.size = _vffSize;
 58
 59	return &vff->d;
 60}
 61
 62bool _vffClose(struct VFile* vf) {
 63	struct VFileFILE* vff = (struct VFileFILE*) vf;
 64	if (fclose(vff->file) < 0) {
 65		return false;
 66	}
 67	free(vff);
 68	return true;
 69}
 70
 71off_t _vffSeek(struct VFile* vf, off_t offset, int whence) {
 72	struct VFileFILE* vff = (struct VFileFILE*) vf;
 73	return fseek(vff->file, offset, whence);
 74}
 75
 76ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) {
 77	struct VFileFILE* vff = (struct VFileFILE*) vf;
 78	return fread(buffer, size, 1, vff->file);
 79}
 80
 81ssize_t _vffWrite(struct VFile* vf, const void* buffer, size_t size) {
 82	struct VFileFILE* vff = (struct VFileFILE*) vf;
 83	return fwrite(buffer, size, 1, vff->file);
 84}
 85
 86static void* _vffMap(struct VFile* vf, size_t size, int flags) {
 87	UNUSED(flags);
 88	struct VFileFILE* vff = (struct VFileFILE*) vf;
 89	void* mem = anonymousMemoryMap(size);
 90	if (!mem) {
 91		return 0;
 92	}
 93	long pos = ftell(vff->file);
 94	fseek(vff->file, 0, SEEK_SET);
 95	fread(mem, size, 1, vff->file);
 96	fseek(vff->file, pos, SEEK_SET);
 97	return mem;
 98}
 99
100static void _vffUnmap(struct VFile* vf, void* memory, size_t size) {
101	struct VFileFILE* vff = (struct VFileFILE*) vf;
102	long pos = ftell(vff->file);
103	fseek(vff->file, 0, SEEK_SET);
104	fwrite(memory, size, 1, vff->file);
105	fseek(vff->file, pos, SEEK_SET);
106	mappedMemoryFree(memory, size);
107}
108
109static void _vffTruncate(struct VFile* vf, size_t size) {
110	struct VFileFILE* vff = (struct VFileFILE*) vf;
111	long pos = ftell(vff->file);
112	fseek(vff->file, 0, SEEK_END);
113	ssize_t realSize = ftell(vff->file);
114	if (realSize < 0) {
115		return;
116	}
117	while (size > (size_t) realSize) {
118		static const char zeros[128] = "";
119		size_t diff = size - realSize;
120		if (diff > sizeof(zeros)) {
121			diff = sizeof(zeros);
122		}
123		fwrite(zeros, diff, 1, vff->file);
124		realSize += diff;
125	}
126	fseek(vff->file, pos, SEEK_SET);
127}
128
129static ssize_t _vffSize(struct VFile* vf) {
130	struct VFileFILE* vff = (struct VFileFILE*) vf;
131	long pos = ftell(vff->file);
132	fseek(vff->file, 0, SEEK_END);
133	ssize_t size = ftell(vff->file);
134	fseek(vff->file, pos, SEEK_SET);
135	return size;
136}