src/util/vfs.c (view raw)
1/* Copyright (c) 2013-2015 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 "vfs.h"
7
8#include "util/string.h"
9
10#ifdef PSP2
11#include "platform/psp2/sce-vfs.h"
12#endif
13#ifdef _3DS
14#include "platform/3ds/3ds-vfs.h"
15#endif
16
17struct VFile* VFileOpen(const char* path, int flags) {
18#ifdef USE_VFS_FILE
19 const char* chflags;
20 switch (flags & O_ACCMODE) {
21 case O_WRONLY:
22 if (flags & O_APPEND) {
23 chflags = "ab";
24 } else {
25 chflags = "wb";
26 }
27 break;
28 case O_RDWR:
29 if (flags & O_APPEND) {
30 chflags = "a+b";
31 } else if (flags & O_TRUNC) {
32 chflags = "w+b";
33 } else {
34 chflags = "r+b";
35 }
36 break;
37 case O_RDONLY:
38 chflags = "rb";
39 break;
40 }
41 return VFileFOpen(path, chflags);
42#elif defined(PSP2)
43 int sceFlags = SCE_O_RDONLY;
44 switch (flags & O_ACCMODE) {
45 case O_WRONLY:
46 sceFlags = SCE_O_WRONLY;
47 break;
48 case O_RDWR:
49 sceFlags = SCE_O_RDWR;
50 break;
51 case O_RDONLY:
52 sceFlags = SCE_O_RDONLY;
53 break;
54 }
55
56 if (flags & O_APPEND) {
57 sceFlags |= SCE_O_APPEND;
58 }
59 if (flags & O_TRUNC) {
60 sceFlags |= SCE_O_TRUNC;
61 }
62 if (flags & O_CREAT) {
63 sceFlags |= SCE_O_CREAT;
64 }
65 return VFileOpenSce(path, sceFlags, 0666);
66#elif defined(USE_VFS_3DS)
67 int ctrFlags = FS_OPEN_READ;
68 switch (flags & O_ACCMODE) {
69 case O_WRONLY:
70 ctrFlags = FS_OPEN_WRITE;
71 break;
72 case O_RDWR:
73 ctrFlags = FS_OPEN_READ | FS_OPEN_WRITE;
74 break;
75 case O_RDONLY:
76 ctrFlags = FS_OPEN_READ;
77 break;
78 }
79
80 if (flags & O_CREAT) {
81 ctrFlags |= FS_OPEN_CREATE;
82 }
83 struct VFile* vf = VFileOpen3DS(&sdmcArchive, path, ctrFlags);
84 if (!vf) {
85 return 0;
86 }
87 if (flags & O_TRUNC) {
88 vf->truncate(vf, 0);
89 }
90 if (flags & O_APPEND) {
91 vf->seek(vf, vf->size(vf), SEEK_SET);
92 }
93 return vf;
94#else
95 return VFileOpenFD(path, flags);
96#endif
97}
98
99struct VDir* VDirOpenArchive(const char* path) {
100 struct VDir* dir = 0;
101 UNUSED(path);
102#if defined(USE_LIBZIP) || defined(USE_ZLIB)
103 if (!dir) {
104 dir = VDirOpenZip(path, 0);
105 }
106#endif
107#if USE_LZMA
108 if (!dir) {
109 dir = VDirOpen7z(path, 0);
110 }
111#endif
112 return dir;
113}
114
115ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size) {
116 size_t bytesRead = 0;
117 while (bytesRead < size - 1) {
118 ssize_t newRead = vf->read(vf, &buffer[bytesRead], 1);
119 if (newRead <= 0) {
120 break;
121 }
122 bytesRead += newRead;
123 if (buffer[bytesRead - newRead] == '\n') {
124 break;
125 }
126 }
127 buffer[bytesRead] = '\0';
128 return bytesRead;
129}
130
131ssize_t VFileWrite32LE(struct VFile* vf, int32_t word) {
132 uint32_t leword;
133 STORE_32LE(word, 0, &leword);
134 return vf->write(vf, &leword, 4);
135}
136
137ssize_t VFileWrite16LE(struct VFile* vf, int16_t hword) {
138 uint16_t lehword;
139 STORE_16LE(hword, 0, &lehword);
140 return vf->write(vf, &lehword, 2);
141}
142
143ssize_t VFileRead32LE(struct VFile* vf, void* word) {
144 uint32_t leword;
145 ssize_t r = vf->read(vf, &leword, 4);
146 if (r == 4) {
147 STORE_32LE(leword, 0, word);
148 }
149 return r;
150}
151
152ssize_t VFileRead16LE(struct VFile* vf, void* hword) {
153 uint16_t lehword;
154 ssize_t r = vf->read(vf, &lehword, 2);
155 if (r == 2) {
156 STORE_16LE(lehword, 0, hword);
157 }
158 return r;
159}
160
161void separatePath(const char* path, char* dirname, char* basename, char* extension) {
162 if (!path) {
163 return;
164 }
165 char* dotPoint = strrchr(path, '.');
166 char* separatorPoint = strnrstr(path, PATH_SEP, strlen(path));
167 if (separatorPoint) {
168 if (dirname) {
169 ptrdiff_t len = separatorPoint - path;
170 if (PATH_MAX <= len) {
171 len = PATH_MAX - 1;
172 } else if (!len) {
173 len = 1;
174 }
175 strncpy(dirname, path, len);
176 dirname[len] = '\0';
177 }
178 path = separatorPoint + 1;
179 } else if (dirname) {
180 strcpy(dirname, ".");
181 }
182 if (basename) {
183 size_t len;
184 if (dotPoint) {
185 len = dotPoint - path;
186 } else {
187 len = strlen(path);
188 }
189 if (PATH_MAX <= len) {
190 len = PATH_MAX - 1;
191 }
192 strncpy(basename, path, len);
193 basename[len] = '\0';
194 }
195 if (extension) {
196 if (dotPoint) {
197 ++dotPoint;
198 size_t len = strlen(dotPoint);
199 if (PATH_MAX <= len) {
200 len = PATH_MAX - 1;
201 }
202 strncpy(extension, dotPoint, len);
203 extension[len] = '\0';
204 } else {
205 extension[0] = '\0';
206 }
207 }
208}
209
210struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) {
211 dir->rewind(dir);
212 struct VDirEntry* dirent = dir->listNext(dir);
213 while (dirent) {
214 struct VFile* vf = dir->openFile(dir, dirent->name(dirent), O_RDONLY);
215 if (!vf) {
216 dirent = dir->listNext(dir);
217 continue;
218 }
219 if (filter(vf)) {
220 return vf;
221 }
222 vf->close(vf);
223 dirent = dir->listNext(dir);
224 }
225 return 0;
226}
227
228struct VFile* VDirFindNextAvailable(struct VDir* dir, const char* basename, const char* infix, const char* suffix, int mode) {
229 if (!dir) {
230 return 0;
231 }
232 dir->rewind(dir);
233 struct VDirEntry* dirent;
234 size_t prefixLen = strlen(basename);
235 size_t infixLen = strlen(infix);
236 char path[PATH_MAX];
237 unsigned next = 0;
238 while ((dirent = dir->listNext(dir))) {
239 const char* filename = dirent->name(dirent);
240 const char* dotPoint = strrchr(filename, '.');
241 size_t len = strlen(filename);
242 if (dotPoint) {
243 len = (dotPoint - filename);
244 }
245 const char* separator = strnrstr(filename, infix, len);
246 if (!separator) {
247 continue;
248 }
249 len = separator - filename;
250 if (len != prefixLen) {
251 continue;
252 }
253 if (strncmp(filename, basename, prefixLen) == 0) {
254 int nlen;
255 separator += infixLen;
256 snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
257 unsigned increment;
258 if (sscanf(separator, path, &increment, &nlen) < 1) {
259 continue;
260 }
261 len = strlen(separator);
262 if (nlen < (ssize_t) len) {
263 continue;
264 }
265 if (next <= increment) {
266 next = increment + 1;
267 }
268 }
269 }
270 snprintf(path, PATH_MAX - 1, "%s%s%u%s", basename, infix, next, suffix);
271 path[PATH_MAX - 1] = '\0';
272 return dir->openFile(dir, path, mode);
273}