| 
									
										
										
										
											2023-08-22 15:30:26 +08:00
										 |  |  | #include "CKContext.hpp"
 | 
					
						
							| 
									
										
										
										
											2023-08-26 16:37:26 +08:00
										 |  |  | #include "ObjImpls/CKObject.hpp"
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | #include "MgrImpls/CKBaseManager.hpp"
 | 
					
						
							|  |  |  | #include "MgrImpls/CKObjectManager.hpp"
 | 
					
						
							|  |  |  | #include "MgrImpls/CKPathManager.hpp"
 | 
					
						
							| 
									
										
										
										
											2023-03-04 14:08:16 +08:00
										 |  |  | #include <cstdarg>
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 21:48:03 +08:00
										 |  |  | namespace LibCmo::CK2 { | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 12:19:06 +08:00
										 |  |  | #pragma region Ctor Dtor
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CKContext::CKContext() : | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// setup manager
 | 
					
						
							|  |  |  | 		m_ManagerList(), | 
					
						
							|  |  |  | 		m_ObjectManager(nullptr), m_PathManager(nullptr), | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		// setup object cache
 | 
					
						
							|  |  |  | 		m_ObjectCache(), m_ObjectPointerCache(), | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// setup file save/load options
 | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		m_CompressionLevel(5), | 
					
						
							|  |  |  | 		m_FileWriteMode(CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED), | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		m_GlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_RAWDATA), | 
					
						
							|  |  |  | 		m_GlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS::CKSOUND_EXTERNAL), | 
					
						
							| 
									
										
										
										
											2023-09-07 21:57:48 +08:00
										 |  |  | 		m_GlobalImagesSaveFormat(), | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// misc init
 | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		m_NameEncoding(), | 
					
						
							|  |  |  | 		m_OutputCallback(nullptr) { | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 21:57:48 +08:00
										 |  |  | 		// setup save format
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		m_GlobalImagesSaveFormat.m_Ext.SetExt(u8"bmp"); | 
					
						
							| 
									
										
										
										
											2023-09-07 21:57:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// setup managers
 | 
					
						
							|  |  |  | 		m_ObjectManager = new MgrImpls::CKObjectManager(this); | 
					
						
							|  |  |  | 		m_ManagerList.emplace_back(m_ObjectManager); | 
					
						
							|  |  |  | 		m_PathManager = new MgrImpls::CKPathManager(this); | 
					
						
							|  |  |  | 		m_ManagerList.emplace_back(m_PathManager); | 
					
						
							| 
									
										
										
										
											2023-09-01 12:19:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CKContext::~CKContext() { | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// reset context
 | 
					
						
							| 
									
										
										
										
											2023-09-04 22:58:53 +08:00
										 |  |  | 		ClearAll(); | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// free all manager
 | 
					
						
							|  |  |  | 		for (auto& mgrptr : m_ManagerList) { | 
					
						
							|  |  |  | 			delete mgrptr; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		// free encoding
 | 
					
						
							|  |  |  | 		this->ClearEncoding(); | 
					
						
							| 
									
										
										
										
											2023-09-01 12:19:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | #pragma region Engine runtime
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 22:58:53 +08:00
										 |  |  | 	void CKContext::ClearAll() { | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		// pre clear all
 | 
					
						
							|  |  |  | 		ExecuteManagersOnPreClearAll(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// order object manager clear all objects
 | 
					
						
							|  |  |  | 		m_ObjectManager->DestroyAllObjects(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// post clear all
 | 
					
						
							|  |  |  | 		ExecuteManagersOnPostClearAll(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma region Objects Management / Access
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ObjImpls::CKObject* CKContext::CreateObject(CK_CLASSID cls, CKSTRING name, CK_OBJECTCREATION_OPTIONS options, CK_CREATIONMODE* res) { | 
					
						
							|  |  |  | 		return m_ObjectManager->CreateObject(cls, name, options, res); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ObjImpls::CKObject* CKContext::GetObject(CK_ID ObjID) { | 
					
						
							|  |  |  | 		return m_ObjectManager->GetObject(ObjID); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CKDWORD CKContext::GetObjectCount() { | 
					
						
							|  |  |  | 		return m_ObjectManager->GetObjectCount(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::DestroyObject(ObjImpls::CKObject* obj) { | 
					
						
							|  |  |  | 		CK_ID id = obj->GetID(); | 
					
						
							|  |  |  | 		return m_ObjectManager->DestroyObjects(&id, 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::DestroyObject(CK_ID id) { | 
					
						
							|  |  |  | 		return m_ObjectManager->DestroyObjects(&id, 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::DestroyObjects(CK_ID* obj_ids, CKDWORD Count) { | 
					
						
							|  |  |  | 		return m_ObjectManager->DestroyObjects(obj_ids, Count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 	ObjImpls::CKObject* GeneralPrevFinder(XContainer::XObjectPointerArray& objptrs, ObjImpls::CKObject* previous) { | 
					
						
							| 
									
										
										
										
											2023-09-07 16:27:41 +08:00
										 |  |  | 		if (objptrs.empty()) return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (previous == nullptr) { | 
					
						
							|  |  |  | 			return objptrs.front(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			auto finder = std::find(objptrs.begin(), objptrs.end(), previous); | 
					
						
							|  |  |  | 			if (finder == objptrs.end()) return nullptr; | 
					
						
							|  |  |  | 			++finder; | 
					
						
							|  |  |  | 			if (finder == objptrs.end()) return nullptr; | 
					
						
							|  |  |  | 			return *finder; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 	ObjImpls::CKObject* CKContext::GetObjectByName(CKSTRING name, ObjImpls::CKObject* previous) { | 
					
						
							|  |  |  | 		if (name == nullptr) return nullptr; | 
					
						
							|  |  |  | 		if (previous == nullptr) { | 
					
						
							|  |  |  | 			m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, CK_CLASSID::CKCID_OBJECT, true); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return GeneralPrevFinder(m_ObjectPointerCache, previous); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ObjImpls::CKObject* CKContext::GetObjectByNameAndClass(CKSTRING name, CK_CLASSID cid, ObjImpls::CKObject* previous) { | 
					
						
							|  |  |  | 		if (name == nullptr) return nullptr; | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		if (previous == nullptr) { | 
					
						
							|  |  |  | 			m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, cid, false); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return GeneralPrevFinder(m_ObjectPointerCache, previous); | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ObjImpls::CKObject* CKContext::GetObjectByNameAndParentClass(CKSTRING name, CK_CLASSID pcid, ObjImpls::CKObject* previous) { | 
					
						
							|  |  |  | 		if (name == nullptr) return nullptr; | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		if (previous == nullptr) { | 
					
						
							|  |  |  | 			m_ObjectPointerCache = m_ObjectManager->GetObjectByNameAndClass(name, pcid, true); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return GeneralPrevFinder(m_ObjectPointerCache, previous); | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const XContainer::XObjectPointerArray CKContext::GetObjectListByType(CK_CLASSID cid, bool derived) { | 
					
						
							|  |  |  | 		return m_ObjectManager->GetObjectByNameAndClass(nullptr, cid, derived); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	CKDWORD CKContext::GetObjectsCountByClassID(CK_CLASSID cid) { | 
					
						
							|  |  |  | 		auto result = m_ObjectManager->GetObjectByNameAndClass(nullptr, cid, false); | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		m_ObjectCache.clear(); | 
					
						
							|  |  |  | 		for (auto& obj : result) { | 
					
						
							|  |  |  | 			m_ObjectCache.emplace_back(obj->GetID()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return static_cast<CKDWORD>(m_ObjectCache.size()); | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CK_ID* CKContext::GetObjectsListByClassID(CK_CLASSID cid) { | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 		return m_ObjectCache.data(); | 
					
						
							| 
									
										
										
										
											2023-08-27 22:14:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | #pragma region Common Managers
 | 
					
						
							| 
									
										
										
										
											2023-09-06 10:42:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	MgrImpls::CKObjectManager* CKContext::GetObjectManager() { | 
					
						
							|  |  |  | 		return m_ObjectManager; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MgrImpls::CKPathManager* CKContext::GetPathManager() { | 
					
						
							|  |  |  | 		return m_PathManager; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 22:58:53 +08:00
										 |  |  | 	CKDWORD CKContext::GetManagerCount() { | 
					
						
							| 
									
										
										
										
											2023-09-22 22:31:51 +08:00
										 |  |  | 		return static_cast<CKDWORD>(m_ManagerList.size()); | 
					
						
							| 
									
										
										
										
											2023-08-28 14:18:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 22:58:53 +08:00
										 |  |  | 	MgrImpls::CKBaseManager* CKContext::GetManager(CKDWORD index) { | 
					
						
							|  |  |  | 		if (index >= m_ManagerList.size()) return nullptr; | 
					
						
							|  |  |  | 		return m_ManagerList[index]; | 
					
						
							| 
									
										
										
										
											2023-08-28 14:18:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	void CKContext::ExecuteManagersOnPreClearAll() { | 
					
						
							|  |  |  | 		ExecuteManagersGeneral([](MgrImpls::CKBaseManager* mgr) -> void { | 
					
						
							|  |  |  | 			mgr->PreClearAll(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::ExecuteManagersOnPostClearAll() { | 
					
						
							|  |  |  | 		ExecuteManagersGeneral([](MgrImpls::CKBaseManager* mgr) -> void { | 
					
						
							|  |  |  | 			mgr->PostClearAll(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::ExecuteManagersOnSequenceToBeDeleted(const CK_ID* objids, CKDWORD count) { | 
					
						
							|  |  |  | 		ExecuteManagersGeneral([objids, count](MgrImpls::CKBaseManager* mgr) -> void { | 
					
						
							|  |  |  | 			mgr->SequenceToBeDeleted(objids, count); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::ExecuteManagersOnSequenceDeleted(const CK_ID* objids, CKDWORD count) { | 
					
						
							|  |  |  | 		ExecuteManagersGeneral([objids, count](MgrImpls::CKBaseManager* mgr) -> void { | 
					
						
							|  |  |  | 			mgr->SequenceDeleted(objids, count); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::ExecuteManagersGeneral(std::function<void(MgrImpls::CKBaseManager*)> fct) { | 
					
						
							|  |  |  | 		for (auto& mgrptr : m_ManagerList) { | 
					
						
							|  |  |  | 			fct(mgrptr); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-28 14:18:58 +08:00
										 |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma region File Save/Load Options
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::SetCompressionLevel(CKINT level) { | 
					
						
							|  |  |  | 		if (level > 0 && level < 10) { | 
					
						
							|  |  |  | 			m_CompressionLevel = level; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CKINT CKContext::GetCompressionLevel() { | 
					
						
							|  |  |  | 		return m_CompressionLevel; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::SetFileWriteMode(CK_FILE_WRITEMODE mode) { | 
					
						
							|  |  |  | 		m_FileWriteMode = mode; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CK_FILE_WRITEMODE CKContext::GetFileWriteMode() { | 
					
						
							|  |  |  | 		return m_FileWriteMode; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	CK_TEXTURE_SAVEOPTIONS CKContext::GetGlobalImagesSaveOptions() { | 
					
						
							|  |  |  | 		return m_GlobalImagesSaveOptions; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::SetGlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS Options) { | 
					
						
							|  |  |  | 		if (Options != CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_USEGLOBAL) { | 
					
						
							|  |  |  | 			m_GlobalImagesSaveOptions = Options; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 21:57:48 +08:00
										 |  |  | 	const CKBitmapProperties& CKContext::GetGlobalImagesSaveFormat() { | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 		return m_GlobalImagesSaveFormat; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 21:57:48 +08:00
										 |  |  | 	void CKContext::SetGlobalImagesSaveFormat(const CKBitmapProperties& Format) { | 
					
						
							|  |  |  | 		m_GlobalImagesSaveFormat = Format; | 
					
						
							| 
									
										
										
										
											2023-09-05 22:23:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CK_SOUND_SAVEOPTIONS CKContext::GetGlobalSoundsSaveOptions() { | 
					
						
							|  |  |  | 		return m_GlobalSoundsSaveOptions; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::SetGlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS Options) { | 
					
						
							|  |  |  | 		if (Options != CK_SOUND_SAVEOPTIONS::CKSOUND_USEGLOBAL) { | 
					
						
							|  |  |  | 			m_GlobalSoundsSaveOptions = Options; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-28 14:18:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | #pragma region Output utilities
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:35:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 	void CKContext::OutputToConsole(CKSTRING str) { | 
					
						
							|  |  |  | 		if (m_OutputCallback == nullptr) return; | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		if (str == nullptr) return; | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 		m_OutputCallback(str); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CKContext::OutputToConsoleEx(CKSTRING fmt, ...) { | 
					
						
							|  |  |  | 		if (m_OutputCallback == nullptr) return; | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		if (fmt == nullptr) return; | 
					
						
							| 
									
										
										
										
											2023-02-26 21:48:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 		va_list argptr; | 
					
						
							|  |  |  | 		va_start(argptr, fmt); | 
					
						
							| 
									
										
										
										
											2024-12-25 13:58:39 +08:00
										 |  |  | 		XContainer::XString result(YYCC::StringHelper::VPrintf(fmt, argptr)); | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 		va_end(argptr); | 
					
						
							| 
									
										
										
										
											2023-02-26 21:48:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-08 10:42:07 +08:00
										 |  |  | 		// use c_str(), not XContainer::NSXString::ToCKSTRING because we want make sure this paramter is not nullptr.
 | 
					
						
							|  |  |  | 		// we always output a valid C style string, even if no chars need to write.
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 		m_OutputCallback(result.c_str()); | 
					
						
							| 
									
										
										
										
											2023-02-26 21:48:03 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | 	void CKContext::SetOutputCallback(OutputCallback cb) { | 
					
						
							|  |  |  | 		m_OutputCallback = cb; | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:35:54 +08:00
										 |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 16:04:58 +08:00
										 |  |  | #pragma region Encoding utilities
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:35:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 11:25:53 +08:00
										 |  |  | 	bool CKContext::GetUTF8String(const std::string& native_name, XContainer::XString& u8_name) { | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		bool conv_success = false, has_valid_token = false; | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		for (const auto& token : this->m_NameEncoding) { | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 			if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue; | 
					
						
							|  |  |  | 			has_valid_token = true; | 
					
						
							|  |  |  | 			conv_success = EncodingHelper::ToUTF8(native_name, u8_name, token); | 
					
						
							|  |  |  | 			if (conv_success) break; | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		// fallback if failed.
 | 
					
						
							|  |  |  | 		if (!conv_success) { | 
					
						
							|  |  |  | 			if (!has_valid_token) { | 
					
						
							|  |  |  | 				throw RuntimeException("Try to get UTF8 string from ordinary string in CKContext but giving empty encoding candidate."); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				u8_name.clear(); | 
					
						
							|  |  |  | 				this->OutputToConsole(u8"Error when converting to UTF8 string from ordinary string. The string will leave to blank."); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-27 11:25:53 +08:00
										 |  |  | 		// return value
 | 
					
						
							|  |  |  | 		return conv_success; | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 11:25:53 +08:00
										 |  |  | 	bool CKContext::GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name) { | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		bool conv_success = false, has_valid_token = false; | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		for (const auto& token : this->m_NameEncoding) { | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 			if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue; | 
					
						
							|  |  |  | 			has_valid_token = true; | 
					
						
							|  |  |  | 			conv_success = EncodingHelper::ToOrdinary(u8_name, native_name, token); | 
					
						
							|  |  |  | 			if (conv_success) break; | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		// fallback if failed.
 | 
					
						
							|  |  |  | 		if (!conv_success) { | 
					
						
							|  |  |  | 			if (!has_valid_token) { | 
					
						
							|  |  |  | 				throw RuntimeException("Try to get ordinary string from UTF8 string in CKContext but giving empty encoding candidate."); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				native_name.clear(); | 
					
						
							|  |  |  | 				this->OutputToConsole(u8"Error when converting to ordinary string from UTF8 string. The string will leave to blank."); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-27 11:25:53 +08:00
										 |  |  | 		// return value
 | 
					
						
							|  |  |  | 		return conv_success; | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 	void CKContext::SetEncoding(const XContainer::XArray<XContainer::XString>& encoding_seq) { | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		// free all current series
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		this->ClearEncoding(); | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		// add new encoding
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 		for (const auto& encoding_str : encoding_seq) { | 
					
						
							|  |  |  | 			this->m_NameEncoding.emplace_back(LibCmo::EncodingHelper::CreateEncodingToken(encoding_str)); | 
					
						
							| 
									
										
										
										
											2023-03-04 11:11:36 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 	void CKContext::ClearEncoding() { | 
					
						
							|  |  |  | 		for (const auto& token : this->m_NameEncoding) { | 
					
						
							|  |  |  | 			if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue; | 
					
						
							|  |  |  | 			LibCmo::EncodingHelper::DestroyEncodingToken(token); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this->m_NameEncoding.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 11:28:49 +08:00
										 |  |  | 	bool CKContext::IsValidEncoding() { | 
					
						
							|  |  |  | 		for (const auto& token : this->m_NameEncoding) { | 
					
						
							|  |  |  | 			if (token != EncodingHelper::INVALID_ENCODING_TOKEN) return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:35:54 +08:00
										 |  |  | #pragma endregion
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:58:28 +08:00
										 |  |  | } |