Add support for memory card dumps in save data imports.

This commit is contained in:
Jean-Philip Desjardins 2023-12-18 13:45:55 -05:00
parent b2b86f9d94
commit 5d4e2acf19
7 changed files with 71 additions and 5 deletions

View file

@ -477,6 +477,8 @@ set(COMMON_SRC_FILES
saves/MaxSaveImporter.h
saves/McDumpReader.cpp
saves/McDumpReader.h
saves/McDumpSaveImporter.cpp
saves/McDumpSaveImporter.h
saves/MemoryCard.cpp
saves/PsuSaveImporter.cpp
saves/PsuSaveImporter.h

View file

@ -46,7 +46,7 @@ CMcDumpReader::CMcDumpReader(Framework::CStream& stream)
m_rawPageSize = m_header.pageSize + pageSpareSize;
}
CMcDumpReader::Directory CMcDumpReader::ReadDirectory(uint32 dirCluster)
CMcDumpReader::Directory CMcDumpReader::ReadDirectory(uint32 dirCluster, int32 entryCount)
{
std::vector<DIRENTRY> result;
CFatReader reader(*this, dirCluster);
@ -54,8 +54,13 @@ CMcDumpReader::Directory CMcDumpReader::ReadDirectory(uint32 dirCluster)
FRAMEWORK_MAYBE_UNUSED uint32 readAmount = reader.Read(&baseDirEntry, sizeof(DIRENTRY));
assert(readAmount == sizeof(DIRENTRY));
result.push_back(baseDirEntry);
assert(baseDirEntry.length >= 2);
for(uint32 i = 0; i < (baseDirEntry.length - 1); i++)
if(entryCount == -1)
{
//Use number of entries from entry itself, only seems to work with root dir.
entryCount = baseDirEntry.length;
}
assert(entryCount >= 2);
for(uint32 i = 0; i < (entryCount - 1); i++)
{
DIRENTRY dirEntry = {};
readAmount = reader.Read(&dirEntry, sizeof(DIRENTRY));

View file

@ -58,7 +58,7 @@ public:
CMcDumpReader(Framework::CStream&);
Directory ReadDirectory(uint32);
Directory ReadDirectory(uint32, int32 = -1);
Directory ReadRootDirectory();
std::vector<uint8> ReadFile(uint32, uint32);

View file

@ -0,0 +1,39 @@
#include "McDumpSaveImporter.h"
#include "StdStreamUtils.h"
void CMcDumpSaveImporter::Import(Framework::CStream& input, const fs::path& basePath)
{
CMcDumpReader reader(input);
auto dir = reader.ReadRootDirectory();
ImportDirectory(reader, dir, basePath);
}
void CMcDumpSaveImporter::ImportDirectory(CMcDumpReader& reader, const CMcDumpReader::Directory& dir, const fs::path& basePath)
{
if(!fs::exists(basePath))
{
fs::create_directory(basePath);
}
for(const auto& dirEntry : dir)
{
if(!strcmp(dirEntry.name, ".")) continue;
if(!strcmp(dirEntry.name, "..")) continue;
auto entryOutputPath = basePath / dirEntry.name;
if(dirEntry.mode & CMcDumpReader::DF_DIRECTORY)
{
auto subDir = reader.ReadDirectory(dirEntry.cluster, dirEntry.length);
ImportDirectory(reader, subDir, entryOutputPath);
}
else
{
if(CanExtractFile(entryOutputPath))
{
auto fileContents = reader.ReadFile(dirEntry.cluster, dirEntry.length);
assert(fileContents.size() == dirEntry.length);
auto output = Framework::CreateOutputStdStream(entryOutputPath.native());
output.Write(fileContents.data(), fileContents.size());
}
}
}
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "SaveImporterBase.h"
#include "McDumpReader.h"
class CMcDumpSaveImporter : public CSaveImporterBase
{
public:
virtual ~CMcDumpSaveImporter() = default;
void Import(Framework::CStream&, const fs::path&) override;
private:
void ImportDirectory(CMcDumpReader&, const CMcDumpReader::Directory&, const fs::path&);
};

View file

@ -3,6 +3,7 @@
#include "PsuSaveImporter.h"
#include "XpsSaveImporter.h"
#include "MaxSaveImporter.h"
#include "McDumpSaveImporter.h"
void CSaveImporter::ImportSave(Framework::CStream& input, const fs::path& outputPath, const OverwritePromptHandlerType& overwritePromptHandler)
{
@ -23,6 +24,10 @@ void CSaveImporter::ImportSave(Framework::CStream& input, const fs::path& output
{
importer = std::make_shared<CMaxSaveImporter>();
}
else if(signature == 0x796E6F53)
{
importer = std::make_shared<CMcDumpSaveImporter>();
}
else
{
throw std::runtime_error("Unknown input file format.");

View file

@ -37,7 +37,7 @@ void MemoryCardManagerDialog::on_import_saves_button_clicked()
QFileDialog dialog(this);
dialog.setDirectory(m_lastpath);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter(tr("All Supported types (*.psu *.sps *.xps *.max);;EMS Memory Adapter Save Dumps (*.psu);;Sharkport/X-Port Save Dumps (*.sps; *.xps);;Action Replay MAX Save Dumps (*.max);;All files (*.*)"));
dialog.setNameFilter(tr("All Supported types (*.psu *.sps *.xps *.max; *.ps2);;EMS Memory Adapter Save Dumps (*.psu);;Sharkport/X-Port Save Dumps (*.sps; *.xps);;Action Replay MAX Save Dumps (*.max);;Raw Memory Card Dumps (*.ps2);;All files (*.*)"));
if(dialog.exec())
{
QString fileName = dialog.selectedFiles().first();