pcsx2/pcsx2-qt/Settings/MemoryCardConvertWorker.cpp

165 lines
5.5 KiB
C++

#include "PrecompiledHeader.h"
#include "MemoryCardConvertWorker.h"
#include "common/Path.h"
#include "common/FileSystem.h"
MemoryCardConvertWorker::MemoryCardConvertWorker(QWidget* parent, MemoryCardType type, MemoryCardFileType fileType, const std::string& srcFileName, const std::string& destFileName)
: QtAsyncProgressThread(parent)
{
this->type = type;
this->fileType = fileType;
this->srcFileName = srcFileName;
this->destFileName = destFileName;
}
MemoryCardConvertWorker::~MemoryCardConvertWorker() = default;
void MemoryCardConvertWorker::runAsync()
{
switch (type)
{
case MemoryCardType::File:
ConvertToFolder(srcFileName, destFileName, fileType);
break;
case MemoryCardType::Folder:
ConvertToFile(srcFileName, destFileName, fileType);
break;
default:
break;
}
}
bool MemoryCardConvertWorker::ConvertToFile(const std::string& srcFolderName, const std::string& destFileName, const MemoryCardFileType type)
{
const std::string srcPath(Path::Combine(EmuFolders::MemoryCards, srcFolderName));
const std::string destPath(Path::Combine(EmuFolders::MemoryCards, destFileName));
size_t sizeInMB = 0;
switch (type)
{
case MemoryCardFileType::PS2_8MB:
sizeInMB = 8;
break;
case MemoryCardFileType::PS2_16MB:
sizeInMB = 16;
break;
case MemoryCardFileType::PS2_32MB:
sizeInMB = 32;
break;
case MemoryCardFileType::PS2_64MB:
sizeInMB = 64;
break;
default:
Console.Error("%s(%s, %s, %d) Received invalid MemoryCardFileType, aborting", __FUNCTION__, srcPath.c_str(), destPath.c_str(), type);
return false;
}
FolderMemoryCard sourceFolderMemoryCard;
Pcsx2Config::McdOptions config;
config.Enabled = true;
config.Type = MemoryCardType::Folder;
sourceFolderMemoryCard.Open(srcPath, config, (sizeInMB * 1024 * 1024) / FolderMemoryCard::ClusterSize, false, "");
const size_t capacity = sourceFolderMemoryCard.GetSizeInClusters() * FolderMemoryCard::ClusterSizeRaw;
std::vector<u8> sourceBuffer;
sourceBuffer.resize(capacity);
size_t address = 0;
this->SetProgressRange(capacity);
this->SetProgressValue(0);
while (address < capacity)
{
sourceFolderMemoryCard.Read(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
address += FolderMemoryCard::PageSizeRaw;
// Only report progress every 16 pages. Substantially speeds up the conversion.
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
this->SetProgressValue(address);
}
bool writeResult = FileSystem::WriteBinaryFile(destPath.c_str(), sourceBuffer.data(), sourceBuffer.size());
if (!writeResult)
{
Console.Error("%s(%s, %s, %d) Failed to write memory card contents to file", __FUNCTION__, srcPath.c_str(), destPath.c_str(), type);
return false;
}
#ifdef _WIN32
else
{
FileSystem::SetPathCompression(destPath.c_str(), true);
}
#endif
sourceFolderMemoryCard.Close(false);
return true;
}
bool MemoryCardConvertWorker::ConvertToFolder(const std::string& srcFileName, const std::string& destFolderName, const MemoryCardFileType type)
{
const std::string srcPath(Path::Combine(EmuFolders::MemoryCards, srcFileName));
const std::string destPath(Path::Combine(EmuFolders::MemoryCards, destFolderName));
FolderMemoryCard targetFolderMemoryCard;
Pcsx2Config::McdOptions config;
config.Enabled = true;
config.Type = MemoryCardType::Folder;
std::optional<std::vector<u8>> sourceBufferOpt = FileSystem::ReadBinaryFile(srcPath.c_str());
if (!sourceBufferOpt.has_value())
{
Console.Error("%s(%s, %s, %d) Failed to open file memory card!", __FUNCTION__, srcFileName.c_str(), destFolderName.c_str(), type);
return false;
}
std::vector<u8> sourceBuffer = sourceBufferOpt.value();
// Set progress bar to the literal number of bytes in the memcard.
// Plus two because there is a lag period after the Save calls complete
// where the progress bar stalls out; this lets us stop the progress bar
// just shy of 50 and 100% so it seems like its still doing some work.
this->SetProgressRange((sourceBuffer.size() * 2) + 2);
this->SetProgressValue(0);
// Attempt the write twice. Once with writes being simulated rather than truly committed.
// Again with actual writes. If a file memcard has a corrupted page or something which would
// cause the conversion to fail, it will fail on the simulated run, with no files committed
// to the filesystem yet.
for (int i = 0; i < 2; i++)
{
bool simulateWrites = (i == 0);
targetFolderMemoryCard.Open(destPath, config, 0, false, "", simulateWrites);
size_t address = 0;
while (address < sourceBuffer.size())
{
targetFolderMemoryCard.Save(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
address += FolderMemoryCard::PageSizeRaw;
// Only report progress every 16 pages. Substantially speeds up the conversion.
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
this->SetProgressValue(address + (i * sourceBuffer.size()));
}
targetFolderMemoryCard.Close();
// If the source file memory card was larger than 8 MB, the raw copy will have also made the superblock of
// the destination folder memory card larger than 8 MB. For compatibility, we always want folder memory cards
// to report 8 MB, so we'll override that here. Don't do this on the simulated run, only the actual.
if (!simulateWrites && sourceBuffer.size() != FolderMemoryCard::TotalSizeRaw)
{
targetFolderMemoryCard.Open(destPath, config, 0, false, "", simulateWrites);
targetFolderMemoryCard.SetSizeInMB(8);
targetFolderMemoryCard.Close();
}
this->IncrementProgressValue();
}
return true;
}