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