mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-20 05:51:44 +12:00
commit
07afcfb24c
13 changed files with 236 additions and 19 deletions
|
@ -26,6 +26,7 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
|||
|
||||
codeFile.clear();
|
||||
saveData.clear();
|
||||
partitionInfo = info;
|
||||
|
||||
size = u64(*(u32*)&header[0x104]) * mediaUnit; // TODO: Maybe don't type pun because big endian will break
|
||||
exheaderSize = *(u32*)&header[0x180];
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "emulator.hpp"
|
||||
|
||||
#include <glad/gl.h>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
@ -581,4 +583,64 @@ void Emulator::updateDiscord() {
|
|||
}
|
||||
#else
|
||||
void Emulator::updateDiscord() {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void dumpRomFSNode(const RomFS::RomFSNode& node, const char* romFSBase, const std::filesystem::path& path) {
|
||||
for (auto& file : node.files) {
|
||||
const auto p = path / file->name;
|
||||
std::ofstream outFile(p);
|
||||
|
||||
outFile.write(romFSBase + file->dataOffset, file->dataSize);
|
||||
}
|
||||
|
||||
for (auto& directory : node.directories) {
|
||||
const auto newPath = path / directory->name;
|
||||
|
||||
// Create the directory for the new folder
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(newPath, ec);
|
||||
|
||||
if (!ec) {
|
||||
dumpRomFSNode(*directory, romFSBase, newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RomFS::DumpingResult Emulator::dumpRomFS(const std::filesystem::path& path) {
|
||||
using namespace RomFS;
|
||||
|
||||
if (romType != ROMType::NCSD && romType != ROMType::CXI && romType != ROMType::HB_3DSX) {
|
||||
return DumpingResult::InvalidFormat;
|
||||
}
|
||||
|
||||
// Contents of RomFS as raw bytes
|
||||
std::vector<u8> romFS;
|
||||
u64 size;
|
||||
|
||||
if (romType == ROMType::HB_3DSX) {
|
||||
auto hb3dsx = memory.get3DSX();
|
||||
if (!hb3dsx->hasRomFs()) {
|
||||
return DumpingResult::NoRomFS;
|
||||
}
|
||||
size = hb3dsx->romFSSize;
|
||||
|
||||
romFS.resize(size);
|
||||
hb3dsx->readRomFSBytes(&romFS[0], 0, size);
|
||||
} else {
|
||||
auto cxi = memory.getCXI();
|
||||
if (!cxi->hasRomFS()) {
|
||||
return DumpingResult::NoRomFS;
|
||||
}
|
||||
|
||||
const u64 offset = cxi->romFS.offset;
|
||||
size = cxi->romFS.size;
|
||||
|
||||
romFS.resize(size);
|
||||
cxi->readFromFile(memory.CXIFile, cxi->partitionInfo, &romFS[0], offset - cxi->fileOffset, size);
|
||||
}
|
||||
|
||||
std::unique_ptr<RomFSNode> node = parseRomFSTree((uintptr_t)&romFS[0], size);
|
||||
dumpRomFSNode(*node, (const char*)&romFS[0], path);
|
||||
|
||||
return DumpingResult::Success;
|
||||
}
|
37
src/memory_mapped_file.cpp
Normal file
37
src/memory_mapped_file.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include "memory_mapped_file.hpp"
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile() : opened(false), filePath(""), pointer(nullptr) {}
|
||||
MemoryMappedFile::MemoryMappedFile(const std::filesystem::path& path) { open(path); }
|
||||
MemoryMappedFile::~MemoryMappedFile() { close(); }
|
||||
|
||||
// TODO: This should probably also return the error one way or another eventually
|
||||
bool MemoryMappedFile::open(const std::filesystem::path& path) {
|
||||
std::error_code error;
|
||||
map = mio::make_mmap_sink(path.string(), 0, mio::map_entire_file, error);
|
||||
|
||||
if (error) {
|
||||
opened = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
filePath = path;
|
||||
pointer = (u8*)map.data();
|
||||
opened = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryMappedFile::close() {
|
||||
if (opened) {
|
||||
opened = false;
|
||||
pointer = nullptr; // Set the pointer to nullptr to avoid errors related to lingering pointers
|
||||
|
||||
map.unmap();
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code MemoryMappedFile::flush() {
|
||||
std::error_code ret;
|
||||
map.sync(ret);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -16,13 +16,19 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
|||
menuBar = new QMenuBar(this);
|
||||
setMenuBar(menuBar);
|
||||
|
||||
// Create menu bar menus
|
||||
auto fileMenu = menuBar->addMenu(tr("File"));
|
||||
auto emulationMenu = menuBar->addMenu(tr("Emulation"));
|
||||
auto toolsMenu = menuBar->addMenu(tr("Tools"));
|
||||
auto helpMenu = menuBar->addMenu(tr("Help"));
|
||||
auto aboutMenu = menuBar->addMenu(tr("About"));
|
||||
|
||||
// Create and bind actions for them
|
||||
auto pandaAction = fileMenu->addAction(tr("panda..."));
|
||||
connect(pandaAction, &QAction::triggered, this, &MainWindow::selectROM);
|
||||
|
||||
auto emulationMenu = menuBar->addMenu(tr("Emulation"));
|
||||
auto helpMenu = menuBar->addMenu(tr("Help"));
|
||||
auto aboutMenu = menuBar->addMenu(tr("About"));
|
||||
auto dumpRomFSAction = toolsMenu->addAction(tr("Dump RomFS"));
|
||||
connect(dumpRomFSAction, &QAction::triggered, this, &MainWindow::dumpRomFS);
|
||||
|
||||
// Set up theme selection
|
||||
setTheme(Theme::Dark);
|
||||
|
@ -64,13 +70,17 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
|||
|
||||
void MainWindow::emuThreadMainLoop() {
|
||||
while (appRunning) {
|
||||
if (needToLoadROM.load()) {
|
||||
bool success = emu->loadROM(romToLoad);
|
||||
if (!success) {
|
||||
printf("Failed to load ROM");
|
||||
}
|
||||
{
|
||||
std::unique_lock lock(messageQueueMutex);
|
||||
|
||||
needToLoadROM.store(false, std::memory_order::seq_cst);
|
||||
if (needToLoadROM) {
|
||||
needToLoadROM = false;
|
||||
|
||||
bool success = emu->loadROM(romToLoad);
|
||||
if (!success) {
|
||||
printf("Failed to load ROM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emu->runFrame();
|
||||
|
@ -93,17 +103,22 @@ void MainWindow::swapEmuBuffer() {
|
|||
|
||||
void MainWindow::selectROM() {
|
||||
// Are we already waiting for a ROM to be loaded? Then complain about it!
|
||||
if (needToLoadROM.load()) {
|
||||
QMessageBox::warning(this, tr("Already loading ROM"), tr("Panda3DS is already busy loading a ROM, please wait"));
|
||||
return;
|
||||
{
|
||||
std::unique_lock lock(messageQueueMutex);
|
||||
if (needToLoadROM) {
|
||||
QMessageBox::warning(this, tr("Already loading ROM"), tr("Panda3DS is already busy loading a ROM, please wait"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto path =
|
||||
QFileDialog::getOpenFileName(this, tr("Select 3DS ROM to load"), "", tr("Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.3dsx *.elf *.axf)"));
|
||||
|
||||
if (!path.isEmpty()) {
|
||||
std::unique_lock lock(messageQueueMutex);
|
||||
|
||||
romToLoad = path.toStdU16String();
|
||||
needToLoadROM.store(true, std::memory_order_seq_cst);
|
||||
needToLoadROM = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,4 +190,39 @@ void MainWindow::setTheme(Theme theme) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::dumpRomFS() {
|
||||
auto folder = QFileDialog::getExistingDirectory(
|
||||
this, tr("Select folder to dump RomFS files to"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
|
||||
);
|
||||
|
||||
if (folder.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
std::filesystem::path path(folder.toStdU16String());
|
||||
|
||||
// TODO: This might break if the game accesses RomFS while we're dumping, we should move it to the emulator thread when we've got a message queue going
|
||||
messageQueueMutex.lock();
|
||||
RomFS::DumpingResult res = emu->dumpRomFS(path);
|
||||
messageQueueMutex.unlock();
|
||||
|
||||
switch (res) {
|
||||
case RomFS::DumpingResult::Success: break; // Yay!
|
||||
case RomFS::DumpingResult::InvalidFormat: {
|
||||
QMessageBox messageBox(
|
||||
QMessageBox::Icon::Warning, tr("Invalid format for RomFS dumping"),
|
||||
tr("The currently loaded app is not in a format that supports RomFS")
|
||||
);
|
||||
|
||||
QAbstractButton* button = messageBox.addButton(tr("OK"), QMessageBox::ButtonRole::YesRole);
|
||||
button->setIcon(QIcon(":/docs/img/rsob_icon.png"));
|
||||
messageBox.exec();
|
||||
break;
|
||||
}
|
||||
|
||||
case RomFS::DumpingResult::NoRomFS:
|
||||
QMessageBox::warning(this, tr("No RomFS found"), tr("No RomFS partition was found in the loaded app"));
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue