Created
April 27, 2017 03:13
-
-
Save ligfx/a9901bc32fd639a3796c7e34b41f5554 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Helper class for describing binary formats like FIFO log files. Create a | |
// subclass and implement Describe(...), then call ::Read or ::Write on it. | |
// Curiously-recurring template pattern | |
template <typename Derived> | |
class BinaryFormatDescription | |
{ | |
template <typename T> | |
struct is_simple | |
{ | |
static const bool value = std::is_arithmetic<T>::value || std::is_enum<T>::value; | |
}; | |
public: | |
template <typename... Args> | |
static auto Read(File::IOFile* file, Args... args) | |
{ | |
Derived d; | |
d.m_file = file; | |
d.m_mode = Mode::Read; | |
auto ret = d.Describe(args...); | |
return ret; | |
} | |
template <typename... Args> | |
static auto Write(File::IOFile* file, Args... args) | |
{ | |
Derived d; | |
d.m_file = file; | |
d.m_mode = Mode::Write; | |
auto ret = d.Describe(args...); | |
return ret; | |
} | |
protected: | |
template <typename T> | |
std::enable_if_t<is_simple<T>::value> Value(T& val) | |
{ | |
ReadOrWrite(&val, sizeof(val)); | |
} | |
template <typename T, typename U> | |
std::enable_if_t<is_simple<T>::value && !std::is_same<T, U>::value> Value(U& val) | |
{ | |
T t = val; | |
ReadOrWrite(&t, sizeof(t)); | |
val = static_cast<U>(t); | |
} | |
template <typename T> | |
std::enable_if_t<is_simple<T>::value, T> Constant(const T& val) | |
{ | |
T t = val; | |
ReadOrWrite(&t, sizeof(t)); | |
return t; | |
} | |
template <typename T, size_t N> | |
std::enable_if_t<is_simple<T>::value> Value(std::array<T, N>& val) | |
{ | |
ReadOrWrite(val.data(), sizeof(T) * N); | |
} | |
template <typename T> | |
std::enable_if_t<is_simple<T>::value> Value(std::vector<T>& val) | |
{ | |
ReadOrWrite(val.data(), sizeof(T) * val.size()); | |
} | |
void Skip(size_t size) { m_file->Seek(size, SEEK_CUR); } | |
template <typename T, typename U = u32> | |
void SizeOf(T& seq) | |
{ | |
U size = seq.size(); | |
ReadOrWrite(&size, sizeof(size)); | |
if (size != seq.size()) | |
seq.resize(size); | |
} | |
private: | |
void ReadOrWrite(void* data, size_t size) | |
{ | |
if (m_mode == Mode::Read) | |
m_file->ReadBytes(data, size); | |
else | |
m_file->WriteBytes(data, size); | |
} | |
enum class Mode | |
{ | |
Read, | |
Write | |
}; | |
File::IOFile* m_file = nullptr; | |
Mode m_mode = Mode::Read; | |
}; | |
class FifoDataFileDescription : public BinaryFormatDescription<FifoDataFileDescription> | |
{ | |
public: | |
bool Describe(FifoDataFile* fifo, bool flags_only) | |
{ | |
u32 file_id = Constant<u32>(FILE_ID); | |
if (file_id != FILE_ID) | |
return false; | |
Value<u32>(fifo->m_Version); | |
auto min_loader_version = Constant<u32>(MIN_LOADER_VERSION); | |
if (min_loader_version > VERSION_NUMBER) | |
return false; | |
Skip(56); | |
SizeOf(fifo->m_Frames); | |
Value<u32>(fifo->m_Flags); | |
Skip(52); | |
if (flags_only) | |
return true; | |
for (auto& frame : fifo->m_Frames) | |
{ | |
Skip(8); | |
SizeOf(frame.fifoData); | |
Value<u32>(frame.fifoStart); | |
Value<u32>(frame.fifoEnd); | |
Skip(8); | |
SizeOf(frame.memoryUpdates); | |
Skip(32); | |
} | |
Value(fifo->m_BPMem); | |
Value(fifo->m_CPMem); | |
Value(fifo->m_XFMem); | |
Value(fifo->m_XFRegs); | |
if (fifo->m_Version >= 4) | |
{ | |
Value(fifo->m_TexMem); | |
} | |
for (auto& frame : fifo->m_Frames) | |
{ | |
Value(frame.fifoData); | |
for (auto& update : frame.memoryUpdates) | |
{ | |
Value<u32>(update.fifoPosition); | |
Value<u32>(update.address); | |
Skip(8); | |
SizeOf(update.data); | |
Value<u8>(update.type); | |
Skip(3); | |
} | |
for (auto& update : frame.memoryUpdates) | |
{ | |
Value(update.data); | |
} | |
} | |
return true; | |
} | |
}; | |
bool FifoDataFile::Save(const std::string& filename) | |
{ | |
File::IOFile file; | |
if (!file.Open(filename, "wb")) | |
return false; | |
return FifoDataFileDescription::Write(&file, this, false); | |
} | |
std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bool flagsOnly) | |
{ | |
File::IOFile file; | |
if (!file.Open(filename, "rb")) | |
return nullptr; | |
auto dataFile = std::make_unique<FifoDataFile>(); | |
if (FifoDataFileDescription::Read(&file, dataFile.get(), flagsOnly)) | |
return dataFile; | |
return nullptr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment