Skip to content

Commit bd3b657

Browse files
authored
Merge pull request #1478 from nicolasnoble/lua-dofile
Adding Support.extra dofile & friends
2 parents cf476b6 + 533a2b9 commit bd3b657

File tree

10 files changed

+237
-29
lines changed

10 files changed

+237
-29
lines changed

src/gui/gui.cc

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ extern "C" {
7474
#include "imgui_internal.h"
7575
#include "imgui_stdlib.h"
7676
#include "json.hpp"
77+
#include "lua/extra.h"
7778
#include "lua/glffi.h"
7879
#include "lua/luafile.h"
7980
#include "lua/luawrapper.h"
@@ -427,7 +428,7 @@ void PCSX::GUI::init(std::function<void()> applyArguments) {
427428
m_luaConsole.setCmdExec([this, luaStdout](const std::string& cmd) {
428429
ScopedOnlyLog scopedOnlyLog(this);
429430
try {
430-
g_emulator->m_lua->load(cmd, "console", false);
431+
g_emulator->m_lua->load(cmd, "console:", false);
431432
g_emulator->m_lua->pcall();
432433
for (const auto& error : m_glErrors) {
433434
m_luaConsole.addError(error);
@@ -1047,6 +1048,7 @@ void PCSX::GUI::endFrame() {
10471048

10481049
bool showOpenIsoFileDialog = false;
10491050
bool showOpenBinaryDialog = false;
1051+
bool showOpenArchiveDialog = false;
10501052

10511053
if (m_showMenu || !m_fullWindowRender || !PCSX::g_system->running()) {
10521054
if (ImGui::BeginMainMenuBar()) {
@@ -1059,6 +1061,9 @@ void PCSX::GUI::endFrame() {
10591061
if (ImGui::MenuItem(_("Load binary"))) {
10601062
showOpenBinaryDialog = true;
10611063
}
1064+
if (ImGui::MenuItem(_("Add Lua archive"))) {
1065+
showOpenArchiveDialog = true;
1066+
}
10621067
ImGui::Separator();
10631068
if (ImGui::MenuItem(_("Dump save state proto schema"))) {
10641069
std::ofstream schema("sstate.proto");
@@ -1378,6 +1383,29 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)"));
13781383
}
13791384
}
13801385

1386+
if (showOpenArchiveDialog) {
1387+
if (!isoPath.empty()) {
1388+
m_openArchiveDialog.m_currentPath = isoPath.value;
1389+
}
1390+
m_openArchiveDialog.openDialog();
1391+
}
1392+
if (m_openArchiveDialog.draw()) {
1393+
isoPath.value = m_openArchiveDialog.m_currentPath;
1394+
changed = true;
1395+
std::vector<PCSX::u8string> fileToOpen = m_openArchiveDialog.selected();
1396+
if (!fileToOpen.empty()) {
1397+
IO<File> file = new PosixFile(fileToOpen[0]);
1398+
try {
1399+
auto& archive = LuaFFI::addArchive(*g_emulator->m_lua, file);
1400+
if (!archive.failed()) {
1401+
g_system->log(LogClass::UI, "Added %s to our list of loaded archives.\n",
1402+
reinterpret_cast<const char*>(fileToOpen[0].c_str()));
1403+
}
1404+
} catch (...) {
1405+
}
1406+
}
1407+
}
1408+
13811409
if (m_showDemo) ImGui::ShowDemoWindow();
13821410

13831411
ImGui::SetNextWindowPos(ImVec2(10, 20), ImGuiCond_FirstUseEver);
@@ -2449,6 +2477,26 @@ void PCSX::GUI::magicOpen(const char* pathStr) {
24492477
}
24502478
}
24512479

2480+
// Maybe it's a zip file to add to our list of Lua archive ?
2481+
{
2482+
uint32_t signature = file->readAt<uint32_t>(0);
2483+
try {
2484+
switch (signature) {
2485+
case 0x02014b50:
2486+
case 0x04034b50:
2487+
case 0x06054b50: {
2488+
auto& archive = LuaFFI::addArchive(*g_emulator->m_lua, file);
2489+
if (!archive.failed()) {
2490+
g_system->log(LogClass::UI, "Added %s to our list of loaded archives.\n", path.string());
2491+
return;
2492+
}
2493+
break;
2494+
}
2495+
}
2496+
} catch (...) {
2497+
}
2498+
}
2499+
24522500
// Iso loader is last because its detection is the most broken at the moment.
24532501
g_emulator->m_cdrom->setIso(new CDRIso(path));
24542502
g_emulator->m_cdrom->check();
@@ -2471,9 +2519,7 @@ std::string PCSX::GUI::getSaveStatePrefix(bool includeSeparator) {
24712519
}
24722520
}
24732521

2474-
std::string PCSX::GUI::getSaveStatePostfix() {
2475-
return ".sstate";
2476-
}
2522+
std::string PCSX::GUI::getSaveStatePostfix() { return ".sstate"; }
24772523

24782524
std::string PCSX::GUI::buildSaveStateFilename(int i) {
24792525
return fmt::format("{}{}{}", getSaveStatePrefix(false), getSaveStatePostfix(), i);

src/gui/gui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ class GUI final : public UI {
375375
Widgets::Disassembly m_disassembly = {settings.get<ShowDisassembly>().value};
376376
Widgets::FileDialog<> m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }};
377377
Widgets::FileDialog<> m_openBinaryDialog = {[]() { return _("Open Binary"); }};
378+
Widgets::FileDialog<> m_openArchiveDialog = {[]() { return _("Open Archive"); }};
378379
Widgets::FileDialog<> m_selectBiosDialog = {[]() { return _("Select BIOS"); }};
379380
Widgets::FileDialog<> m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }};
380381
Widgets::NamedSaveStates m_namedSaveStates = {settings.get<ShowNamedSaveStates>().value};

src/lua/extra.cc

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,83 @@
1919

2020
#include "lua/extra.h"
2121

22+
#include <filesystem>
23+
#include <string_view>
24+
#include <vector>
25+
2226
#include "lua-protobuf/pb.h"
27+
#include "lua/luafile.h"
2328
#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+
}
2499

25100
void PCSX::LuaFFI::open_extra(Lua L) {
26101
L.getfieldtable("_LOADED", LUA_REGISTRYINDEX);
@@ -76,5 +151,67 @@ void PCSX::LuaFFI::open_extra(Lua L) {
76151
L.load(protoc, "internal:lua-protobuf/protoc.lua");
77152
L.setfield("protoc");
78153

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+
79216
L.pop();
80217
}

src/lua/extra.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
#pragma once
2121

2222
#include "lua/luawrapper.h"
23+
#include "support/file.h"
24+
#include "support/zip.h"
2325

2426
namespace PCSX {
2527

2628
namespace LuaFFI {
2729
void open_extra(Lua);
28-
}
30+
ZipArchive& addArchive(Lua, IO<File>);
31+
} // namespace LuaFFI
2932

3033
} // namespace PCSX

src/lua/luawrapper.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <functional>
2323
#include <map>
24+
#include <optional>
2425
#include <string>
2526
#include <string_view>
2627

@@ -234,6 +235,15 @@ class Lua {
234235

235236
bool newmetatable(const char* name) { return luaL_newmetatable(L, name) != 0; }
236237

238+
std::optional<lua_Debug> getinfo(const char* what, int level = 1) {
239+
lua_Debug ar;
240+
int r = lua_getstack(L, level, &ar);
241+
if (!r) return std::nullopt;
242+
r = lua_getinfo(L, what, &ar);
243+
if (!r) return std::nullopt;
244+
return ar;
245+
}
246+
237247
private:
238248
lua_State* L;
239249
};

src/main/main.cc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "flags.h"
3434
#include "fmt/chrono.h"
3535
#include "gui/gui.h"
36+
#include "lua/extra.h"
3637
#include "lua/luawrapper.h"
3738
#include "main/textui.h"
3839
#include "spu/interface.h"
@@ -373,25 +374,30 @@ int pcsxMain(int argc, char **argv) {
373374
PCSX::g_system = nullptr;
374375
});
375376
try {
377+
auto &L = emulator->m_lua;
376378
// Before going into the main loop, let's first load all of the Lua files
377379
// from the command-line specified using the -dofile switch.
380+
auto archives = args.values("archive");
381+
for (auto &archive : archives) {
382+
PCSX::IO<PCSX::File> file = new PCSX::PosixFile(archive);
383+
if (file->failed()) {
384+
throw std::runtime_error(fmt::format("Couldn't load file {}", archive));
385+
}
386+
PCSX::LuaFFI::addArchive(*L, file);
387+
}
378388
auto dofiles = args.values("dofile");
389+
L->load("return function(name) Support.extra.dofile(name) end", "internal:");
379390
for (auto &dofile : dofiles) {
380-
std::string name = std::string(dofile);
381-
std::ifstream in(name, std::ifstream::in);
382-
if (!in) {
383-
throw std::runtime_error("Couldn't load file " + name);
384-
}
385-
std::ostringstream code;
386-
code << in.rdbuf();
387-
in.close();
388-
emulator->m_lua->load(code.str(), name.c_str());
391+
L->copy(-1);
392+
L->push(dofile);
393+
L->pcall(1);
389394
}
395+
L->pop();
390396

391397
// Then run all of the Lua "exec" commands.
392398
auto luaexecs = args.values("exec");
393399
for (auto &luaexec : luaexecs) {
394-
emulator->m_lua->load(luaexec.data(), "cmdline");
400+
L->load(luaexec.data(), "cmdline:");
395401
}
396402

397403
system->m_inStartup = false;

src/support/version-linux.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) {
4343

4444
std::string filename;
4545

46-
zip.listAllFiles([&zip, &filename, &tmp](const std::string_view& name) {
46+
zip.listAllFiles([&zip, &filename, &tmp](std::string_view name) {
4747
IO<File> out(new UvFile(tmp / name, FileOps::TRUNCATE));
48-
IO<File> in(zip.openFile(name));
48+
IO<File> in(zip.openFile(std::string(name)));
4949
Slice data = in->read(in->size());
5050
out->write(std::move(data));
5151
filename = out->filename();

src/support/version-windows.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) {
7474
script->writeString("$failed = $False\n");
7575

7676
unsigned count = 0;
77-
zip.listAllFiles([&zip, &script, &tmp, &binDir, &count](const std::string_view& name) {
77+
zip.listAllFiles([&zip, &script, &tmp, &binDir, &count](std::string_view name) {
7878
auto filename = tmp / ("pcsx-update-file-" + std::to_string(count++) + ".tmp");
7979
IO<File> out(new UvFile(filename, FileOps::TRUNCATE));
80-
IO<File> in(zip.openFile(name));
80+
IO<File> in(zip.openFile(std::string(name)));
8181
Slice data = in->read(in->size());
8282
uint8_t digest[16];
8383
MD5 md5;

0 commit comments

Comments
 (0)