all repos — mgba @ 1402593855729beaca177d43700eb462bd8c123d

mGBA Game Boy Advance Emulator

src/util/vfs/vfs-mem.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 <mgba-util/vfs.h>
  7#include <mgba-util/math.h>
  8#include <mgba-util/memory.h>
  9
 10struct VFileMem {
 11	struct VFile d;
 12	void* mem;
 13	size_t size;
 14	size_t bufferSize;
 15	size_t offset;
 16};
 17
 18static bool _vfmClose(struct VFile* vf);
 19static bool _vfmCloseFree(struct VFile* vf);
 20static off_t _vfmSeek(struct VFile* vf, off_t offset, int whence);
 21static off_t _vfmSeekExpanding(struct VFile* vf, off_t offset, int whence);
 22static ssize_t _vfmRead(struct VFile* vf, void* buffer, size_t size);
 23static ssize_t _vfmWrite(struct VFile* vf, const void* buffer, size_t size);
 24static ssize_t _vfmWriteExpanding(struct VFile* vf, const void* buffer, size_t size);
 25static ssize_t _vfmWriteNoop(struct VFile* vf, const void* buffer, size_t size);
 26static void* _vfmMap(struct VFile* vf, size_t size, int flags);
 27static void _vfmUnmap(struct VFile* vf, void* memory, size_t size);
 28static void _vfmTruncate(struct VFile* vf, size_t size);
 29static void _vfmTruncateNoop(struct VFile* vf, size_t size);
 30static ssize_t _vfmSize(struct VFile* vf);
 31static bool _vfmSync(struct VFile* vf, const void* buffer, size_t size);
 32
 33struct VFile* VFileFromMemory(void* mem, size_t size) {
 34	if (!mem || !size) {
 35		return 0;
 36	}
 37
 38	struct VFileMem* vfm = malloc(sizeof(struct VFileMem));
 39	if (!vfm) {
 40		return 0;
 41	}
 42
 43	vfm->mem = mem;
 44	vfm->size = size;
 45	vfm->bufferSize = size;
 46	vfm->offset = 0;
 47	vfm->d.close = _vfmClose;
 48	vfm->d.seek = _vfmSeek;
 49	vfm->d.read = _vfmRead;
 50	vfm->d.readline = VFileReadline;
 51	vfm->d.write = _vfmWrite;
 52	vfm->d.map = _vfmMap;
 53	vfm->d.unmap = _vfmUnmap;
 54	vfm->d.truncate = _vfmTruncateNoop;
 55	vfm->d.size = _vfmSize;
 56	vfm->d.sync = _vfmSync;
 57
 58	return &vfm->d;
 59}
 60
 61struct VFile* VFileFromConstMemory(const void* mem, size_t size) {
 62	if (!mem || !size) {
 63		return 0;
 64	}
 65
 66	struct VFileMem* vfm = malloc(sizeof(struct VFileMem));
 67	if (!vfm) {
 68		return 0;
 69	}
 70
 71	vfm->mem = (void*) mem;
 72	vfm->size = size;
 73	vfm->bufferSize = size;
 74	vfm->offset = 0;
 75	vfm->d.close = _vfmClose;
 76	vfm->d.seek = _vfmSeek;
 77	vfm->d.read = _vfmRead;
 78	vfm->d.readline = VFileReadline;
 79	vfm->d.write = _vfmWriteNoop;
 80	vfm->d.map = _vfmMap;
 81	vfm->d.unmap = _vfmUnmap;
 82	vfm->d.truncate = _vfmTruncateNoop;
 83	vfm->d.size = _vfmSize;
 84	vfm->d.sync = _vfmSync;
 85
 86	return &vfm->d;
 87}
 88
 89struct VFile* VFileMemChunk(const void* mem, size_t size) {
 90	struct VFileMem* vfm = malloc(sizeof(struct VFileMem));
 91	if (!vfm) {
 92		return 0;
 93	}
 94
 95	vfm->size = size;
 96	vfm->bufferSize = toPow2(size);
 97	if (size) {
 98		vfm->mem = anonymousMemoryMap(vfm->bufferSize);
 99		if (mem) {
100			memcpy(vfm->mem, mem, size);
101		}
102	} else {
103		vfm->mem = 0;
104	}
105	vfm->offset = 0;
106	vfm->d.close = _vfmCloseFree;
107	vfm->d.seek = _vfmSeekExpanding;
108	vfm->d.read = _vfmRead;
109	vfm->d.readline = VFileReadline;
110	vfm->d.write = _vfmWriteExpanding;
111	vfm->d.map = _vfmMap;
112	vfm->d.unmap = _vfmUnmap;
113	vfm->d.truncate = _vfmTruncate;
114	vfm->d.size = _vfmSize;
115	vfm->d.sync = _vfmSync;
116
117	return &vfm->d;
118}
119
120void _vfmExpand(struct VFileMem* vfm, size_t newSize) {
121	size_t alignedSize = toPow2(newSize);
122	if (alignedSize > vfm->bufferSize) {
123		void* oldBuf = vfm->mem;
124		vfm->mem = anonymousMemoryMap(alignedSize);
125		if (oldBuf) {
126			if (newSize < vfm->size) {
127				memcpy(vfm->mem, oldBuf, newSize);
128			} else {
129				memcpy(vfm->mem, oldBuf, vfm->size);
130			}
131			mappedMemoryFree(oldBuf, vfm->bufferSize);
132		}
133		vfm->bufferSize = alignedSize;
134	}
135	vfm->size = newSize;
136}
137
138bool _vfmClose(struct VFile* vf) {
139	struct VFileMem* vfm = (struct VFileMem*) vf;
140	vfm->mem = 0;
141	free(vfm);
142	return true;
143}
144
145bool _vfmCloseFree(struct VFile* vf) {
146	struct VFileMem* vfm = (struct VFileMem*) vf;
147	mappedMemoryFree(vfm->mem, vfm->bufferSize);
148	vfm->mem = 0;
149	free(vfm);
150	return true;
151}
152
153off_t _vfmSeek(struct VFile* vf, off_t offset, int whence) {
154	struct VFileMem* vfm = (struct VFileMem*) vf;
155
156	size_t position;
157	switch (whence) {
158	case SEEK_SET:
159		if (offset < 0) {
160			return -1;
161		}
162		position = offset;
163		break;
164	case SEEK_CUR:
165		if (offset < 0 && ((vfm->offset < (size_t) -offset) || (offset == INT_MIN))) {
166			return -1;
167		}
168		position = vfm->offset + offset;
169		break;
170	case SEEK_END:
171		if (offset < 0 && ((vfm->size < (size_t) -offset) || (offset == INT_MIN))) {
172			return -1;
173		}
174		position = vfm->size + offset;
175		break;
176	default:
177		return -1;
178	}
179
180	if (position > vfm->size) {
181		return -1;
182	}
183
184	vfm->offset = position;
185	return position;
186}
187
188off_t _vfmSeekExpanding(struct VFile* vf, off_t offset, int whence) {
189	struct VFileMem* vfm = (struct VFileMem*) vf;
190
191	size_t position;
192	switch (whence) {
193	case SEEK_SET:
194		if (offset < 0) {
195			return -1;
196		}
197		position = offset;
198		break;
199	case SEEK_CUR:
200		if (offset < 0 && ((vfm->offset < (size_t) -offset) || (offset == INT_MIN))) {
201			return -1;
202		}
203		position = vfm->offset + offset;
204		break;
205	case SEEK_END:
206		if (offset < 0 && ((vfm->size < (size_t) -offset) || (offset == INT_MIN))) {
207			return -1;
208		}
209		position = vfm->size + offset;
210		break;
211	default:
212		return -1;
213	}
214
215	if (position > vfm->size) {
216		_vfmExpand(vfm, position);
217	}
218
219	vfm->offset = position;
220	return position;
221}
222
223ssize_t _vfmRead(struct VFile* vf, void* buffer, size_t size) {
224	struct VFileMem* vfm = (struct VFileMem*) vf;
225
226	if (size + vfm->offset >= vfm->size) {
227		size = vfm->size - vfm->offset;
228	}
229
230	memcpy(buffer, (void*) ((uintptr_t) vfm->mem + vfm->offset), size);
231	vfm->offset += size;
232	return size;
233}
234
235ssize_t _vfmWrite(struct VFile* vf, const void* buffer, size_t size) {
236	struct VFileMem* vfm = (struct VFileMem*) vf;
237
238	if (size + vfm->offset >= vfm->size) {
239		size = vfm->size - vfm->offset;
240	}
241
242	memcpy((void*) ((uintptr_t) vfm->mem + vfm->offset), buffer, size);
243	vfm->offset += size;
244	return size;
245}
246
247ssize_t _vfmWriteExpanding(struct VFile* vf, const void* buffer, size_t size) {
248	struct VFileMem* vfm = (struct VFileMem*) vf;
249
250	if (size + vfm->offset > vfm->size) {
251		_vfmExpand(vfm, vfm->offset + size);
252	}
253
254	memcpy((void*) ((uintptr_t) vfm->mem + vfm->offset), buffer, size);
255	vfm->offset += size;
256	return size;
257}
258
259
260ssize_t _vfmWriteNoop(struct VFile* vf, const void* buffer, size_t size) {
261	UNUSED(vf);
262	UNUSED(buffer);
263	UNUSED(size);
264	return -1;
265}
266
267void* _vfmMap(struct VFile* vf, size_t size, int flags) {
268	struct VFileMem* vfm = (struct VFileMem*) vf;
269
270	UNUSED(flags);
271	if (size > vfm->size) {
272		return 0;
273	}
274
275	return vfm->mem;
276}
277
278void _vfmUnmap(struct VFile* vf, void* memory, size_t size) {
279	UNUSED(vf);
280	UNUSED(memory);
281	UNUSED(size);
282}
283
284void _vfmTruncate(struct VFile* vf, size_t size) {
285	struct VFileMem* vfm = (struct VFileMem*) vf;
286	_vfmExpand(vfm, size);
287}
288
289void _vfmTruncateNoop(struct VFile* vf, size_t size) {
290	// TODO: Return value?
291	UNUSED(vf);
292	UNUSED(size);
293}
294
295ssize_t _vfmSize(struct VFile* vf) {
296	struct VFileMem* vfm = (struct VFileMem*) vf;
297	return vfm->size;
298}
299
300bool _vfmSync(struct VFile* vf, const void* buffer, size_t size) {
301	UNUSED(vf);
302	UNUSED(buffer);
303	UNUSED(size);
304	return true;
305}