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/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}