Exteor/include/xtr/io/SerializationManager.hpp

99 lines
2.9 KiB
C++
Raw Permalink Normal View History

2024-06-07 20:30:06 +03:00
#pragma once
#include "ccl/tools/JSON.h"
#include "xtr/doc/FileVersions.hpp"
#include "CArchiveAdapter.hpp"
using JSON = nlohmann::ordered_json;
inline void to_json(JSON& object, const CString str) {
object = xtr::mfc::ToSTL(str);
}
inline void from_json(const JSON& object, CString& str) {
const auto result = object.get<std::string>();
str = xtr::mfc::ToMFC(result);
}
namespace xtr::io {
//! MFC serializable abstract base
template<typename Version>
class MFCSerializable {
inline static const std::string jsonDocumentName = "document.json";
public:
void Serialize(CArchive& ar) {
CArchiveAdapter adapter{ ar };
ASSERT(!ar.IsStoring());
if (!LegacyLoad(adapter)) {
AfxThrowArchiveException(CArchiveException::genericException);
}
}
bool SaveJSON(const std::u8string& path) {
auto json = ExtractData();
json["version"] = static_cast<uint16_t>(Version::Latest());
json["versionInfo"] = Version::LastestInfo();
return WriteToFile(json.dump(4), path);
}
bool LoadJSON(const std::u8string& path) {
const auto data = ReadFromFile(path);
if (!data.has_value()) {
return false;
}
const Version versionID = static_cast<Version::VersionID>(data->at("version").get<uint16_t>());
return Version::Latest() >= versionID && LoadData(data.value());
}
private:
virtual JSON ExtractData() const = 0;
virtual bool LoadData(const JSON& object) = 0;
virtual bool LegacyLoad(CArchiveAdapter& ar) = 0;
bool WriteToFile(std::string_view data, const std::u8string& path) {
try {
std::ofstream outputFile(std::filesystem::path(path), std::ios::binary);
Poco::Zip::Compress archive(outputFile, true);
Poco::MemoryInputStream inputStream(data.data(), size(data));
archive.addFile(inputStream, Poco::DateTime(), jsonDocumentName);
archive.close();
outputFile.close();
} catch (const Poco::Exception& /*error*/) {
return false;
}
return true;
}
std::optional<JSON> ReadFromFile(const std::u8string& path) {
namespace fs = std::filesystem;
auto tmpDirectory = fs::temp_directory_path() / "exteor" / fs::path(path).filename().replace_extension("");
std::ifstream inputFile(fs::path(path), std::ios::binary);
if (!inputFile) {
return std::nullopt;
}
try {
const auto u8folder = tmpDirectory.u8string();
const auto outputFolder = Poco::Path(std::string{ begin(u8folder), end(u8folder) });
Poco::Zip::Decompress(inputFile, outputFolder).decompressAllFiles();
inputFile.close();
} catch (const Poco::Exception& /*error*/) {
return std::nullopt;
}
std::ifstream jsonFile(tmpDirectory / jsonDocumentName);
if (!jsonFile) {
fs::remove_all(tmpDirectory);
return std::nullopt;
} else {
auto jsonData = JSON::parse(jsonFile);
jsonFile.close();
fs::remove_all(tmpDirectory);
return jsonData;
}
}
};
} // namespace xtr::io