Applied some fixes to the binary reader/writer classes
This commit is contained in:
parent
c6e6ccaa89
commit
5a398423e1
|
@ -6,11 +6,14 @@
|
||||||
|
|
||||||
class CHashFNV1A
|
class CHashFNV1A
|
||||||
{
|
{
|
||||||
u64 mHash;
|
public:
|
||||||
|
|
||||||
enum EHashLength {
|
enum EHashLength {
|
||||||
e32Bit, e64Bit
|
e32Bit, e64Bit
|
||||||
} mHashLength;
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
u64 mHash;
|
||||||
|
EHashLength mHashLength;
|
||||||
|
|
||||||
static const u64 skFNVOffsetBasis32 = 0x811C9DC5;
|
static const u64 skFNVOffsetBasis32 = 0x811C9DC5;
|
||||||
static const u64 skFNVOffsetBasis64 = 0xCBF29CE484222325;
|
static const u64 skFNVOffsetBasis64 = 0xCBF29CE484222325;
|
||||||
|
@ -18,9 +21,12 @@ class CHashFNV1A
|
||||||
static const u64 skFNVPrime64 = 0x100000001B3;
|
static const u64 skFNVPrime64 = 0x100000001B3;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CHashFNV1A()
|
CHashFNV1A(EHashLength Length)
|
||||||
{
|
{
|
||||||
Init32();
|
if (Length == e32Bit)
|
||||||
|
Init32();
|
||||||
|
else
|
||||||
|
Init64();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init32()
|
void Init32()
|
||||||
|
|
|
@ -11,7 +11,8 @@ class CBinaryReader : public IArchive
|
||||||
{
|
{
|
||||||
u32 Offset;
|
u32 Offset;
|
||||||
u16 Size;
|
u16 Size;
|
||||||
bool HasChildren;
|
u16 NumChildren;
|
||||||
|
u16 ChildIndex;
|
||||||
bool Abstract;
|
bool Abstract;
|
||||||
};
|
};
|
||||||
std::vector<SParameter> mParamStack;
|
std::vector<SParameter> mParamStack;
|
||||||
|
@ -30,7 +31,7 @@ public:
|
||||||
CSerialVersion Version(*mpStream);
|
CSerialVersion Version(*mpStream);
|
||||||
SetVersion(Version);
|
SetVersion(Version);
|
||||||
|
|
||||||
mParamStack.reserve(20);
|
InitParamStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBinaryReader(IInputStream *pStream, const CSerialVersion& rkVersion)
|
CBinaryReader(IInputStream *pStream, const CSerialVersion& rkVersion)
|
||||||
|
@ -41,7 +42,7 @@ public:
|
||||||
mpStream = pStream;
|
mpStream = pStream;
|
||||||
SetVersion(rkVersion);
|
SetVersion(rkVersion);
|
||||||
|
|
||||||
mParamStack.reserve(20);
|
InitParamStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
~CBinaryReader()
|
~CBinaryReader()
|
||||||
|
@ -49,27 +50,43 @@ public:
|
||||||
if (mOwnsStream) delete mpStream;
|
if (mOwnsStream) delete mpStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitParamStack()
|
||||||
|
{
|
||||||
|
mpStream->Skip(4); // Skip root ID (which is always -1)
|
||||||
|
u16 Size = mpStream->ReadShort();
|
||||||
|
u32 Offset = mpStream->Tell();
|
||||||
|
u16 NumChildren = mpStream->ReadShort();
|
||||||
|
mParamStack.push_back( SParameter { Offset, Size, NumChildren, 0, false } );
|
||||||
|
mParamStack.reserve(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
// Interface
|
// Interface
|
||||||
virtual bool ParamBegin(const char *pkName)
|
virtual bool ParamBegin(const char *pkName)
|
||||||
{
|
{
|
||||||
// If this is the parent parameter's first child, then skip the child count
|
// If this is the parent parameter's first child, then read the child count
|
||||||
if (!mParamStack.empty() && !mParamStack.back().HasChildren)
|
if (mParamStack.back().NumChildren == 0xFFFF)
|
||||||
{
|
{
|
||||||
mpStream->Seek(0x2, SEEK_CUR);
|
mParamStack.back().NumChildren = mpStream->ReadShort();
|
||||||
mParamStack.back().HasChildren = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the next parameter ID first and check whether it's a match for the current parameter
|
// Save current offset
|
||||||
u32 ParamID = TString(pkName).Hash32();
|
|
||||||
u32 Offset = mpStream->Tell();
|
u32 Offset = mpStream->Tell();
|
||||||
u32 NextID = mpStream->ReadLong();
|
u32 ParamID = TString(pkName).Hash32();
|
||||||
u16 NextSize = mpStream->ReadShort();
|
|
||||||
|
|
||||||
// Does the next parameter ID match the current one?
|
// Check the next parameter ID first and check whether it's a match for the current parameter
|
||||||
if (NextID == ParamID)
|
if (mParamStack.back().ChildIndex < mParamStack.back().NumChildren)
|
||||||
{
|
{
|
||||||
mParamStack.push_back( SParameter { Offset, NextSize, false, false } );
|
u32 NextID = mpStream->ReadLong();
|
||||||
return true;
|
u16 NextSize = mpStream->ReadShort();
|
||||||
|
|
||||||
|
// Does the next parameter ID match the current one?
|
||||||
|
if (NextID == ParamID)
|
||||||
|
{
|
||||||
|
mParamStack.push_back( SParameter { Offset, NextSize, 0xFFFF, 0, false } );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's not a match - return to the parent parameter's first child and check all children to find a match
|
// It's not a match - return to the parent parameter's first child and check all children to find a match
|
||||||
|
@ -77,26 +94,27 @@ public:
|
||||||
{
|
{
|
||||||
bool ParentAbstract = mParamStack.back().Abstract;
|
bool ParentAbstract = mParamStack.back().Abstract;
|
||||||
u32 ParentOffset = mParamStack.back().Offset;
|
u32 ParentOffset = mParamStack.back().Offset;
|
||||||
mpStream->Seek(ParentOffset + (ParentAbstract ? 0xA : 0x6), SEEK_SET);
|
u16 NumChildren = mParamStack.back().NumChildren;
|
||||||
u16 NumChildren = mpStream->ReadShort();
|
mpStream->GoTo(ParentOffset + (ParentAbstract ? 0xC : 0x8));
|
||||||
|
|
||||||
for (u32 iChild = 0; iChild < NumChildren; iChild++)
|
for (u32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++)
|
||||||
{
|
{
|
||||||
u32 ChildID = mpStream->ReadLong();
|
u32 ChildID = mpStream->ReadLong();
|
||||||
u16 ChildSize = mpStream->ReadShort();
|
u16 ChildSize = mpStream->ReadShort();
|
||||||
|
|
||||||
if (ChildID != ParamID)
|
if (ChildID != ParamID)
|
||||||
mpStream->Seek(ChildSize, SEEK_CUR);
|
mpStream->Skip(ChildSize);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mParamStack.push_back( SParameter { (u32) mpStream->Tell() - 6, NextSize, false, false } );
|
mParamStack.back().ChildIndex = (u16) ChildIdx;
|
||||||
|
mParamStack.push_back( SParameter { mpStream->Tell() - 6, ChildSize, 0xFFFF, 0, false } );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// None of the children were a match - this parameter isn't in the file
|
// None of the children were a match - this parameter isn't in the file
|
||||||
mpStream->Seek(Offset, SEEK_SET);
|
mpStream->GoTo(Offset);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +123,12 @@ public:
|
||||||
// Make sure we're at the end of the parameter
|
// Make sure we're at the end of the parameter
|
||||||
SParameter& rParam = mParamStack.back();
|
SParameter& rParam = mParamStack.back();
|
||||||
u32 EndOffset = rParam.Offset + rParam.Size + 6;
|
u32 EndOffset = rParam.Offset + rParam.Size + 6;
|
||||||
mpStream->Seek(EndOffset, SEEK_SET);
|
mpStream->GoTo(EndOffset);
|
||||||
mParamStack.pop_back();
|
mParamStack.pop_back();
|
||||||
|
|
||||||
|
// Increment parent child index
|
||||||
|
if (!mParamStack.empty())
|
||||||
|
mParamStack.back().ChildIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/)
|
virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/)
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
|
|
||||||
SetVersion(skCurrentArchiveVersion, FileVersion, Game);
|
SetVersion(skCurrentArchiveVersion, FileVersion, Game);
|
||||||
GetVersionInfo().Write(*mpStream);
|
GetVersionInfo().Write(*mpStream);
|
||||||
|
InitParamStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBinaryWriter(IOutputStream *pStream, u16 FileVersion, EGame Game = eUnknownGame)
|
CBinaryWriter(IOutputStream *pStream, u16 FileVersion, EGame Game = eUnknownGame)
|
||||||
|
@ -36,6 +37,7 @@ public:
|
||||||
ASSERT(pStream->IsValid());
|
ASSERT(pStream->IsValid());
|
||||||
mpStream = pStream;
|
mpStream = pStream;
|
||||||
SetVersion(skCurrentArchiveVersion, FileVersion, Game);
|
SetVersion(skCurrentArchiveVersion, FileVersion, Game);
|
||||||
|
InitParamStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBinaryWriter(IOutputStream *pStream, const CSerialVersion& rkVersion)
|
CBinaryWriter(IOutputStream *pStream, const CSerialVersion& rkVersion)
|
||||||
|
@ -45,49 +47,71 @@ public:
|
||||||
ASSERT(pStream->IsValid());
|
ASSERT(pStream->IsValid());
|
||||||
mpStream = pStream;
|
mpStream = pStream;
|
||||||
SetVersion(rkVersion);
|
SetVersion(rkVersion);
|
||||||
|
InitParamStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
~CBinaryWriter()
|
~CBinaryWriter()
|
||||||
{
|
{
|
||||||
if (mOwnsStream) delete mpStream;
|
// Ensure all params have been finished
|
||||||
|
ASSERT(mParamStack.size() == 1);
|
||||||
|
|
||||||
|
// Finish root param
|
||||||
|
ParamEnd();
|
||||||
|
|
||||||
|
// Delete stream
|
||||||
|
if (mOwnsStream)
|
||||||
|
delete mpStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitParamStack()
|
||||||
|
{
|
||||||
|
mParamStack.reserve(20);
|
||||||
|
mpStream->WriteLong(0xFFFFFFFF);
|
||||||
|
mpStream->WriteShort(0); // Size filler
|
||||||
|
mParamStack.push_back( SParameter { mpStream->Tell(), 0, false } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
// Interface
|
// Interface
|
||||||
virtual bool ParamBegin(const char *pkName)
|
virtual bool ParamBegin(const char *pkName)
|
||||||
{
|
{
|
||||||
if (!mParamStack.empty())
|
// Update parent param
|
||||||
{
|
mParamStack.back().NumSubParams++;
|
||||||
mParamStack.back().NumSubParams++;
|
|
||||||
|
|
||||||
if (mParamStack.back().NumSubParams == 1)
|
if (mParamStack.back().NumSubParams == 1)
|
||||||
mpStream->WriteShort(-1); // Sub-param count filler
|
mpStream->WriteShort(-1); // Sub-param count filler
|
||||||
}
|
|
||||||
|
|
||||||
mParamStack.push_back( SParameter { (u32) mpStream->Tell(), 0, false } );
|
|
||||||
|
|
||||||
|
// Write param metadata
|
||||||
u32 ParamID = TString(pkName).Hash32();
|
u32 ParamID = TString(pkName).Hash32();
|
||||||
mpStream->WriteLong(ParamID);
|
mpStream->WriteLong(ParamID);
|
||||||
mpStream->WriteShort((u16) 0xFFFF); // Param size filler
|
mpStream->WriteShort((u16) 0xFFFF); // Param size filler
|
||||||
|
|
||||||
|
// Add new param to the stack
|
||||||
|
mParamStack.push_back( SParameter { mpStream->Tell(), 0, false } );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void ParamEnd()
|
virtual void ParamEnd()
|
||||||
{
|
{
|
||||||
|
// Write param size
|
||||||
SParameter& rParam = mParamStack.back();
|
SParameter& rParam = mParamStack.back();
|
||||||
u32 StartOffset = rParam.Offset;
|
u32 StartOffset = rParam.Offset;
|
||||||
u32 EndOffset = mpStream->Tell();
|
u32 EndOffset = mpStream->Tell();
|
||||||
u16 ParamSize = (u16) (EndOffset - StartOffset) - 6;
|
u16 ParamSize = (u16) (EndOffset - StartOffset);
|
||||||
|
|
||||||
mpStream->Seek(StartOffset + 4, SEEK_SET);
|
mpStream->GoTo(StartOffset - 2);
|
||||||
mpStream->WriteShort(ParamSize);
|
mpStream->WriteShort(ParamSize);
|
||||||
|
|
||||||
if (rParam.NumSubParams > 0)
|
// Write param child count
|
||||||
|
if (rParam.NumSubParams > 0 || mParamStack.size() == 1)
|
||||||
{
|
{
|
||||||
if (rParam.Abstract) mpStream->Seek(4, SEEK_CUR);
|
if (rParam.Abstract) mpStream->Skip(4);
|
||||||
mpStream->WriteShort(rParam.NumSubParams);
|
mpStream->WriteShort(rParam.NumSubParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpStream->Seek(EndOffset, SEEK_SET);
|
mpStream->GoTo(EndOffset);
|
||||||
mParamStack.pop_back();
|
mParamStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,24 @@
|
||||||
#include "TString.h"
|
#include "TString.h"
|
||||||
|
#include "CHashFNV1A.h"
|
||||||
#include <FileIO/IOUtil.h>
|
#include <FileIO/IOUtil.h>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
// ************ TString ************
|
// ************ TString ************
|
||||||
|
u32 TString::Hash32() const
|
||||||
|
{
|
||||||
|
CHashFNV1A Hash(CHashFNV1A::e32Bit);
|
||||||
|
Hash.HashString(*this);
|
||||||
|
return Hash.GetHash32();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 TString::Hash64() const
|
||||||
|
{
|
||||||
|
CHashFNV1A Hash(CHashFNV1A::e64Bit);
|
||||||
|
Hash.HashString(*this);
|
||||||
|
return Hash.GetHash64();
|
||||||
|
}
|
||||||
|
|
||||||
TWideString TString::ToUTF16() const
|
TWideString TString::ToUTF16() const
|
||||||
{
|
{
|
||||||
TWideString Out;
|
TWideString Out;
|
||||||
|
@ -81,6 +96,20 @@ TWideString TString::ToUTF16() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ TWideString ************
|
// ************ TWideString ************
|
||||||
|
u32 TWideString::Hash32() const
|
||||||
|
{
|
||||||
|
CHashFNV1A Hash(CHashFNV1A::e32Bit);
|
||||||
|
Hash.HashData(Data(), Size() * sizeof(wchar_t));
|
||||||
|
return Hash.GetHash32();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 TWideString::Hash64() const
|
||||||
|
{
|
||||||
|
CHashFNV1A Hash(CHashFNV1A::e64Bit);
|
||||||
|
Hash.HashData(Data(), Size() * sizeof(wchar_t));
|
||||||
|
return Hash.GetHash64();
|
||||||
|
}
|
||||||
|
|
||||||
TString TWideString::ToUTF8() const
|
TString TWideString::ToUTF8() const
|
||||||
{
|
{
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> Convert;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> Convert;
|
||||||
|
|
|
@ -387,32 +387,6 @@ public:
|
||||||
return SubString(0, Size() - Amount);
|
return SubString(0, Size() - Amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Hash32() const
|
|
||||||
{
|
|
||||||
u32 Hash = 0;
|
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < Size(); iChar++)
|
|
||||||
{
|
|
||||||
Hash += At(iChar);
|
|
||||||
Hash *= 101;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Hash64() const
|
|
||||||
{
|
|
||||||
u64 Hash = 0;
|
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < Size(); iChar++)
|
|
||||||
{
|
|
||||||
Hash += At(iChar);
|
|
||||||
Hash *= 101;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 ToInt32(int Base = 16) const
|
inline u32 ToInt32(int Base = 16) const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -1112,6 +1086,8 @@ public:
|
||||||
TString(const std::string& rkText) : TBasicString<char>(rkText) {}
|
TString(const std::string& rkText) : TBasicString<char>(rkText) {}
|
||||||
TString(const TBasicString<char>& rkStr) : TBasicString<char>(rkStr) {}
|
TString(const TBasicString<char>& rkStr) : TBasicString<char>(rkStr) {}
|
||||||
|
|
||||||
|
u32 Hash32() const;
|
||||||
|
u64 Hash64() const;
|
||||||
class TWideString ToUTF16() const;
|
class TWideString ToUTF16() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1127,6 +1103,8 @@ public:
|
||||||
TWideString(const std::wstring& rkText) : TBasicString<wchar_t>(rkText) {}
|
TWideString(const std::wstring& rkText) : TBasicString<wchar_t>(rkText) {}
|
||||||
TWideString(const TBasicString<wchar_t>& rkStr) : TBasicString<wchar_t>(rkStr) {}
|
TWideString(const TBasicString<wchar_t>& rkStr) : TBasicString<wchar_t>(rkStr) {}
|
||||||
|
|
||||||
|
u32 Hash32() const;
|
||||||
|
u64 Hash64() const;
|
||||||
class TString ToUTF8() const;
|
class TString ToUTF8() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -243,8 +243,7 @@ u64 CMaterial::HashParameters()
|
||||||
{
|
{
|
||||||
if (mRecalcHash)
|
if (mRecalcHash)
|
||||||
{
|
{
|
||||||
CHashFNV1A Hash;
|
CHashFNV1A Hash(CHashFNV1A::e64Bit);
|
||||||
Hash.Init64();
|
|
||||||
|
|
||||||
Hash.HashLong(mVersion);
|
Hash.HashLong(mVersion);
|
||||||
Hash.HashLong(mOptions);
|
Hash.HashLong(mOptions);
|
||||||
|
|
Loading…
Reference in New Issue