2023-02-25 17:39:39 +08:00
# pragma once
2023-08-25 17:35:45 +08:00
# include "../VTAll.hpp"
namespace LibCmo : : XContainer {
2023-09-16 18:31:25 +08:00
using XIntArray = XArray < CKINT > ;
using XFileObjectsTable = XHashTable < CK2 : : CK_ID , CKINT > ;
2023-08-25 17:35:45 +08:00
}
2023-02-25 17:39:39 +08:00
2023-02-26 21:48:03 +08:00
namespace LibCmo : : CK2 {
2023-02-25 17:39:39 +08:00
class CKBufferParser {
private :
2023-09-17 10:38:46 +08:00
CKBYTE * m_MemBegin ;
CKDWORD m_MemPos ;
2023-02-25 17:39:39 +08:00
bool m_NeedManualFree ;
2023-09-17 10:38:46 +08:00
CKDWORD m_MemSize ;
2023-02-25 17:39:39 +08:00
public :
2023-08-28 14:18:58 +08:00
/**
* @ brief Create CKBufferParser from a existed buffer .
* @ param ptr The start pointer of buffer . This buffer should be allocated by ' new [ ] ' , not ' new ' or ' malloc ( ) ' .
* @ param rsize The size of buffer .
* @ param need_manual_free True if provided buffer need freed by CKBufferParser automatically .
*/
2023-09-17 10:38:46 +08:00
CKBufferParser ( const void * ptr , CKDWORD rsize , bool need_manual_free ) :
m_MemBegin ( const_cast < CKBYTE * > ( static_cast < const CKBYTE * > ( ptr ) ) ) ,
2023-08-25 17:35:45 +08:00
m_MemPos ( 0u ) , m_MemSize ( rsize ) ,
2023-08-28 14:18:58 +08:00
m_NeedManualFree ( need_manual_free )
{ }
/**
* @ brief Create CKBufferParser from a new created buffer .
* @ param newsize The size of new buffer .
*/
2023-09-17 10:38:46 +08:00
CKBufferParser ( CKDWORD newsize ) :
m_MemBegin ( new CKBYTE [ newsize ] ) ,
2023-08-28 14:18:58 +08:00
m_MemPos ( 0u ) , m_MemSize ( newsize ) ,
m_NeedManualFree ( true )
{ }
2023-08-25 17:35:45 +08:00
~ CKBufferParser ( ) {
if ( this - > m_NeedManualFree ) delete [ ] ( this - > m_MemBegin ) ;
}
LIBCMO_DISABLE_COPY_MOVE ( CKBufferParser ) ;
2023-02-25 17:39:39 +08:00
2023-09-17 10:38:46 +08:00
const void * GetPtr ( CKINT extraoff = 0 ) { return ( this - > m_MemBegin + m_MemPos + extraoff ) ; }
void * GetMutablePtr ( CKINT extraoff = 0 ) { return ( this - > m_MemBegin + m_MemPos + extraoff ) ; }
void * GetBase ( void ) { return this - > m_MemBegin ; }
CKDWORD GetSize ( void ) { return this - > m_MemSize ; }
CKDWORD GetCursor ( void ) { return this - > m_MemPos ; }
void MoveCursor ( CKINT off ) { this - > m_MemPos + = off ; }
void SetCursor ( CKDWORD off ) { this - > m_MemPos = off ; }
void Read ( void * data , CKDWORD data_size ) {
2023-02-26 21:48:03 +08:00
std : : memcpy ( data , ( this - > m_MemBegin + m_MemPos ) , data_size ) ;
2023-02-25 17:39:39 +08:00
this - > m_MemPos + = data_size ;
}
2023-09-17 10:38:46 +08:00
template < class _Ty >
void Read ( _Ty * data ) {
Read ( data , CKSizeof ( _Ty ) ) ;
}
void Write ( const void * data , CKDWORD data_size ) {
2023-02-26 21:48:03 +08:00
std : : memcpy ( ( this - > m_MemBegin + m_MemPos ) , data , data_size ) ;
2023-02-25 17:39:39 +08:00
this - > m_MemPos + = data_size ;
}
2023-09-17 10:38:46 +08:00
template < class _Ty >
void Write ( const _Ty * data ) {
Write ( data , CKSizeof ( _Ty ) ) ;
}
2023-02-25 17:39:39 +08:00
} ;
# pragma pack(push)
# pragma pack(1)
struct CKRawFileInfo {
CKBYTE NeMo [ 8 ] ;
CKDWORD Crc ;
CKDWORD CKVersion ;
CKDWORD FileVersion ;
CKDWORD Zero ;
CKDWORD FileWriteMode ;
CKDWORD Hdr1PackSize ;
CKDWORD DataPackSize ;
CKDWORD DataUnPackSize ;
CKDWORD ManagerCount ;
CKDWORD ObjectCount ;
CKDWORD MaxIDSaved ;
CKDWORD ProductVersion ;
CKDWORD ProductBuild ;
CKDWORD Hdr1UnPackSize ;
} ;
# pragma pack(pop)
class CKFileInfo {
public :
2023-08-25 17:35:45 +08:00
CKFileInfo ( ) :
ProductVersion ( 0u ) , ProductBuild ( 0x01010000u ) , FileWriteMode ( CK_FILE_WRITEMODE : : CKFILE_UNCOMPRESSED ) ,
FileVersion ( 8u ) , CKVersion ( CKVERSION ) , FileSize ( 0u ) ,
ObjectCount ( 0u ) , ManagerCount ( 0u ) , MaxIDSaved ( 0u ) , Crc ( 0u ) ,
Hdr1PackSize ( 0u ) , Hdr1UnPackSize ( 0u ) , DataPackSize ( 0u ) , DataUnPackSize ( 0u ) { }
~ CKFileInfo ( ) { }
LIBCMO_DEFAULT_COPY_MOVE ( CKFileInfo ) ;
2023-08-25 21:57:22 +08:00
CKDWORD ProductVersion ; /**< Virtools Version (Dev/Creation). (CK_VIRTOOLS_VERSION) */
CKDWORD ProductBuild ; /**< Virtools Build Number. */
CK_FILE_WRITEMODE FileWriteMode ; /**< Options used to save this file. (CK_FILE_WRITEMODE) */
CKDWORD FileVersion ; /**< Version of file format when file was saved. */
CKDWORD CKVersion ; /**< Version of CK when file was saved. */
CKDWORD FileSize ; /**< Size of file in bytes. */
CKDWORD ObjectCount ; /**< Number of objects stored in the file. */
CKDWORD ManagerCount ; /**< Number of managers which saved data in the file. */
2023-09-30 14:24:37 +08:00
CK_ID MaxIDSaved ; /**< Maximum Object identifier saved */
2023-08-25 21:57:22 +08:00
CKDWORD Crc ; /**< Crc of data */
CKDWORD Hdr1PackSize ; /**< The compressed size of Header section. */
CKDWORD Hdr1UnPackSize ; /**< The uncompressed size of Header section. */
CKDWORD DataPackSize ; /**< The compressed size of Data section. */
CKDWORD DataUnPackSize ; /**< The uncompressed size of Data section. */
2023-02-25 17:39:39 +08:00
} ;
class CKFileObject {
public :
CKFileObject ( ) ;
2023-02-28 14:04:38 +08:00
CKFileObject ( const CKFileObject & ) ;
2023-08-25 17:35:45 +08:00
CKFileObject ( CKFileObject & & ) ;
2023-02-28 14:04:38 +08:00
CKFileObject & operator = ( const CKFileObject & ) ;
2023-08-25 17:35:45 +08:00
CKFileObject & operator = ( CKFileObject & & ) ;
2023-02-25 17:39:39 +08:00
~ CKFileObject ( ) ;
2023-08-25 21:57:22 +08:00
CK_ID ObjectId ; /**< ID of the object being load/saved (as it will be/was saved in the file) */
CK_ID CreatedObjectId ; /**< ID of the object being created */
CK_CLASSID ObjectCid ; /**< Class Identifier of the object */
2023-08-26 16:37:26 +08:00
ObjImpls : : CKObject * ObjPtr ; /**< A pointer to the object itself (as CreatedObject when loading) */
2023-09-16 18:31:25 +08:00
XContainer : : XString Name ; /**< Name of the Object */
2023-08-25 21:57:22 +08:00
CKStateChunk * Data ; /**< A CKStateChunk that contains object information */
2023-08-28 17:04:28 +08:00
CKDWORD PackSize ; /**< The CKStateChunk data size */
2023-08-25 21:57:22 +08:00
//CKINT PostPackSize; /**< When compressed chunk by chunk : size of Data after compression */
//CKINT 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 */
2023-08-29 10:42:13 +08:00
CKDWORD FileIndex ; /**< Position of the object data inside uncompressed file buffer */
2023-08-25 21:57:22 +08:00
CKDWORD SaveFlags ; /**< Flags used when this object was saved. */
2023-02-25 17:39:39 +08:00
} ;
class CKFileManagerData {
public :
CKFileManagerData ( ) ;
2023-02-28 14:04:38 +08:00
CKFileManagerData ( const CKFileManagerData & ) ;
2023-08-25 17:35:45 +08:00
CKFileManagerData ( CKFileManagerData & & ) ;
2023-02-28 14:04:38 +08:00
CKFileManagerData & operator = ( const CKFileManagerData & ) ;
2023-08-25 17:35:45 +08:00
CKFileManagerData & operator = ( CKFileManagerData & & ) ;
2023-02-25 17:39:39 +08:00
~ CKFileManagerData ( ) ;
CKStateChunk * Data ;
CKGUID Manager ;
} ;
class CKFilePluginDependencies {
public :
2023-08-25 17:35:45 +08:00
CKFilePluginDependencies ( ) :
m_PluginCategory ( CK_PLUGIN_TYPE : : CKPLUGIN_MANAGER_DLL ) , m_Guids ( ) { }
~ CKFilePluginDependencies ( ) { }
LIBCMO_DEFAULT_COPY_MOVE ( CKFilePluginDependencies ) ;
2023-02-25 17:39:39 +08:00
CK_PLUGIN_TYPE m_PluginCategory ;
2023-08-25 17:35:45 +08:00
XContainer : : XArray < CKGUID > m_Guids ;
2023-08-25 21:57:22 +08:00
//XContainer::XBitArray ValidGuids;
2023-03-03 11:06:26 +08:00
} ;
2023-02-25 17:39:39 +08:00
2023-08-25 21:57:22 +08:00
class CKFileVisitor {
2023-02-25 17:39:39 +08:00
public :
2023-08-25 21:57:22 +08:00
CKFileVisitor ( CKFileReader * reader ) ;
CKFileVisitor ( CKFileWriter * writer ) ;
CKFileVisitor ( const CKFileVisitor & ) ;
CKFileVisitor ( CKFileVisitor & & ) ;
CKFileVisitor & operator = ( const CKFileVisitor & ) ;
CKFileVisitor & operator = ( CKFileVisitor & & ) ;
2023-09-24 20:56:23 +08:00
const CKFileObject * GetFileObjectByIndex ( CKDWORD index ) ;
2023-09-24 12:21:33 +08:00
CKDWORD GetIndexByObjectID ( CK_ID objid ) ;
2023-09-28 23:29:52 +08:00
bool AddSavedFile ( CKSTRING u8FileName ) ;
2023-08-25 21:57:22 +08:00
protected :
2023-08-29 14:00:34 +08:00
bool m_IsReader ;
2023-08-25 21:57:22 +08:00
CKFileReader * m_Reader ;
CKFileWriter * m_Writer ;
CKContext * m_Ctx ;
} ;
2023-02-25 17:39:39 +08:00
2023-08-25 21:57:22 +08:00
class CKFileReader {
friend class CKFileVisitor ;
public :
CKFileReader ( CKContext * ctx ) ;
~ CKFileReader ( ) ;
LIBCMO_DISABLE_COPY_MOVE ( CKFileReader ) ;
2023-02-25 17:39:39 +08:00
2023-08-25 17:35:45 +08:00
// ========== Loading ==========
CKERROR ShallowLoad ( CKSTRING u8_filename ) ;
CKERROR DeepLoad ( CKSTRING u8_filename ) ;
2023-02-25 17:39:39 +08:00
2023-08-25 17:35:45 +08:00
// ========== Loading Result ==========
2023-09-30 14:24:37 +08:00
CK_ID GetSaveIdMax ( ) ;
2023-08-25 17:35:45 +08:00
const XContainer : : XArray < CKFileObject > & GetFileObjects ( ) ;
2023-08-26 20:34:51 +08:00
const XContainer : : XArray < CKFileManagerData > & GetManagersData ( ) ;
const XContainer : : XArray < CKFilePluginDependencies > & GetPluginsDep ( ) ;
2023-08-25 17:35:45 +08:00
const XContainer : : XArray < XContainer : : XString > & GetIncludedFiles ( ) ;
2023-08-26 20:34:51 +08:00
const CKFileInfo GetFileInfo ( ) ;
2023-08-25 17:35:45 +08:00
2023-08-25 21:57:22 +08:00
protected :
2023-08-29 14:00:34 +08:00
bool m_Done ;
2023-09-30 14:24:37 +08:00
CK_ID m_SaveIDMax ; /**< Maximum CK_ID found when saving or loading objects */
2023-08-25 21:57:22 +08:00
XContainer : : XArray < CKFileObject > m_FileObjects ; /**< List of objects being saved / loaded */
XContainer : : XArray < CKFileManagerData > m_ManagersData ; /**< Manager Data loaded */
XContainer : : XArray < CKFilePluginDependencies > m_PluginsDep ; /**< Plugins dependencies for this file */
// XContainer::XClassArray<XContainer::XIntArray> m_IndexByClassId; /**< List of index in the m_FileObjects table sorted by ClassID */
2023-09-30 14:24:37 +08:00
/**
* @ brief List of files that should be inserted in the CMO file .
* @ remark Each item is just file name , not the full path to file .
*/
XContainer : : XArray < XContainer : : XString > m_IncludedFiles ;
2023-08-25 21:57:22 +08:00
CKFileInfo m_FileInfo ; /**< Headers summary */
CKERROR ReadFileHeader ( CKBufferParser * ParserPtr ) ;
CKERROR ReadFileData ( CKBufferParser * ParserPtr ) ;
CKContext * m_Ctx ;
CKFileVisitor m_Visitor ;
} ;
class CKFileWriter {
friend class CKFileVisitor ;
public :
CKFileWriter ( CKContext * ctx ) ;
2023-09-30 14:24:37 +08:00
CKFileWriter ( CKContext * ctx , CKFileReader * reader , bool is_shallow ) ;
2023-08-25 21:57:22 +08:00
~ CKFileWriter ( ) ;
LIBCMO_DISABLE_COPY_MOVE ( CKFileWriter ) ;
2023-08-25 17:35:45 +08:00
// ========== Saving Preparing ==========
2023-08-29 14:00:34 +08:00
bool AddSavedObject ( ObjImpls : : CKObject * obj , CKDWORD flags = CK_STATESAVE_ALL ) ;
2023-09-24 12:21:33 +08:00
bool AddSavedObjects ( const XContainer : : XObjectPointerArray & objarray , CKDWORD flags = CK_STATESAVE_ALL ) ;
2023-08-29 14:00:34 +08:00
bool AddSavedFile ( CKSTRING u8FileName ) ;
2023-08-25 17:35:45 +08:00
// ========== Saving ==========
CKERROR Save ( CKSTRING u8_filename ) ;
2023-02-25 17:39:39 +08:00
2023-08-25 21:57:22 +08:00
protected :
2023-10-02 09:16:45 +08:00
/**
* @ brief A helper function to check whether given file can be written .
* @ param filename [ in ] The name of file to be wriiten
* @ return CKERROR : : CK_OK if can write .
*/
CKERROR PrepareFile ( CKSTRING filename ) ;
/**
* @ brief Internal used Object Adder .
*
* This function is used by AddSavedObject ( ) and Copy from reader constructor .
* This function accept a object pointer , and try adding them .
* And set m_IncludedFiles and m_ObjectsHashTable properly .
*
* @ param obj The pointer to added object .
* @ param flags The flag used when saving this object .
* @ return True if success .
*/
bool InternalObjectAdder ( ObjImpls : : CKObject * obj , CKDWORD flags = CK_STATESAVE_ALL ) ;
protected :
bool m_Done ; /**< True if this writer is already written into file. A written CKFileWriter can no be written again. */
2023-08-28 14:18:58 +08:00
/**
2023-09-30 14:24:37 +08:00
* @ brief True if this writer is not allowed to add objects .
* @ remark
* + This field should be false in default .
* + This field usually be set when importing from reader .
*/
bool m_DisableAddingObject ;
/**
* @ brief True if this writer is not allowed to add files .
* @ remark
* + This field should be false in default .
* + This field usually be set when importing from reader .
2023-08-28 14:18:58 +08:00
*/
2023-09-30 14:24:37 +08:00
bool m_DisableAddingFile ;
2023-08-28 14:18:58 +08:00
2023-09-30 14:24:37 +08:00
CK_ID m_SaveIDMax ; /**< Maximum CK_ID found when saving or loading objects */
2023-08-28 14:18:58 +08:00
XContainer : : XArray < CKFileObject > m_FileObjects ; /**< List of objects being saved / loaded */
XContainer : : XArray < CKFileManagerData > m_ManagersData ; /**< Manager Data loaded */
XContainer : : XArray < CKFilePluginDependencies > m_PluginsDep ; /**< Plugins dependencies for this file */
2023-09-30 14:24:37 +08:00
/**
* @ brief List of files that should be inserted in the CMO file .
* @ remark Each item is the full path to file .
*/
XContainer : : XArray < XContainer : : XString > m_IncludedFiles ;
2023-09-24 12:21:33 +08:00
XContainer : : XHashTable < CK_ID , CKDWORD > m_ObjectsHashTable ; /**< A Object ID to save index hash table. */
XContainer : : XBitArray m_AlreadySavedMask ; /**< Field recording saved object id. If this object is saved, set m_AlreadySavedMask[id] to true. Also used to check whether object already is in save list. */
2023-08-28 21:21:40 +08:00
CKFileInfo m_FileInfo ; /**< Headers summary */
2023-08-28 17:04:28 +08:00
2023-08-25 17:35:45 +08:00
CKContext * m_Ctx ;
2023-08-25 21:57:22 +08:00
CKFileVisitor m_Visitor ;
2023-02-25 17:39:39 +08:00
} ;
}