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 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
141 u32 sizeWritten;
142 FSFILE_Write(vf3d->handle, &sizeWritten, 0, memory, size, FS_WRITE_FLUSH);
143 mappedMemoryFree(memory, size);
144}
145
146static void _vf3dTruncate(struct VFile* vf, size_t size) {
147 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
148 FSFILE_SetSize(vf3d->handle, size);
149}
150
151ssize_t _vf3dSize(struct VFile* vf) {
152 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
153 u64 size;
154 FSFILE_GetSize(vf3d->handle, &size);
155 return size;
156}
157
158static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) {
159 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
160 if (buffer) {
161 u32 sizeWritten;
162 Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH);
163 if (res) {
164 return false;
165 }
166 }
167 FSFILE_Flush(vf3d->handle);
168 return true;
169}
170
171struct VDir* VDirOpen(const char* path) {
172 struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS));
173 if (!vd3d) {
174 return 0;
175 }
176
177 FS_path newPath = FS_makePath(PATH_CHAR, path);
178 Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
179 if (res & 0xFFFC03FF) {
180 free(vd3d);
181 return 0;
182 }
183
184 vd3d->path = strdup(path);
185
186 vd3d->d.close = _vd3dClose;
187 vd3d->d.rewind = _vd3dRewind;
188 vd3d->d.listNext = _vd3dListNext; //// Crashes here for no good reason
189 vd3d->d.openFile = _vd3dOpenFile;
190
191 vd3d->vde.d.name = _vd3deName;
192 vd3d->vde.d.type = _vd3deType;
193
194 return &vd3d->d;
195}
196
197static bool _vd3dClose(struct VDir* vd) {
198 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
199 FSDIR_Close(vd3d->handle);
200 free(vd3d->path);
201 free(vd3d);
202 return true;
203}
204
205static void _vd3dRewind(struct VDir* vd) {
206 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
207 FSDIR_Close(vd3d->handle);
208 FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path);
209 FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
210}
211
212static struct VDirEntry* _vd3dListNext(struct VDir* vd) {
213 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
214 u32 n = 0;
215 memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent));
216 memset(vd3d->vde.utf8Name, 0, sizeof(vd3d->vde.utf8Name));
217 FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent);
218 if (!n) {
219 return 0;
220 }
221 return &vd3d->vde.d;
222}
223
224static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) {
225 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
226 if (!path) {
227 return 0;
228 }
229 const char* dir = vd3d->path;
230 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
231 sprintf(combined, "%s/%s", dir, path);
232
233 struct VFile* file = VFileOpen(combined, mode);
234 free(combined);
235 return file;
236}
237
238static const char* _vd3deName(struct VDirEntry* vde) {
239 struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
240 if (!vd3de->utf8Name[0]) {
241 utf16_to_utf8(vd3de->utf8Name, vd3de->ent.name, sizeof(vd3de->ent.name));
242 }
243 return vd3de->utf8Name;
244}
245
246static enum VFSType _vd3deType(struct VDirEntry* vde) {
247 struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
248 if (vd3de->ent.isDirectory) {
249 return VFS_DIRECTORY;
250 }
251 return VFS_FILE;
252}
253#endif