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