all repos — mgba @ 8e99508717c7c5e2316c50a03dd156d4d86bceeb

mGBA Game Boy Advance Emulator

src/platform/3ds/3ds-vfs.c (view raw)

  1/* Copyright (c) 2013-2014 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 "3ds-vfs.h"
  7
  8#ifdef USE_VFS_3DS
  9#include "util/memory.h"
 10#include "util/string.h"
 11
 12struct VFile3DS {
 13	struct VFile d;
 14
 15	Handle handle;
 16	u64 offset;
 17};
 18
 19struct VDirEntry3DS {
 20	struct VDirEntry d;
 21	FS_DirectoryEntry ent;
 22	char utf8Name[256];
 23};
 24
 25struct VDir3DS {
 26	struct VDir d;
 27
 28	char* path;
 29	Handle handle;
 30	struct VDirEntry3DS vde;
 31};
 32
 33static bool _vf3dClose(struct VFile* vf);
 34static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence);
 35static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size);
 36static ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size);
 37static void* _vf3dMap(struct VFile* vf, size_t size, int flags);
 38static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size);
 39static void _vf3dTruncate(struct VFile* vf, size_t size);
 40static ssize_t _vf3dSize(struct VFile* vf);
 41static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size);
 42
 43static bool _vd3dClose(struct VDir* vd);
 44static void _vd3dRewind(struct VDir* vd);
 45static struct VDirEntry* _vd3dListNext(struct VDir* vd);
 46static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode);
 47static struct VDir* _vd3dOpenDir(struct VDir* vd, const char* path);
 48
 49static const char* _vd3deName(struct VDirEntry* vde);
 50static enum VFSType _vd3deType(struct VDirEntry* vde);
 51
 52struct VFile* VFileOpen3DS(FS_Archive* archive, const char* path, int flags) {
 53	struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS));
 54	if (!vf3d) {
 55		return 0;
 56	}
 57
 58	// TODO: Use UTF-16
 59	FS_Path newPath = fsMakePath(PATH_ASCII, path);
 60	Result res = FSUSER_OpenFile(&vf3d->handle, *archive, newPath, flags, 0);
 61	if (res & 0xFFFC03FF) {
 62		free(vf3d);
 63		return 0;
 64	}
 65
 66	vf3d->offset = 0;
 67
 68	vf3d->d.close = _vf3dClose;
 69	vf3d->d.seek = _vf3dSeek;
 70	vf3d->d.read = _vf3dRead;
 71	vf3d->d.readline = VFileReadline;
 72	vf3d->d.write = _vf3dWrite;
 73	vf3d->d.map = _vf3dMap;
 74	vf3d->d.unmap = _vf3dUnmap;
 75	vf3d->d.truncate = _vf3dTruncate;
 76	vf3d->d.size = _vf3dSize;
 77	vf3d->d.sync = _vf3dSync;
 78
 79	return &vf3d->d;
 80}
 81
 82bool _vf3dClose(struct VFile* vf) {
 83	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
 84
 85	FSFILE_Close(vf3d->handle);
 86	svcCloseHandle(vf3d->handle);
 87	return true;
 88}
 89
 90off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence) {
 91	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
 92	u64 size;
 93	switch (whence) {
 94	case SEEK_SET:
 95		vf3d->offset = offset;
 96		break;
 97	case SEEK_END:
 98		FSFILE_GetSize(vf3d->handle, &size);
 99		vf3d->offset = size;
100		// Fall through
101	case SEEK_CUR:
102		vf3d->offset += offset;
103		break;
104	}
105	return vf3d->offset;
106}
107
108ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size) {
109	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
110	u32 sizeRead;
111	Result res = FSFILE_Read(vf3d->handle, &sizeRead, vf3d->offset, buffer, size);
112	if (res) {
113		return -1;
114	}
115	vf3d->offset += sizeRead;
116	return sizeRead;
117}
118
119ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size) {
120	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
121	u32 sizeWritten;
122	Result res = FSFILE_Write(vf3d->handle, &sizeWritten, vf3d->offset, buffer, size, FS_WRITE_FLUSH);
123	if (res) {
124		return -1;
125	}
126	vf3d->offset += sizeWritten;
127	return sizeWritten;
128}
129
130static void* _vf3dMap(struct VFile* vf, size_t size, int flags) {
131	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
132	UNUSED(flags);
133	void* buffer = anonymousMemoryMap(size);
134	if (buffer) {
135		u32 sizeRead;
136		FSFILE_Read(vf3d->handle, &sizeRead, 0, buffer, size);
137	}
138	return buffer;
139}
140
141static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size) {
142	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
143	u32 sizeWritten;
144	FSFILE_Write(vf3d->handle, &sizeWritten, 0, memory, size, FS_WRITE_FLUSH);
145	mappedMemoryFree(memory, size);
146}
147
148static void _vf3dTruncate(struct VFile* vf, size_t size) {
149	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
150	FSFILE_SetSize(vf3d->handle, size);
151}
152
153ssize_t _vf3dSize(struct VFile* vf) {
154	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
155	u64 size;
156	FSFILE_GetSize(vf3d->handle, &size);
157	return size;
158}
159
160static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) {
161	struct VFile3DS* vf3d = (struct VFile3DS*) vf;
162	if (buffer) {
163		u32 sizeWritten;
164		Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH);
165		if (res) {
166			return false;
167		}
168	}
169	FSFILE_Flush(vf3d->handle);
170	return true;
171}
172
173struct VDir* VDirOpen(const char* path) {
174	struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS));
175	if (!vd3d) {
176		return 0;
177	}
178
179	// TODO: Use UTF-16
180	FS_Path newPath = fsMakePath(PATH_ASCII, path);
181	Result res = FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath);
182	if (res & 0xFFFC03FF) {
183		free(vd3d);
184		return 0;
185	}
186
187	vd3d->path = strdup(path);
188
189	vd3d->d.close = _vd3dClose;
190	vd3d->d.rewind = _vd3dRewind;
191	vd3d->d.listNext = _vd3dListNext;
192	vd3d->d.openFile = _vd3dOpenFile;
193	vd3d->d.openDir = _vd3dOpenDir;
194
195	vd3d->vde.d.name = _vd3deName;
196	vd3d->vde.d.type = _vd3deType;
197
198	return &vd3d->d;
199}
200
201static bool _vd3dClose(struct VDir* vd) {
202	struct VDir3DS* vd3d = (struct VDir3DS*) vd;
203	FSDIR_Close(vd3d->handle);
204	free(vd3d->path);
205	free(vd3d);
206	return true;
207}
208
209static void _vd3dRewind(struct VDir* vd) {
210	struct VDir3DS* vd3d = (struct VDir3DS*) vd;
211	FSDIR_Close(vd3d->handle);
212	// TODO: Use UTF-16
213	FS_Path newPath = fsMakePath(PATH_ASCII, vd3d->path);
214	FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath);
215}
216
217static struct VDirEntry* _vd3dListNext(struct VDir* vd) {
218	struct VDir3DS* vd3d = (struct VDir3DS*) vd;
219	u32 n = 0;
220	memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent));
221	memset(vd3d->vde.utf8Name, 0, sizeof(vd3d->vde.utf8Name));
222	FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent);
223	if (!n) {
224		return 0;
225	}
226	return &vd3d->vde.d;
227}
228
229static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) {
230	struct VDir3DS* vd3d = (struct VDir3DS*) vd;
231	if (!path) {
232		return 0;
233	}
234	const char* dir = vd3d->path;
235	char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
236	sprintf(combined, "%s/%s", dir, path);
237
238	struct VFile* file = VFileOpen(combined, mode);
239	free(combined);
240	return file;
241}
242
243static struct VDir* _vd3dOpenDir(struct VDir* vd, const char* path) {
244	struct VDir3DS* vd3d = (struct VDir3DS*) vd;
245	if (!path) {
246		return 0;
247	}
248	const char* dir = vd3d->path;
249	char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
250	sprintf(combined, "%s/%s", dir, path);
251
252	struct VDir* vd2 = VDirOpen(combined);
253	if (!vd2) {
254		vd2 = VDirOpenArchive(combined);
255	}
256	free(combined);
257	return vd2;
258}
259
260static const char* _vd3deName(struct VDirEntry* vde) {
261	struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
262	if (!vd3de->utf8Name[0]) {
263		utf16_to_utf8(vd3de->utf8Name, vd3de->ent.name, sizeof(vd3de->utf8Name));
264	}
265	return vd3de->utf8Name;
266}
267
268static enum VFSType _vd3deType(struct VDirEntry* vde) {
269	struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
270	if (vd3de->ent.attributes & FS_ATTRIBUTE_DIRECTORY) {
271		return VFS_DIRECTORY;
272	}
273	return VFS_FILE;
274}
275#endif