// Chunk library #ifndef _chunk_hpp #define _chunk_hpp 1 #if engine #include "3dc.h" #include "mem3dc.h" // for debug new and delete #include "inline.h" #if SupportModules #include "module.h" #endif #include "list_tem.hpp" #endif #if cencon #include "AFXWIN.H" #ifdef _DEBUG #undef new #define new DEBUG_NEW #define my_new DEBUG_NEW #else #define my_new new #endif #include "list_tem.hpp" #endif #if objedit || sprite_edit || ANIMEXP #include "StdAfx.h" #include "list_tem.hpp" #endif #if shpedit #include "stdafx.h" #include "list_tem.hpp" #endif #if standard #include "advwin32.h" #include #include "list_tem.hpp" #endif #define CHUNK_FAILED_ON_LOAD -1 #define CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED -2 #define CHUNK_FAILED_ON_WRITE -3 #define CHECK_FAILED_NOT_OPEN -4 #define DisableLock 1 #define GENERAL_FLAG_LOCKED 0x0000001 // Non class functions ( only one as yet ) // The function will return a list of file pointers // for the starting position of each chunk within a chunk // File pointers are offset from the start of the file. // we start at the header of the chunk we are in // so that we can stop at the end of the chunk #if cencon extern char users_name[]; #endif #ifndef RIFF_OPTIMIZE // define this to get compiler errors where you are calling the old slow functions extern List list_chunks_in_file (HANDLE &, const char * chunk_id); #endif extern void list_chunks_in_file (List * pList, HANDLE, const char * chunk_id); // Structures for interfacing with the outside application // these are going to be basically very C-ee so that C // functions can also read them // The basic chunk class structure is as follows // // Base_Chunk // | | // Chunk_With_Children Data Chunks // | // File_Chunk // // Most chunk classes are either derived from the Chunk // class or the Chunk_With_Children class. // A chunk with data is derived from the Chunk class as follows // class Sample_Data_Chunk : public Chunk // { // public: // // // Constructors are placed either here or may be private // // The constructors for most shape data chunks are private // // as only the Shape_Chunk can call them. This is because // // the shape chunk deals with the data. // // // // Any constuctor should initialise class chunk with the // // correct identifier for the current chunk. // // // // There are normally two constructors - one for constructing // // from interface data one for constructing from raw data. // // // // A destructor can also be placed here or may not be needed // // // // Any variables that are made available for the user should also // // be placed here. // // // // The next three functions are vital for the io functions // // // virtual BOOL output_chunk (HANDLE &hand); // // This function will write the chunk data to the file specified // // by the windows file handle - hand. // // // virtual size_t size_chunk (); // // This function will return the size of the chunk (including the header). // // IT MUST SET the variable chunk_size to the size it returns // // // virtual fill_data_block (char * data_start); // // This function will fill a data block with data. The data will be // // the same as the file data. The data is assumed to be pre-allocated // // with the size given by the size_chunk function. // // // } // A chunk with children is derived from the Chunk_With_Children class // as follows // // class Sample_Chunk_With_Children : public Chunk // { // public: // // // Constructors may be used to construct child chunks from // // interface data. A parsing constructor should be used for // // constructing from raw data (look at Shape_Chunk). // // // // Any constructor should initialise class Chunk_With_Children with // // the correct identifier for the current chunk. // // // // The Destructor does not need to destroy child chunks as the // // Chunk_With_Children destructor will automatically do this. // // // // The three functions (size_chunk, output_chunk and fill_data_block) // // are not needed as Chunk_With_Children can deal with these - but may // // be put in. // // // } // // // The logic behind the locking is as follows. // There are two functions for locking and unlocking chunks // these are currently only in the shape and object chunks // lock_chunk(File_Chunk &) // will lock a chunk, this must only be called once // and will return false if it tries to lock a chunk // that has already been locked by anyone. // unlock_chunk (File_Chunk &, BOOL updatedyn) // will unlock the chunk locally and in the file if it is not to be updated // If it is to be updated, it will set the updated flag and // the chunk can only be locked again once it is written to a file. // The user may call File_Chunk::update_file() whenever // (either after every chunk update, or once a minute) // Note that this fully unlocks locally locked chunks // that are being written to the file. // Another function File_Chunk::update_chunks_from_file() // will reload those chunks that have been externally upadted // This must be done with care!! // The objects are associated with shapes primarily // When a shape is being edited, a list of objects will // be with that shape in the header. These objects will be locked // also. /////////////////////////////////////////////// class Chunk { public: //destructor virtual ~Chunk (); // constructors Chunk (class Chunk_With_Children * parent, const char * ident); virtual size_t size_chunk () = 0; virtual BOOL output_chunk (HANDLE &); virtual void fill_data_block (char * data_start) = 0; // this function is virtual, but will probably not be used elsewhere virtual char * make_data_block_from_chunk (); // Selective output functions, these are similar to the normal ones // and will normally call the equivalents. // special chunks will have there own functions which will only respond // if they have a flag set virtual char * make_data_block_for_process(); virtual size_t size_chunk_for_process(); virtual void fill_data_block_for_process(char * data_start); // these functions are virtual, but will only be used sparingly virtual void prepare_for_output() {} virtual void post_input_processing() {} const char * identifier; int error_code; // this allows chunks with children to trap miscellaneous chunks // that shouldn't be miscellaneous !!! virtual BOOL r_u_miscellaneous() { return FALSE; } static void Register(const char* idChunk,const char* idParent ,Chunk * (* pfnCreate) (Chunk_With_Children* parent,const char* data) ); private: // copy - private to stop chunks // from being copied Chunk (const Chunk &); // ditto void operator=(const Chunk &); // pointers to siblings friend class Chunk_With_Children; friend class Sprite_Header_Chunk; // sprite updating needs to scan through all child chunks friend class File_Chunk; friend class RIF_File_Chunk; friend class Shape_Chunk; Chunk * next; Chunk * previous; // identifier store char identifier_store[9]; protected: size_t chunk_size; // pointer to parent class Chunk_With_Children * parent; public : class Chunk_With_Children * GetRootChunk(void); class Chunk_With_Children const * GetRootChunk(void) const; }; /////////////////////////////////////////////// class Miscellaneous_Chunk : public Chunk { public: Miscellaneous_Chunk (Chunk_With_Children * parent, const char * identifier, const char * _data, size_t _data_size); virtual ~Miscellaneous_Chunk (); virtual size_t size_chunk () { return (chunk_size = (data_size + 12)); } virtual void fill_data_block (char * data_start); const size_t data_size; const char * const data; // this allows chunks with children to trap miscellaneous chunks // that shouldn't be miscellaneous !!! virtual BOOL r_u_miscellaneous() { return TRUE; } private: char * data_store; }; /////////////////////////////////////////////// class Chunk_With_Children : public Chunk { public: virtual ~Chunk_With_Children(); Chunk_With_Children (Chunk_With_Children * parent, const char * identifier) : Chunk (parent, identifier), children (NULL) {} virtual size_t size_chunk (); virtual BOOL output_chunk (HANDLE &); virtual void fill_data_block (char * data_start); virtual void prepare_for_output(); virtual void post_input_processing(); // look for child chunk(s) #ifndef RIFF_OPTIMIZE // define this to get compiler errors where you are calling the old slow functions List lookup_child (const char *) const; #endif void lookup_child (const char *,List&) const; Chunk* lookup_single_child(const char*) const; unsigned count_children(char const *) const; // Selective output functions, these are similar to the normal ones // and will normally call the equivalents. // special chunks will have there own functions which will only respond // if they have a flag set virtual size_t size_chunk_for_process(); virtual void fill_data_block_for_process(char * data_start); Chunk* Chunk_With_Children::DynCreate(const char* data); protected: friend class Chunk; friend class File_Chunk; // points to a doubly linked list Chunk * children; }; ///////////////////////////////////////////// // macros to save typing for chunk with children loader extern Chunk * Parent_File; #define CHUNK_WITH_CHILDREN_LOADER_PARENT __parent #define CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ chunkclass::chunkclass(Chunk_With_Children * const CHUNK_WITH_CHILDREN_LOADER_PARENT, char const * __data, size_t const __size) \ :Chunk_With_Children(CHUNK_WITH_CHILDREN_LOADER_PARENT,id) #define CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 { \ const char * const __buffer_ptr = __data; \ while (__data - __buffer_ptr < (signed)__size){ \ if (*(int *)(__data + 8) + (__data-__buffer_ptr) > (signed)__size){ \ Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; \ break;} #define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ chunkclass::chunkclass(Chunk_With_Children * const CHUNK_WITH_CHILDREN_LOADER_PARENT, char const * __data, size_t const __size) \ :Lockable_Chunk_With_Children(CHUNK_WITH_CHILDREN_LOADER_PARENT,id) #define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 { \ const char * const __buffer_ptr = __data; \ while (__data - __buffer_ptr < (signed) __size){ \ if (*(int *)(__data + 8) + (__data-__buffer_ptr) > (signed) __size){ \ Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; \ break;} #define CHUNK_WITH_CHILDREN_LOADER_INIT(id,chunkclass) \ CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 #define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT(id,chunkclass) \ LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 #define CHUNK_WITH_CHILDREN_LOADER_FOR(id,chunkclass) \ else if (!strncmp(__data,id,8)){ \ new chunkclass(this,__data+12,*(int *)(__data+8)-12); \ __data += *(int *)(__data+8);} #define CHUNK_WITH_CHILDREN_LOADER_END \ else { \ new Miscellaneous_Chunk (this, __data, (__data + 12), (*(int *) (__data + 8)) -12 ); \ __data += *(int *)(__data + 8);}}} // example: // // CHUNK_WITH_CHILDREN_LOADER_INIT("GAMEMODE",Environment_Game_Mode_Chunk) // CHUNK_WITH_CHILDREN_LOADER_FOR("ENVPALET",Environment_Palette_Chunk) // CHUNK_WITH_CHILDREN_LOADER_FOR("ENVTXLIT",Environment_TLT_Chunk) // CHUNK_WITH_CHILDREN_LOADER_FOR("CLRLOOKP",Coloured_Polygons_Lookup_Chunk) // CHUNK_WITH_CHILDREN_LOADER_FOR("RIFCHILD",RIF_Name_Chunk) // CHUNK_WITH_CHILDREN_LOADER_END /////////////////////////////////////////////// //macros for use in chunk construction from buffer, assume buffer is called data //read variable of type 'type' #define CHUNK_EXTRACT(var,type) \ var=*(type*)data; \ data+=sizeof(type); //read 4 byte aligned string #define CHUNK_EXTRACT_STRING(var) { \ int __length=strlen(data); \ if(__length) \ { \ var=new char[__length+1]; \ strcpy(var,data); \ } \ else var=0; \ data+=(__length+4) &~3 ;} //read array //length is an int (filled in by macro) //pointer is a pointer of type 'type' #define CHUNK_EXTRACT_ARRAY(length,pointer,type){\ CHUNK_EXTRACT(length,int) \ if(length) \ { \ pointer=new type[length]; \ for(int __i=0;__i (signed) __size) {\ Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;\ break;\ }\ \ DynCreate(__data);\ __data += *(int *)(__data + 8);\ }\ } /* Load from buffer function for standard Lockable_Chunk_With_Children */ #define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER(id,chunk_class) \ chunk_class::chunk_class(Chunk_With_Children * const parent,char const * __data, size_t const __size)\ :Lockable_Chunk_With_Children(parent,id)\ {\ const char * __buffer_ptr = __data;\ while ((__data-__buffer_ptr)< (signed) __size) {\ if ((*(int *)(__data + 8)) + (__data-__buffer_ptr) > (signed) __size) {\ Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;\ break;\ }\ \ DynCreate(__data);\ __data += *(int *)(__data + 8);\ }\ } //macros for forcing inclusion of chunk files from a library #define FORCE_CHUNK_INCLUDE_START //not needed anymore #define FORCE_CHUNK_INCLUDE(filename)\ extern int __Chunk_Include_##filename;\ int* p__Chunk_Include_##filename =& __Chunk_Include_##filename; #define FORCE_CHUNK_INCLUDE_END //not needed anymore #define FORCE_CHUNK_INCLUDE_IMPLEMENT(filename) int __Chunk_Include_##filename; /* //eg. FORCE_CHUNK_INCLUDE_START FORCE_CHUNK_INCLUDE(mishchnk) FORCE_CHUNK_INCLUDE(shpchunk) FORCE_CHUNK_INCLUDE(obchunk) FORCE_CHUNK_INCLUDE(envchunk) FORCE_CHUNK_INCLUDE(animchnk) FORCE_CHUNK_INCLUDE(hierchnk) FORCE_CHUNK_INCLUDE(animobs) FORCE_CHUNK_INCLUDE(sndchunk) FORCE_CHUNK_INCLUDE(avpchunk) FORCE_CHUNK_INCLUDE(bmpnames) FORCE_CHUNK_INCLUDE(chunkpal) FORCE_CHUNK_INCLUDE(dummyobjectchunk) FORCE_CHUNK_INCLUDE(enumchnk) FORCE_CHUNK_INCLUDE(enumsch) FORCE_CHUNK_INCLUDE(fragchnk) FORCE_CHUNK_INCLUDE(gsprchnk) FORCE_CHUNK_INCLUDE(hierplace) FORCE_CHUNK_INCLUDE(ltchunk) FORCE_CHUNK_INCLUDE(oechunk) FORCE_CHUNK_INCLUDE(pathchnk) FORCE_CHUNK_INCLUDE(sprchunk) FORCE_CHUNK_INCLUDE(strachnk) FORCE_CHUNK_INCLUDE(toolchnk) FORCE_CHUNK_INCLUDE(wpchunk) FORCE_CHUNK_INCLUDE_END */ #endif // !included