Add disk archive serialization (fix crash in driver renegade etc.)

This commit is contained in:
Hamish Milne 2020-04-11 11:52:11 +01:00
parent a210e7e2bd
commit e9ab8f82d4
3 changed files with 83 additions and 23 deletions

View file

@ -16,6 +16,7 @@
#include <vector> #include <vector>
#include <boost/serialization/split_member.hpp> #include <boost/serialization/split_member.hpp>
#include <boost/serialization/string.hpp> #include <boost/serialization/string.hpp>
#include <boost/serialization/wrapper.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include "common/string_util.h" #include "common/string_util.h"
@ -41,6 +42,34 @@ enum class UserPath {
UserDir, UserDir,
}; };
// Replaces install-specific paths with standard placeholders, and back again
std::string SerializePath(const std::string& input, bool is_saving);
// A serializable path string
struct Path : public boost::serialization::wrapper_traits<const Path> {
std::string& str;
explicit Path(std::string& _str) : str(_str) {}
static const Path make(std::string& str) {
return Path(str);
}
template <class Archive>
void save(Archive& ar, const unsigned int) const {
auto s_path = SerializePath(str, true);
ar << s_path;
}
template <class Archive>
void load(Archive& ar, const unsigned int) const {
ar >> str;
str = SerializePath(str, false);
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
friend class boost::serialization::access;
};
// FileSystem tree node/ // FileSystem tree node/
struct FSTEntry { struct FSTEntry {
bool isDirectory; bool isDirectory;
@ -48,6 +77,17 @@ struct FSTEntry {
std::string physicalName; // name on disk std::string physicalName; // name on disk
std::string virtualName; // name in FST names table std::string virtualName; // name in FST names table
std::vector<FSTEntry> children; std::vector<FSTEntry> children;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& isDirectory;
ar& size;
ar& Path::make(physicalName);
ar& Path::make(virtualName);
ar& children;
}
friend class boost::serialization::access;
}; };
// Returns true if file filename exists // Returns true if file filename exists
@ -146,9 +186,6 @@ void SetCurrentRomPath(const std::string& path);
// directory. To be used in "multi-user" mode (that is, installed). // directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path); const std::string& GetUserPath(UserPath path);
// Replaces install-specific paths with standard placeholders, and back again
std::string SerializePath(const std::string& input, bool is_saving);
// Returns the path to where the sys file are // Returns the path to where the sys file are
std::string GetSysDirectory(); std::string GetSysDirectory();
@ -322,27 +359,20 @@ private:
u32 flags; u32 flags;
template <class Archive> template <class Archive>
void save(Archive& ar, const unsigned int) const { void serialize(Archive& ar, const unsigned int) {
auto s_filename = SerializePath(filename, true); ar& Path::make(filename);
ar << s_filename; ar& openmode;
ar << openmode; ar& flags;
ar << flags;
ar << Tell();
}
template <class Archive>
void load(Archive& ar, const unsigned int) {
ar >> filename;
filename = SerializePath(filename, false);
ar >> openmode;
ar >> flags;
u64 pos; u64 pos;
ar >> pos; if (Archive::is_saving::value) {
pos = Tell();
}
ar& pos;
if (Archive::is_loading::value) {
Open(); Open();
Seek(pos, SEEK_SET); Seek(pos, SEEK_SET);
} }
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
friend class boost::serialization::access; friend class boost::serialization::access;
}; };

View file

@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <memory> #include <memory>
#include "common/archives.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -14,6 +15,9 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace // FileSys namespace
SERIALIZE_EXPORT_IMPL(FileSys::DiskFile)
SERIALIZE_EXPORT_IMPL(FileSys::DiskDirectory)
namespace FileSys { namespace FileSys {
ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length, ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length,

View file

@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include <boost/serialization/base_object.hpp> #include <boost/serialization/base_object.hpp>
#include <boost/serialization/unique_ptr.hpp> #include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "core/file_sys/archive_backend.h" #include "core/file_sys/archive_backend.h"
@ -46,12 +47,16 @@ protected:
Mode mode; Mode mode;
std::unique_ptr<FileUtil::IOFile> file; std::unique_ptr<FileUtil::IOFile> file;
private:
DiskFile() = default;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int) { void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<FileBackend>(*this); ar& boost::serialization::base_object<FileBackend>(*this);
ar& mode; ar& mode.hex;
ar& file; ar& file;
} }
friend class boost::serialization::access;
}; };
class DiskDirectory : public DirectoryBackend { class DiskDirectory : public DirectoryBackend {
@ -74,6 +79,27 @@ protected:
// We need to remember the last entry we returned, so a subsequent call to Read will continue // We need to remember the last entry we returned, so a subsequent call to Read will continue
// from the next one. This iterator will always point to the next unread entry. // from the next one. This iterator will always point to the next unread entry.
std::vector<FileUtil::FSTEntry>::iterator children_iterator; std::vector<FileUtil::FSTEntry>::iterator children_iterator;
private:
DiskDirectory() = default;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<DirectoryBackend>(*this);
ar& directory;
u64 child_index;
if (Archive::is_saving::value) {
child_index = children_iterator - directory.children.begin();
}
ar& child_index;
if (Archive::is_loading::value) {
children_iterator = directory.children.begin() + child_index;
}
}
friend class boost::serialization::access;
}; };
} // namespace FileSys } // namespace FileSys
BOOST_CLASS_EXPORT_KEY(FileSys::DiskFile)
BOOST_CLASS_EXPORT_KEY(FileSys::DiskDirectory)