finish half writing function
This commit is contained in:
		| @ -99,7 +99,7 @@ namespace LibCmo::CK2 { | |||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	MgrImpls::CKBaseManager* CKContext::GetManager(int index) { | 	MgrImpls::CKBaseManager* CKContext::GetManager(CKINT index) { | ||||||
| 		return nullptr; | 		return nullptr; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -188,12 +188,18 @@ namespace LibCmo::CK2 { | |||||||
| 		EncodingHelper::SetStdPathFromU8Path(this->m_TempFolder, u8_temp); | 		EncodingHelper::SetStdPathFromU8Path(this->m_TempFolder, u8_temp); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	FILE* CKContext::OpenTempFile(CKSTRING u8_filename, CKBOOL is_read) { | 	FILE* CKContext::OpenTempFile(CKSTRING u8_filename, CKSTRING u8_mode) { | ||||||
| 		std::filesystem::path stdfilename; | 		std::filesystem::path stdfilename; | ||||||
| 		EncodingHelper::SetStdPathFromU8Path(stdfilename, u8_filename); | 		EncodingHelper::SetStdPathFromU8Path(stdfilename, u8_filename); | ||||||
|  |  | ||||||
| 		auto realfile = this->m_TempFolder / stdfilename; | 		auto realfile = this->m_TempFolder / stdfilename; | ||||||
| 		return EncodingHelper::OpenStdPathFile(realfile, is_read); | 		return EncodingHelper::StdPathFOpen(realfile, u8_mode); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	FILE* CKContext::OpenFile(CKSTRING u8_filename, CKSTRING u8_mode) { | ||||||
|  | 		std::filesystem::path stdfilename; | ||||||
|  | 		EncodingHelper::SetStdPathFromU8Path(stdfilename, u8_filename); | ||||||
|  | 		return EncodingHelper::StdPathFOpen(stdfilename, u8_mode); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #pragma endregion | #pragma endregion | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ namespace LibCmo::CK2 { | |||||||
| 		// ========== Common Managers Functions ========== | 		// ========== Common Managers Functions ========== | ||||||
|  |  | ||||||
| 		CKINT GetManagerCount(); | 		CKINT GetManagerCount(); | ||||||
| 		MgrImpls::CKBaseManager* GetManager(int index); | 		MgrImpls::CKBaseManager* GetManager(CKINT index); | ||||||
|  |  | ||||||
| 		// ========== File Save/Load Options ========== | 		// ========== File Save/Load Options ========== | ||||||
| 		 | 		 | ||||||
| @ -79,7 +79,8 @@ namespace LibCmo::CK2 { | |||||||
| 		// ========== Temp IO utilities ========== | 		// ========== Temp IO utilities ========== | ||||||
|  |  | ||||||
| 		void SetTempPath(CKSTRING u8_temp); | 		void SetTempPath(CKSTRING u8_temp); | ||||||
| 		FILE* OpenTempFile(CKSTRING u8_filename, CKBOOL is_read); | 		FILE* OpenTempFile(CKSTRING u8_filename, CKSTRING u8_mode); | ||||||
|  | 		FILE* OpenFile(CKSTRING u8_filename, CKSTRING u8_mode); | ||||||
|  |  | ||||||
| 		// ========== Print utilities ========== | 		// ========== Print utilities ========== | ||||||
|  |  | ||||||
|  | |||||||
| @ -9,14 +9,19 @@ | |||||||
| #include <functional> | #include <functional> | ||||||
|  |  | ||||||
| namespace LibCmo::CK2 { | namespace LibCmo::CK2 { | ||||||
|  | 	/** | ||||||
|  | 	 * @brief The identifier of Virtools file. | ||||||
|  | 	*/ | ||||||
|  | 	constexpr const char CKNEMOFI[] = "Nemo Fi"; | ||||||
| 	/** | 	/** | ||||||
| 	 * @brief Current Version of CK Engine (Day/Month/Year) | 	 * @brief Current Version of CK Engine (Day/Month/Year) | ||||||
| 	*/ | 	*/ | ||||||
| 	constexpr const CKDWORD CKVERSION = 0x05082002u; | 	constexpr const CKDWORD CKVERSION = 0x13022002u; | ||||||
| 	/** | 	/** | ||||||
| 	 * @brief Current Version of Dev | 	 * @brief Current Version of Dev | ||||||
| 	*/ | 	*/ | ||||||
| 	constexpr const CKDWORD DEVVERSION = 0x02050000u; | 	constexpr const CKDWORD DEVVERSION = 0x02010001u; | ||||||
|  | 	constexpr const CKDWORD DEVBUILD = 0u; | ||||||
| 	constexpr const CKGUID VIRTOOLS_GUID = CKGUID(0x56495254u, 0x4f4f4c53u); | 	constexpr const CKGUID VIRTOOLS_GUID = CKGUID(0x56495254u, 0x4f4f4c53u); | ||||||
|  |  | ||||||
| 	// ========== Class registration utilities ========== | 	// ========== Class registration utilities ========== | ||||||
|  | |||||||
| @ -121,6 +121,7 @@ namespace LibCmo::CK2 { | |||||||
| 		ObjImpls::CKObject* ObjPtr; /**< A pointer to the object itself (as CreatedObject when loading) */ | 		ObjImpls::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 */ | ||||||
|  | 		CKDWORD PackSize;  /**< The CKStateChunk data size */ | ||||||
| 		//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 */ | ||||||
| @ -233,11 +234,14 @@ namespace LibCmo::CK2 { | |||||||
| 		*/ | 		*/ | ||||||
| 		CKBOOL m_IsCopyFromReader; | 		CKBOOL m_IsCopyFromReader; | ||||||
| 		 | 		 | ||||||
|  | 		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<CKFileObject> m_FileObjects; /**< List of objects being saved / loaded */ | ||||||
| 		XContainer::XArray<CKFileManagerData> m_ManagersData; /**< Manager Data loaded */ | 		XContainer::XArray<CKFileManagerData> m_ManagersData; /**< Manager Data loaded */ | ||||||
| 		XContainer::XArray<CKFilePluginDependencies> m_PluginsDep;	/**< Plugins dependencies for this file */ | 		XContainer::XArray<CKFilePluginDependencies> m_PluginsDep;	/**< Plugins dependencies for this file */ | ||||||
| 		XContainer::XArray<XContainer::XString> m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */ | 		XContainer::XArray<XContainer::XString> m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */ | ||||||
| 		CKFileInfo m_FileInfo; /**< Headers summary */ | 		//CKFileInfo m_FileInfo; /**< Headers summary */ | ||||||
|  |  | ||||||
|  | 		CKERROR PrepareFile(CKSTRING filename); | ||||||
|  |  | ||||||
| 		CKContext* m_Ctx; | 		CKContext* m_Ctx; | ||||||
| 		CKFileVisitor m_Visitor; | 		CKFileVisitor m_Visitor; | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "CKFile.hpp" | #include "CKFile.hpp" | ||||||
| #include "CKStateChunk.hpp" | #include "CKStateChunk.hpp" | ||||||
|  | #include "ObjImpls/CKObject.hpp" | ||||||
| #include <cstdarg> | #include <cstdarg> | ||||||
|  |  | ||||||
| namespace LibCmo::CK2 { | namespace LibCmo::CK2 { | ||||||
| @ -13,12 +14,12 @@ namespace LibCmo::CK2 { | |||||||
| 	CKFileObject::CKFileObject() : | 	CKFileObject::CKFileObject() : | ||||||
| 		ObjectId(0u), CreatedObjectId(0u), ObjectCid(CK_CLASSID::CKCID_OBJECT), | 		ObjectId(0u), CreatedObjectId(0u), ObjectCid(CK_CLASSID::CKCID_OBJECT), | ||||||
| 		ObjPtr(nullptr), Name(), Data(nullptr), Options(CK_FO_OPTIONS::CK_FO_DEFAULT), | 		ObjPtr(nullptr), Name(), Data(nullptr), Options(CK_FO_OPTIONS::CK_FO_DEFAULT), | ||||||
| 		FileIndex(0u), SaveFlags(CK_STATESAVE_ALL) {} | 		FileIndex(0u), SaveFlags(CK_STATESAVE_ALL), PackSize(0u) {} | ||||||
|  |  | ||||||
| 	CKFileObject::CKFileObject(const CKFileObject& rhs) : | 	CKFileObject::CKFileObject(const CKFileObject& rhs) : | ||||||
| 		ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid), | 		ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid), | ||||||
| 		ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options), | 		ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options), | ||||||
| 		FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags) { | 		FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags), PackSize(rhs.PackSize) { | ||||||
| 		if (this->Data != nullptr) { | 		if (this->Data != nullptr) { | ||||||
| 			this->Data = new CKStateChunk(*(rhs.Data)); | 			this->Data = new CKStateChunk(*(rhs.Data)); | ||||||
| 		} | 		} | ||||||
| @ -27,7 +28,7 @@ namespace LibCmo::CK2 { | |||||||
| 	CKFileObject::CKFileObject(CKFileObject&& rhs) : | 	CKFileObject::CKFileObject(CKFileObject&& rhs) : | ||||||
| 		ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid), | 		ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid), | ||||||
| 		ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options), | 		ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options), | ||||||
| 		FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags) { | 		FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags), PackSize(rhs.PackSize) { | ||||||
| 		rhs.Data = nullptr; | 		rhs.Data = nullptr; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -43,6 +44,7 @@ namespace LibCmo::CK2 { | |||||||
| 			this->Data = new CKStateChunk(*(rhs.Data)); | 			this->Data = new CKStateChunk(*(rhs.Data)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		this->PackSize = rhs.PackSize; | ||||||
| 		this->Options = rhs.Options; | 		this->Options = rhs.Options; | ||||||
| 		this->FileIndex = rhs.FileIndex; | 		this->FileIndex = rhs.FileIndex; | ||||||
| 		this->SaveFlags = rhs.SaveFlags; | 		this->SaveFlags = rhs.SaveFlags; | ||||||
| @ -59,7 +61,8 @@ namespace LibCmo::CK2 { | |||||||
|  |  | ||||||
| 		this->Data = rhs.Data; | 		this->Data = rhs.Data; | ||||||
| 		rhs.Data = nullptr; | 		rhs.Data = nullptr; | ||||||
|  | 		 | ||||||
|  | 		this->PackSize = rhs.PackSize; | ||||||
| 		this->Options = rhs.Options; | 		this->Options = rhs.Options; | ||||||
| 		this->FileIndex = rhs.FileIndex; | 		this->FileIndex = rhs.FileIndex; | ||||||
| 		this->SaveFlags = rhs.SaveFlags; | 		this->SaveFlags = rhs.SaveFlags; | ||||||
| @ -160,16 +163,19 @@ namespace LibCmo::CK2 { | |||||||
| 	CKFileWriter::CKFileWriter(CKContext* ctx) : | 	CKFileWriter::CKFileWriter(CKContext* ctx) : | ||||||
| 		m_Ctx(ctx), m_Visitor(this), | 		m_Ctx(ctx), m_Visitor(this), | ||||||
| 		m_Done(false), m_IsCopyFromReader(false), | 		m_Done(false), m_IsCopyFromReader(false), | ||||||
| 		m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(), | 		m_SaveIDMax(0), | ||||||
| 		m_FileInfo() | 		m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles() | ||||||
| 	{} | 	{} | ||||||
|  |  | ||||||
| 	CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader) : | 	CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader) : | ||||||
| 		m_Ctx(ctx), m_Visitor(this), | 		m_Ctx(ctx), m_Visitor(this), | ||||||
| 		m_Done(false), m_IsCopyFromReader(true), | 		m_Done(false), m_IsCopyFromReader(true), | ||||||
| 		m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(), | 		m_SaveIDMax(0), | ||||||
| 		m_FileInfo() | 		m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles() | ||||||
| 	{ | 	{ | ||||||
|  | 		// sync save id max | ||||||
|  | 		this->m_SaveIDMax = reader->GetSaveIdMax(); | ||||||
|  |  | ||||||
| 		// copy objects | 		// copy objects | ||||||
| 		for (const auto& item : reader->GetFileObjects()) { | 		for (const auto& item : reader->GetFileObjects()) { | ||||||
| 			CKFileObject obj; | 			CKFileObject obj; | ||||||
| @ -182,8 +188,11 @@ namespace LibCmo::CK2 { | |||||||
| 				obj.Data = new CKStateChunk(*item.Data); | 				obj.Data = new CKStateChunk(*item.Data); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// copy save flag | 			// copy other data | ||||||
|  | 			obj.ObjectId = item.ObjectId; | ||||||
|  | 			obj.ObjectCid = item.ObjectCid; | ||||||
| 			obj.SaveFlags = item.SaveFlags; | 			obj.SaveFlags = item.SaveFlags; | ||||||
|  | 			obj.Name = item.Name; | ||||||
|  |  | ||||||
| 			// insert | 			// insert | ||||||
| 			m_FileObjects.emplace_back(std::move(obj)); | 			m_FileObjects.emplace_back(std::move(obj)); | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ namespace LibCmo::CK2 { | |||||||
|  |  | ||||||
| 	CKERROR CKFileReader::ShallowLoad(CKSTRING u8_filename) { | 	CKERROR CKFileReader::ShallowLoad(CKSTRING u8_filename) { | ||||||
| 		// check document status | 		// check document status | ||||||
| 		if (this->m_Done) LIBPANIC("Can not load multiple times for single CKFileReader.") | 		if (this->m_Done) CKERROR::CKERR_CANCELLED; | ||||||
|  |  | ||||||
| 		// 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; | ||||||
| @ -46,7 +46,7 @@ namespace LibCmo::CK2 { | |||||||
| 		// ========== read header ========== | 		// ========== read header ========== | ||||||
| 		// check header size | 		// check header size | ||||||
| 		if (parser->GetSize() < sizeof(CKRawFileInfo)) return CKERROR::CKERR_INVALIDFILE; | 		if (parser->GetSize() < sizeof(CKRawFileInfo)) return CKERROR::CKERR_INVALIDFILE; | ||||||
| 		if (std::memcmp(parser->GetPtr(), "Nemo Fi", sizeof(CKRawFileInfo::NeMo))) return CKERROR::CKERR_INVALIDFILE; | 		if (std::memcmp(parser->GetPtr(), CKNEMOFI, sizeof(CKRawFileInfo::NeMo))) return CKERROR::CKERR_INVALIDFILE; | ||||||
| 		// read header | 		// read header | ||||||
| 		CKRawFileInfo rawHeader; | 		CKRawFileInfo rawHeader; | ||||||
| 		parser->Read(&rawHeader, sizeof(CKRawFileInfo)); | 		parser->Read(&rawHeader, sizeof(CKRawFileInfo)); | ||||||
| @ -168,7 +168,7 @@ namespace LibCmo::CK2 { | |||||||
| 				parser->Read(&includedFileCount, sizeof(CKDWORD)); | 				parser->Read(&includedFileCount, sizeof(CKDWORD)); | ||||||
| 				this->m_IncludedFiles.resize(includedFileCount); | 				this->m_IncludedFiles.resize(includedFileCount); | ||||||
|  |  | ||||||
| 				hasIncludedFile -= 4; | 				hasIncludedFile -= sizeof(CKDWORD); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// MARK: backward pos | 			// MARK: backward pos | ||||||
| @ -263,13 +263,12 @@ namespace LibCmo::CK2 { | |||||||
| 		// only works file version >= 4. < 4 section has been removed. | 		// only works file version >= 4. < 4 section has been removed. | ||||||
| 		if (this->m_FileInfo.ObjectCount != 0) { | 		if (this->m_FileInfo.ObjectCount != 0) { | ||||||
| 			// new file reader section | 			// new file reader section | ||||||
| 			CKDWORD stateChunkLen = 0u; |  | ||||||
| 			bool stateChkParseSuccess = false; | 			bool stateChkParseSuccess = false; | ||||||
| 			for (auto& obj : this->m_FileObjects) { | 			for (auto& obj : this->m_FileObjects) { | ||||||
| 				// get statechunk len | 				// get statechunk len | ||||||
| 				parser->Read(&stateChunkLen, sizeof(CKDWORD)); | 				parser->Read(&obj.PackSize, sizeof(CKDWORD)); | ||||||
| 				// check state chunk len | 				// check state chunk len | ||||||
| 				if (stateChunkLen == 0) { | 				if (obj.PackSize == 0) { | ||||||
| 					obj.Data = nullptr; | 					obj.Data = nullptr; | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| @ -281,7 +280,7 @@ namespace LibCmo::CK2 { | |||||||
| 					delete obj.Data; | 					delete obj.Data; | ||||||
| 					obj.Data = nullptr; | 					obj.Data = nullptr; | ||||||
| 				} | 				} | ||||||
| 				parser->MoveCursor(stateChunkLen); | 				parser->MoveCursor(obj.PackSize); | ||||||
|  |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -311,7 +310,7 @@ namespace LibCmo::CK2 { | |||||||
| 				parser->Read(&filebodylen, sizeof(CKDWORD)); | 				parser->Read(&filebodylen, sizeof(CKDWORD)); | ||||||
|  |  | ||||||
| 				// read file body | 				// read file body | ||||||
| 				FILE* fp = m_Ctx->OpenTempFile(file.c_str(), false); | 				FILE* fp = m_Ctx->OpenTempFile(file.c_str(), "wb"); | ||||||
| 				if (fp != nullptr) { | 				if (fp != nullptr) { | ||||||
| 					StreamHelper::CopyStream(parser->GetPtr(), fp, filebodylen); | 					StreamHelper::CopyStream(parser->GetPtr(), fp, filebodylen); | ||||||
| 					fclose(fp); | 					fclose(fp); | ||||||
| @ -326,6 +325,9 @@ namespace LibCmo::CK2 { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	CKERROR CKFileReader::DeepLoad(CKSTRING u8_filename) { | 	CKERROR CKFileReader::DeepLoad(CKSTRING u8_filename) { | ||||||
|  | 		// check document status | ||||||
|  | 		if (this->m_Done) CKERROR::CKERR_CANCELLED; | ||||||
|  |  | ||||||
| 		// ========== prepare work ========== | 		// ========== prepare work ========== | ||||||
| 		CKERROR err = CKERROR::CKERR_OK; | 		CKERROR err = CKERROR::CKERR_OK; | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,9 +1,212 @@ | |||||||
| #include "CKFile.hpp" | #include "CKFile.hpp" | ||||||
|  | #include "CKContext.hpp" | ||||||
|  | #include "CKStateChunk.hpp" | ||||||
|  | #include "ObjImpls/CKObject.hpp" | ||||||
|  | #include "MgrImpls/CKBaseManager.hpp" | ||||||
|  | #include "../VxMath/VxMemoryMappedFile.hpp" | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
| namespace LibCmo::CK2 { | namespace LibCmo::CK2 { | ||||||
|  |  | ||||||
| 	CKERROR CKFileWriter::Save(CKSTRING u8_filename) { | 	CKERROR CKFileWriter::Save(CKSTRING u8_filename) { | ||||||
| 		return CKERROR::CKERR_OK; | 		// check document status | ||||||
|  | 		if (this->m_Done) CKERROR::CKERR_CANCELLED; | ||||||
|  |  | ||||||
|  | 		// try detect filename legality | ||||||
|  | 		CKERROR err = PrepareFile(u8_filename); | ||||||
|  | 		if (err != CKERROR::CKERR_OK) return err; | ||||||
|  | 		 | ||||||
|  | 		// ========== Prepare Stage ========== | ||||||
|  | 		// todo: add TOBEDELETED flag for all Referenced objects's m_ObjectFlags | ||||||
|  |  | ||||||
|  | 		// MARK: ignore the notification to all CKBehavior based objects. | ||||||
|  |  | ||||||
|  | 		// ========== StateChunk convertion ========== | ||||||
|  | 		 | ||||||
|  | 		// iterate all objects and transform it into CKStateChunk | ||||||
|  | 		// MARK: Drop the support of collecting the sum of InterfaceChunk's size. | ||||||
|  | 		// because it is useless. | ||||||
|  | 		for (auto& obj : m_FileObjects) { | ||||||
|  | 			// if there is a chunk, skip | ||||||
|  | 			if (obj.Data != nullptr) continue; | ||||||
|  |  | ||||||
|  | 			obj.Data = new CKStateChunk(&m_Visitor, m_Ctx); | ||||||
|  | 			obj.Data->StartWrite(); | ||||||
|  | 			bool suc = obj.ObjPtr->Save(obj.Data, &m_Visitor, obj.SaveFlags); | ||||||
|  | 			obj.Data->StopWrite(); | ||||||
|  | 			if (!suc) { | ||||||
|  | 				// fail to parse | ||||||
|  | 				delete obj.Data; | ||||||
|  | 				obj.Data = nullptr; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// iterate manager | ||||||
|  | 		// if copied from reader. skip | ||||||
|  | 		if (!m_IsCopyFromReader) { | ||||||
|  | 			CKINT mgrcount = m_Ctx->GetManagerCount(); | ||||||
|  | 			CKINT availablemgr = 0; | ||||||
|  |  | ||||||
|  | 			// place manager | ||||||
|  | 			// if no data, skip it | ||||||
|  | 			m_ManagersData.resize(mgrcount); | ||||||
|  | 			for (CKINT i = 0; i < mgrcount; ++i) { | ||||||
|  | 				MgrImpls::CKBaseManager* mgr = m_Ctx->GetManager(i); | ||||||
|  |  | ||||||
|  | 				m_ManagersData[availablemgr].Manager = mgr->GetGuid(); | ||||||
|  |  | ||||||
|  | 				m_ManagersData[availablemgr].Data = new CKStateChunk(&m_Visitor, m_Ctx); | ||||||
|  | 				m_ManagersData[availablemgr].Data->StartWrite(); | ||||||
|  | 				bool suc = mgr->SaveData(m_ManagersData[availablemgr].Data, &m_Visitor); | ||||||
|  | 				m_ManagersData[availablemgr].Data->StopWrite(); | ||||||
|  | 				if (!suc) { | ||||||
|  | 					delete m_ManagersData[availablemgr].Data; | ||||||
|  | 					m_ManagersData[availablemgr].Data = nullptr; | ||||||
|  | 				} else { | ||||||
|  | 					++availablemgr; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			// resize to the new size which erase all skipped manager | ||||||
|  | 			m_ManagersData.resize(availablemgr); | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// if copied from reader, skip plugin dep | ||||||
|  | 		if (!m_IsCopyFromReader) { | ||||||
|  | 			// todo: finish plugin dep filling | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// MARK: skip include file filling. | ||||||
|  | 		// we order user manually fill it. | ||||||
|  |  | ||||||
|  | 		// ========== Size Calc ========== | ||||||
|  | 		// iterate 3 list to get each parts' size | ||||||
|  | 		CKDWORD sumDataObjSize = 0, | ||||||
|  | 			sumHdrObjSize = 0; | ||||||
|  | 		for (auto& obj : m_FileObjects) { | ||||||
|  | 			// += 4DWORD(ObjId, ObjCid, FileIndex, NameLen) + Name size | ||||||
|  | 			sumHdrObjSize += 4 * sizeof(CKDWORD) + obj.Name.size(); | ||||||
|  |  | ||||||
|  | 			if (obj.Data == nullptr) { | ||||||
|  | 				obj.PackSize = 0; | ||||||
|  | 			} else { | ||||||
|  | 				obj.PackSize = obj.Data->ConvertToBuffer(nullptr); | ||||||
|  | 			} | ||||||
|  | 			// += chunk size + chunk | ||||||
|  | 			sumDataObjSize += obj.PackSize + sizeof(CKDWORD); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		CKDWORD sumDataMgrSize = 0; | ||||||
|  | 		for (auto& mgr : m_ManagersData) { | ||||||
|  | 			CKDWORD chunksize; | ||||||
|  | 			if (mgr.Data == nullptr) { | ||||||
|  | 				chunksize = 0; | ||||||
|  | 			} else { | ||||||
|  | 				chunksize = mgr.Data->ConvertToBuffer(nullptr); | ||||||
|  | 			} | ||||||
|  | 			// += GUID(2 DWORD) + chunk size + chunk | ||||||
|  | 			sumDataMgrSize += chunksize + 3 * sizeof(CKDWORD); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// += Plugin Dep list size | ||||||
|  | 		CKDWORD sumHdrPlgSize = sizeof(CKDWORD); | ||||||
|  | 		for (auto& plg : m_PluginsDep) { | ||||||
|  | 			// += GUID list + (dep category + GUID list size) | ||||||
|  | 			sumHdrPlgSize += sizeof(CKGUID) * plg.m_Guids.size() + 2 * sizeof(CKDWORD); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		CKDWORD sumHdrIncludedFiles = sizeof(int32_t) + sizeof(CKDWORD); | ||||||
|  |  | ||||||
|  | 		// calc the whole size | ||||||
|  | 		CKDWORD sumHdrSize = sumHdrObjSize + sumHdrPlgSize + sumHdrIncludedFiles; | ||||||
|  | 		CKDWORD sumDataSize = sumDataObjSize + sumDataMgrSize; | ||||||
|  |  | ||||||
|  | 		// compute file index for all object | ||||||
|  | 		if (!m_FileObjects.empty()) { | ||||||
|  | 			// set base for first one | ||||||
|  | 			m_FileObjects[0].FileIndex = sumHdrSize + sumDataMgrSize + sizeof(CKRawFileInfo); | ||||||
|  | 			// calc the remains | ||||||
|  | 			for (size_t i = 1; i < m_FileObjects.size(); ++i) { | ||||||
|  | 				// prev obj PackSize + prev obj FileIndex + prev obj chunk size | ||||||
|  | 				m_FileObjects[i].FileIndex = m_FileObjects[i - 1].FileIndex +  m_FileObjects[i - 1].PackSize + sizeof(CKDWORD); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// ========== Construct File Header ========== | ||||||
|  | 		CKRawFileInfo rawHeader; | ||||||
|  | 		std::memcpy(&rawHeader.NeMo, CKNEMOFI, sizeof(CKRawFileInfo::NeMo)); | ||||||
|  | 		rawHeader.Crc = 0; | ||||||
|  | 		rawHeader.Zero = 0; | ||||||
|  | 		rawHeader.CKVersion = CKVERSION; | ||||||
|  | 		rawHeader.FileVersion = 8; | ||||||
|  | 		rawHeader.FileWriteMode = static_cast<CKDWORD>(m_Ctx->GetFileWriteMode()); | ||||||
|  | 		rawHeader.ObjectCount = static_cast<CKDWORD>(m_FileObjects.size()); | ||||||
|  | 		rawHeader.ManagerCount = static_cast<CKDWORD>(m_ManagersData.size()); | ||||||
|  | 		rawHeader.Hdr1UnPackSize = sumHdrSize; | ||||||
|  | 		rawHeader.DataUnPackSize = sumDataSize; | ||||||
|  | 		rawHeader.Hdr1PackSize = sumHdrSize; | ||||||
|  | 		rawHeader.DataPackSize = sumDataSize; | ||||||
|  | 		rawHeader.ProductVersion = DEVVERSION; | ||||||
|  | 		rawHeader.ProductBuild = DEVBUILD; | ||||||
|  | 		rawHeader.MaxIDSaved = m_SaveIDMax; | ||||||
|  | 		// crc will filled later | ||||||
|  |  | ||||||
|  | 		// create a encoding conversion helper string | ||||||
|  | 		std::string name_conv; | ||||||
|  |  | ||||||
|  | 		// ========== Writing header ========== | ||||||
|  | 		// create a buffer | ||||||
|  | 		std::unique_ptr<CKBufferParser> hdrparser(new CKBufferParser(sumHdrSize)); | ||||||
|  |  | ||||||
|  | 		// write obj | ||||||
|  | 		for (auto& obj : m_FileObjects) { | ||||||
|  |  | ||||||
|  | 			// todo: remove TOBEDELETED for referenced objects' m_ObjectFlags | ||||||
|  |  | ||||||
|  | 			hdrparser->Write(&obj.ObjectId, sizeof(CK_ID)); | ||||||
|  | 			hdrparser->Write(&obj.ObjectCid, sizeof(CK_CLASSID)); | ||||||
|  | 			hdrparser->Write(&obj.FileIndex, sizeof(CKDWORD)); | ||||||
|  |  | ||||||
|  | 			if (obj.Name.c_str() != nullptr) { | ||||||
|  | 				m_Ctx->GetNativeString(obj.Name.string(), name_conv); | ||||||
|  | 				CKDWORD namelen = static_cast<CKDWORD>(name_conv.size()); | ||||||
|  | 				hdrparser->Write(&namelen, sizeof(CKDWORD)); | ||||||
|  | 				hdrparser->Write(name_conv.data(), namelen); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// write plugin dep | ||||||
|  | 		{ | ||||||
|  | 			CKDWORD depsize = static_cast<CKDWORD>(m_PluginsDep.size()); | ||||||
|  | 			hdrparser->Write(&depsize, sizeof(CKDWORD)); | ||||||
|  |  | ||||||
|  | 			for (auto& dep : m_PluginsDep) { | ||||||
|  | 				hdrparser->Write(&dep.m_PluginCategory, sizeof(CK_PLUGIN_TYPE)); | ||||||
|  |  | ||||||
|  | 				CKDWORD guidsize = static_cast<CKDWORD>(dep.m_Guids.size()); | ||||||
|  | 				hdrparser->Write(&guidsize, sizeof(CKDWORD)); | ||||||
|  |  | ||||||
|  | 				hdrparser->Write(dep.m_Guids.data(), sizeof(CKGUID) * guidsize); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	CKERROR CKFileWriter::PrepareFile(CKSTRING filename) { | ||||||
|  | 		// check nullptr | ||||||
|  | 		if (filename == nullptr) return CKERROR::CKERR_INVALIDFILE; | ||||||
|  | 		 | ||||||
|  | 		// try open file to check whether we can write it. | ||||||
|  | 		CKERROR err; | ||||||
|  | 		FILE* tryfile = m_Ctx->OpenFile(filename, "ab"); | ||||||
|  | 		if (tryfile == nullptr) { | ||||||
|  | 			err = CKERROR::CKERR_CANTWRITETOFILE; | ||||||
|  | 		} else { | ||||||
|  | 			err = CKERROR::CKERR_OK; | ||||||
|  | 			std::fclose(tryfile); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return err; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -46,10 +46,12 @@ namespace LibCmo::CK2 { | |||||||
| 	CKDWORD CKComputeDataCRC(const void* data, CKINT size, CKDWORD PreviousCRC = 0); | 	CKDWORD CKComputeDataCRC(const void* data, CKINT size, CKDWORD PreviousCRC = 0); | ||||||
|  |  | ||||||
| 	// ========== CKClass Registration ========== | 	// ========== CKClass Registration ========== | ||||||
|  |  | ||||||
| 	void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid, | 	void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid, | ||||||
| 		CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct); | 		CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct); | ||||||
|  |  | ||||||
| 	// ========== Class Hierarchy Management ========== | 	// ========== Class Hierarchy Management ========== | ||||||
|  |  | ||||||
| 	CKINT CKGetClassCount(); | 	CKINT CKGetClassCount(); | ||||||
| 	const CKClassDesc* CKGetClassDesc(CK_CLASSID cid); | 	const CKClassDesc* CKGetClassDesc(CK_CLASSID cid); | ||||||
| 	CKSTRING CKClassIDToString(CK_CLASSID cid); | 	CKSTRING CKClassIDToString(CK_CLASSID cid); | ||||||
|  | |||||||
| @ -69,8 +69,8 @@ namespace LibCmo::CK2::MgrImpls { | |||||||
| 			data for your manager. | 			data for your manager. | ||||||
| 		@see CKStateChunk, LoadData | 		@see CKStateChunk, LoadData | ||||||
| 		*/ | 		*/ | ||||||
| 		virtual CKStateChunk* SaveData(CKFileVisitor* SavedFile) { | 		virtual bool SaveData(CKStateChunk* chunk, CKFileVisitor* SavedFile) { | ||||||
| 			return nullptr; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		/** | 		/** | ||||||
| 		@brief Called to load manager data. | 		@brief Called to load manager data. | ||||||
|  | |||||||
| @ -6,8 +6,8 @@ namespace LibCmo::CK2::ObjImpls { | |||||||
|  |  | ||||||
| 	void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {} | 	void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {} | ||||||
|  |  | ||||||
| 	CKStateChunk* CKObject::Save(CKFileVisitor* file, CKDWORD flags) { | 	bool CKObject::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) { | ||||||
| 		return nullptr; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool CKObject::Load(CKStateChunk* chunk, CKFileVisitor* file) { | 	bool CKObject::Load(CKStateChunk* chunk, CKFileVisitor* file) { | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ namespace LibCmo::CK2::ObjImpls { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		virtual void PreSave(CKFileVisitor* file, CKDWORD flags); | 		virtual void PreSave(CKFileVisitor* file, CKDWORD flags); | ||||||
| 		virtual CKStateChunk* Save(CKFileVisitor* file, CKDWORD flags); | 		virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags); | ||||||
| 		virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file); | 		virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file); | ||||||
| 		virtual void PostLoad(); | 		virtual void PostLoad(); | ||||||
|  |  | ||||||
|  | |||||||
| @ -187,9 +187,15 @@ namespace LibCmo::EncodingHelper { | |||||||
| 			stdpath = u8_path; | 			stdpath = u8_path; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	 | ||||||
| 	FILE* OpenStdPathFile(std::filesystem::path& u8_filepath, bool is_read) { | 	FILE* StdPathFOpen(std::filesystem::path& std_filepath, const char* u8_mode) { | ||||||
| 		return _wfopen(u8_filepath.wstring().c_str(), is_read ? L"rb" : L"wb"); | 		std::wstring wmode; | ||||||
|  | 		if (CharToWchar(u8_mode, wmode, CP_UTF8)) { | ||||||
|  | 			return _wfopen(std_filepath.wstring().c_str(), wmode.c_str()); | ||||||
|  | 		} else { | ||||||
|  | 			// fallback | ||||||
|  | 			return std::fopen(std_filepath.string().c_str(), u8_mode); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #else | #else | ||||||
| @ -237,8 +243,8 @@ namespace LibCmo::EncodingHelper { | |||||||
| 		stdpath = u8_path; | 		stdpath = u8_path; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	FILE* OpenStdPathFile(std::filesystem::path& u8_filepath, bool is_read) { | 	FILE* StdPathFOpen(std::filesystem::path& std_filepath, const char* u8_mode) { | ||||||
| 		return fopen(u8_filepath.string().c_str(), is_read ? "rb" : "wb"); | 		return std::fopen(u8_filepath.string().c_str(), u8_mode); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ namespace LibCmo::EncodingHelper { | |||||||
| 	bool GetNativeVirtoolsName(const std::string& u8_name, std::string& native_name, const ENCODING_TOKEN& token); | 	bool GetNativeVirtoolsName(const std::string& u8_name, std::string& native_name, const ENCODING_TOKEN& token); | ||||||
|  |  | ||||||
| 	void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path); | 	void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path); | ||||||
| 	FILE* OpenStdPathFile(std::filesystem::path& u8_filepath, bool is_read); | 	FILE* StdPathFOpen(std::filesystem::path& std_filepath, const char* u8_mode); | ||||||
|  |  | ||||||
| #pragma endregion | #pragma endregion | ||||||
|  |  | ||||||
|  | |||||||
| @ -119,7 +119,9 @@ namespace LibCmo { | |||||||
| 			const char* c_str() const { | 			const char* c_str() const { | ||||||
| 				return m_HasStr ? m_Str.c_str() : nullptr; | 				return m_HasStr ? m_Str.c_str() : nullptr; | ||||||
| 			} | 			} | ||||||
|  | 			const std::string& string() const { | ||||||
|  | 				return m_Str; | ||||||
|  | 			} | ||||||
| 			const size_t size() const { | 			const size_t size() const { | ||||||
| 				return m_HasStr ? m_Str.size() : 0u; | 				return m_HasStr ? m_Str.size() : 0u; | ||||||
| 			} | 			} | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user