/*************************************************************************/ /* File : CKFile.h */ /* Author : Romain Sididris */ /* */ /* Virtools SDK */ /* Copyright (c) Virtools 2000, All Rights Reserved. */ /*************************************************************************/ #ifndef CKFILE_H #define CKFILE_H "$Id:$" #include "CKObjectArray.h" #include "CKObject.h" #include "XClassArray.h" #include "CKStateChunk.h" typedef XArray XIntArray; typedef XHashTable XFileObjectsTable; typedef XFileObjectsTable::Iterator XFileObjectsTableIt; struct CKFileObject; // Summary: Callback for customized reference resolution when loading a file. // //See Also:CKFile::SetResolveReferenceCallback typedef CKObject* (*CKRRCALLBACKFCT) (CKFileObject* iFileObject); #ifdef PSX2 // Default Loading system is to allocate // for each object in the file a CKStateChunk // which in its turn allocate the appropriate memory // to load an object data, to avoid memory fragmentation on PSX2 // a unique buffer is created at the beginning of a load // in which the chunks and their buffers are created #define USECHUNKTABLE #endif typedef struct CKFileManagerData { CKStateChunk *data; CKGUID Manager; } CKFileManagerData; /************************************************* Summary: Handle the saving of .cmo/.nmo files in stream (memory,file,etc..). Remarks: A CMO,NMO or NMS is saved using a standard file by default but this the save operation can made in any stream (memory , file) provided that a instance of this class is given to handle the different operation. The various method of this class should be overriden if a inheritated class and will be called by the framework when trying to save a file. Example: //----------------------------------------- //The default file saver for a CKFile struct CKFileStreamWriter : public CKStreamWriter { CKFileStreamWriter() { m_Filename = NULL; } virtual ~CKFileStreamWriter() { } virtual XBOOL Open(CKSTRING filename) { m_Filename = filename; return m_File.Open(filename,VxFile::WRITEONLY); } virtual XDWORD Write(const void* iBuffer,XDWORD iSize) { return m_File.Write(iBuffer,iSize); } virtual XBOOL Close() { m_Filename = NULL; return m_File.Close(); } virtual XBOOL IsValid(CKSTRING filename) { if (!m_File.Open(filename,VxFile::APPEND)) { return FALSE; } m_File.Close(); return TRUE; } CKSTRING m_Filename; VxFile m_File; }; //--------------------------------------- //A writer to a memory buffer struct CKMemoryStreamWriter : public CKStreamWriter { CKMemoryStreamWriter() { } virtual ~CKMemoryStreamWriter() { } virtual XBOOL Open(CKSTRING filename) { m_Buffer.Resize(0); } virtual XDWORD Write(const void* iBuffer,XDWORD iSize) { XDWORD OldSize = m_Buffer.Size(); m_Buffer.Resize(OldSize + iSize); memcpy(m_Buffer.Begin()+OldSize, iBuffer, iSize); } virtual XBOOL Close() { } virtual XBOOL IsValid(CKSTRING filename) { return TRUE; } XArray m_Buffer; }; //Usage example //Saving a content in memory CKObjectArray* objectToSave; CKStreamWriter* myWriter = new CKMemoryStreamWriter; //Install our writer g_Context->SetStreamWriter(myWriter); //Save Data : No file will be created instead we will call //the writer methods g_Context->Save("testFile.cmo",objectToSave); //Restore default saving behavior g_Context->SetStreamWriter(NULL); //And free our saving object delete myWriter; See also: CKContext::SetStreamWriter *************************************************/ struct CKStreamWriter { virtual ~CKStreamWriter() {}; /************************************************* Summary: Called by the framework when opening a stream to write to Remarks: The filename that given in argument is only useful if this writer handles writing to a file otherwise it can be ignored. ***************************************************/ virtual XBOOL Open(CKSTRING filename) = 0; /************************************************************ Summary: Called by the framework to write data to the stream. Remarks: This method should return the number of bytes actually written. *************************************************************/ virtual XDWORD Write(const void* iBuffer,XDWORD iSize) = 0; /************************************************************ Summary: Called by the framework when the stream can be closed. *************************************************************/ virtual XBOOL Close() = 0; /*************************************************** Summary: Called by the framework when starting to save a composition. Remarks: This method is called to ensure that the save operation can continue. For example to check that a file can be written. The filename that given in argument is only useful if this writer handles writing to a file otherwise it can be ignored. It should return TRUE if the save operation can continue. *****************************************************/ virtual XBOOL IsValid(CKSTRING filename) = 0; }; /************************************************* Summary: List of Plugins guids used by a file. Remarks: + When saving a file, a list of the plugins needed See also: CKFile::GetMissingPlugins *************************************************/ class CKFilePluginDependencies { public: int m_PluginCategory; XArray m_Guids; XBitArray ValidGuids; }; /************************************************* Summary: Description of a loaded/saved object. Remarks: + When saving or loading a file, each object is assigned a description that can be used by managers to do remapping or data modification. See also: CKObject::Save,CKObject::Load *************************************************/ typedef struct CKFileObject { // Options that will be used to create this object... enum CK_FO_OPTIONS { CK_FO_DEFAULT = 0, // Default behavior : a new object will be created with the name stored in CKFileObject CK_FO_RENAMEOBJECT, // Renaming : a new object will be created with the name stored in CKFileObject + a integer value XXX to ensure its uniqueness CK_FO_REPLACEOBJECT, // Do not create a new object, instead use an existing one which CK_ID is given by CreatedObject // to load the chunk on CK_FO_DONTLOADOBJECT, // Object chunk will not be read either because it is a reference // or because the loaded object already exist in the current level // and the user choose to keep the existing one. }; CK_ID Object; // ID of the object being load/saved (as it will be/was saved in the file) CK_ID CreatedObject; // ID of the object being created CK_CLASSID ObjectCid; // Class Identifier of the object CKObject* ObjPtr; // A pointer to the object itself (as CreatedObject when loading) CKSTRING Name; // Name of the Object CKStateChunk* Data; // A CKStateChunk that contains object information int PostPackSize; // When compressed chunk by chunk : size of Data after compression int PrePackSize; // When compressed chunk by chunk : size of Data before compression CK_FO_OPTIONS Options; // When loading an object it may be renamed , use to replace another object int FileIndex; // Position of the object data inside uncompressed file buffer CKDWORD SaveFlags; // Flags used when this object was saved. BOOL CanBeLoad() { return (ObjPtr && Data && (Options !=CK_FO_DONTLOADOBJECT)); } void CleanData() { #ifndef USECHUNKTABLE // No need to delete if memory is taken from a global table... delete Data; #endif Data = NULL; } CKFileObject() { memset(this,0,sizeof(CKFileObject)); } } CKFileObject; class CKFileChunk; class CKMemoryBufferParser; /********************************************************* {secret} Base class to parse a buffer ( two implementation exist using either a memory buffer or a file... *********************************************************/ class CKBufferParser : public VxPoolObject { friend class CKFile; public: virtual ~CKBufferParser() {}; //----- Read Write method virtual BOOL Write(void* x,int size) = 0; virtual BOOL Read(void* x,int size) = 0; virtual char* ReadString() = 0; virtual int ReadInt() = 0; //------ Cursor position virtual void Seek(int Pos) = 0; virtual void Skip(int Offset) = 0; //------- Is Buffer valid virtual BOOL IsValid() = 0; virtual int Size() = 0; virtual int CursorPos() = 0; //----- Reading Utilities (always relative to current cursor position // Warning : All these methods advance the Cursor of Size bytes ! // Create a CKStateChunk from the Size bytes // returns NULL if data was not valid virtual CKStateChunk* ExtractChunk(int Size,CKFile* f) = 0; virtual void ExtractChunk(int Size,CKFile* f,CKFileChunk* chnk) = 0; // Returns the CRC of the next Size bytes virtual DWORD ComputeCRC(int Size,DWORD PrevCRC=0) = 0; // Returns a new BufferParser containing the next size bytes or NULL // if Size is <=0 virtual CKMemoryBufferParser* Extract(int Size) = 0; // Saves the next Size bytes to a file virtual BOOL ExtractFile(char* Filename,int Size) = 0; // Same version but with decoding virtual CKMemoryBufferParser* ExtractDecoded(int Size,DWORD Key[4]) = 0; // Returns a new BufferParser containing the next PackSize bytes // unpacked to UnpackSize virtual CKBufferParser* UnPack(int UnpackSize,int PackSize) = 0; //----- Writing Utilities (always relative to current cursor position // Warning : All these methods advance the Cursor of Size bytes ! virtual void InsertChunk(CKStateChunk* chunk) = 0; // Returns a new BufferParser containing the next Size bytes // packed with given compression level virtual CKMemoryBufferParser* Pack(int Size,int CompressionLevel) = 0; //---- Others //- Encode the next Size bytes (This does not increment the cursor pointer) virtual void Encode(int Size,DWORD Key[4]) = 0; //secret void SkipString(); }; CKDWORD GetCurrentFileLoadOption(); // returns TheHeader.FileVersion (from CKFileHader). CKDWORD GetCurrentFileVersion(); // returns TheHeader.CKVersion (from CKFileHader). CKDWORD GetCurrentVersion(); // set last ckfile version 0 => reset last ckfileloaded version with current dev's version void SetCurrentVersion(CKDWORD iNewVersion=0); /************************************************* Summary: CKFile provides functions to save/load files in Virtools format. Remarks: + A CKFile is created through CreateCKFile and should be deleted after use using DeleteCKFile. + Once created a CKFile can be used to save one or more objects to disk or memory. + Normally you should not have to use this class directly since the CKContext::Load and CKContext::Save methods handle most cases. See also: CreateCKFile,DeleteCKFile *************************************************/ class CKFile { friend class CKStateChunk; public: //------------------------------------------------ // Loading (OpenFile then LoadFileData ) CKERROR OpenFile(CKSTRING filename,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); CKERROR OpenMemory(void* MemoryBuffer,int BufferSize,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); CKERROR OpenStream(VxStream* stream,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); CKERROR LoadFileData(CKObjectArray *list); //------------------------------------------------ // Direct Loading CKERROR Load(CKSTRING filename,CKObjectArray *list,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); CKERROR Load(void* MemoryBuffer,int BufferSize,CKObjectArray *list,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); CKERROR Load(VxStream* stream,CKObjectArray *list,CK_LOAD_FLAGS Flags=CK_LOAD_DEFAULT); void UpdateAndApplyAnimationsTo(CKCharacter* character); //------------------------------------------------ // Saving CKERROR StartSave(CKSTRING filename,CKDWORD Flags=CK_STATESAVE_ALL); void SaveObject(CKObject *obj,CKDWORD flags=CK_STATESAVE_ALL); void SaveObjects(CKObjectArray *array,CKDWORD flags=CK_STATESAVE_ALL); void SaveObjects(CK_ID* ids,int count,CKDWORD flags=CK_STATESAVE_ALL); void SaveObjects(CKObject** obs,int count,CKDWORD flags=CK_STATESAVE_ALL); // Add obj to the list of objects to be saved void SaveObjectAsReference(CKObject *obj,CKDWORD flags=0); // Add obj to the list of objects to be saved as references CKERROR EndSave(); CKBOOL IncludeFile(CKSTRING FileName,int SearchPathCategory = -1); CKBOOL IsObjectToBeSaved(CK_ID iID); //------------------------------------------------- // Used to update from old file formats void LoadAndSave(CKSTRING filename,CKSTRING filename_new); //-- Remap every chunks according to the conversion table void RemapManagerInt(CKGUID Manager,int* ConversionTable,int TableSize); // Sets a customized reference resolution function, // which replaces CKFile::ResolveReference() implementation. void SetResolveReferenceCallback(CKRRCALLBACKFCT iCallback); //------------------------------------------------- // Dependencies : XClassArray *GetMissingPlugins(); #ifdef DOCJETDUMMY // Docjet secret macro #else CKFile(CKContext* Context); ~CKFile(); //----------------------------------------------- // find the created object ID, knowing the chunk read ID //--------------------------------------------- int FindCreatedID(CK_ID iReadIDFromChunk) { int count = m_FileObjects.Size(); for (int i=0;i=0) ? m_FileObjects[index].CreatedObject : 0; } //----------------------------------------------- // The object stored in this file object is only a reference to // another object that is supposed to be already existing // This method is only supported for parameters for the moment // to enable an automatic shortcut remapping //--------------------------------------------- CKObject* ResolveReference(CKFileObject* Data); //----------------------------------------------- // This method check every loaded object name unicity // and is called at the end of OpenFile according // to the load options. It builds a list of // duplicates and store it in m_DuplicateNameFounds // (List of indices in the m_FileObjects table) //--------------------------------------------- void CheckDuplicateNames(); //This method saves a thumbnail for Windows explorer in the CKFile if the //File Options/Save Thumbnail of the variable manager is TRUE. CKBOOL SaveThumbnail(); public: int m_SaveIDMax; // Maximum CK_ID found when saving or loading objects {secret} XArray m_FileObjects; // List of objects being saved / loaded {secret} XArray m_ManagersData; // Manager Data loaded {secret} XClassArray m_PluginsDep; // Plugins dependencies for this file {secret} XClassArray m_IndexByClassId; // List of index in the m_FileObjects table sorted by ClassID {secret} XClassArray m_IncludedFiles; // List of files that should be inserted in the CMO file. {secret} CKFileInfo m_FileInfo; // Headers summary {secret} CKDWORD m_Flags; // Flags used to save file {secret} CKSTRING m_FileName; // Current file name {secret} CKContext* m_Context; // CKContext on which file is loaded/Saved {secret} CKBufferParser* m_Parser; VxMemoryMappedFile* m_MappedFile; XFileObjectsTable m_ObjectsHashTable; #ifdef USECHUNKTABLE XClassArray m_FileChunks; // Instead of allocating chunk per chunk a whole memory buffer is allocated to store all chunks and their readers CKFileChunk* m_ObjectChunks; CKFileChunk* m_ManagersChunks; VxMemoryPool m_ChunkBuffers; // Store all decompressed file buffer in memory so that all chunks directly points to it... // can only work for recent files ( > 2.0) BYTE* m_CurrentChunkBufferPtr; #endif CKBOOL m_ReadFileDataDone; CKBOOL m_SceneSaved; //----------- XIntArray m_DuplicateNameFounds; // A List of file object index for which a existing object with the same name has been // found, this list is build if the load option contains CK_LOAD_AUTOMATICMODE or CK_LOAD_DODIALOG //----- XBitArray m_AlreadySavedMask; // BitArray of IDs already saved {secret} XBitArray m_AlreadyReferencedMask; // BitArray of IDs already referenced {secret} XObjectPointerArray m_ReferencedObjects; VxTimeProfiler m_Chrono; protected: CKRRCALLBACKFCT m_ResolveReferenceCallbackFct; // callback called in place of ResolveReference() implementation public: static char m_CIDNeedName[CKCID_MAXCLASSID]; #endif // Docjet secret macro }; #endif