all repos — mgba @ 7177af28f8de39c21a2363b794048de1b915156b

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