all repos — mgba @ fb82257d03d8ad01b2353513f11981308ee47126

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