1 #include "Common/Log.h"
2 #include "Common/File/VFS/VFS.h"
3 #include "Common/File/VFS/AssetReader.h"
4 #include "Common/File/AndroidStorage.h"
5 
6 struct VFSEntry {
7 	const char *prefix;
8 	AssetReader *reader;
9 };
10 
11 static VFSEntry entries[16];
12 static int num_entries = 0;
13 
14 void VFSRegister(const char *prefix, AssetReader *reader) {
15 	entries[num_entries].prefix = prefix;
16 	entries[num_entries].reader = reader;
~AssetReader()17 	DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
18 	num_entries++;
19 }
20 
21 void VFSShutdown() {
22 	for (int i = 0; i < num_entries; i++) {
23 		delete entries[i].reader;
24 	}
25 	num_entries = 0;
26 }
27 
28 // TODO: Use Path more.
29 static bool IsLocalAbsolutePath(const char *path) {
30 	bool isUnixLocal = path[0] == '/';
31 #ifdef _WIN32
32 	bool isWindowsLocal = isalpha(path[0]) && path[1] == ':';
33 #else
34 	bool isWindowsLocal = false;
35 #endif
toString()36 	bool isContentURI = Android_IsContentUri(path);
37 	return isUnixLocal || isWindowsLocal || isContentURI;
38 }
39 
40 // The returned data should be free'd with delete[].
41 uint8_t *VFSReadFile(const char *filename, size_t *size) {
42 	if (IsLocalAbsolutePath(filename)) {
43 		// Local path, not VFS.
44 		// INFO_LOG(IO, "Not a VFS path: %s . Reading local file.", filename);
45 		return File::ReadLocalFile(Path(filename), size);
46 	}
47 
48 	int fn_len = (int)strlen(filename);
49 	bool fileSystemFound = false;
50 	for (int i = 0; i < num_entries; i++) {
51 		int prefix_len = (int)strlen(entries[i].prefix);
52 		if (prefix_len >= fn_len) continue;
toString()53 		if (0 == memcmp(filename, entries[i].prefix, prefix_len)) {
54 			fileSystemFound = true;
55 			// INFO_LOG(IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
56 			uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size);
57 			if (data)
58 				return data;
59 			else
60 				continue;
61 			// Else try the other registered file systems.
62 		}
63 	}
64 	if (!fileSystemFound) {
65 		ERROR_LOG(IO, "Missing filesystem for '%s'", filename);
66 	}  // Otherwise, the file was just missing. No need to log.
67 	return 0;
68 }
69 
70 bool VFSGetFileListing(const char *path, std::vector<File::FileInfo> *listing, const char *filter) {
71 	if (IsLocalAbsolutePath(path)) {
72 		// Local path, not VFS.
73 		// INFO_LOG(IO, "Not a VFS path: %s . Reading local directory.", path);
74 		File::GetFilesInDir(Path(std::string(path)), listing, filter);
75 		return true;
76 	}
77 
78 	int fn_len = (int)strlen(path);
79 	bool fileSystemFound = false;
80 	for (int i = 0; i < num_entries; i++) {
81 		int prefix_len = (int)strlen(entries[i].prefix);
82 		if (prefix_len >= fn_len) continue;
83 		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
84 			fileSystemFound = true;
85 			if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter)) {
86 				return true;
87 			}
88 		}
89 	}
90 
91 	if (!fileSystemFound) {
92 		ERROR_LOG(IO, "Missing filesystem for %s", path);
93 	}  // Otherwise, the file was just missing. No need to log.
94 	return false;
95 }
96 
97 bool VFSGetFileInfo(const char *path, File::FileInfo *info) {
98 	if (IsLocalAbsolutePath(path)) {
99 		// Local path, not VFS.
100 		// INFO_LOG(IO, "Not a VFS path: %s . Getting local file info.", path);
101 		return File::GetFileInfo(Path(std::string(path)), info);
102 	}
103 
104 	bool fileSystemFound = false;
105 	int fn_len = (int)strlen(path);
106 	for (int i = 0; i < num_entries; i++) {
107 		int prefix_len = (int)strlen(entries[i].prefix);
108 		if (prefix_len >= fn_len) continue;
109 		if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
110 			fileSystemFound = true;
111 			if (entries[i].reader->GetFileInfo(path + prefix_len, info))
112 				return true;
113 			else
114 				continue;
115 		}
116 	}
117 	if (!fileSystemFound) {
118 		ERROR_LOG(IO, "Missing filesystem for %s", path);
119 	}  // Otherwise, the file was just missing. No need to log.
120 	return false;
121 }
122