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#include "util/memory.h"
9#include "util/string.h"
10
11struct VFile3DS {
12 struct VFile d;
13
14 Handle handle;
15 u64 offset;
16};
17
18struct VDirEntry3DS {
19 struct VDirEntry d;
20 FS_dirent ent;
21 char* utf8Name;
22};
23
24struct VDir3DS {
25 struct VDir d;
26
27 char* path;
28 Handle handle;
29 struct VDirEntry3DS vde;
30};
31
32static bool _vf3dClose(struct VFile* vf);
33static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence);
34static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size);
35static ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size);
36static void* _vf3dMap(struct VFile* vf, size_t size, int flags);
37static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size);
38static void _vf3dTruncate(struct VFile* vf, size_t size);
39static ssize_t _vf3dSize(struct VFile* vf);
40static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size);
41
42static bool _vd3dClose(struct VDir* vd);
43static void _vd3dRewind(struct VDir* vd);
44static struct VDirEntry* _vd3dListNext(struct VDir* vd);
45static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode);
46
47static const char* _vd3deName(struct VDirEntry* vde);
48
49struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags) {
50 struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS));
51 if (!vf3d) {
52 return 0;
53 }
54
55 FS_path newPath = FS_makePath(PATH_CHAR, path);
56 Result res = FSUSER_OpenFile(0, &vf3d->handle, *archive, newPath, flags, FS_ATTRIBUTE_NONE);
57 if (res & 0xFFFC03FF) {
58 free(vf3d);
59 return 0;
60 }
61
62 vf3d->offset = 0;
63
64 vf3d->d.close = _vf3dClose;
65 vf3d->d.seek = _vf3dSeek;
66 vf3d->d.read = _vf3dRead;
67 vf3d->d.readline = 0;
68 vf3d->d.write = _vf3dWrite;
69 vf3d->d.map = _vf3dMap;
70 vf3d->d.unmap = _vf3dUnmap;
71 vf3d->d.truncate = _vf3dTruncate;
72 vf3d->d.size = _vf3dSize;
73 vf3d->d.sync = _vf3dSync;
74
75 return &vf3d->d;
76}
77
78bool _vf3dClose(struct VFile* vf) {
79 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
80
81 FSFILE_Close(vf3d->handle);
82 svcCloseHandle(vf3d->handle);
83 return true;
84}
85
86off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence) {
87 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
88 u64 size;
89 switch (whence) {
90 case SEEK_SET:
91 vf3d->offset = offset;
92 break;
93 case SEEK_END:
94 FSFILE_GetSize(vf3d->handle, &size);
95 vf3d->offset = size;
96 // Fall through
97 case SEEK_CUR:
98 vf3d->offset += offset;
99 break;
100 }
101 return vf3d->offset;
102}
103
104ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size) {
105 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
106 u32 sizeRead;
107 Result res = FSFILE_Read(vf3d->handle, &sizeRead, vf3d->offset, buffer, size);
108 if (res) {
109 return -1;
110 }
111 vf3d->offset += sizeRead;
112 return sizeRead;
113}
114
115ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size) {
116 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
117 u32 sizeWritten;
118 Result res = FSFILE_Write(vf3d->handle, &sizeWritten, vf3d->offset, buffer, size, FS_WRITE_FLUSH);
119 if (res) {
120 return -1;
121 }
122 vf3d->offset += sizeWritten;
123 return sizeWritten;
124}
125
126static void* _vf3dMap(struct VFile* vf, size_t size, int flags) {
127 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
128 UNUSED(flags);
129 void* buffer = anonymousMemoryMap(size);
130 if (buffer) {
131 u32 sizeRead;
132 FSFILE_Read(vf3d->handle, &sizeRead, 0, buffer, size);
133 }
134 return buffer;
135}
136
137static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size) {
138 UNUSED(vf);
139 mappedMemoryFree(memory, size);
140}
141
142static void _vf3dTruncate(struct VFile* vf, size_t size) {
143 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
144 FSFILE_SetSize(vf3d->handle, size);
145}
146
147ssize_t _vf3dSize(struct VFile* vf) {
148 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
149 u64 size;
150 FSFILE_GetSize(vf3d->handle, &size);
151 return size;
152}
153
154static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) {
155 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
156 if (buffer) {
157 u32 sizeWritten;
158 Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH);
159 if (res) {
160 return false;
161 }
162 }
163 FSFILE_Flush(vf3d->handle);
164 return true;
165}
166
167struct VDir* VDirOpen(const char* path) {
168 struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS));
169 if (!vd3d) {
170 return 0;
171 }
172
173 FS_path newPath = FS_makePath(PATH_CHAR, path);
174 Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
175 if (res & 0xFFFC03FF) {
176 free(vd3d);
177 return 0;
178 }
179
180 vd3d->path = strdup(path);
181
182 vd3d->d.close = _vd3dClose;
183 vd3d->d.rewind = _vd3dRewind;
184 vd3d->d.listNext = _vd3dListNext; //// Crashes here for no good reason
185 vd3d->d.openFile = _vd3dOpenFile;
186
187 vd3d->vde.d.name = _vd3deName;
188 vd3d->vde.utf8Name = 0;
189
190 return &vd3d->d;
191}
192
193static bool _vd3dClose(struct VDir* vd) {
194 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
195 FSDIR_Close(vd3d->handle);
196 free(vd3d->path);
197 if (vd3d->vde.utf8Name) {
198 free(vd3d->vde.utf8Name);
199 }
200 free(vd3d);
201 return true;
202}
203
204static void _vd3dRewind(struct VDir* vd) {
205 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
206 FSDIR_Close(vd3d->handle);
207 FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path);
208 FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
209}
210
211static struct VDirEntry* _vd3dListNext(struct VDir* vd) {
212 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
213 u32 n = 0;
214 memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent));
215 if (vd3d->vde.utf8Name) {
216 free(vd3d->vde.utf8Name);
217 vd3d->vde.utf8Name = 0;
218 };
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 const char* _vd3deName(struct VDirEntry* vde) {
241 struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
242 if (!vd3de->utf8Name) {
243 vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2);
244 }
245 return vd3de->utf8Name;
246}