/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /* $Header: /VSS_Sync/wwlib/tagblock.h 6 10/17/00 4:48p Vss_sync $ */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WWLib * * * * $Archive:: /VSS_Sync/wwlib/tagblock.h $* * * * $Author:: Vss_sync $* * * * $Modtime:: 10/16/00 11:42a $* * * * $Revision:: 6 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef TAGBLOCK_H #define TAGBLOCK_H #include "slist.h" #include "crc.h" #include "rawfile.h" #include class TagBlockHandle; class TagBlockIndex; ////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////// Start of TagBlockHandle/////////////////////////////////////// // TagBlockFile: Enables a file to have named (tagged) variable size blocks. User can // then open a block for reading. User may also create new blocks at the end of the // file. There may only be one block open for writting, unlimited blocks can be open for // reading. It can be thought of as a .MIX file that can have files added to it at any time. // One problem is it is a Write Once/Read Many solution. // // Usage: All user access to a TagBlockFile is done through TagBlockHandle. // A TagBlockHandle is created by TagBlockFile::Create_Tag() or Open_Tag(). It is destroyed // by either TagBlockFile::Close_Tag() or you can just destroy the handle with delete(). // // class TagBlockFile : protected RawFileClass { public: ////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Public Member Functions /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// // Open up the tag file. It may or may not exist. TagBlockFile(const char *fname); virtual ~TagBlockFile(); // DANGEROUS!! Resets entire file and makes small virtual void Reset_File(); // Creation of a Handle so block can be crated/writen/read. // Use delete to destroy handle or use Close_Tag(). // Open_Tag() returns NULL if tag not found. // Create_Tag() returns NULL if tag already exists. TagBlockHandle *Open_Tag(const char *tagname); TagBlockHandle *Create_Tag(const char *tagname); void Close_Tag(TagBlockHandle *handle); int Does_Tag_Exist(const char *tagname) { return(Find_Block(tagname) != NULL); } virtual unsigned long Get_Date_Time(void) { return(FileTime); } // Methods to figure an offset of the tag name and the data // given the offset of the start of the block (BlockHeader).. static int Calc_Tag_Offset(int blockoffset) { return(blockoffset + sizeof(BlockHeader)); } static int Calc_Data_Offset(int blockoffset, const char *tagname) { return(Calc_Tag_Offset(blockoffset) + strlen(tagname) + 1); } protected: /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Supporting Structures ///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// enum { // Put in date when format is changed. FILE_VERSION = 20000626, MAX_TAG_NAME_SIZE = 1024, }; // This is the header that is in both the IndexFile and the DataFile. // They should be match except for the difference in the Version number as defined by enum. struct FileHeader { FileHeader() {memset(this, 0, sizeof(*this));} // Version number to make sure that it we are compatable and also to // verify that this is the file we think it is. unsigned Version; // Number of blocks in file. int NumBlocks; // This is how much data is actually valid in the file. There may be // extra room at end of file if file size is preset or the file is corrupt. int FileSize; }; // Each block in the file has a header before it. struct BlockHeader { BlockHeader() {memset(this, 0, sizeof(*this));} BlockHeader(int index, int tagsize, int datasize):Index(index),TagSize(tagsize),DataSize(datasize) {} BlockHeader(BlockHeader& bh) {memcpy(this, &bh, sizeof(BlockHeader));} // Used to verify file integrity. int Index; // Size of tagname (including NULL) that follows this block. int TagSize; // Size of block not including header. int DataSize; // A variable length name (NULL terminated) follows this structure. // The name is then followed by the Data. // The entire length of the block is sizeof(BlockHeader) + TagSize + DataSize. }; protected: /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Member Data Fields //////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// // This is the data at the start of the file. FileHeader Header; // Only one handle has permission to write to the end of the file if any. // This is a pointer to that handle. TagBlockHandle *CreateHandle; // To help those stupid programmers from leaving open handles when // this file is closed down. int NumOpenHandles; // Last time file was written to before we opened it. unsigned long FileTime; // Keep list of all blocks in file. This list is sorted by CRC value. // TagBlockIndex is defined in TagBlock.cpp. SList IndexList; protected: /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Protected Member Functions //////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// // Search for block given tag. TagBlockIndex *Find_Block(const char *tagname); // Create an index that can be used for seaching. TagBlockIndex *Create_Index(const char *tagname, int blockoffset); // Is this the handle that has creation priveledges? int Handle_Can_Write(TagBlockHandle *handle) { return(CreateHandle == handle); } // Called only by ~TagBlockHandle! void Destroy_Handle(TagBlockHandle *handle); // Stop write access - flushes data out but keeps handle available for reading. int End_Write_Access(TagBlockHandle *handle); // Save the header when it has been updated. void Save_Header() { Seek(0, SEEK_SET); Write(&Header, sizeof(Header)); } void Empty_Index_List(); friend class TagBlockHandle; }; ///////////////////////////////////////// End of TagBlockFile ///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////// Start of TagBlockHandle///////////////////////////////////// // All external access to the TagBlockFile is done through handles. class TagBlockHandle { public: // Access functions. int Write(const void *buf, int nbytes); int Read(void *buf, int nbytes); int Seek(int pos, int dir = SEEK_CUR); // Stop write access - flushes data out but keeps handle available for reading. int End_Write_Access() { return (File->End_Write_Access(this)); } int Tell() { return(Position); } int Get_Data_Size() { return(BlockHeader->DataSize); } // User must call TagBlockFile::New_Handle() to create a TagBlockHandle object. // User may call this delete to destry handle or // he may call TagBlockFile::Close_Tag(). ~TagBlockHandle(); private: // Pointer to parent file object. TagBlockFile *File; // Pointer to index for aditional information. TagBlockIndex *Index; // Keep header infomation in memory so that it can be updated. TagBlockFile::BlockHeader *BlockHeader; // Current postion we are in the file. int Position; private: // User must call TagBlockFile::New_Handle() to create a TagBlockHandle object. // The constructor is private so only TagBlockFile can create the handle. // This is so that a handle will not be created if the TagBlock // does not exist on a CREAD or if there was already a WRITE access granted. // User needs to call detete to destroy the handle. TagBlockHandle(TagBlockFile *tagfile, TagBlockIndex *tagindex, TagBlockFile::BlockHeader *blockheader); friend class TagBlockFile; // Used to prevent TagBlockFile::Destroy_Handle() from being called // except by this destructor. static int _InDestructor; int Called_By_Destructor() { return(_InDestructor); } }; ////////////////////////////////////// End of TagBlockHandle/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// #endif //TAGBLOCK_H