mirror of
https://github.com/AxioDL/LibCommon.git
synced 2026-03-30 11:47:23 -07:00
7f20a5ef97
Makes any future potential of a class unlikely.
197 lines
7.2 KiB
C++
197 lines
7.2 KiB
C++
#ifndef AXIO_CBINARYREADER_H
|
|
#define AXIO_CBINARYREADER_H
|
|
|
|
#include "Common/CFourCC.h"
|
|
#include "Common/FileIO/CFileInStream.h"
|
|
#include "Common/Serialization/IArchive.h"
|
|
#include "Common/Serialization/CSerialVersion.h"
|
|
|
|
class CBinaryReader : public IArchive
|
|
{
|
|
struct SBinaryParm
|
|
{
|
|
uint32_t Offset;
|
|
uint32_t Size;
|
|
uint32_t NumChildren;
|
|
uint32_t ChildIndex;
|
|
};
|
|
std::vector<SBinaryParm> mBinaryParmStack;
|
|
|
|
IInputStream *mpStream = nullptr;
|
|
bool mMagicValid = false;
|
|
bool mOwnsStream = false;
|
|
bool mInAttribute = false;
|
|
|
|
public:
|
|
explicit CBinaryReader(const TString& rkFilename, uint32_t Magic)
|
|
: mOwnsStream(true)
|
|
{
|
|
mArchiveFlags = AF_Reader | AF_Binary;
|
|
mpStream = new CFileInStream(rkFilename, std::endian::big);
|
|
|
|
if (mpStream->IsValid())
|
|
{
|
|
mMagicValid = (mpStream->ReadU32() == Magic);
|
|
}
|
|
|
|
// check for incorrectly-formatted data (bug with older version of binary serializer)
|
|
if (mpStream->PeekS16() == -1)
|
|
{
|
|
InitParamStack();
|
|
SerializeVersion();
|
|
}
|
|
else
|
|
{
|
|
mArchiveVersion = mpStream->ReadU16();
|
|
mFileVersion = mpStream->ReadU16();
|
|
mGame = GameFrom4CC(mpStream->ReadFourCC());
|
|
InitParamStack();
|
|
}
|
|
}
|
|
|
|
explicit CBinaryReader(IInputStream *pStream, const CSerialVersion& rkVersion)
|
|
: mMagicValid(true)
|
|
{
|
|
ASSERT(pStream && pStream->IsValid());
|
|
mArchiveFlags = AF_Reader | AF_Binary;
|
|
mpStream = pStream;
|
|
SetVersion(rkVersion);
|
|
|
|
InitParamStack();
|
|
}
|
|
|
|
~CBinaryReader() override
|
|
{
|
|
if (mOwnsStream) delete mpStream;
|
|
}
|
|
|
|
bool IsValid() const { return mpStream->IsValid() && mMagicValid; }
|
|
|
|
private:
|
|
void InitParamStack()
|
|
{
|
|
mpStream->Skip(4); // Skip root ID (which is always -1)
|
|
const auto Size = ReadSize();
|
|
const auto Offset = mpStream->Tell();
|
|
const auto NumChildren = ReadSize();
|
|
mBinaryParmStack.push_back(SBinaryParm{Offset, Size, NumChildren, 0});
|
|
mBinaryParmStack.reserve(20);
|
|
}
|
|
|
|
public:
|
|
// Interface
|
|
uint32_t ReadSize()
|
|
{
|
|
return (mArchiveVersion < eArVer_32BitBinarySize ? (uint32_t) mpStream->ReadU16() : mpStream->ReadU32());
|
|
}
|
|
|
|
bool ParamBegin(const char* pkName, uint32_t Flags) override
|
|
{
|
|
// If this is the parent parameter's first child, then read the child count
|
|
if (mBinaryParmStack.back().NumChildren == 0xFFFFFFFF)
|
|
{
|
|
mBinaryParmStack.back().NumChildren = ReadSize();
|
|
}
|
|
|
|
// Save current offset
|
|
const auto Offset = mpStream->Tell();
|
|
const auto ParamID = TString(pkName).Hash32();
|
|
|
|
// Check the next parameter ID first and check whether it's a match for the current parameter
|
|
if (mBinaryParmStack.back().ChildIndex < mBinaryParmStack.back().NumChildren)
|
|
{
|
|
const auto NextID = mpStream->ReadU32();
|
|
const auto NextSize = ReadSize();
|
|
|
|
// Does the next parameter ID match the current one?
|
|
if (NextID == ParamID || (Flags & SH_IgnoreName))
|
|
{
|
|
mBinaryParmStack.push_back( SBinaryParm { mpStream->Tell(), NextSize, 0xFFFFFFFF, 0 } );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// It's not a match - return to the parent parameter's first child and check all children to find a match
|
|
if (!mBinaryParmStack.empty())
|
|
{
|
|
const auto ParentOffset = mBinaryParmStack.back().Offset;
|
|
const auto NumChildren = mBinaryParmStack.back().NumChildren;
|
|
mpStream->GoTo(ParentOffset);
|
|
|
|
for (uint32_t ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++)
|
|
{
|
|
const auto ChildID = mpStream->ReadU32();
|
|
const auto ChildSize = ReadSize();
|
|
|
|
if (ChildID != ParamID)
|
|
{
|
|
mpStream->Skip(ChildSize);
|
|
}
|
|
else
|
|
{
|
|
mBinaryParmStack.back().ChildIndex = ChildIdx;
|
|
mBinaryParmStack.push_back(SBinaryParm{mpStream->Tell(), ChildSize, 0xFFFFFFFF, 0});
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// None of the children were a match - this parameter isn't in the file
|
|
mpStream->GoTo(Offset);
|
|
return false;
|
|
}
|
|
|
|
void ParamEnd() override
|
|
{
|
|
// Make sure we're at the end of the parameter
|
|
const auto& rParam = mBinaryParmStack.back();
|
|
const auto EndOffset = rParam.Offset + rParam.Size;
|
|
mpStream->GoTo(EndOffset);
|
|
mBinaryParmStack.pop_back();
|
|
|
|
// Increment parent child index
|
|
if (!mBinaryParmStack.empty())
|
|
mBinaryParmStack.back().ChildIndex++;
|
|
}
|
|
|
|
bool PreSerializePointer(void*& Pointer, uint32_t Flags) override
|
|
{
|
|
if (ArchiveVersion() >= eArVer_Refactor)
|
|
{
|
|
bool ValidPtr = (Pointer != nullptr);
|
|
*this << SerialParameter("PointerValid", ValidPtr);
|
|
return ValidPtr;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
virtual void SerializeContainerSize(uint32_t& rSize, const TString& /*rkElemName*/)
|
|
{
|
|
// Mostly handled by ParamBegin, we just need to return the size correctly so the container can be resized
|
|
rSize = (mArchiveVersion < eArVer_32BitBinarySize ? (uint32_t) mpStream->PeekU16() : mpStream->PeekU32());
|
|
}
|
|
|
|
void SerializePrimitive(bool& rValue, uint32_t Flags) override { rValue = mpStream->ReadBool(); }
|
|
void SerializePrimitive(char& rValue, uint32_t Flags) override { rValue = mpStream->ReadS8(); }
|
|
void SerializePrimitive(int8_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadS8(); }
|
|
void SerializePrimitive(uint8_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadU8(); }
|
|
void SerializePrimitive(int16_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadS16(); }
|
|
void SerializePrimitive(uint16_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadU16(); }
|
|
void SerializePrimitive(int32_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadS32(); }
|
|
void SerializePrimitive(uint32_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadU32(); }
|
|
void SerializePrimitive(int64_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadS64(); }
|
|
void SerializePrimitive(uint64_t& rValue, uint32_t Flags) override { rValue = mpStream->ReadU64(); }
|
|
void SerializePrimitive(float& rValue, uint32_t Flags) override { rValue = mpStream->ReadF32(); }
|
|
void SerializePrimitive(double& rValue, uint32_t Flags) override { rValue = mpStream->ReadF64(); }
|
|
void SerializePrimitive(TString& rValue, uint32_t Flags) override { rValue = mpStream->ReadSizedString(); }
|
|
void SerializePrimitive(CFourCC& rValue, uint32_t Flags) override { rValue = CFourCC(*mpStream); }
|
|
void SerializePrimitive(CAssetID& rValue, uint32_t Flags) override { rValue = CAssetID(*mpStream, Game()); }
|
|
void SerializeBulkData(void* pData, uint32_t Size, uint32_t Flags) override { mpStream->ReadBytes(pData, Size); }
|
|
};
|
|
|
|
#endif // AXIO_CBINARYREADER_H
|
|
|