all repos — mgba @ 4c38f769565e8ddd7d3a8eef1a41975206c129a0

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		memcpy(vfm->mem, oldBuf, vfm->size);
120		mappedMemoryFree(oldBuf, vfm->size);
121	}
122	vfm->size = newSize;
123}
124
125bool _vfmClose(struct VFile* vf) {
126	struct VFileMem* vfm = (struct VFileMem*) vf;
127	vfm->mem = 0;
128	free(vfm);
129	return true;
130}
131
132bool _vfmCloseFree(struct VFile* vf) {
133	struct VFileMem* vfm = (struct VFileMem*) vf;
134	mappedMemoryFree(vfm->mem, vfm->size);
135	vfm->mem = 0;
136	free(vfm);
137	return true;
138}
139
140off_t _vfmSeek(struct VFile* vf, off_t offset, int whence) {
141	struct VFileMem* vfm = (struct VFileMem*) vf;
142
143	size_t position;
144	switch (whence) {
145	case SEEK_SET:
146		if (offset < 0) {
147			return -1;
148		}
149		position = offset;
150		break;
151	case SEEK_CUR:
152		if (offset < 0 && ((vfm->offset < (size_t) -offset) || (offset == INT_MIN))) {
153			return -1;
154		}
155		position = vfm->offset + offset;
156		break;
157	case SEEK_END:
158		if (offset < 0 && ((vfm->size < (size_t) -offset) || (offset == INT_MIN))) {
159			return -1;
160		}
161		position = vfm->size + offset;
162		break;
163	default:
164		return -1;
165	}
166
167	if (position > vfm->size) {
168		return -1;
169	}
170
171	vfm->offset = position;
172	return position;
173}
174
175off_t _vfmSeekExpanding(struct VFile* vf, off_t offset, int whence) {
176	struct VFileMem* vfm = (struct VFileMem*) vf;
177
178	size_t position;
179	switch (whence) {
180	case SEEK_SET:
181		if (offset < 0) {
182			return -1;
183		}
184		position = offset;
185		break;
186	case SEEK_CUR:
187		if (offset < 0 && ((vfm->offset < (size_t) -offset) || (offset == INT_MIN))) {
188			return -1;
189		}
190		position = vfm->offset + offset;
191		break;
192	case SEEK_END:
193		if (offset < 0 && ((vfm->size < (size_t) -offset) || (offset == INT_MIN))) {
194			return -1;
195		}
196		position = vfm->size + offset;
197		break;
198	default:
199		return -1;
200	}
201
202	if (position > vfm->size) {
203		_vfmExpand(vfm, position);
204	}
205
206	vfm->offset = position;
207	return position;
208}
209
210ssize_t _vfmRead(struct VFile* vf, void* buffer, size_t size) {
211	struct VFileMem* vfm = (struct VFileMem*) vf;
212
213	if (size + vfm->offset >= vfm->size) {
214		size = vfm->size - vfm->offset;
215	}
216
217	memcpy(buffer, (void*) ((uintptr_t) vfm->mem + vfm->offset), size);
218	vfm->offset += size;
219	return size;
220}
221
222ssize_t _vfmWrite(struct VFile* vf, const void* buffer, size_t size) {
223	struct VFileMem* vfm = (struct VFileMem*) vf;
224
225	if (size + vfm->offset >= vfm->size) {
226		size = vfm->size - vfm->offset;
227	}
228
229	memcpy((void*) ((uintptr_t) vfm->mem + vfm->offset), buffer, size);
230	vfm->offset += size;
231	return size;
232}
233
234ssize_t _vfmWriteExpanding(struct VFile* vf, const void* buffer, size_t size) {
235	struct VFileMem* vfm = (struct VFileMem*) vf;
236
237	if (size + vfm->offset >= vfm->size) {
238		_vfmExpand(vfm, vfm->offset + size);
239	}
240
241	memcpy((void*) ((uintptr_t) vfm->mem + vfm->offset), buffer, size);
242	vfm->offset += size;
243	return size;
244}
245
246
247ssize_t _vfmWriteNoop(struct VFile* vf, const void* buffer, size_t size) {
248	UNUSED(vf);
249	UNUSED(buffer);
250	UNUSED(size);
251	return -1;
252}
253
254void* _vfmMap(struct VFile* vf, size_t size, int flags) {
255	struct VFileMem* vfm = (struct VFileMem*) vf;
256
257	UNUSED(flags);
258	if (size > vfm->size) {
259		return 0;
260	}
261
262	return vfm->mem;
263}
264
265void _vfmUnmap(struct VFile* vf, void* memory, size_t size) {
266	UNUSED(vf);
267	UNUSED(memory);
268	UNUSED(size);
269}
270
271void _vfmTruncate(struct VFile* vf, size_t size) {
272	struct VFileMem* vfm = (struct VFileMem*) vf;
273	if (size > vfm->size) {
274		_vfmExpand(vfm, size);
275	} else {
276		// TODO
277	}
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}