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}