174 lines
4.8 KiB
C++
174 lines
4.8 KiB
C++
#pragma once
|
|
#include "../dependency/minidef/src/TypeDef.h"
|
|
#include "../game/Log.h"
|
|
|
|
#include "bx/string.h"
|
|
#include <bx/file.h>
|
|
#include <cstdint>
|
|
|
|
namespace Generated
|
|
{
|
|
struct Serializer
|
|
{
|
|
bx::Error Err;
|
|
bx::FilePath Path;
|
|
bx::FileWriter Writer;
|
|
|
|
bool Init(const bx::FilePath& path, const char* _4cc)
|
|
{
|
|
if (_4cc == nullptr)
|
|
{
|
|
LOG_ERROR("Provided invalid 4cc!");
|
|
return false;
|
|
}
|
|
if (path.isEmpty())
|
|
{
|
|
LOG_ERROR("Provided empty path!");
|
|
return false;
|
|
}
|
|
Path = path;
|
|
if (!Writer.open(path, false, &Err))
|
|
{
|
|
LOG_ERROR("Failed to open file %s: %s", path.getCPtr(), Err.getMessage().getCPtr());
|
|
return false;
|
|
}
|
|
Writer.write(_4cc, 4, &Err);
|
|
if (!Err.isOk())
|
|
{
|
|
LOG_ERROR("Failed to write to file %s: %s", path.getCPtr(), Err.getMessage().getCPtr());
|
|
}
|
|
return Err.isOk();
|
|
}
|
|
|
|
template <typename T> bool WriteT(const T& data)
|
|
{
|
|
uint32_t hash = data.Hash;
|
|
if (!Write(&hash, sizeof(hash))) return false;
|
|
|
|
uint32_t defSize = 0;
|
|
if (!Write(&defSize, sizeof(defSize))) return false;
|
|
|
|
// auto& definitions = GetDefinitions();
|
|
// if (!Write(&definitions, sizeof(definitions))) return false;
|
|
|
|
uint32_t size = sizeof(T);
|
|
if (!Write(&size, sizeof(size))) return false;
|
|
|
|
return Save(&data, 1, *this);
|
|
}
|
|
|
|
bool Write(const void* data, uint32_t size)
|
|
{
|
|
Writer.write(data, size, &Err);
|
|
if (!Err.isOk()) LOG_ERROR("Write error: %s", Err.getMessage().getCPtr());
|
|
return Err.isOk();
|
|
}
|
|
|
|
void Finish()
|
|
{
|
|
Writer.close();
|
|
}
|
|
|
|
~Serializer()
|
|
{
|
|
Writer.close();
|
|
}
|
|
};
|
|
|
|
struct Deserializer
|
|
{
|
|
bx::Error Err;
|
|
bx::FilePath Path;
|
|
bx::FileReader Reader;
|
|
|
|
bool Init(const bx::FilePath& path, const char* _4cc)
|
|
{
|
|
Path = path;
|
|
if (!Reader.open(path, &Err))
|
|
{
|
|
LOG_ERROR("Failed to open file %s: %s", path.getCPtr(), Err.getMessage().getCPtr());
|
|
return false;
|
|
}
|
|
char read4cc[4]{0};
|
|
int32_t readAmount = Reader.read(read4cc, 4, &Err);
|
|
if (!Err.isOk())
|
|
{
|
|
LOG_ERROR("Failed to read from file %s: %s", path.getCPtr(), Err.getMessage().getCPtr());
|
|
return false;
|
|
}
|
|
if (readAmount < 4)
|
|
{
|
|
LOG_ERROR("Failed to read enough bytes from file %s", path.getCPtr());
|
|
return false;
|
|
}
|
|
if (read4cc[0] != _4cc[0] || read4cc[1] != _4cc[1] || read4cc[2] != _4cc[2] || read4cc[3] != _4cc[3])
|
|
{
|
|
LOG_ERROR("4CC mismatch! %.4s != %.4s", read4cc, _4cc);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Read(void* data, uint32_t size)
|
|
{
|
|
Reader.read(data, size, &Err);
|
|
if (!Err.isOk()) LOG_ERROR("Read error: %s", Err.getMessage().getCPtr());
|
|
return Err.isOk();
|
|
}
|
|
|
|
template <typename T> bool ReadT(T& data)
|
|
{
|
|
uint32_t hash = 0;
|
|
if (!Read(&hash, sizeof(hash))) return false;
|
|
|
|
uint32_t defSize = 0;
|
|
if (!Read(&defSize, sizeof(defSize))) return false;
|
|
|
|
if (data.Hash != hash)
|
|
{
|
|
LOG_WARN("Hash mismatch! %u != %u", data.Hash, hash);
|
|
|
|
// TODO: figure out upgrade data
|
|
data = {};
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LOG("Hash match!");
|
|
|
|
// Skip definitions, we know they match
|
|
Reader.seek(defSize);
|
|
|
|
uint32_t size = 0;
|
|
if (!Read(&size, sizeof(size))) return false;
|
|
if (sizeof(T) != size)
|
|
{
|
|
LOG_ERROR("Size mismatch! %u != %u", sizeof(T), size);
|
|
return false;
|
|
}
|
|
|
|
if (!Load(&data, 1, *this))
|
|
{
|
|
LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Finish()
|
|
{
|
|
Reader.close();
|
|
}
|
|
|
|
~Deserializer()
|
|
{
|
|
Reader.close();
|
|
}
|
|
};
|
|
|
|
template <typename T> bool Save(const T* obj, uint32_t count, Serializer& serializer);
|
|
template <typename T> bool Load(T* obj, uint32_t count, Deserializer& serializer);
|
|
} // namespace Generated
|