#pragma once
#include "BuildSettings.h"
#include "../common/mptBaseTypes.h"
#include "../common/mptIO.h"
#include "../common/Endianness.h"
#include <algorithm>
#include <bitset>
#include <ios>
#include <iosfwd>
#include <limits>
#include <string>
#include <vector>
#include <istream>
#include <ostream>
#include <cstring>
OPENMPT_NAMESPACE_BEGIN
namespace srlztn {
typedef std::ios::off_type Offtype;
typedef Offtype Postype;
typedef uintptr_t DataSize; typedef uintptr_t RposType; typedef uintptr_t NumType;
const DataSize invalidDatasize = DataSize(-1);
enum
{
SNT_PROGRESS = 0x08000000, SNT_FAILURE = 0x40000000, SNT_NOTE = 0x20000000, SNT_WARNING = 0x10000000, SNT_NONE = 0,
SNRW_BADGIVEN_STREAM = 1 | SNT_FAILURE,
SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 2 | SNT_FAILURE,
SNR_STARTBYTE_MISMATCH = 3 | SNT_FAILURE,
SNR_BADSTREAM_AT_MAP_READ = 4 | SNT_FAILURE,
SNR_INSUFFICIENT_STREAM_OFFTYPE = 5 | SNT_FAILURE,
SNR_OBJECTCLASS_IDMISMATCH = 6 | SNT_FAILURE,
SNR_TOO_MANY_ENTRIES_TO_READ = 7 | SNT_FAILURE,
SNR_INSUFFICIENT_RPOSTYPE = 8 | SNT_FAILURE,
SNR_ZEROENTRYCOUNT = 0x80 | SNT_NOTE, SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x100 | SNT_NOTE,
SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x200 | SNT_NOTE,
SNW_INSUFFICIENT_FIXEDSIZE = (0x10) | SNT_FAILURE,
SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = (0x11) | SNT_FAILURE,
SNW_DATASIZETYPE_OVERFLOW = (0x13) | SNT_FAILURE,
SNW_MAX_WRITE_COUNT_REACHED = (0x14) | SNT_FAILURE,
SNW_INSUFFICIENT_DATASIZETYPE = (0x16) | SNT_FAILURE
};
enum
{
IdSizeVariable = uint16_max,
IdSizeMaxFixedSize = (uint8_max >> 1)
};
typedef int32 SsbStatus;
struct ReadEntry
{
ReadEntry() : nIdpos(0), rposStart(0), nSize(invalidDatasize), nIdLength(0) {}
uintptr_t nIdpos; RposType rposStart; DataSize nSize; uint16 nIdLength; };
enum Rwf
{
RwfWMapStartPosEntry, RwfWMapSizeEntry, RwfWMapDescEntry, RwfWVersionNum, RwfRMapCached, RwfRMapHasId, RwfRMapHasStartpos, RwfRMapHasSize, RwfRMapHasDesc, RwfRTwoBytesDescChar, RwfRHeaderIsRead, RwfRwHasMap, RwfNumFlags
};
template<class T>
inline void Binarywrite(std::ostream& oStrm, const T& data)
{
mpt::IO::WriteIntLE(oStrm, data);
}
template<>
inline void Binarywrite(std::ostream& oStrm, const float& data)
{
IEEE754binary32LE tmp = IEEE754binary32LE(data);
mpt::IO::Write(oStrm, tmp);
}
template<>
inline void Binarywrite(std::ostream& oStrm, const double& data)
{
IEEE754binary64LE tmp = IEEE754binary64LE(data);
mpt::IO::Write(oStrm, tmp);
}
template <class T>
inline void WriteItem(std::ostream& oStrm, const T& data)
{
static_assert(std::is_trivial<T>::value == true, "");
Binarywrite(oStrm, data);
}
void WriteItemString(std::ostream& oStrm, const std::string &str);
template <>
inline void WriteItem<std::string>(std::ostream& oStrm, const std::string& str) {WriteItemString(oStrm, str);}
template<class T>
inline void Binaryread(std::istream& iStrm, T& data)
{
mpt::IO::ReadIntLE(iStrm, data);
}
template<>
inline void Binaryread(std::istream& iStrm, float& data)
{
IEEE754binary32LE tmp = IEEE754binary32LE(0.0f);
mpt::IO::Read(iStrm, tmp);
data = tmp;
}
template<>
inline void Binaryread(std::istream& iStrm, double& data)
{
IEEE754binary64LE tmp = IEEE754binary64LE(0.0);
mpt::IO::Read(iStrm, tmp);
data = tmp;
}
template <class T>
inline void Binaryread(std::istream& iStrm, T& data, const Offtype bytecount)
{
mpt::IO::ReadBinaryTruncatedLE(iStrm, data, static_cast<std::size_t>(bytecount));
}
template <>
inline void Binaryread<float>(std::istream& iStrm, float& data, const Offtype bytecount)
{
typedef IEEE754binary32LE T;
mpt::byte bytes[sizeof(T)];
std::memset(bytes, 0, sizeof(T));
mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
data = 0.0f;
}
template <>
inline void Binaryread<double>(std::istream& iStrm, double& data, const Offtype bytecount)
{
typedef IEEE754binary64LE T;
mpt::byte bytes[sizeof(T)];
std::memset(bytes, 0, sizeof(T));
mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
data = 0.0;
}
template <class T>
inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize)
{
static_assert(std::is_trivial<T>::value == true, "");
if (nSize == sizeof(T) || nSize == invalidDatasize)
Binaryread(iStrm, data);
else
Binaryread(iStrm, data, nSize);
}
void ReadItemString(std::istream& iStrm, std::string& str, const DataSize);
template <>
inline void ReadItem<std::string>(std::istream& iStrm, std::string& str, const DataSize nSize)
{
ReadItemString(iStrm, str, nSize);
}
class ID
{
private:
std::string m_ID; public:
ID() { }
ID(const std::string &id) : m_ID(id) { }
ID(const char *beg, const char *end) : m_ID(beg, end) { }
ID(const char *id) : m_ID(id?id:"") { }
ID(const char * str, std::size_t len) : m_ID(str, str + len) { }
template <typename T>
static ID FromInt(const T &val)
{
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
typename mpt::make_le<T>::type valle;
valle = val;
return ID(std::string(mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data()), mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data() + sizeof(valle))));
}
bool IsPrintable() const;
mpt::ustring AsString() const;
const char *GetBytes() const { return m_ID.c_str(); }
std::size_t GetSize() const { return m_ID.length(); }
bool operator == (const ID &other) const { return m_ID == other.m_ID; }
bool operator != (const ID &other) const { return m_ID != other.m_ID; }
};
class Ssb
{
protected:
Ssb();
public:
SsbStatus GetStatus() const
{
return m_Status;
}
protected:
NumType GetCounter() const {return m_nCounter;}
void SetFlag(Rwf flag, bool val) {m_Flags.set(flag, val);}
bool GetFlag(Rwf flag) const {return m_Flags[flag];}
protected:
SsbStatus m_Status;
uint32 m_nFixedEntrySize;
Postype m_posStart;
uint16 m_nIdbytes; NumType m_nCounter;
std::bitset<RwfNumFlags> m_Flags;
protected:
enum : uint8 { s_DefaultFlagbyte = 0 };
static const char s_EntryID[3];
};
class SsbRead
: public Ssb
{
public:
enum ReadRv {
EntryRead,
EntryNotFound
};
enum IdMatchStatus
{
IdMatch, IdMismatch
};
typedef std::vector<ReadEntry>::const_iterator ReadIterator;
SsbRead(std::istream& iStrm);
void BeginRead(const ID &id, const uint64& nVersion);
NumType GetNumEntries() const {return m_nReadEntrycount;}
ReadIterator GetReadBegin();
ReadIterator GetReadEnd();
IdMatchStatus CompareId(const ReadIterator& iter, const ID &id);
uint64 GetReadVersion() {return m_nReadVersion;}
template <class T>
ReadRv ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem<T>);}
template <class T, class FuncObj>
ReadRv ReadItem(T& obj, const ID &id, FuncObj);
template <class T>
ReadRv ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem<T>);}
template <class T, class FuncObj>
ReadRv ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func);
private:
void CacheMap();
const ReadEntry* Find(const ID &id);
ReadRv OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin);
void AddReadNote(const SsbStatus s);
void AddReadNote(const ReadEntry* const pRe, const NumType nNum);
void ResetReadstatus();
private:
std::istream& iStrm;
std::vector<char> m_Idarray;
std::vector<ReadEntry> mapData; uint64 m_nReadVersion; RposType m_rposMapBegin; Postype m_posMapEnd; Postype m_posDataBegin; RposType m_rposEndofHdrData; NumType m_nReadEntrycount;
NumType m_nNextReadHint;
};
class SsbWrite
: public Ssb
{
public:
SsbWrite(std::ostream& oStrm);
void BeginWrite(const ID &id, const uint64& nVersion);
template <class T>
void WriteItem(const T& obj, const ID &id) {WriteItem(obj, id, &srlztn::WriteItem<T>);}
template <class T, class FuncObj>
void WriteItem(const T& obj, const ID &id, FuncObj);
void FinishWrite();
private:
void OnWroteItem(const ID &id, const Postype& posBeforeWrite);
void AddWriteNote(const SsbStatus s);
void AddWriteNote(const ID &id,
const NumType nEntryNum,
const DataSize nBytecount,
const RposType rposStart);
void WriteMapItem(const ID &id,
const RposType& rposDataStart,
const DataSize& nDatasize,
const char* pszDesc);
void ResetWritestatus() {m_Status = SNT_NONE;}
void IncrementWriteCounter();
private:
std::ostream& oStrm;
Postype m_posEntrycount; Postype m_posMapPosField; std::string m_MapStreamString;
};
template <class T, class FuncObj>
void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
{
const Postype pos = oStrm.tellp();
Func(oStrm, obj);
OnWroteItem(id, pos);
}
template <class T, class FuncObj>
SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
{
const ReadEntry* pE = Find(id);
const Postype pos = iStrm.tellg();
if (pE != nullptr || GetFlag(RwfRMapHasId) == false)
Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize);
return OnReadEntry(pE, id, pos);
}
template <class T, class FuncObj>
SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func)
{
iStrm.clear();
if (iter->rposStart != 0)
iStrm.seekg(m_posStart + Postype(iter->rposStart));
const Postype pos = iStrm.tellg();
func(iStrm, obj, iter->nSize);
return OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos);
}
inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const ID &id)
{
if(iter->nIdpos >= m_Idarray.size()) return IdMismatch;
return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)) ? IdMatch : IdMismatch;
}
inline SsbRead::ReadIterator SsbRead::GetReadBegin()
{
MPT_ASSERT(GetFlag(RwfRMapHasId) && (GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0));
if (GetFlag(RwfRMapCached) == false)
CacheMap();
return mapData.begin();
}
inline SsbRead::ReadIterator SsbRead::GetReadEnd()
{
if (GetFlag(RwfRMapCached) == false)
CacheMap();
return mapData.end();
}
template <class T>
struct VectorWriter
{
VectorWriter(size_t nCount) : m_nCount(nCount) {}
void operator()(std::ostream &oStrm, const std::vector<T> &vec)
{
for(size_t i = 0; i < m_nCount; i++)
{
Binarywrite(oStrm, vec[i]);
}
}
size_t m_nCount;
};
template <class T>
struct VectorReader
{
VectorReader(size_t nCount) : m_nCount(nCount) {}
void operator()(std::istream& iStrm, std::vector<T> &vec, const size_t)
{
vec.resize(m_nCount);
for(std::size_t i = 0; i < m_nCount; ++i)
{
Binaryread(iStrm, vec[i]);
}
}
size_t m_nCount;
};
template <class T>
struct ArrayReader
{
ArrayReader(size_t nCount) : m_nCount(nCount) {}
void operator()(std::istream& iStrm, T* pData, const size_t)
{
for(std::size_t i=0; i<m_nCount; ++i)
{
Binaryread(iStrm, pData[i]);
}
}
size_t m_nCount;
};
}
OPENMPT_NAMESPACE_END