refactor (4/?)

This commit is contained in:
yyc12345 2023-08-25 21:57:22 +08:00
parent c8c2c6e20b
commit 4a787610f1
17 changed files with 323 additions and 265 deletions

View File

@ -13,8 +13,7 @@ namespace LibCmo::CK2 {
#pragma region Objects Management #pragma region Objects Management
CKObject* CKContext::CreateCKObject(CK_CLASSID cls, CKSTRING name, CKObject* CKContext::CreateCKObject(CK_CLASSID cls, CKSTRING name,
CK_OBJECTCREATION_OPTIONS options = CK_OBJECTCREATION_OPTIONS::CK_OBJECTCREATION_NONAMECHECK, CK_OBJECTCREATION_OPTIONS options, CK_CREATIONMODE* res) {
CK_CREATIONMODE* res = nullptr) {
// todo: Process paramter options and res // todo: Process paramter options and res
// get description first // get description first

View File

@ -76,20 +76,20 @@ namespace LibCmo::CK2 {
~CKFileInfo() {} ~CKFileInfo() {}
LIBCMO_DEFAULT_COPY_MOVE(CKFileInfo); LIBCMO_DEFAULT_COPY_MOVE(CKFileInfo);
CKDWORD ProductVersion; ///< Virtools Version (Dev/Creation). (CK_VIRTOOLS_VERSION) CKDWORD ProductVersion; /**< Virtools Version (Dev/Creation). (CK_VIRTOOLS_VERSION) */
CKDWORD ProductBuild; ///< Virtools Build Number. CKDWORD ProductBuild; /**< Virtools Build Number. */
CK_FILE_WRITEMODE FileWriteMode; ///< Options used to save this file. (CK_FILE_WRITEMODE) CK_FILE_WRITEMODE FileWriteMode; /**< Options used to save this file. (CK_FILE_WRITEMODE) */
CKDWORD FileVersion; ///< Version of file format when file was saved. CKDWORD FileVersion; /**< Version of file format when file was saved. */
CKDWORD CKVersion; ///< Version of CK when file was saved. CKDWORD CKVersion; /**< Version of CK when file was saved. */
CKDWORD FileSize; ///< Size of file in bytes. CKDWORD FileSize; /**< Size of file in bytes. */
CKDWORD ObjectCount; ///< Number of objects stored in the file. CKDWORD ObjectCount; /**< Number of objects stored in the file. */
CKDWORD ManagerCount; ///< Number of managers which saved data in the file. CKDWORD ManagerCount; /**< Number of managers which saved data in the file. */
CKDWORD MaxIDSaved; ///< Maximum Object identifier saved CKDWORD MaxIDSaved; /**< Maximum Object identifier saved */
CKDWORD Crc; ///< Crc of data CKDWORD Crc; /**< Crc of data */
CKDWORD Hdr1PackSize; ///< Reserved CKDWORD Hdr1PackSize; /**< The compressed size of Header section. */
CKDWORD Hdr1UnPackSize; ///< Reserved CKDWORD Hdr1UnPackSize; /**< The uncompressed size of Header section. */
CKDWORD DataPackSize; ///< Reserved CKDWORD DataPackSize; /**< The compressed size of Data section. */
CKDWORD DataUnPackSize; ///< Reserved CKDWORD DataUnPackSize; /**< The uncompressed size of Data section. */
}; };
class CKFileObject { class CKFileObject {
@ -101,17 +101,17 @@ namespace LibCmo::CK2 {
CKFileObject& operator=(CKFileObject&&); CKFileObject& operator=(CKFileObject&&);
~CKFileObject(); ~CKFileObject();
CK_ID ObjectId; ///< ID of the object being load/saved (as it will be/was saved in the file) 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_ID CreatedObjectId; /**< ID of the object being created */
CK_CLASSID ObjectCid; ///< Class Identifier of the object CK_CLASSID ObjectCid; /**< Class Identifier of the object */
CKObject* ObjPtr; ///< A pointer to the object itself (as CreatedObject when loading) CKObject* ObjPtr; /**< A pointer to the object itself (as CreatedObject when loading) */
TypeHelper::MKString Name; ///< Name of the Object TypeHelper::MKString Name; /**< Name of the Object */
CKStateChunk* Data; ///< A CKStateChunk that contains object information CKStateChunk* Data; /**< A CKStateChunk that contains object information */
//CKINT PostPackSize; ///< When compressed chunk by chunk : size of Data after compression //CKINT PostPackSize; /**< When compressed chunk by chunk : size of Data after compression */
//CKINT PrePackSize; ///< When compressed chunk by chunk : size of Data before 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 CK_FO_OPTIONS Options; /**< When loading an object it may be renamed , use to replace another object */
CKINT FileIndex; ///< Position of the object data inside uncompressed file buffer CKINT FileIndex; /**< Position of the object data inside uncompressed file buffer */
CKDWORD SaveFlags; ///< Flags used when this object was saved. CKDWORD SaveFlags; /**< Flags used when this object was saved. */
}; };
class CKFileManagerData { class CKFileManagerData {
@ -136,26 +136,32 @@ namespace LibCmo::CK2 {
CK_PLUGIN_TYPE m_PluginCategory; CK_PLUGIN_TYPE m_PluginCategory;
XContainer::XArray<CKGUID> m_Guids; XContainer::XArray<CKGUID> m_Guids;
XContainer::XBitArray ValidGuids; //XContainer::XBitArray ValidGuids;
}; };
/** class CKFileVisitor {
@brief CKFile provides functions to save/load files in Virtools format.
@remark
+ Use CKFile just like a normal C++ class with passing CKCotext pointer.
+ Once created a CKFile can be used to save one or more objects to disk.
+ Only can load objects when this CKFile is empty. Use ClearData() to clear any existed CKFile.
+ In any case, CKFile can run Save(). So you can create a CKFile, add some obejcts and save it.
Or you can load a file by CKFile and add/modify something then save it.
*/
class CKFile {
public: public:
CKFile(CKContext* ctx); CKFileVisitor(CKFileReader* reader);
~CKFile(); CKFileVisitor(CKFileWriter* writer);
LIBCMO_DISABLE_COPY_MOVE(CKFile); CKFileVisitor(const CKFileVisitor&);
CKFileVisitor(CKFileVisitor&&);
CKFileVisitor& operator=(const CKFileVisitor&);
CKFileVisitor& operator=(CKFileVisitor&&);
// ========== Reset CKFile ========== const CKFileObject* GetFileObjectByIndex(size_t index);
void ClearData(void); protected:
CKBOOL m_IsReader;
CKFileReader* m_Reader;
CKFileWriter* m_Writer;
CKContext* m_Ctx;
};
class CKFileReader {
friend class CKFileVisitor;
public:
CKFileReader(CKContext* ctx);
~CKFileReader();
LIBCMO_DISABLE_COPY_MOVE(CKFileReader);
// ========== Loading ========== // ========== Loading ==========
CKERROR ShallowLoad(CKSTRING u8_filename); CKERROR ShallowLoad(CKSTRING u8_filename);
@ -165,6 +171,31 @@ namespace LibCmo::CK2 {
const XContainer::XArray<CKFileObject>& GetFileObjects(); const XContainer::XArray<CKFileObject>& GetFileObjects();
const XContainer::XArray<XContainer::XString>& GetIncludedFiles(); const XContainer::XArray<XContainer::XString>& GetIncludedFiles();
protected:
CKBOOL m_Done;
CKINT m_SaveIDMax; /**< Maximum CK_ID found when saving or loading objects */
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 */
XContainer::XArray<XContainer::XString> m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */
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);
CKFileWriter(CKContext* ctx, CKFileReader* reader);
~CKFileWriter();
LIBCMO_DISABLE_COPY_MOVE(CKFileWriter);
// ========== Saving Preparing ========== // ========== Saving Preparing ==========
CKBOOL AddSavedObject(CKObject* obj, CKDWORD flags = CK_STATESAVE_ALL); CKBOOL AddSavedObject(CKObject* obj, CKDWORD flags = CK_STATESAVE_ALL);
CKBOOL AddSavedObjects(CKObjectArray* objarray, CKDWORD flags = CK_STATESAVE_ALL); CKBOOL AddSavedObjects(CKObjectArray* objarray, CKDWORD flags = CK_STATESAVE_ALL);
@ -173,41 +204,9 @@ namespace LibCmo::CK2 {
// ========== Saving ========== // ========== Saving ==========
CKERROR Save(CKSTRING u8_filename); CKERROR Save(CKSTRING u8_filename);
//CKERROR Load(CKSTRING u8_filename, /*CKObjectArray list, */ CK_LOAD_FLAGS flags); protected:
//CKERROR OpenFile(CKSTRING u8_filename, CK_LOAD_FLAGS flags);
//CKERROR OpenMemory(void* MemoryBuffer, size_t BufferSize, CK_LOAD_FLAGS Flags);
//CKERROR ReadFileHeaders(CKBufferParser** ParserPtr);
//CKERROR ReadFileData(CKBufferParser** ParserPtr);
//CKERROR LoadFileData(void/*CKObjectArray list*/);
//CKERROR FinishLoading(/*CKObjectArray list, */CK_LOAD_FLAGS flags);
CKINT m_SaveIDMax; // Maximum CK_ID found when saving or loading objects
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
XContainer::XArray<XContainer::XString> m_IncludedFiles; // List of files that should be inserted in the CMO file.
CKFileInfo m_FileInfo; // Headers summary
//XContainer::XFileObjectsTable m_ObjectsHashTable;
//CKBOOL m_ReadFileDataDone;
//CKBOOL m_SceneSaved;
//XContainer::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
//XContainer::XBitArray m_AlreadySavedMask; // BitArray of IDs already saved {secret}
//XContainer::XBitArray m_AlreadyReferencedMask; // BitArray of IDs already referenced {secret}
//XContainer::XObjectPointerArray m_ReferencedObjects;
private:
// reader function and variables
CKERROR ReadFileHeader(CKBufferParser* ParserPtr);
CKERROR ReadFileData(CKBufferParser* ParserPtr);
// writer function and varibales
// shared function and variables
bool mCanLoad;
CKContext* m_Ctx; CKContext* m_Ctx;
CKFileVisitor m_Visitor;
}; };
} }

View File

@ -64,6 +64,7 @@ namespace LibCmo::CK2 {
this->FileIndex = rhs.FileIndex; this->FileIndex = rhs.FileIndex;
this->SaveFlags = rhs.SaveFlags; this->SaveFlags = rhs.SaveFlags;
return *this;
} }
CKFileObject::~CKFileObject() { CKFileObject::~CKFileObject() {
@ -107,6 +108,8 @@ namespace LibCmo::CK2 {
this->Data = rhs.Data; this->Data = rhs.Data;
rhs.Data = nullptr; rhs.Data = nullptr;
return *this;
} }
CKFileManagerData::~CKFileManagerData() { CKFileManagerData::~CKFileManagerData() {
@ -115,36 +118,94 @@ namespace LibCmo::CK2 {
#pragma endregion #pragma endregion
#pragma region CKFilePluginDependencies #pragma region CKFileReader
CKFilePluginDependencies::CKFilePluginDependencies() : CKFileReader::CKFileReader(CKContext* ctx) :
m_PluginCategory(CK_PLUGIN_TYPE::CKPLUGIN_MANAGER_DLL), m_Guids() {} m_Ctx(ctx), m_Visitor(this),
m_Done(false),
m_SaveIDMax(0),
m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(),
m_FileInfo() {}
CKFilePluginDependencies::CKFilePluginDependencies(const CKFilePluginDependencies& rhs) : CKFileReader::~CKFileReader() {}
m_PluginCategory(rhs.m_PluginCategory), m_Guids(rhs.m_Guids) {}
CKFilePluginDependencies& CKFilePluginDependencies::operator=(const CKFilePluginDependencies& rhs) { const XContainer::XArray<CKFileObject>& CKFileReader::GetFileObjects() {
this->m_PluginCategory = rhs.m_PluginCategory; return m_FileObjects;
this->m_Guids = rhs.m_Guids; }
const XContainer::XArray<XContainer::XString>& CKFileReader::GetIncludedFiles() {
return m_IncludedFiles;
}
#pragma endregion
#pragma region CKFileWriter
CKFileWriter::CKFileWriter(CKContext* ctx) :
m_Ctx(ctx), m_Visitor(this) {}
CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader) :
m_Ctx(ctx), m_Visitor(this) {}
CKFileWriter::~CKFileWriter() {}
CKBOOL CKFileWriter::AddSavedObject(CKObject* obj, CKDWORD flags) {
return CKFALSE;
}
CKBOOL CKFileWriter::AddSavedObjects(CKObjectArray* objarray, CKDWORD flags) {
return CKFALSE;
}
CKBOOL CKFileWriter::AddSavedFile(CKSTRING u8FileName) {
return CKFALSE;
}
#pragma endregion
#pragma region CKFileVisitor
CKFileVisitor::CKFileVisitor(CKFileReader* reader) :
m_IsReader(CKTRUE), m_Reader(reader), m_Writer(nullptr) {
if (reader == nullptr) LIBPANIC("Reader is nullptr.");
}
CKFileVisitor::CKFileVisitor(CKFileWriter* writer) :
m_IsReader(false), m_Reader(nullptr), m_Writer(nullptr) {
if (writer == nullptr) LIBPANIC("Writer is nullptr.");
}
CKFileVisitor::CKFileVisitor(const CKFileVisitor& rhs) :
m_IsReader(rhs.m_IsReader), m_Reader(rhs.m_Reader), m_Writer(rhs.m_Writer) {}
CKFileVisitor::CKFileVisitor(CKFileVisitor&& rhs) :
m_IsReader(rhs.m_IsReader), m_Reader(rhs.m_Reader), m_Writer(rhs.m_Writer) {}
CKFileVisitor& CKFileVisitor::operator=(const CKFileVisitor& rhs) {
this->m_IsReader = rhs.m_IsReader;
this->m_Reader = rhs.m_Reader;
this->m_Writer = rhs.m_Writer;
return *this; return *this;
} }
CKFilePluginDependencies::~CKFilePluginDependencies() {} CKFileVisitor& CKFileVisitor::operator=(CKFileVisitor&& rhs) {
this->m_IsReader = rhs.m_IsReader;
this->m_Reader = rhs.m_Reader;
this->m_Writer = rhs.m_Writer;
#pragma endregion return *this;
#pragma region CKFile Misc
CKFile::CKFile(CKContext* ctx) :
m_Ctx(ctx) {
;
} }
CKFile::~CKFile() {} const CKFileObject* CKFileVisitor::GetFileObjectByIndex(size_t index) {
if (m_IsReader) {
return &m_Reader->m_FileObjects[index];
} else {
return nullptr;
}
}
#pragma endregion #pragma endregion
} }

View File

@ -14,45 +14,34 @@ namespace LibCmo::CK2 {
* No need to support them. * No need to support them.
*/ */
CKERROR CKFile::ShallowLoad(CKSTRING u8_filename) { CKERROR CKFileReader::ShallowLoad(CKSTRING u8_filename) {
// preset value // check document status
*out_doc = nullptr; if (this->m_Done) LIBPANIC("Can not load multiple times for single CKFileReader.")
// check file and open memory // check file and open memory
if (u8_filename == nullptr) return CKERROR::CKERR_INVALIDPARAMETER; if (u8_filename == nullptr) return CKERROR::CKERR_INVALIDPARAMETER;
std::unique_ptr<VxMath::VxMemoryMappedFile> mappedFile(new(std::nothrow) VxMath::VxMemoryMappedFile(u8_filename)); std::unique_ptr<VxMath::VxMemoryMappedFile> mappedFile(new VxMath::VxMemoryMappedFile(u8_filename));
if (mappedFile == nullptr) {
this->m_MinCtx->Printf("Out of memory when creating Memory File.");
return CKERROR::CKERR_OUTOFMEMORY;
}
if (!mappedFile->IsValid()) { if (!mappedFile->IsValid()) {
this->m_MinCtx->Printf("Fail to create Memory File for \"%s\".", u8_filename); this->m_Ctx->OutputToConsoleEx("Fail to create Memory File for \"%s\".", u8_filename);
return CKERROR::CKERR_INVALIDFILE; return CKERROR::CKERR_INVALIDFILE;
} }
// create document
std::unique_ptr<CKFileDocument> doc(new(std::nothrow) CKFileDocument());
if (doc == nullptr) return CKERROR::CKERR_OUTOFMEMORY;
// create buffer and start loading // create buffer and start loading
std::unique_ptr<CKBufferParser> parser(new(std::nothrow) CKBufferParser(mappedFile->GetBase(), mappedFile->GetFileSize(), false)); std::unique_ptr<CKBufferParser> parser(new CKBufferParser(mappedFile->GetBase(), mappedFile->GetFileSize(), false));
CKERROR err = this->ReadFileHeader(parser.get(), doc.get()); CKERROR err = this->ReadFileHeader(parser.get());
if (err != CKERROR::CKERR_OK) return err; if (err != CKERROR::CKERR_OK) return err;
err = this->ReadFileData(parser.get(), doc.get()); err = this->ReadFileData(parser.get());
if (err != CKERROR::CKERR_OK) return err; if (err != CKERROR::CKERR_OK) return err;
// unbind document and assign it
*out_doc = doc.release();
// other data will be free automatically // other data will be free automatically
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }
CKERROR CKFile::ReadFileHeader(CKBufferParser* ParserPtr, CKFileDocument* doc) { CKERROR CKFileReader::ReadFileHeader(CKBufferParser* ParserPtr) {
std::unique_ptr<CKBufferParser> parser(new(std::nothrow) CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false)); std::unique_ptr<CKBufferParser> parser(new CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false));
if (parser == nullptr) return CKERROR::CKERR_OUTOFMEMORY;
parser->SetCursor(ParserPtr->GetCursor()); parser->SetCursor(ParserPtr->GetCursor());
std::string name_conv; std::string name_conv, name_dest;
// ========== read header ========== // ========== read header ==========
// check header size // check header size
@ -74,23 +63,23 @@ namespace LibCmo::CK2 {
} }
// ========== assign value ========== // ========== assign value ==========
doc->m_FileInfo.ProductVersion = rawHeader.ProductVersion; this->m_FileInfo.ProductVersion = rawHeader.ProductVersion;
doc->m_FileInfo.ProductBuild = rawHeader.ProductBuild; this->m_FileInfo.ProductBuild = rawHeader.ProductBuild;
doc->m_FileInfo.FileWriteMode = static_cast<CK_FILE_WRITEMODE>(rawHeader.FileWriteMode); this->m_FileInfo.FileWriteMode = static_cast<CK_FILE_WRITEMODE>(rawHeader.FileWriteMode);
doc->m_FileInfo.CKVersion = rawHeader.CKVersion; this->m_FileInfo.CKVersion = rawHeader.CKVersion;
doc->m_FileInfo.FileVersion = rawHeader.FileVersion; this->m_FileInfo.FileVersion = rawHeader.FileVersion;
doc->m_FileInfo.FileSize = parser->GetSize(); this->m_FileInfo.FileSize = static_cast<CKDWORD>(parser->GetSize());
doc->m_FileInfo.ManagerCount = rawHeader.ManagerCount; this->m_FileInfo.ManagerCount = rawHeader.ManagerCount;
doc->m_FileInfo.ObjectCount = rawHeader.ObjectCount; this->m_FileInfo.ObjectCount = rawHeader.ObjectCount;
doc->m_FileInfo.MaxIDSaved = rawHeader.MaxIDSaved; this->m_FileInfo.MaxIDSaved = rawHeader.MaxIDSaved;
doc->m_FileInfo.Hdr1PackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1PackSize : 0u; this->m_FileInfo.Hdr1PackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1PackSize : 0u;
doc->m_FileInfo.Hdr1UnPackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1UnPackSize : 0u; this->m_FileInfo.Hdr1UnPackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1UnPackSize : 0u;
doc->m_FileInfo.DataPackSize = rawHeader.DataPackSize; this->m_FileInfo.DataPackSize = rawHeader.DataPackSize;
doc->m_FileInfo.DataUnPackSize = rawHeader.DataUnPackSize; this->m_FileInfo.DataUnPackSize = rawHeader.DataUnPackSize;
doc->m_FileInfo.Crc = rawHeader.Crc; this->m_FileInfo.Crc = rawHeader.Crc;
// ========== crc and body unpacker ========== // ========== crc and body unpacker ==========
if (doc->m_FileInfo.FileVersion >= 8) { if (this->m_FileInfo.FileVersion >= 8) {
// crc checker for file ver >= 8 // crc checker for file ver >= 8
// reset crc field of header // reset crc field of header
rawHeader.Crc = 0u; rawHeader.Crc = 0u;
@ -98,12 +87,12 @@ namespace LibCmo::CK2 {
// compute crc // compute crc
CKDWORD gotten_crc = CKComputeDataCRC(&rawHeader, sizeof(CKRawFileInfo), 0u); CKDWORD gotten_crc = CKComputeDataCRC(&rawHeader, sizeof(CKRawFileInfo), 0u);
parser->SetCursor(sizeof(CKRawFileInfo)); parser->SetCursor(sizeof(CKRawFileInfo));
gotten_crc = CKComputeDataCRC(parser->GetPtr(), doc->m_FileInfo.Hdr1PackSize, gotten_crc); gotten_crc = CKComputeDataCRC(parser->GetPtr(), this->m_FileInfo.Hdr1PackSize, gotten_crc);
parser->MoveCursor(doc->m_FileInfo.Hdr1PackSize); parser->MoveCursor(this->m_FileInfo.Hdr1PackSize);
gotten_crc = CKComputeDataCRC(parser->GetPtr(), doc->m_FileInfo.DataPackSize, gotten_crc); gotten_crc = CKComputeDataCRC(parser->GetPtr(), this->m_FileInfo.DataPackSize, gotten_crc);
if (gotten_crc != doc->m_FileInfo.Crc) { if (gotten_crc != this->m_FileInfo.Crc) {
this->m_MinCtx->Printf("Virtools file CRC error."); this->m_Ctx->OutputToConsole("Virtools file CRC error.");
return CKERROR::CKERR_FILECRCERROR; return CKERROR::CKERR_FILECRCERROR;
} }
@ -111,13 +100,9 @@ namespace LibCmo::CK2 {
parser->SetCursor(sizeof(CKRawFileInfo)); parser->SetCursor(sizeof(CKRawFileInfo));
// compare size to decide wheher use compress feature // compare size to decide wheher use compress feature
void* decomp_buffer = CKUnPackData(doc->m_FileInfo.Hdr1UnPackSize, parser->GetPtr(), doc->m_FileInfo.Hdr1PackSize); void* decomp_buffer = CKUnPackData(this->m_FileInfo.Hdr1UnPackSize, parser->GetPtr(), this->m_FileInfo.Hdr1PackSize);
if (decomp_buffer != nullptr) { if (decomp_buffer != nullptr) {
parser = std::unique_ptr<CKBufferParser>(new(std::nothrow) CKBufferParser(decomp_buffer, doc->m_FileInfo.Hdr1UnPackSize, true)); parser = std::unique_ptr<CKBufferParser>(new CKBufferParser(decomp_buffer, this->m_FileInfo.Hdr1UnPackSize, true));
if (parser == nullptr) {
delete[] reinterpret_cast<char*>(decomp_buffer);
return CKERROR::CKERR_OUTOFMEMORY;
}
} }
} }
@ -125,12 +110,12 @@ namespace LibCmo::CK2 {
// file ver >= 7 have this features // file ver >= 7 have this features
{ {
// apply max id saved // apply max id saved
doc->m_SaveIDMax = doc->m_FileInfo.MaxIDSaved; this->m_SaveIDMax = this->m_FileInfo.MaxIDSaved;
// resize // resize
doc->m_FileObjects.resize(doc->m_FileInfo.ObjectCount); this->m_FileObjects.resize(this->m_FileInfo.ObjectCount);
// read data // read data
for (auto& fileobj : doc->m_FileObjects) { for (auto& fileobj : this->m_FileObjects) {
// read basic fields // read basic fields
parser->Read(&(fileobj.ObjectId), sizeof(CK_ID)); parser->Read(&(fileobj.ObjectId), sizeof(CK_ID));
parser->Read(&(fileobj.ObjectCid), sizeof(CK_CLASSID)); parser->Read(&(fileobj.ObjectCid), sizeof(CK_CLASSID));
@ -141,21 +126,22 @@ namespace LibCmo::CK2 {
if (namelen != 0) { if (namelen != 0) {
name_conv.resize(namelen); name_conv.resize(namelen);
parser->Read(name_conv.data(), namelen); parser->Read(name_conv.data(), namelen);
m_MinCtx->GetUtf8String(name_conv, fileobj.Name); m_Ctx->GetUtf8String(name_conv, name_dest);
fileobj.Name = name_dest;
} }
} }
} }
// ========== dep list read ========== // ========== dep list read ==========
// file ver >= 8 have this feature // file ver >= 8 have this feature
if (doc->m_FileInfo.FileVersion >= 8) { if (this->m_FileInfo.FileVersion >= 8) {
// get size and resize // get size and resize
CKDWORD depSize; CKDWORD depSize;
parser->Read(&depSize, sizeof(CKDWORD)); parser->Read(&depSize, sizeof(CKDWORD));
doc->m_PluginDep.resize(depSize); this->m_PluginsDep.resize(depSize);
CKDWORD guid_size; CKDWORD guid_size;
for (auto& dep : doc->m_PluginDep) { for (auto& dep : this->m_PluginsDep) {
// read category // read category
parser->Read(&(dep.m_PluginCategory), sizeof(CK_PLUGIN_TYPE)); parser->Read(&(dep.m_PluginCategory), sizeof(CK_PLUGIN_TYPE));
// get size and resize // get size and resize
@ -171,7 +157,7 @@ namespace LibCmo::CK2 {
// ========== included file list read ========== // ========== included file list read ==========
// file ver >= 8 have this feature // file ver >= 8 have this feature
if (doc->m_FileInfo.FileVersion >= 8) { if (this->m_FileInfo.FileVersion >= 8) {
// MARK: i don't knwo what is this! // MARK: i don't knwo what is this!
int32_t hasIncludedFile; int32_t hasIncludedFile;
parser->Read(&hasIncludedFile, sizeof(int32_t)); parser->Read(&hasIncludedFile, sizeof(int32_t));
@ -180,7 +166,7 @@ namespace LibCmo::CK2 {
// read included file size and resize // read included file size and resize
CKDWORD includedFileCount; CKDWORD includedFileCount;
parser->Read(&includedFileCount, sizeof(CKDWORD)); parser->Read(&includedFileCount, sizeof(CKDWORD));
doc->m_IncludedFiles.resize(includedFileCount); this->m_IncludedFiles.resize(includedFileCount);
hasIncludedFile -= 4; hasIncludedFile -= 4;
} }
@ -191,10 +177,10 @@ namespace LibCmo::CK2 {
} }
// ========== sync main parser ========== // ========== sync main parser ==========
if (doc->m_FileInfo.FileVersion >= 8) { if (this->m_FileInfo.FileVersion >= 8) {
// file ver >= 8, use header offset // file ver >= 8, use header offset
// because it have compress feature // because it have compress feature
ParserPtr->SetCursor(doc->m_FileInfo.Hdr1PackSize + sizeof(CKRawFileInfo)); ParserPtr->SetCursor(this->m_FileInfo.Hdr1PackSize + sizeof(CKRawFileInfo));
} else { } else {
// otherwise, sync with current parser. // otherwise, sync with current parser.
ParserPtr->SetCursor(parser->GetCursor()); ParserPtr->SetCursor(parser->GetCursor());
@ -203,7 +189,7 @@ namespace LibCmo::CK2 {
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }
CKERROR CKFile::ReadFileData(CKBufferParser* ParserPtr, CKFileDocument* doc) { CKERROR CKFileReader::ReadFileData(CKBufferParser* ParserPtr) {
std::unique_ptr<CKBufferParser> parser(new(std::nothrow) CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false)); std::unique_ptr<CKBufferParser> parser(new(std::nothrow) CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false));
if (parser == nullptr) return CKERROR::CKERR_OUTOFMEMORY; if (parser == nullptr) return CKERROR::CKERR_OUTOFMEMORY;
parser->SetCursor(ParserPtr->GetCursor()); parser->SetCursor(ParserPtr->GetCursor());
@ -211,52 +197,47 @@ namespace LibCmo::CK2 {
std::string name_conv; std::string name_conv;
// ========== compress feature process ========== // ========== compress feature process ==========
if (EnumsHelper::FlagEnumHas(doc->m_FileInfo.FileWriteMode, CK_FILE_WRITEMODE::CKFILE_CHUNKCOMPRESSED_OLD) || if (EnumsHelper::Has(this->m_FileInfo.FileWriteMode, CK_FILE_WRITEMODE::CKFILE_CHUNKCOMPRESSED_OLD) ||
EnumsHelper::FlagEnumHas(doc->m_FileInfo.FileWriteMode, CK_FILE_WRITEMODE::CKFILE_WHOLECOMPRESSED)) { EnumsHelper::Has(this->m_FileInfo.FileWriteMode, CK_FILE_WRITEMODE::CKFILE_WHOLECOMPRESSED)) {
void* decomp_buffer = CKUnPackData(doc->m_FileInfo.DataUnPackSize, parser->GetPtr(), doc->m_FileInfo.DataPackSize); void* decomp_buffer = CKUnPackData(this->m_FileInfo.DataUnPackSize, parser->GetPtr(), this->m_FileInfo.DataPackSize);
if (decomp_buffer != nullptr) { if (decomp_buffer != nullptr) {
parser = std::unique_ptr<CKBufferParser>(new(std::nothrow) CKBufferParser(decomp_buffer, doc->m_FileInfo.DataUnPackSize, true)); parser = std::unique_ptr<CKBufferParser>(new CKBufferParser(decomp_buffer, this->m_FileInfo.DataUnPackSize, true));
if (parser == nullptr) {
delete[] reinterpret_cast<char*>(decomp_buffer);
return CKERROR::CKERR_OUTOFMEMORY;
}
} }
} }
// ========== old file crc and obj list read ========== // ========== old file crc and obj list read ==========
// only file ver < 8 run this // only file ver < 8 run this
if (doc->m_FileInfo.FileVersion < 8) { if (this->m_FileInfo.FileVersion < 8) {
// check crc // check crc
CKDWORD gotten_crc = CKComputeDataCRC( CKDWORD gotten_crc = CKComputeDataCRC(
parser->GetPtr(), parser->GetPtr(),
parser->GetSize() - parser->GetCursor(), parser->GetSize() - parser->GetCursor(),
0u 0u
); );
if (gotten_crc != doc->m_FileInfo.Crc) { if (gotten_crc != this->m_FileInfo.Crc) {
this->m_MinCtx->Printf("Virtools file CRC error."); this->m_Ctx->OutputToConsole("Virtools file CRC error.");
return CKERROR::CKERR_FILECRCERROR; return CKERROR::CKERR_FILECRCERROR;
} }
// MARK: why read again? especially for file ver == 7. // MARK: why read again? especially for file ver == 7.
// get save id max // get save id max
parser->Read(&doc->m_SaveIDMax, sizeof(int32_t)); parser->Read(&this->m_SaveIDMax, sizeof(int32_t));
// get object count and resize // get object count and resize
parser->Read(&doc->m_FileInfo.ObjectCount, sizeof(CKDWORD)); parser->Read(&this->m_FileInfo.ObjectCount, sizeof(CKDWORD));
if (doc->m_FileObjects.empty()) { if (this->m_FileObjects.empty()) {
doc->m_FileObjects.resize(doc->m_FileInfo.ObjectCount); this->m_FileObjects.resize(this->m_FileInfo.ObjectCount);
} }
} }
// ========== manager read ========== // ========== manager read ==========
// only file ver >= 6 have this // only file ver >= 6 have this
if (doc->m_FileInfo.ManagerCount != 0) { if (this->m_FileInfo.ManagerCount != 0) {
doc->m_FileManagersData.resize(doc->m_FileInfo.ManagerCount); this->m_ManagersData.resize(this->m_FileInfo.ManagerCount);
CKDWORD stateChunkLen = 0u; CKDWORD stateChunkLen = 0u;
bool stateChkParseSuccess = false; bool stateChkParseSuccess = false;
for (auto& mgr : doc->m_FileManagersData) { for (auto& mgr : this->m_ManagersData) {
// read guid // read guid
parser->Read(&(mgr.Manager), sizeof(CKGUID)); parser->Read(&(mgr.Manager), sizeof(CKGUID));
@ -269,13 +250,11 @@ namespace LibCmo::CK2 {
} }
// read statechunk // read statechunk
mgr.Data = new(std::nothrow) CKStateChunk(doc, this->m_MinCtx); mgr.Data = new CKStateChunk(&this->m_Visitor, this->m_Ctx);
if (mgr.Data != nullptr) { stateChkParseSuccess = mgr.Data->ConvertFromBuffer(parser->GetPtr());
stateChkParseSuccess = mgr.Data->ConvertFromBuffer(parser->GetPtr()); if (!stateChkParseSuccess) {
if (!stateChkParseSuccess) { delete mgr.Data;
delete mgr.Data; mgr.Data = nullptr;
mgr.Data = nullptr;
}
} }
parser->MoveCursor(stateChunkLen); parser->MoveCursor(stateChunkLen);
} }
@ -283,11 +262,11 @@ namespace LibCmo::CK2 {
// ========== object read ========== // ========== object read ==========
// only works file version >= 4. < 4 section has been removed. // only works file version >= 4. < 4 section has been removed.
if (doc->m_FileInfo.ObjectCount != 0) { if (this->m_FileInfo.ObjectCount != 0) {
// new file reader section // new file reader section
CKDWORD stateChunkLen = 0u; CKDWORD stateChunkLen = 0u;
bool stateChkParseSuccess = false; bool stateChkParseSuccess = false;
for (auto& obj : doc->m_FileObjects) { for (auto& obj : this->m_FileObjects) {
// get statechunk len // get statechunk len
parser->Read(&stateChunkLen, sizeof(CKDWORD)); parser->Read(&stateChunkLen, sizeof(CKDWORD));
// check state chunk len // check state chunk len
@ -297,13 +276,11 @@ namespace LibCmo::CK2 {
} }
// read state chunk // read state chunk
obj.Data = new(std::nothrow) CKStateChunk(doc, this->m_MinCtx); obj.Data = new CKStateChunk(&this->m_Visitor, this->m_Ctx);
if (obj.Data != nullptr) { stateChkParseSuccess = obj.Data->ConvertFromBuffer(parser->GetPtr());
stateChkParseSuccess = obj.Data->ConvertFromBuffer(parser->GetPtr()); if (!stateChkParseSuccess) {
if (!stateChkParseSuccess) { delete obj.Data;
delete obj.Data; obj.Data = nullptr;
obj.Data = nullptr;
}
} }
parser->MoveCursor(stateChunkLen); parser->MoveCursor(stateChunkLen);
@ -314,11 +291,11 @@ namespace LibCmo::CK2 {
// before reading, we need switch back to original parser. // before reading, we need switch back to original parser.
// and skip data chunk size // and skip data chunk size
parser = std::unique_ptr<CKBufferParser>(new(std::nothrow) CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false)); parser = std::unique_ptr<CKBufferParser>(new(std::nothrow) CKBufferParser(ParserPtr->GetBase(), ParserPtr->GetSize(), false));
parser->MoveCursor(doc->m_FileInfo.DataPackSize); parser->MoveCursor(this->m_FileInfo.DataPackSize);
// then we can read it. // then we can read it.
if (doc->m_IncludedFiles.size() != 0) { if (this->m_IncludedFiles.size() != 0) {
for (auto& file : doc->m_IncludedFiles) { for (auto& file : this->m_IncludedFiles) {
// get file name length and resize it // get file name length and resize it
CKDWORD filenamelen = 0u; CKDWORD filenamelen = 0u;
parser->Read(&filenamelen, sizeof(CKDWORD)); parser->Read(&filenamelen, sizeof(CKDWORD));
@ -327,7 +304,7 @@ namespace LibCmo::CK2 {
// read filename // read filename
if (filenamelen != 0) { if (filenamelen != 0) {
parser->Read(name_conv.data(), filenamelen); parser->Read(name_conv.data(), filenamelen);
m_MinCtx->GetUtf8String(name_conv, file); m_Ctx->GetUtf8String(name_conv, file);
} }
// read file body length // read file body length
@ -335,7 +312,7 @@ namespace LibCmo::CK2 {
parser->Read(&filebodylen, sizeof(CKDWORD)); parser->Read(&filebodylen, sizeof(CKDWORD));
// read file body // read file body
FILE* fp = m_MinCtx->OpenTempFile(file.c_str(), false); FILE* fp = m_Ctx->OpenTempFile(file.c_str(), false);
if (fp != nullptr) { if (fp != nullptr) {
StreamHelper::CopyStream(parser->GetPtr(), fp, filebodylen); StreamHelper::CopyStream(parser->GetPtr(), fp, filebodylen);
fclose(fp); fclose(fp);
@ -349,32 +326,26 @@ namespace LibCmo::CK2 {
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }
CKERROR CKFile::DeepLoad(CKSTRING u8_filename, CKFileDocument** out_doc) { CKERROR CKFileReader::DeepLoad(CKSTRING u8_filename) {
// ========== prepare work ========== // ========== prepare work ==========
// preset value
*out_doc = nullptr;
CKERROR err = CKERROR::CKERR_OK; CKERROR err = CKERROR::CKERR_OK;
// get shallow document first // get shallow document first
CKFileDocument* rawShallowDoc = nullptr; err = this->ShallowLoad(u8_filename);
err = this->ShallowLoad(u8_filename, &rawShallowDoc);
if (rawShallowDoc == nullptr) return err;
// use unique ptr wrap it as a deep doc
std::unique_ptr<CKFileDocument> deepDoc(rawShallowDoc);
if (err != CKERROR::CKERR_OK) return err; if (err != CKERROR::CKERR_OK) return err;
// ========== create object first ========== // ========== create object first ==========
for (auto& obj : deepDoc->m_FileObjects) { for (auto& obj : this->m_FileObjects) {
// todo: skip CK_LEVEL // todo: skip CK_LEVEL
// todo: resolve references // todo: resolve references
if (obj.Data == nullptr) continue; if (obj.Data == nullptr) continue;
// create object and assign created obj ckid // create object and assign created obj ckid
obj.ObjPtr = m_MinCtx->CreateCKObject(obj.ObjectId, obj.ObjectCid, obj.Name.c_str()); obj.ObjPtr = m_Ctx->CreateCKObject(obj.ObjectCid, obj.Name.c_str());
if (obj.ObjPtr == nullptr) { if (obj.ObjPtr == nullptr) {
obj.CreatedObject = 0u; obj.CreatedObjectId = 0u;
} else { } else {
obj.CreatedObject = obj.ObjPtr->m_ID; obj.CreatedObjectId = obj.ObjPtr->GetID();
} }
} }
@ -386,13 +357,13 @@ namespace LibCmo::CK2 {
// todo... // todo...
// ========== analyze objects CKStateChunk ========== // ========== analyze objects CKStateChunk ==========
for (auto& obj : deepDoc->m_FileObjects) { for (auto& obj : this->m_FileObjects) {
if (obj.Data == nullptr || obj.ObjPtr == nullptr) continue; if (obj.Data == nullptr || obj.ObjPtr == nullptr) continue;
// todo: special treat for CK_LEVEL // todo: special treat for CK_LEVEL
// try parsing data // try parsing data
obj.Data->StartRead(); obj.Data->StartRead();
bool success = obj.ObjPtr->Load(obj.Data, deepDoc.get()); bool success = obj.ObjPtr->Load(obj.Data, &this->m_Visitor);
obj.Data->StopRead(); obj.Data->StopRead();
if (success) { if (success) {
// if success, clear CKStateChunk* // if success, clear CKStateChunk*
@ -400,15 +371,13 @@ namespace LibCmo::CK2 {
obj.Data = nullptr; obj.Data = nullptr;
} else { } else {
// if failed, delete it // if failed, delete it
m_MinCtx->DestroyCKObject(obj.ObjectId); m_Ctx->DestroyCKObject(obj.ObjectId);
obj.ObjPtr = nullptr; obj.ObjPtr = nullptr;
obj.CreatedObject = 0u; obj.CreatedObjectId = 0u;
} }
} }
// ========== finalize work ========== // ========== finalize work ==========
// detach and return
*out_doc = deepDoc.release();
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }

View File

@ -2,6 +2,8 @@
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
CKERROR CKFileWriter::Save(CKSTRING u8_filename) {
return CKERROR::CKERR_OK;
}
} }

View File

@ -10,6 +10,8 @@
#include <algorithm> #include <algorithm>
#include <zlib.h> #include <zlib.h>
#include "CKObjectImplements/CKObject.hpp"
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
#pragma region Compression utilities #pragma region Compression utilities
@ -68,7 +70,7 @@ namespace LibCmo::CK2 {
// find direct parent // find direct parent
auto finder = g_CKClassInfoId2Idx.find(desc.Parent); auto finder = g_CKClassInfoId2Idx.find(desc.Parent);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
CKClassDesc& parent = g_CKClassInfo[finder->second]; CKClassDesc& parent = g_CKClassInfo[finder->second];
// if it is not self inheritance, call recursively // if it is not self inheritance, call recursively
@ -80,7 +82,7 @@ namespace LibCmo::CK2 {
desc.Parents = parent.Parents; desc.Parents = parent.Parents;
// and set self as its parent // and set self as its parent
finder = g_CKClassInfoId2Idx.find(desc.Self); finder = g_CKClassInfoId2Idx.find(desc.Self);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
desc.Parents[finder->second] = true; desc.Parents[finder->second] = true;
// set derivation level // set derivation level
@ -105,7 +107,7 @@ namespace LibCmo::CK2 {
// iterate CKClassDesc::Parents and register it self to gotten parents // iterate CKClassDesc::Parents and register it self to gotten parents
for (auto& item : g_CKClassInfo) { for (auto& item : g_CKClassInfo) {
auto finder = g_CKClassInfoId2Idx.find(item.Self); auto finder = g_CKClassInfoId2Idx.find(item.Self);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
size_t selfidx = finder->second; size_t selfidx = finder->second;
for (size_t idx = 0; idx < classCount; ++idx) { for (size_t idx = 0; idx < classCount; ++idx) {
@ -154,10 +156,10 @@ namespace LibCmo::CK2 {
CKBOOL CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent) { CKBOOL CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent) {
// get corresponding index first // get corresponding index first
auto finder = g_CKClassInfoId2Idx.find(child); auto finder = g_CKClassInfoId2Idx.find(child);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
size_t child_idx = finder->second; size_t child_idx = finder->second;
finder = g_CKClassInfoId2Idx.find(parent); finder = g_CKClassInfoId2Idx.find(parent);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
size_t parent_idx = finder->second; size_t parent_idx = finder->second;
return g_CKClassInfo[child_idx].Parents[parent_idx]; return g_CKClassInfo[child_idx].Parents[parent_idx];
@ -165,7 +167,7 @@ namespace LibCmo::CK2 {
CK_CLASSID CKGetParentClassID(CK_CLASSID child) { CK_CLASSID CKGetParentClassID(CK_CLASSID child) {
auto finder = g_CKClassInfoId2Idx.find(child); auto finder = g_CKClassInfoId2Idx.find(child);
if (finder == g_CKClassInfoId2Idx.end()) std::abort(); if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID.");
return g_CKClassInfo[finder->second].Parent; return g_CKClassInfo[finder->second].Parent;
} }
@ -188,6 +190,10 @@ namespace LibCmo::CK2 {
CKERROR CKStartUp() { CKERROR CKStartUp() {
// todo: add class type registrations // todo: add class type registrations
CKClassRegister(CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT,
[](CKContext* ctx, CK_ID id, CKSTRING name) -> CKObject* { return new CKObject(ctx, id, name); },
[](CKContext* ctx, CKObject* obj) -> void { delete obj; },
[]() -> CKSTRING { return "Basic Object"; });
/* /*
// register CKObjects // register CKObjects
@ -218,6 +224,8 @@ namespace LibCmo::CK2 {
} }
*/ */
CKBuildClassHierarchyTable();
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }

View File

@ -69,7 +69,7 @@ namespace LibCmo::CK2 {
data for your manager. data for your manager.
@see CKStateChunk, LoadData @see CKStateChunk, LoadData
*/ */
virtual CKStateChunk* SaveData(CKFile* SavedFile) { virtual CKStateChunk* SaveData(CKFileVisitor* SavedFile) {
return nullptr; return nullptr;
} }
/** /**
@ -81,7 +81,7 @@ namespace LibCmo::CK2 {
+ During a load operation, each manager is automatically called if there was a chunk saved in the file with SaveData. + During a load operation, each manager is automatically called if there was a chunk saved in the file with SaveData.
@see CKStateChunk, SaveData @see CKStateChunk, SaveData
*/ */
virtual CKERROR LoadData(CKStateChunk* chunk, CKFile* LoadedFile) { virtual CKERROR LoadData(CKStateChunk* chunk, CKFileVisitor* LoadedFile) {
return CKERROR::CKERR_OK; return CKERROR::CKERR_OK;
} }

View File

@ -4,13 +4,13 @@
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
void CKObject::PreSave(CKFile* file, CKDWORD flags) {} void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {}
CKStateChunk* CKObject::Save(CKFile* file, CKDWORD flags) { CKStateChunk* CKObject::Save(CKFileVisitor* file, CKDWORD flags) {
return nullptr; return nullptr;
} }
bool CKObject::Load(CKStateChunk* chunk, CKFile* file) { bool CKObject::Load(CKStateChunk* chunk, CKFileVisitor* file) {
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIDDEN)) { if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIDDEN)) {
EnumsHelper::Rm(this->m_ObjectFlags, EnumsHelper::Rm(this->m_ObjectFlags,
EnumsHelper::Merge({ CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE })); EnumsHelper::Merge({ CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE }));

View File

@ -39,9 +39,9 @@ namespace LibCmo::CK2 {
return CK_CLASSID::CKCID_OBJECT; return CK_CLASSID::CKCID_OBJECT;
} }
virtual void PreSave(CKFile* file, CKDWORD flags); virtual void PreSave(CKFileVisitor* file, CKDWORD flags);
virtual CKStateChunk* Save(CKFile* file, CKDWORD flags); virtual CKStateChunk* Save(CKFileVisitor* file, CKDWORD flags);
virtual bool Load(CKStateChunk* chunk, CKFile* file); virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file);
virtual void PostLoad(); virtual void PostLoad();
private: private:

View File

@ -1,7 +1,6 @@
#include "VTUtils.hpp"
#include "CKStateChunk.hpp" #include "CKStateChunk.hpp"
#include "CKMinContext.hpp"
#include "CKFile.hpp" #include "CKFile.hpp"
#include "CKContext.hpp"
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
@ -16,21 +15,20 @@ namespace LibCmo::CK2 {
//{ //{
// ; // ;
//} //}
CKStateChunk::CKStateChunk(CKFileDocument* doc, CKMinContext* ctx) : CKStateChunk::CKStateChunk(CKFileVisitor* visitor, CKContext* ctx) :
m_ClassId(CK_CLASSID::CKCID_OBJECT), m_DataDwSize(0u), m_pData(nullptr), m_ClassId(CK_CLASSID::CKCID_OBJECT), m_DataDwSize(0u), m_pData(nullptr),
m_DataVersion(CK_STATECHUNK_DATAVERSION::CHUNKDATA_CURRENTVERSION), m_ChunkVersion(CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4), m_DataVersion(CK_STATECHUNK_DATAVERSION::CHUNKDATA_CURRENTVERSION), m_ChunkVersion(CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4),
m_Parser{ CKStateChunkStatus::IDLE, 0u, 0u, 0u }, m_Parser{ CKStateChunkStatus::IDLE, 0u, 0u, 0u },
m_ObjectList(), m_ChunkList(), m_ManagerList(), m_ObjectList(), m_ChunkList(), m_ManagerList(),
m_BindDoc(doc), m_BindContext(ctx) m_BindFile(visitor), m_BindContext(ctx)
{ {}
;
}
CKStateChunk::CKStateChunk(const CKStateChunk& rhs) : CKStateChunk::CKStateChunk(const CKStateChunk& rhs) :
m_ClassId(rhs.m_ClassId), m_DataVersion(rhs.m_DataVersion), m_ChunkVersion(rhs.m_ChunkVersion), m_ClassId(rhs.m_ClassId), m_DataVersion(rhs.m_DataVersion), m_ChunkVersion(rhs.m_ChunkVersion),
m_Parser(rhs.m_Parser), m_Parser(rhs.m_Parser),
m_ObjectList(rhs.m_ObjectList), m_ManagerList(rhs.m_ManagerList), m_ChunkList(rhs.m_ChunkList), m_ObjectList(rhs.m_ObjectList), m_ManagerList(rhs.m_ManagerList), m_ChunkList(rhs.m_ChunkList),
m_pData(nullptr), m_DataDwSize(rhs.m_DataDwSize), m_pData(nullptr), m_DataDwSize(rhs.m_DataDwSize),
m_BindDoc(rhs.m_BindDoc), m_BindContext(rhs.m_BindContext) { m_BindFile(rhs.m_BindFile), m_BindContext(rhs.m_BindContext) {
// copy buffer // copy buffer
if (rhs.m_pData != nullptr) { if (rhs.m_pData != nullptr) {
this->m_pData = new(std::nothrow) CKDWORD[rhs.m_DataDwSize]; this->m_pData = new(std::nothrow) CKDWORD[rhs.m_DataDwSize];
@ -39,6 +37,7 @@ namespace LibCmo::CK2 {
} }
} }
} }
CKStateChunk& CKStateChunk::operator=(const CKStateChunk& rhs) { CKStateChunk& CKStateChunk::operator=(const CKStateChunk& rhs) {
this->Clear(); this->Clear();
@ -52,7 +51,7 @@ namespace LibCmo::CK2 {
this->m_ManagerList = rhs.m_ManagerList; this->m_ManagerList = rhs.m_ManagerList;
this->m_ChunkList = rhs.m_ChunkList; this->m_ChunkList = rhs.m_ChunkList;
this->m_BindDoc = rhs.m_BindDoc; this->m_BindFile = rhs.m_BindFile;
this->m_BindContext = rhs.m_BindContext; this->m_BindContext = rhs.m_BindContext;
// copy buffer // copy buffer
@ -292,23 +291,23 @@ namespace LibCmo::CK2 {
std::memcpy(this->m_pData, dwbuf + bufpos, sizeof(CKDWORD) * this->m_DataDwSize); std::memcpy(this->m_pData, dwbuf + bufpos, sizeof(CKDWORD) * this->m_DataDwSize);
bufpos += this->m_DataDwSize; bufpos += this->m_DataDwSize;
} }
if (EnumsHelper::FlagEnumHas(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_FILE)) { if (EnumsHelper::Has(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_FILE)) {
// MARK: set ckfile = nullptr; // MARK: set ckfile = nullptr;
; ;
} }
if (EnumsHelper::FlagEnumHas(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_IDS)) { if (EnumsHelper::Has(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_IDS)) {
this->m_ObjectList.resize(dwbuf[bufpos]); this->m_ObjectList.resize(dwbuf[bufpos]);
bufpos += 1u; bufpos += 1u;
std::memcpy(this->m_ObjectList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ObjectList.size()); std::memcpy(this->m_ObjectList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ObjectList.size());
bufpos += this->m_ObjectList.size(); bufpos += this->m_ObjectList.size();
} }
if (EnumsHelper::FlagEnumHas(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_CHN)) { if (EnumsHelper::Has(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_CHN)) {
this->m_ChunkList.resize(dwbuf[bufpos]); this->m_ChunkList.resize(dwbuf[bufpos]);
bufpos += 1u; bufpos += 1u;
std::memcpy(this->m_ChunkList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ChunkList.size()); std::memcpy(this->m_ChunkList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ChunkList.size());
bufpos += this->m_ChunkList.size(); bufpos += this->m_ChunkList.size();
} }
if (EnumsHelper::FlagEnumHas(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_MAN)) { if (EnumsHelper::Has(options, CK_STATECHUNK_CHUNKOPTIONS::CHNK_OPTION_MAN)) {
this->m_ManagerList.resize(dwbuf[bufpos]); this->m_ManagerList.resize(dwbuf[bufpos]);
bufpos += 1u; bufpos += 1u;
std::memcpy(this->m_ManagerList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ManagerList.size()); std::memcpy(this->m_ManagerList.data(), dwbuf + bufpos, sizeof(CKDWORD) * this->m_ManagerList.size());
@ -426,7 +425,7 @@ namespace LibCmo::CK2 {
return true; return true;
} else { } else {
// failed, report to context // failed, report to context
m_BindContext->Printf("CKStateChunk read length error at %" PRICKdword ".", this->m_Parser.m_CurrentPos); m_BindContext->OutputToConsoleEx("CKStateChunk read length error at %" PRIckDWORD ".", this->m_Parser.m_CurrentPos);
return false; return false;
} }
} }
@ -464,13 +463,13 @@ namespace LibCmo::CK2 {
// new file // new file
// if no doc associated, return directly // if no doc associated, return directly
if (this->m_BindDoc == nullptr) { if (this->m_BindFile == nullptr) {
*id = static_cast<CK_ID>(gotten_id); *id = static_cast<CK_ID>(gotten_id);
return true; return true;
} }
// if it is positive, return corresponding value // if it is positive, return corresponding value
if (gotten_id >= 0) { if (gotten_id >= 0) {
*id = this->m_BindDoc->m_FileObjects[gotten_id].CreatedObject; *id = this->m_BindFile->GetFileObjectByIndex(gotten_id)->CreatedObjectId;
return true; return true;
} }
@ -510,7 +509,7 @@ namespace LibCmo::CK2 {
if (!this->EnsureReadSpace(subChunkSize)) goto subchunk_defer; if (!this->EnsureReadSpace(subChunkSize)) goto subchunk_defer;
// create statechunk // create statechunk
subchunk = new(std::nothrow) CKStateChunk(this->m_BindDoc, this->m_BindContext); subchunk = new(std::nothrow) CKStateChunk(this->m_BindFile, this->m_BindContext);
if (subchunk == nullptr) goto subchunk_defer; if (subchunk == nullptr) goto subchunk_defer;
// start read data // start read data
@ -535,7 +534,7 @@ namespace LibCmo::CK2 {
// has bind file? // has bind file?
CKDWORD hasBindFile; CKDWORD hasBindFile;
if (!this->ReadStruct(hasBindFile)) goto subchunk_defer; if (!this->ReadStruct(hasBindFile)) goto subchunk_defer;
if (hasBindFile == 1) subchunk->m_BindDoc = nullptr; if (hasBindFile == 1) subchunk->m_BindFile = nullptr;
// 3 list size // 3 list size
// manager only existed when ver > 4 // manager only existed when ver > 4
@ -738,11 +737,11 @@ namespace LibCmo::CK2 {
} }
// remap id // remap id
if (this->m_BindDoc != nullptr) { if (this->m_BindFile != nullptr) {
if (cache < 0) { if (cache < 0) {
id = 0u; id = 0u;
} else { } else {
id = this->m_BindDoc->m_FileObjects[cache].CreatedObject; id = this->m_BindFile->GetFileObjectByIndex(cache)->CreatedObjectId;
} }
} else { } else {
id = static_cast<CK_ID>(cache); id = static_cast<CK_ID>(cache);

View File

@ -1,18 +1,17 @@
#pragma once #pragma once
#include "CKDefines.hpp" #include "../VTAll.hpp"
#include "CKEnums.hpp"
#include <type_traits>
#include <cinttypes>
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
class CKStateChunk { class CKStateChunk {
public: public:
//CKStateChunk(); //CKStateChunk();
CKStateChunk(CKFileDocument* doc, CKMinContext* ctx); CKStateChunk(CKFileVisitor* visitor, CKContext* ctx);
CKStateChunk(const CKStateChunk&); CKStateChunk(const CKStateChunk&);
CKStateChunk(CKStateChunk&&);
CKStateChunk& operator=(const CKStateChunk&); CKStateChunk& operator=(const CKStateChunk&);
CKStateChunk& operator-(const CKStateChunk&&);
~CKStateChunk(); ~CKStateChunk();
private: private:
@ -40,8 +39,8 @@ namespace LibCmo::CK2 {
std::vector<CKDWORD> m_ChunkList; std::vector<CKDWORD> m_ChunkList;
std::vector<CKDWORD> m_ManagerList; std::vector<CKDWORD> m_ManagerList;
CKFileDocument* m_BindDoc; CKFileVisitor* m_BindFile;
CKMinContext* m_BindContext; CKContext* m_BindContext;
#pragma region Buffer Related #pragma region Buffer Related

View File

@ -161,6 +161,7 @@ namespace LibCmo::CK2 {
}; };
// ========== Type Definition ========== // ========== Type Definition ==========
// type define
using CKMUTSTRING = char*; using CKMUTSTRING = char*;
using CKSTRING = const char*; using CKSTRING = const char*;
@ -181,6 +182,12 @@ namespace LibCmo::CK2 {
using CKAttributeType = int32_t; using CKAttributeType = int32_t;
using CKAttributeCategory = int32_t; using CKAttributeCategory = int32_t;
// type print style define
#define PRIckBYTE PRIu8
#define PRIckDWORD PRIu32
#define PRIckWORD PRIu16
#define PRIckINT PRIi32
// ========== Class List ========== // ========== Class List ==========
// Objects and derivated classes // Objects and derivated classes
@ -269,7 +276,9 @@ namespace LibCmo::CK2 {
//--- Important classes //--- Important classes
class CKContext; class CKContext;
class CKStateChunk; class CKStateChunk;
class CKFile; class CKFileReader;
class CKFileWriter;
class CKFileVisitor;
/** /**

View File

@ -2,6 +2,12 @@
namespace LibCmo { namespace LibCmo {
void LibPanic(int line, const char* file, const char* errmsg) {
fprintf(stderr, "LIBCMO PANIC:%s (%s:L%d)\n",
errmsg ? errmsg : "", file, line);
std::abort();
}
namespace StreamHelper { namespace StreamHelper {
static constexpr const size_t CHUNK_SIZE = 10240; static constexpr const size_t CHUNK_SIZE = 10240;

View File

@ -68,6 +68,9 @@
namespace LibCmo { namespace LibCmo {
[[noreturn]] void LibPanic(int line, const char* file, const char* errmsg);
#define LIBPANIC(msg) LibCmo::LibPanic(__LINE__, __FILE__, msg);
namespace TypeHelper { namespace TypeHelper {
/** /**
@ -88,11 +91,13 @@ namespace LibCmo {
MKString& operator=(const char* cstr) { MKString& operator=(const char* cstr) {
m_HasStr = cstr != nullptr; m_HasStr = cstr != nullptr;
m_Str = m_HasStr ? cstr : ""; m_Str = m_HasStr ? cstr : "";
return *this;
} }
MKString(const std::string& cstr) : m_HasStr(true), m_Str(cstr) {} MKString(const std::string& cstr) : m_HasStr(true), m_Str(cstr) {}
MKString& operator=(const std::string& cstr) { MKString& operator=(const std::string& cstr) {
m_HasStr = true; m_HasStr = true;
m_Str = cstr; m_Str = cstr;
return *this;
} }
MKString(const MKString& rhs) : m_HasStr(rhs.m_HasStr), m_Str(rhs.m_Str) {} MKString(const MKString& rhs) : m_HasStr(rhs.m_HasStr), m_Str(rhs.m_Str) {}
@ -102,11 +107,13 @@ namespace LibCmo {
MKString& operator=(const MKString& rhs) { MKString& operator=(const MKString& rhs) {
m_HasStr = rhs.m_HasStr; m_HasStr = rhs.m_HasStr;
m_Str = rhs.m_Str; m_Str = rhs.m_Str;
return *this;
} }
MKString& operator=(MKString&& rhs) noexcept { MKString& operator=(MKString&& rhs) noexcept {
m_HasStr = rhs.m_HasStr; m_HasStr = rhs.m_HasStr;
m_Str = std::move(rhs.m_Str); m_Str = std::move(rhs.m_Str);
rhs.m_HasStr = false; rhs.m_HasStr = false;
return *this;
} }
const char* c_str() const { const char* c_str() const {
@ -135,12 +142,12 @@ namespace LibCmo {
} }
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0> template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Rm(TEnum& e1, TEnum e2) { inline void Rm(TEnum& e1, TEnum e2) {
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(Inv(e2))); e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(Inv(e2)));
} }
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0> template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Add(TEnum& e1, TEnum e2) { inline void Add(TEnum& e1, TEnum e2) {
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) | static_cast<std::underlying_type_t<TEnum>>(e2)); e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) | static_cast<std::underlying_type_t<TEnum>>(e2));
} }

View File

@ -1,5 +1,5 @@
#include "VxMemoryMappedFile.hpp" #include "VxMemoryMappedFile.hpp"
#include "VTEncoding.hpp" #include "../VTEncoding.hpp"
namespace LibCmo::VxMath { namespace LibCmo::VxMath {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "VTUtils.hpp" #include "../VTAll.hpp"
#if defined(LIBCMO_OS_WIN32) #if defined(LIBCMO_OS_WIN32)
#include <Windows.h> #include <Windows.h>
#else #else
@ -40,9 +40,9 @@ namespace LibCmo::VxMath {
VxMemoryMappedFile& operator=(const VxMemoryMappedFile&) = delete; VxMemoryMappedFile& operator=(const VxMemoryMappedFile&) = delete;
~VxMemoryMappedFile(void); ~VxMemoryMappedFile(void);
inline void* GetBase(void) { return this->m_pMemoryMappedFileBase; } void* GetBase(void) { return this->m_pMemoryMappedFileBase; }
inline size_t GetFileSize(void) { return this->m_cbFile; } size_t GetFileSize(void) { return this->m_cbFile; }
inline bool IsValid(void) { return this->m_bIsValid; } bool IsValid(void) { return this->m_bIsValid; }
}; };
} }

View File

@ -42,7 +42,7 @@ namespace LibCmo::VxMath {
Vx2DVector() : x(0.0f), y(0.0f) {} Vx2DVector() : x(0.0f), y(0.0f) {}
Vx2DVector(float f) : x(f), y(f) {} Vx2DVector(float f) : x(f), y(f) {}
Vx2DVector(float _x, float _y, float _z) : x(_x), y(_y) {} Vx2DVector(float _x, float _y) : x(_x), y(_y) {}
Vx2DVector(CK2::CKINT iX, CK2::CKINT iY) : x((float)iX), y((float)iY) {} Vx2DVector(CK2::CKINT iX, CK2::CKINT iY) : x((float)iX), y((float)iY) {}
Vx2DVector(const float f[2]) : x(f[0]), y(f[1]) {} Vx2DVector(const float f[2]) : x(f[0]), y(f[1]) {}
}; };