#ifndef CBINARYWRITER #define CBINARYWRITER #include "IArchive.h" #include "Common/CFourCC.h" class CBinaryWriter : public IArchive { struct SParameter { u32 Offset; u16 NumSubParams; bool Abstract; }; std::vector mParamStack; IOutputStream *mpStream; bool mOwnsStream; public: CBinaryWriter(const TString& rkFilename, u16 FileVersion, EGame Game = eUnknownGame) : IArchive(false, true) , mOwnsStream(true) { mpStream = new CFileOutStream(rkFilename.ToStdString(), IOUtil::eBigEndian); ASSERT(mpStream->IsValid()); SetVersion(skCurrentArchiveVersion, FileVersion, Game); GetVersionInfo().Write(*mpStream); } CBinaryWriter(IOutputStream *pStream, u16 FileVersion, EGame Game = eUnknownGame) : IArchive(false, true) , mOwnsStream(false) { ASSERT(pStream->IsValid()); mpStream = pStream; SetVersion(skCurrentArchiveVersion, FileVersion, Game); } CBinaryWriter(IOutputStream *pStream, const CSerialVersion& rkVersion) : IArchive(false, true) , mOwnsStream(false) { ASSERT(pStream->IsValid()); mpStream = pStream; SetVersion(rkVersion); } ~CBinaryWriter() { if (mOwnsStream) delete mpStream; } // Interface virtual bool ParamBegin(const char *pkName) { if (!mParamStack.empty()) { mParamStack.back().NumSubParams++; if (mParamStack.back().NumSubParams == 1) mpStream->WriteShort(-1); // Sub-param count filler } mParamStack.push_back( SParameter { mpStream->Tell(), 0, false } ); u32 ParamID = TString(pkName).Hash32(); mpStream->WriteLong(ParamID); mpStream->WriteShort((u16) 0xFFFF); // Param size filler return true; } virtual void ParamEnd() { SParameter& rParam = mParamStack.back(); u32 StartOffset = rParam.Offset; u32 EndOffset = mpStream->Tell(); u16 ParamSize = (u16) (EndOffset - StartOffset) - 6; mpStream->Seek(StartOffset + 4, SEEK_SET); mpStream->WriteShort(ParamSize); if (rParam.NumSubParams > 0) { if (rParam.Abstract) mpStream->Seek(4, SEEK_CUR); mpStream->WriteShort(rParam.NumSubParams); } mpStream->Seek(EndOffset, SEEK_SET); mParamStack.pop_back(); } virtual void SerializeContainerSize(u32& rSize) { // Normally handled by ParamBegin and ParamEnd but we need to do something here to account for zero-sized containers if (rSize == 0) mpStream->WriteShort(0); } virtual void SerializeAbstractObjectType(u32& rType) { // Mark this parameter as abstract so we can account for the object type in the filestream mpStream->WriteLong(rType); mParamStack.back().Abstract = true; } virtual void SerializePrimitive(bool& rValue) { mpStream->WriteBool(rValue); } virtual void SerializePrimitive(char& rValue) { mpStream->WriteByte(rValue); } virtual void SerializePrimitive(s8& rValue) { mpStream->WriteByte(rValue); } virtual void SerializePrimitive(u8& rValue) { mpStream->WriteByte(rValue); } virtual void SerializePrimitive(s16& rValue) { mpStream->WriteShort(rValue); } virtual void SerializePrimitive(u16& rValue) { mpStream->WriteShort(rValue); } virtual void SerializePrimitive(s32& rValue) { mpStream->WriteLong(rValue); } virtual void SerializePrimitive(u32& rValue) { mpStream->WriteLong(rValue); } virtual void SerializePrimitive(s64& rValue) { mpStream->WriteLongLong(rValue); } virtual void SerializePrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } virtual void SerializePrimitive(float& rValue) { mpStream->WriteFloat(rValue); } virtual void SerializePrimitive(double& rValue) { mpStream->WriteDouble(rValue); } virtual void SerializePrimitive(TString& rValue) { mpStream->WriteSizedString(rValue.ToStdString()); } virtual void SerializePrimitive(TWideString& rValue) { mpStream->WriteSizedWideString(rValue.ToStdString()); } virtual void SerializePrimitive(CFourCC& rValue) { rValue.Write(*mpStream); } virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream); } virtual void SerializeHexPrimitive(u8& rValue) { mpStream->WriteByte(rValue); } virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); } virtual void SerializeHexPrimitive(u32& rValue) { mpStream->WriteLong(rValue); } virtual void SerializeHexPrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } }; #endif // CBINARYWRITER