all repos — mgba @ 6af9a742bda66c3785cd13f76895558eeac77725

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