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