|
19 | 19 |
|
20 | 20 | #include "lua/extra.h" |
21 | 21 |
|
| 22 | +#include <filesystem> |
| 23 | +#include <string_view> |
| 24 | +#include <vector> |
| 25 | + |
22 | 26 | #include "lua-protobuf/pb.h" |
| 27 | +#include "lua/luafile.h" |
23 | 28 | #include "lua/luawrapper.h" |
| 29 | +#include "support/file.h" |
| 30 | +#include "support/strings-helpers.h" |
| 31 | +#include "support/zip.h" |
| 32 | + |
| 33 | +namespace { |
| 34 | + |
| 35 | +std::vector<PCSX::ZipArchive> s_archives; |
| 36 | +PCSX::File* load(std::string_view name, std::string_view from, bool inArchives = true) { |
| 37 | + bool doRelative = false; |
| 38 | + if (!from.empty() && (from[0] == '@')) { |
| 39 | + from = from.substr(1); |
| 40 | + doRelative = true; |
| 41 | + } |
| 42 | + std::filesystem::path fromPath(from); |
| 43 | + std::filesystem::path absolutePath(name); |
| 44 | + std::filesystem::path relativePath(fromPath.parent_path() / name); |
| 45 | + relativePath = std::filesystem::weakly_canonical(relativePath); |
| 46 | + |
| 47 | + PCSX::File* file = nullptr; |
| 48 | + |
| 49 | + if (inArchives) { |
| 50 | + for (auto archivei = s_archives.rbegin(); archivei != s_archives.rend(); archivei++) { |
| 51 | + auto& archive = *archivei; |
| 52 | + if (doRelative) { |
| 53 | + file = archive.openFile(relativePath.string()); |
| 54 | + if (!file->failed()) return file; |
| 55 | + delete file; |
| 56 | + } |
| 57 | + file = archive.openFile(absolutePath.string()); |
| 58 | + if (!file->failed()) return file; |
| 59 | + delete file; |
| 60 | + } |
| 61 | + } else { |
| 62 | + for (auto archivei = s_archives.rbegin(); archivei != s_archives.rend(); archivei++) { |
| 63 | + auto& archive = *archivei; |
| 64 | + std::filesystem::path fromPath(from); |
| 65 | + std::filesystem::path relativePath(archive.archiveFilename().parent_path() / name); |
| 66 | + relativePath = std::filesystem::weakly_canonical(relativePath); |
| 67 | + file = archive.openFile(relativePath.string()); |
| 68 | + if (!file->failed()) return file; |
| 69 | + delete file; |
| 70 | + file = archive.openFile(absolutePath.string()); |
| 71 | + if (!file->failed()) return file; |
| 72 | + delete file; |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + if (doRelative) { |
| 77 | + file = new PCSX::PosixFile(relativePath); |
| 78 | + if (!file->failed()) return file; |
| 79 | + delete file; |
| 80 | + } |
| 81 | + return new PCSX::PosixFile(absolutePath); |
| 82 | +} |
| 83 | + |
| 84 | +} // namespace |
| 85 | + |
| 86 | +PCSX::ZipArchive& PCSX::LuaFFI::addArchive(Lua L, IO<File> file) { |
| 87 | + auto& newArchive = s_archives.emplace_back(file); |
| 88 | + if (newArchive.failed()) { |
| 89 | + s_archives.pop_back(); |
| 90 | + throw std::runtime_error("Invalid zip file"); |
| 91 | + } |
| 92 | + IO<File> autoexec = newArchive.openFile("autoexec.lua"); |
| 93 | + if (!autoexec->failed()) { |
| 94 | + std::string code = autoexec->readString(autoexec->size()); |
| 95 | + L.load(code, fmt::format("{}:@autoexec.lua", file->filename().string()).c_str()); |
| 96 | + } |
| 97 | + return newArchive; |
| 98 | +} |
24 | 99 |
|
25 | 100 | void PCSX::LuaFFI::open_extra(Lua L) { |
26 | 101 | L.getfieldtable("_LOADED", LUA_REGISTRYINDEX); |
@@ -76,5 +151,67 @@ void PCSX::LuaFFI::open_extra(Lua L) { |
76 | 151 | L.load(protoc, "internal:lua-protobuf/protoc.lua"); |
77 | 152 | L.setfield("protoc"); |
78 | 153 |
|
| 154 | + L.load(R"( |
| 155 | +Support.extra = { |
| 156 | +
|
| 157 | +loadfile = function(name) |
| 158 | + return loadstring(Support._internal.loadfile(name), '@' .. name) |
| 159 | +end, |
| 160 | +
|
| 161 | +dofile = function(name) |
| 162 | + local func, msg = loadstring(Support._internal.loadfile(name), '@' .. name) |
| 163 | + if func then return func() end |
| 164 | + error(msg) |
| 165 | +end, |
| 166 | +} |
| 167 | +
|
| 168 | +Support.extra.open = function(name) |
| 169 | + return Support.File._createFileWrapper(ffi.cast('LuaFile*', Support._internal.open(name))) |
| 170 | +end |
| 171 | +)", |
| 172 | + "internal:extra.lua"); |
| 173 | + |
| 174 | + L.getfieldtable("Support", LUA_GLOBALSINDEX); |
| 175 | + L.getfieldtable("extra"); |
| 176 | + L.declareFunc( |
| 177 | + "addArchive", |
| 178 | + [](lua_State* L_) -> int { |
| 179 | + Lua L(L_); |
| 180 | + auto ar = L.getinfo("S"); |
| 181 | + auto name = L.tostring(); |
| 182 | + IO<File> file = load(name, ar.has_value() ? ar->source : ""); |
| 183 | + if (file->failed()) return L.error("Unable to locate archive file"); |
| 184 | + addArchive(L, file); |
| 185 | + return 0; |
| 186 | + }, |
| 187 | + -1); |
| 188 | + L.pop(); |
| 189 | + L.getfieldtable("_internal"); |
| 190 | + L.declareFunc( |
| 191 | + "open", |
| 192 | + [](lua_State* L_) -> int { |
| 193 | + Lua L(L_); |
| 194 | + auto ar = L.getinfo("S", 1); |
| 195 | + auto name = L.tostring(); |
| 196 | + IO<File> file = load(name, ar.has_value() ? ar->source : ""); |
| 197 | + L.push(new LuaFile(file)); |
| 198 | + return 1; |
| 199 | + }, |
| 200 | + -1); |
| 201 | + L.declareFunc( |
| 202 | + "loadfile", |
| 203 | + [](lua_State* L_) -> int { |
| 204 | + Lua L(L_); |
| 205 | + auto ar = L.getinfo("S", 2); |
| 206 | + auto name = L.tostring(); |
| 207 | + IO<File> file = load(name, ar.has_value() ? ar->source : ""); |
| 208 | + if (file->failed()) return L.error("Unable to locate file"); |
| 209 | + L.push(file->readString(file->size())); |
| 210 | + return 1; |
| 211 | + }, |
| 212 | + -1); |
| 213 | + L.pop(); |
| 214 | + L.pop(); |
| 215 | + |
79 | 216 | L.pop(); |
80 | 217 | } |
0 commit comments