all repos — mgba @ 41452ec4e6ab7d914409b9ed52fd661a654907d0

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