490 lines
18 KiB
C++
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 |