Skip to content

Commit

Permalink
Merge pull request #1478 from nicolasnoble/lua-dofile
Browse files Browse the repository at this point in the history
Adding Support.extra dofile & friends
  • Loading branch information
nicolasnoble authored Dec 9, 2023
2 parents cf476b6 + 533a2b9 commit bd3b657
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 29 deletions.
54 changes: 50 additions & 4 deletions src/gui/gui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ extern "C" {
#include "imgui_internal.h"
#include "imgui_stdlib.h"
#include "json.hpp"
#include "lua/extra.h"
#include "lua/glffi.h"
#include "lua/luafile.h"
#include "lua/luawrapper.h"
Expand Down Expand Up @@ -427,7 +428,7 @@ void PCSX::GUI::init(std::function<void()> applyArguments) {
m_luaConsole.setCmdExec([this, luaStdout](const std::string& cmd) {
ScopedOnlyLog scopedOnlyLog(this);
try {
g_emulator->m_lua->load(cmd, "console", false);
g_emulator->m_lua->load(cmd, "console:", false);
g_emulator->m_lua->pcall();
for (const auto& error : m_glErrors) {
m_luaConsole.addError(error);
Expand Down Expand Up @@ -1047,6 +1048,7 @@ void PCSX::GUI::endFrame() {

bool showOpenIsoFileDialog = false;
bool showOpenBinaryDialog = false;
bool showOpenArchiveDialog = false;

if (m_showMenu || !m_fullWindowRender || !PCSX::g_system->running()) {
if (ImGui::BeginMainMenuBar()) {
Expand All @@ -1059,6 +1061,9 @@ void PCSX::GUI::endFrame() {
if (ImGui::MenuItem(_("Load binary"))) {
showOpenBinaryDialog = true;
}
if (ImGui::MenuItem(_("Add Lua archive"))) {
showOpenArchiveDialog = true;
}
ImGui::Separator();
if (ImGui::MenuItem(_("Dump save state proto schema"))) {
std::ofstream schema("sstate.proto");
Expand Down Expand Up @@ -1378,6 +1383,29 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)"));
}
}

if (showOpenArchiveDialog) {
if (!isoPath.empty()) {
m_openArchiveDialog.m_currentPath = isoPath.value;
}
m_openArchiveDialog.openDialog();
}
if (m_openArchiveDialog.draw()) {
isoPath.value = m_openArchiveDialog.m_currentPath;
changed = true;
std::vector<PCSX::u8string> fileToOpen = m_openArchiveDialog.selected();
if (!fileToOpen.empty()) {
IO<File> file = new PosixFile(fileToOpen[0]);
try {
auto& archive = LuaFFI::addArchive(*g_emulator->m_lua, file);
if (!archive.failed()) {
g_system->log(LogClass::UI, "Added %s to our list of loaded archives.\n",
reinterpret_cast<const char*>(fileToOpen[0].c_str()));
}
} catch (...) {
}
}
}

if (m_showDemo) ImGui::ShowDemoWindow();

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

// Maybe it's a zip file to add to our list of Lua archive ?
{
uint32_t signature = file->readAt<uint32_t>(0);
try {
switch (signature) {
case 0x02014b50:
case 0x04034b50:
case 0x06054b50: {
auto& archive = LuaFFI::addArchive(*g_emulator->m_lua, file);
if (!archive.failed()) {
g_system->log(LogClass::UI, "Added %s to our list of loaded archives.\n", path.string());
return;
}
break;
}
}
} catch (...) {
}
}

// Iso loader is last because its detection is the most broken at the moment.
g_emulator->m_cdrom->setIso(new CDRIso(path));
g_emulator->m_cdrom->check();
Expand All @@ -2471,9 +2519,7 @@ std::string PCSX::GUI::getSaveStatePrefix(bool includeSeparator) {
}
}

std::string PCSX::GUI::getSaveStatePostfix() {
return ".sstate";
}
std::string PCSX::GUI::getSaveStatePostfix() { return ".sstate"; }

std::string PCSX::GUI::buildSaveStateFilename(int i) {
return fmt::format("{}{}{}", getSaveStatePrefix(false), getSaveStatePostfix(), i);
Expand Down
1 change: 1 addition & 0 deletions src/gui/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ class GUI final : public UI {
Widgets::Disassembly m_disassembly = {settings.get<ShowDisassembly>().value};
Widgets::FileDialog<> m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }};
Widgets::FileDialog<> m_openBinaryDialog = {[]() { return _("Open Binary"); }};
Widgets::FileDialog<> m_openArchiveDialog = {[]() { return _("Open Archive"); }};
Widgets::FileDialog<> m_selectBiosDialog = {[]() { return _("Select BIOS"); }};
Widgets::FileDialog<> m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }};
Widgets::NamedSaveStates m_namedSaveStates = {settings.get<ShowNamedSaveStates>().value};
Expand Down
137 changes: 137 additions & 0 deletions src/lua/extra.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,83 @@

#include "lua/extra.h"

#include <filesystem>
#include <string_view>
#include <vector>

#include "lua-protobuf/pb.h"
#include "lua/luafile.h"
#include "lua/luawrapper.h"
#include "support/file.h"
#include "support/strings-helpers.h"
#include "support/zip.h"

namespace {

std::vector<PCSX::ZipArchive> s_archives;
PCSX::File* load(std::string_view name, std::string_view from, bool inArchives = true) {
bool doRelative = false;
if (!from.empty() && (from[0] == '@')) {
from = from.substr(1);
doRelative = true;
}
std::filesystem::path fromPath(from);
std::filesystem::path absolutePath(name);
std::filesystem::path relativePath(fromPath.parent_path() / name);
relativePath = std::filesystem::weakly_canonical(relativePath);

PCSX::File* file = nullptr;

if (inArchives) {
for (auto archivei = s_archives.rbegin(); archivei != s_archives.rend(); archivei++) {
auto& archive = *archivei;
if (doRelative) {
file = archive.openFile(relativePath.string());
if (!file->failed()) return file;
delete file;
}
file = archive.openFile(absolutePath.string());
if (!file->failed()) return file;
delete file;
}
} else {
for (auto archivei = s_archives.rbegin(); archivei != s_archives.rend(); archivei++) {
auto& archive = *archivei;
std::filesystem::path fromPath(from);
std::filesystem::path relativePath(archive.archiveFilename().parent_path() / name);
relativePath = std::filesystem::weakly_canonical(relativePath);
file = archive.openFile(relativePath.string());
if (!file->failed()) return file;
delete file;
file = archive.openFile(absolutePath.string());
if (!file->failed()) return file;
delete file;
}
}

if (doRelative) {
file = new PCSX::PosixFile(relativePath);
if (!file->failed()) return file;
delete file;
}
return new PCSX::PosixFile(absolutePath);
}

} // namespace

PCSX::ZipArchive& PCSX::LuaFFI::addArchive(Lua L, IO<File> file) {
auto& newArchive = s_archives.emplace_back(file);
if (newArchive.failed()) {
s_archives.pop_back();
throw std::runtime_error("Invalid zip file");
}
IO<File> autoexec = newArchive.openFile("autoexec.lua");
if (!autoexec->failed()) {
std::string code = autoexec->readString(autoexec->size());
L.load(code, fmt::format("{}:@autoexec.lua", file->filename().string()).c_str());
}
return newArchive;
}

void PCSX::LuaFFI::open_extra(Lua L) {
L.getfieldtable("_LOADED", LUA_REGISTRYINDEX);
Expand Down Expand Up @@ -76,5 +151,67 @@ void PCSX::LuaFFI::open_extra(Lua L) {
L.load(protoc, "internal:lua-protobuf/protoc.lua");
L.setfield("protoc");

L.load(R"(
Support.extra = {
loadfile = function(name)
return loadstring(Support._internal.loadfile(name), '@' .. name)
end,
dofile = function(name)
local func, msg = loadstring(Support._internal.loadfile(name), '@' .. name)
if func then return func() end
error(msg)
end,
}
Support.extra.open = function(name)
return Support.File._createFileWrapper(ffi.cast('LuaFile*', Support._internal.open(name)))
end
)",
"internal:extra.lua");

L.getfieldtable("Support", LUA_GLOBALSINDEX);
L.getfieldtable("extra");
L.declareFunc(
"addArchive",
[](lua_State* L_) -> int {
Lua L(L_);
auto ar = L.getinfo("S");
auto name = L.tostring();
IO<File> file = load(name, ar.has_value() ? ar->source : "");
if (file->failed()) return L.error("Unable to locate archive file");
addArchive(L, file);
return 0;
},
-1);
L.pop();
L.getfieldtable("_internal");
L.declareFunc(
"open",
[](lua_State* L_) -> int {
Lua L(L_);
auto ar = L.getinfo("S", 1);
auto name = L.tostring();
IO<File> file = load(name, ar.has_value() ? ar->source : "");
L.push(new LuaFile(file));
return 1;
},
-1);
L.declareFunc(
"loadfile",
[](lua_State* L_) -> int {
Lua L(L_);
auto ar = L.getinfo("S", 2);
auto name = L.tostring();
IO<File> file = load(name, ar.has_value() ? ar->source : "");
if (file->failed()) return L.error("Unable to locate file");
L.push(file->readString(file->size()));
return 1;
},
-1);
L.pop();
L.pop();

L.pop();
}
5 changes: 4 additions & 1 deletion src/lua/extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
#pragma once

#include "lua/luawrapper.h"
#include "support/file.h"
#include "support/zip.h"

namespace PCSX {

namespace LuaFFI {
void open_extra(Lua);
}
ZipArchive& addArchive(Lua, IO<File>);
} // namespace LuaFFI

} // namespace PCSX
10 changes: 10 additions & 0 deletions src/lua/luawrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <functional>
#include <map>
#include <optional>
#include <string>
#include <string_view>

Expand Down Expand Up @@ -234,6 +235,15 @@ class Lua {

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

std::optional<lua_Debug> getinfo(const char* what, int level = 1) {
lua_Debug ar;
int r = lua_getstack(L, level, &ar);
if (!r) return std::nullopt;
r = lua_getinfo(L, what, &ar);
if (!r) return std::nullopt;
return ar;
}

private:
lua_State* L;
};
Expand Down
26 changes: 16 additions & 10 deletions src/main/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "flags.h"
#include "fmt/chrono.h"
#include "gui/gui.h"
#include "lua/extra.h"
#include "lua/luawrapper.h"
#include "main/textui.h"
#include "spu/interface.h"
Expand Down Expand Up @@ -373,25 +374,30 @@ int pcsxMain(int argc, char **argv) {
PCSX::g_system = nullptr;
});
try {
auto &L = emulator->m_lua;
// Before going into the main loop, let's first load all of the Lua files
// from the command-line specified using the -dofile switch.
auto archives = args.values("archive");
for (auto &archive : archives) {
PCSX::IO<PCSX::File> file = new PCSX::PosixFile(archive);
if (file->failed()) {
throw std::runtime_error(fmt::format("Couldn't load file {}", archive));
}
PCSX::LuaFFI::addArchive(*L, file);
}
auto dofiles = args.values("dofile");
L->load("return function(name) Support.extra.dofile(name) end", "internal:");
for (auto &dofile : dofiles) {
std::string name = std::string(dofile);
std::ifstream in(name, std::ifstream::in);
if (!in) {
throw std::runtime_error("Couldn't load file " + name);
}
std::ostringstream code;
code << in.rdbuf();
in.close();
emulator->m_lua->load(code.str(), name.c_str());
L->copy(-1);
L->push(dofile);
L->pcall(1);
}
L->pop();

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

system->m_inStartup = false;
Expand Down
4 changes: 2 additions & 2 deletions src/support/version-linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) {

std::string filename;

zip.listAllFiles([&zip, &filename, &tmp](const std::string_view& name) {
zip.listAllFiles([&zip, &filename, &tmp](std::string_view name) {
IO<File> out(new UvFile(tmp / name, FileOps::TRUNCATE));
IO<File> in(zip.openFile(name));
IO<File> in(zip.openFile(std::string(name)));
Slice data = in->read(in->size());
out->write(std::move(data));
filename = out->filename();
Expand Down
4 changes: 2 additions & 2 deletions src/support/version-windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) {
script->writeString("$failed = $False\n");

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

0 comments on commit bd3b657

Please sign in to comment.