all repos — mgba @ 7d5dff4fc9737c1174f37fbe8313e6a553d47074

mGBA Game Boy Advance Emulator

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