memcard: migrate folder memory cards to `rapidyaml`

This commit is contained in:
Tyler Wilding 2021-12-23 22:01:26 -05:00 committed by refractionpcsx2
parent 83e5aa6137
commit bda3835cb1
1 changed files with 108 additions and 57 deletions

View File

@ -22,17 +22,19 @@
#include "System.h" #include "System.h"
#include "Config.h" #include "Config.h"
#include "yaml-cpp/yaml.h" #include "ryml_std.hpp"
#include "ryml.hpp"
#include "svnrev.h" #include "svnrev.h"
#include <sstream>
bool RemoveDirectory(const wxString& dirname); bool RemoveDirectory(const wxString& dirname);
// A helper function to parse the YAML file // A helper function to parse the YAML file
static YAML::Node LoadYAMLFromFile(const wxString& fileName) static ryml::Tree LoadYAMLFromFile(const wxString& fileName)
{ {
YAML::Node index; ryml::Tree index;
wxFFile indexFile; wxFFile indexFile;
bool result; bool result;
{ {
@ -43,11 +45,12 @@ static YAML::Node LoadYAMLFromFile(const wxString& fileName)
if (result) if (result)
{ {
size_t len = indexFile.Length(); const size_t len = indexFile.Length();
std::string fileContents(len, '\0'); std::string fileContents(len, '\0');
if (indexFile.Read(fileContents.data(), len) == len) if (indexFile.Read(fileContents.data(), len) && !indexFile.Error() && indexFile.Eof())
{ {
index = YAML::Load(fileContents); const ryml::substr view = c4::basic_substring<char>(fileContents.data(), len);
index = ryml::parse(view);
} }
} }
@ -55,13 +58,15 @@ static YAML::Node LoadYAMLFromFile(const wxString& fileName)
} }
/// A helper function to write a YAML file /// A helper function to write a YAML file
static void SaveYAMLToFile(const wxString& filename, const YAML::Node& node) static void SaveYAMLToFile(const wxString& filename, const ryml::NodeRef& node)
{ {
wxFFile file; wxFFile file;
if (file.Open(filename, L"w")) if (file.Open(filename, L"w"))
{ {
// Make sure WX doesn't do anything funny with encoding // Make sure WX doesn't do anything funny with encoding
std::string yaml = YAML::Dump(node); std::stringstream ss;
ss << node;
std::string yaml = ss.str();
file.Write(yaml.data(), yaml.length()); file.Write(yaml.data(), yaml.length());
} }
} }
@ -1255,14 +1260,22 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin
// write the directory index // write the directory index
metaFileName.SetName(L"_pcsx2_index"); metaFileName.SetName(L"_pcsx2_index");
YAML::Node index = LoadYAMLFromFile(metaFileName.GetFullPath()); ryml::Tree indexTree = LoadYAMLFromFile(metaFileName.GetFullPath());
YAML::Node entryNode = index["%ROOT"];
entryNode["timeCreated"] = entry->entry.data.timeCreated.ToTime(); if (!indexTree.empty())
entryNode["timeModified"] = entry->entry.data.timeModified.ToTime(); {
ryml::NodeRef index = indexTree.rootref();
if (index.has_child("%ROOT"))
{
ryml::NodeRef entryNode = index["%ROOT"];
// Write out the changes entryNode["timeCreated"] << entry->entry.data.timeCreated.ToTime();
SaveYAMLToFile(metaFileName.GetFullPath(), index); entryNode["timeModified"] << entry->entry.data.timeModified.ToTime();
// Write out the changes
SaveYAMLToFile(metaFileName.GetFullPath(), index);
}
}
} }
MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess(entry, parent); MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess(entry, parent);
@ -1664,9 +1677,6 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
wxDir dir(dirPath); wxDir dir(dirPath);
if (dir.IsOpened()) if (dir.IsOpened())
{ {
const YAML::Node index = LoadYAMLFromFile(wxFileName(dirPath, "_pcsx2_index").GetFullPath());
// We must be able to support legacy folder memcards without the index file, so for those // We must be able to support legacy folder memcards without the index file, so for those
// track an order variable and make it negative - this way new files get their order preserved // track an order variable and make it negative - this way new files get their order preserved
// and old files are listed first. // and old files are listed first.
@ -1678,15 +1688,6 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
int64_t orderForDirectories = 1; int64_t orderForDirectories = 1;
int64_t orderForLegacyFiles = -1; int64_t orderForLegacyFiles = -1;
const auto getOptionalNodeAttribute = [](const YAML::Node& node, const char* attribName, auto def) {
auto result = std::move(def);
if (node.IsDefined())
{
result = node[attribName].as<decltype(def)>(def);
}
return result;
};
wxString fileName; wxString fileName;
bool hasNext = dir.GetFirst(&fileName); bool hasNext = dir.GetFirst(&fileName);
while (hasNext) while (hasNext)
@ -1703,13 +1704,34 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
wxDateTime creationTime, modificationTime; wxDateTime creationTime, modificationTime;
fileInfo.GetTimes(nullptr, &modificationTime, &creationTime); fileInfo.GetTimes(nullptr, &modificationTime, &creationTime);
const ryml::Tree indexTree = LoadYAMLFromFile(wxFileName(dirPath, "_pcsx2_index").GetFullPath());
EnumeratedFileEntry entry{fileName, creationTime.GetTicks(), modificationTime.GetTicks(), true};
const wxCharTypeBuffer fileNameUTF8(fileName.ToUTF8()); const wxCharTypeBuffer fileNameUTF8(fileName.ToUTF8());
const YAML::Node& node = index[fileNameUTF8.data()]; int64_t newOrder = orderForLegacyFiles--;
if (!indexTree.empty())
{
const ryml::NodeRef index = indexTree.rootref();
if (index.has_child(c4::to_csubstr(fileNameUTF8)))
{
const ryml::NodeRef& node = index[c4::to_csubstr(fileNameUTF8)];
if (node.has_child("timeCreated"))
{
node["timeCreated"] >> entry.m_timeCreated;
}
if (node.has_child("timeModified"))
{
node["timeModified"] >> entry.m_timeModified;
}
if (node.has_child("order"))
{
node["order"] >> newOrder;
}
}
}
// orderForLegacyFiles will decrement even if it ends up being unused, but that's fine // orderForLegacyFiles will decrement even if it ends up being unused, but that's fine
auto key = std::make_pair(true, getOptionalNodeAttribute(node, "order", orderForLegacyFiles--)); auto key = std::make_pair(true, newOrder);
EnumeratedFileEntry entry{fileName, getOptionalNodeAttribute(node, "timeCreated", creationTime.GetTicks()),
getOptionalNodeAttribute(node, "timeModified", modificationTime.GetTicks()), true};
sortContainer.try_emplace(std::move(key), std::move(entry)); sortContainer.try_emplace(std::move(key), std::move(entry));
} }
else else
@ -1720,13 +1742,28 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
wxDateTime creationTime, modificationTime; wxDateTime creationTime, modificationTime;
fileInfo.GetTimes(nullptr, &modificationTime, &creationTime); fileInfo.GetTimes(nullptr, &modificationTime, &creationTime);
const YAML::Node indexForDirectory = LoadYAMLFromFile(wxFileName(fileInfo.GetFullPath(), "_pcsx2_index").GetFullPath()); const ryml::Tree indexTree = LoadYAMLFromFile(wxFileName(fileInfo.GetFullPath(), "_pcsx2_index").GetFullPath());
const YAML::Node& node = indexForDirectory["%ROOT"];
EnumeratedFileEntry entry{fileName, creationTime.GetTicks(), modificationTime.GetTicks(), false};
if (!indexTree.empty())
{
const ryml::NodeRef indexForDirectory = indexTree.rootref();
if (indexForDirectory.has_child("%ROOT"))
{
const ryml::NodeRef& node = indexForDirectory["%ROOT"];
if (node.has_child("timeCreated"))
{
node["timeCreated"] >> entry.m_timeCreated;
}
if (node.has_child("timeModified"))
{
node["timeModified"] >> entry.m_timeModified;
}
}
}
// orderForDirectories will increment even if it ends up being unused, but that's fine // orderForDirectories will increment even if it ends up being unused, but that's fine
auto key = std::make_pair(false, orderForDirectories++); auto key = std::make_pair(false, orderForDirectories++);
EnumeratedFileEntry entry{fileName, getOptionalNodeAttribute(node, "timeCreated", creationTime.GetTicks()),
getOptionalNodeAttribute(node, "timeModified", modificationTime.GetTicks()), false};
sortContainer.try_emplace(std::move(key), std::move(entry)); sortContainer.try_emplace(std::move(key), std::move(entry));
} }
@ -1748,13 +1785,16 @@ void FolderMemoryCard::DeleteFromIndex(const wxString& filePath, const wxString&
{ {
const wxString indexName = wxFileName(filePath, "_pcsx2_index").GetFullPath(); const wxString indexName = wxFileName(filePath, "_pcsx2_index").GetFullPath();
YAML::Node index = LoadYAMLFromFile(indexName); ryml::Tree indexTree = LoadYAMLFromFile(indexName);
if (!indexTree.empty())
{
ryml::NodeRef index = indexTree.rootref();
const wxCharTypeBuffer key(entry.ToUTF8());
index.remove_child(c4::to_csubstr(key));
const wxCharTypeBuffer entryUTF8(entry.ToUTF8()); // Write out the changes
index.remove(entryUTF8.data()); SaveYAMLToFile(indexName, index);
}
// Write out the changes
SaveYAMLToFile(indexName, index);
} }
// from http://www.oocities.org/siliconvalley/station/8269/sma02/sma02.html#ECC // from http://www.oocities.org/siliconvalley/station/8269/sma02/sma02.html#ECC
@ -1919,28 +1959,39 @@ void FileAccessHelper::WriteIndex(wxFileName folderName, MemoryCardFileEntry* co
const wxCharTypeBuffer fileName(folderName.GetName().ToUTF8()); const wxCharTypeBuffer fileName(folderName.GetName().ToUTF8());
folderName.SetName(L"_pcsx2_index"); folderName.SetName(L"_pcsx2_index");
YAML::Node index = LoadYAMLFromFile(folderName.GetFullPath()); const c4::csubstr key = c4::to_csubstr(fileName);
YAML::Node entryNode = index[fileName.data()]; ryml::Tree indexTree = LoadYAMLFromFile(folderName.GetFullPath());
if (!entryNode.IsDefined()) if (!indexTree.empty())
{ {
// Newly added file - figure out the sort order as the entry should be added to the end of the list ryml::NodeRef index = indexTree.rootref();
unsigned int order = 0;
for (const auto& node : index) if (!index.has_child(key))
{ {
order = std::max(order, node.second["order"].as<unsigned int>(0)); // Newly added file - figure out the sort order as the entry should be added to the end of the list
index[key] = "";
unsigned int maxOrder = 0;
for (const ryml::NodeRef& n : index.children())
{
unsigned int currOrder = 0;
if (n.has_child("order"))
{
n["order"] >> currOrder;
}
maxOrder = std::max(maxOrder, currOrder);
}
index[key]["order"] << maxOrder + 1;
} }
ryml::NodeRef entryNode = index[key];
entryNode["order"] = order + 1; // Update timestamps basing on internal data
const auto* e = &entry->entry.data;
entryNode["timeCreated"] << e->timeCreated.ToTime();
entryNode["timeModified"] << e->timeModified.ToTime();
// Write out the changes
SaveYAMLToFile(folderName.GetFullPath(), index);
} }
// Update timestamps basing on internal data
const auto* e = &entry->entry.data;
entryNode["timeCreated"] = e->timeCreated.ToTime();
entryNode["timeModified"] = e->timeModified.ToTime();
// Write out the changes
SaveYAMLToFile(folderName.GetFullPath(), index);
} }
wxFFile* FileAccessHelper::ReOpen(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata) wxFFile* FileAccessHelper::ReOpen(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata)