all repos — mgba @ 6d898542c765f4efc4a094c5ebd3f3465c36f417

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