Files
Lioncache 7f20a5ef97 General: Add AXIO_ prefix to header guards
Makes any future potential of a class unlikely.
2026-01-16 22:45:09 -05:00

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