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
VFSRegister(const char * prefix,AssetReader * reader)14 void VFSRegister(const char *prefix, AssetReader *reader) {
15 entries[num_entries].prefix = prefix;
16 entries[num_entries].reader = reader;
17 DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
18 num_entries++;
19 }
20
VFSShutdown()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.
IsLocalAbsolutePath(const char * path)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
36 bool isContentURI = Android_IsContentUri(path);
37 return isUnixLocal || isWindowsLocal || isContentURI;
38 }
39
40 // The returned data should be free'd with delete[].
VFSReadFile(const char * filename,size_t * size)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;
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
VFSGetFileListing(const char * path,std::vector<File::FileInfo> * listing,const char * filter)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
VFSGetFileInfo(const char * path,File::FileInfo * info)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