all repos — mgba @ 85298a0a54ed4ebdee218af29a7220ddf1697cb4

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