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