deargui-vpl/ref/virtools/Includes/CKFile.h

490 lines
18 KiB
C++

/*************************************************************************/
/* 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<int> XIntArray;
typedef XHashTable<int,CK_ID> 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<BYTE> 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<CKGUID> 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<CKFilePluginDependencies> *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<count;++i)
{
if (m_FileObjects[i].Object==iReadIDFromChunk)
return m_FileObjects[i].CreatedObject;
}
return 0;
}
protected:
void ClearData();
CKERROR ReadFileHeaders(CKBufferParser** ParserPtr);
CKERROR ReadFileData(CKBufferParser** ParserPtr);
void FinishLoading(CKObjectArray *list,DWORD flags);
//-----------------------------------------------
// Debug ouput :
// File statistic on file size and memory taken by each
// class of objects...
//---------------------------------------------
void WriteStats(int InterfaceDataSize);
//-----------------------------------------------
// When writing the ID of an object inside a chunk,
// we instead write its index inside the file which was
// stored in the m_ObjectsHashTable
//---------------------------------------------
int SaveFindObjectIndex(CK_ID obj) {
int Index=-1;
m_ObjectsHashTable.LookUp(obj,Index);
return Index;
}
//-----------------------------------------------
// when loading an object we can then convert an index inside the
// file object table into the CK_ID of the object that as been created
//---------------------------------------------
CK_ID LoadFindObject(int index) {
return (index>=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<CKFileObject> m_FileObjects; // List of objects being saved / loaded {secret}
XArray<CKFileManagerData> m_ManagersData; // Manager Data loaded {secret}
XClassArray<CKFilePluginDependencies> m_PluginsDep; // Plugins dependencies for this file {secret}
XClassArray<XIntArray> m_IndexByClassId; // List of index in the m_FileObjects table sorted by ClassID {secret}
XClassArray<XString> 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<CKFileChunk> 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