diff --git a/LibCmo/CK2/CKContext.cpp b/LibCmo/CK2/CKContext.cpp index 3f0764c..af76e64 100644 --- a/LibCmo/CK2/CKContext.cpp +++ b/LibCmo/CK2/CKContext.cpp @@ -1,5 +1,6 @@ #include "CKContext.hpp" #include "ObjImpls/CKObject.hpp" +#include "../XContainer/XBitArray.hpp" #include namespace LibCmo::CK2 { @@ -10,6 +11,29 @@ namespace LibCmo::CK2 { static char g_UniqueFolder[] = "LibCmo"; #endif +#pragma region Ctor Dtor + + CKContext::CKContext() : + m_ObjectsList(), m_ReturnedObjectIds(), + m_GroupGlobalIndex(), m_SceneGlobalIndex(), + m_CompressionLevel(5), m_FileWriteMode(CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED), + m_NameEncoding(), m_TempFolder(), + m_OutputCallback(nullptr) + { + // preset for temp folder + // todo: add current CKContext pointer as the part of temp path. + // thus multiple CKContext can work. + m_TempFolder = std::filesystem::temp_directory_path(); + m_TempFolder /= g_UniqueFolder; + std::filesystem::create_directory(m_TempFolder); + } + + CKContext::~CKContext() { + DestroyAllCKObjects(); + } + +#pragma endregion + #pragma region Objects Management ObjImpls::CKObject* CKContext::CreateCKObject(CK_CLASSID cls, CKSTRING name, @@ -78,6 +102,45 @@ namespace LibCmo::CK2 { } + CKDWORD CKContext::AllocateGroupGlobalIndex() { + // try find first non-true position + CKDWORD index; + if (!XContainer::XBitArrayPatch::GetSetBitPosition(m_GroupGlobalIndex, 0, index)) { + // failed. distribute new one + index = static_cast(m_GroupGlobalIndex.size()); + m_GroupGlobalIndex.resize(m_GroupGlobalIndex.size() + 1); + } + + // set to occupy + m_GroupGlobalIndex[index] = true; + return index; + } + + CKDWORD CKContext::AllocateSceneGlobalIndex() { + // same as group + CKDWORD index; + if (!XContainer::XBitArrayPatch::GetSetBitPosition(m_SceneGlobalIndex, 0, index)) { + index = static_cast(m_SceneGlobalIndex.size()); + m_SceneGlobalIndex.resize(m_SceneGlobalIndex.size() + 1); + } + + m_SceneGlobalIndex[index] = true; + return index; + } + + void CKContext::FreeGroupGlobalIndex(CKDWORD id) { + // check position + if (id >= m_GroupGlobalIndex.size()) return; + // set value + m_GroupGlobalIndex[id] = false; + } + + void CKContext::FreeSceneGlobalIndex(CKDWORD id) { + // same as group + if (id >= m_SceneGlobalIndex.size()) return; + m_SceneGlobalIndex[id] = false; + } + void CKContext::DestroyAllCKObjects() { // free all created objects for (auto& ptr : m_ObjectsList) { @@ -89,6 +152,10 @@ namespace LibCmo::CK2 { m_ReturnedObjectIds.clear(); // empty object list m_ObjectsList.clear(); + + // clear group and scene global index at the same time + m_SceneGlobalIndex.clear(); + m_GroupGlobalIndex.clear(); } #pragma endregion @@ -128,29 +195,6 @@ namespace LibCmo::CK2 { #pragma endregion - -#pragma region Ctor Dtor - - CKContext::CKContext() : - m_ObjectsList(), m_ReturnedObjectIds(), - m_CompressionLevel(5), m_FileWriteMode(CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED), - m_NameEncoding(), m_TempFolder(), - m_OutputCallback(nullptr) - { - // preset for temp folder - // todo: add current CKContext pointer as the part of temp path. - // thus multiple CKContext can work. - m_TempFolder = std::filesystem::temp_directory_path(); - m_TempFolder /= g_UniqueFolder; - std::filesystem::create_directory(m_TempFolder); - } - - CKContext::~CKContext() { - DestroyAllCKObjects(); - } - -#pragma endregion - #pragma region Output utilities void CKContext::OutputToConsole(CKSTRING str) { diff --git a/LibCmo/CK2/CKContext.hpp b/LibCmo/CK2/CKContext.hpp index 882ae25..4abaacb 100644 --- a/LibCmo/CK2/CKContext.hpp +++ b/LibCmo/CK2/CKContext.hpp @@ -42,6 +42,12 @@ namespace LibCmo::CK2 { CK_CREATIONMODE* res = nullptr); ObjImpls::CKObject* GetCKObject(CK_ID id); void DestroyCKObject(CK_ID id); + + CKDWORD AllocateGroupGlobalIndex(); + CKDWORD AllocateSceneGlobalIndex(); + void FreeGroupGlobalIndex(CKDWORD id); + void FreeSceneGlobalIndex(CKDWORD id); + void DestroyAllCKObjects(); // ========== Object Access ========== @@ -94,6 +100,9 @@ namespace LibCmo::CK2 { XContainer::XArray m_ObjectsList; std::deque m_ReturnedObjectIds; + XContainer::XBitArray m_GroupGlobalIndex; + XContainer::XBitArray m_SceneGlobalIndex; + // ========== File Save/Load Options ========== CKINT m_CompressionLevel; CK_FILE_WRITEMODE m_FileWriteMode; diff --git a/LibCmo/CK2/CKDefines.hpp b/LibCmo/CK2/CKDefines.hpp index a6b5da3..358f7ce 100644 --- a/LibCmo/CK2/CKDefines.hpp +++ b/LibCmo/CK2/CKDefines.hpp @@ -34,6 +34,7 @@ namespace LibCmo::CK2 { //using CKClassDependenciesCountFct = std::function; struct CKClassDesc { + bool IsValid; /**< True if this CKClassDesc is a valid one. Because CK_CLASSID may not be consecutive. */ bool Done; // Initialized upon class registration CK_CLASSID Self; @@ -62,6 +63,7 @@ namespace LibCmo::CK2 { //XContainer::XSArray ToNotify; // List of ClassID to notify when an object of this class is deleted (inverse of ToBeNotify) CKClassDesc() : + IsValid(false), Done(false), Self(CK_CLASSID::CKCID_OBJECT), Parent(CK_CLASSID::CKCID_OBJECT), CreationFct(nullptr), ReleaseFct(nullptr), NameFct(nullptr), diff --git a/LibCmo/CK2/CKGlobals.cpp b/LibCmo/CK2/CKGlobals.cpp index 8dea8b6..70aff57 100644 --- a/LibCmo/CK2/CKGlobals.cpp +++ b/LibCmo/CK2/CKGlobals.cpp @@ -11,6 +11,9 @@ #include #include "ObjImpls/CKObject.hpp" +#include "ObjImpls/CKSceneObject.hpp" +#include "ObjImpls/CKBeObject.hpp" +#include "ObjImpls/CKGroup.hpp" namespace LibCmo::CK2 { @@ -61,17 +64,23 @@ namespace LibCmo::CK2 { #pragma region CKClass Registration static XContainer::XArray g_CKClassInfo; - static std::map g_CKClassInfoId2Idx; - static CK_CLASSID g_CKClassInfoMaxID = static_cast(0); + + CK_CLASSID CKClassGetNewIdentifier() { + size_t classsize = g_CKClassInfo.size(); + if (classsize < static_cast(CK_CLASSID::CKCID_MAXCLASSID)) { + return CK_CLASSID::CKCID_MAXCLASSID; + } else { + return static_cast(classsize); + } + } static void ComputeParentsTable(CKClassDesc& desc) { // if it has done, do not process it again. if (desc.Done) return; // find direct parent - auto finder = g_CKClassInfoId2Idx.find(desc.Parent); - if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID."); - CKClassDesc& parent = g_CKClassInfo[finder->second]; + CKClassDesc& parent = g_CKClassInfo[static_cast(desc.Parent)]; + if (!parent.IsValid) LIBPANIC("No such CK_CLASSID."); // if it is not self inheritance, call recursively if (desc.Self != desc.Parent) { @@ -81,9 +90,7 @@ namespace LibCmo::CK2 { // copy parent's parents desc.Parents = parent.Parents; // and set self as its parent - finder = g_CKClassInfoId2Idx.find(desc.Self); - if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID."); - desc.Parents[finder->second] = true; + desc.Parents[static_cast(desc.Self)] = true; // set derivation level desc.DerivationLevel = parent.DerivationLevel + 1; @@ -95,26 +102,30 @@ namespace LibCmo::CK2 { // set Done to false and resize all XBitArray size_t classCount = g_CKClassInfo.size(); for (auto& item : g_CKClassInfo) { + if (!item.IsValid) continue; + item.Done = false; item.Parents.resize(classCount, false); item.Children.resize(classCount, false); } // compute parents for (auto& item : g_CKClassInfo) { + if (!item.IsValid) continue; + ComputeParentsTable(item); } // compute children by parents table // iterate CKClassDesc::Parents and register it self to gotten parents for (auto& item : g_CKClassInfo) { - auto finder = g_CKClassInfoId2Idx.find(item.Self); - if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID."); - size_t selfidx = finder->second; + if (!item.IsValid) continue; for (size_t idx = 0; idx < classCount; ++idx) { + if (!g_CKClassInfo[idx].IsValid) continue; + // if this idx is its parent, // add self to parent. if (item.Parents[idx]) { - g_CKClassInfo[idx].Children[selfidx] = true; + g_CKClassInfo[idx].Children[static_cast(item.Self)] = true; } } } @@ -122,54 +133,60 @@ namespace LibCmo::CK2 { void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct) { + // resize class desc array + size_t intcid = static_cast(cid); + if (intcid >= g_CKClassInfo.size()) { + g_CKClassInfo.resize(intcid + 1); + } + + // emplace desc CKClassDesc desc; + desc.IsValid = true; desc.Self = cid; desc.Parent = parentCid; desc.CreationFct = createFct; desc.ReleaseFct = relFct; desc.NameFct = nameFct; - g_CKClassInfoId2Idx.emplace(cid, g_CKClassInfo.size()); - g_CKClassInfo.emplace_back(std::move(desc)); - g_CKClassInfoMaxID = std::max(g_CKClassInfoMaxID, cid); + g_CKClassInfo[intcid] = std::move(desc); } #pragma endregion #pragma region Class Hierarchy Management - CKINT CKGetClassCount() { - return static_cast(g_CKClassInfo.size()); + static bool GetClassIdIndex(CK_CLASSID cid, size_t& intcid) { + intcid = static_cast(cid); + if (intcid >= g_CKClassInfo.size()) return false; + if (!g_CKClassInfo[intcid].IsValid) return false; + return true; + } + + CKDWORD CKGetClassCount() { + return static_cast(g_CKClassInfo.size()); } const CKClassDesc* CKGetClassDesc(CK_CLASSID cid) { - auto finder = g_CKClassInfoId2Idx.find(cid); - if (finder == g_CKClassInfoId2Idx.end()) return nullptr; - return g_CKClassInfo.data() + finder->second; + size_t intcid; + if (!GetClassIdIndex(cid, intcid)) return nullptr; + return &g_CKClassInfo[intcid]; } CKSTRING CKClassIDToString(CK_CLASSID cid) { - auto finder = g_CKClassInfoId2Idx.find(cid); - if (finder == g_CKClassInfoId2Idx.end() || g_CKClassInfo[finder->second].NameFct == nullptr) return "Invalid Class Identifier"; - return g_CKClassInfo[finder->second].NameFct(); + const CKClassDesc* desc = CKGetClassDesc(cid); + if (desc == nullptr) return "Undefined Type"; + else return desc->NameFct(); } bool CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent) { - // get corresponding index first - // if we can't find it, return false anyway. - auto finder = g_CKClassInfoId2Idx.find(child); - if (finder == g_CKClassInfoId2Idx.end()) return false; - size_t child_idx = finder->second; - finder = g_CKClassInfoId2Idx.find(parent); - if (finder == g_CKClassInfoId2Idx.end()) return false; - size_t parent_idx = finder->second; - - return g_CKClassInfo[child_idx].Parents[parent_idx]; + size_t intchild, intparent; + if (!GetClassIdIndex(child, intchild) || !GetClassIdIndex(parent, intparent)) return false; + return g_CKClassInfo[intchild].Parents[intparent]; } CK_CLASSID CKGetParentClassID(CK_CLASSID child) { - auto finder = g_CKClassInfoId2Idx.find(child); - if (finder == g_CKClassInfoId2Idx.end()) LIBPANIC("No such CK_CLASSID."); - return g_CKClassInfo[finder->second].Parent; + const CKClassDesc* desc = CKGetClassDesc(child); + if (desc == nullptr) return CK_CLASSID::CKCID_OBJECT; + return desc->Parent; } CK_CLASSID CKGetCommonParent(CK_CLASSID cid1, CK_CLASSID cid2) { @@ -190,11 +207,28 @@ namespace LibCmo::CK2 { #pragma region Initializations functions CKERROR CKStartUp() { + + // reserve class info array. + g_CKClassInfo.reserve(static_cast(CK_CLASSID::CKCID_MAXCLASSID)); + // todo: add class type registrations - CKClassRegister(CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT, - [](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new ObjImpls::CKObject(ctx, id, name); }, - [](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, - []() -> CKSTRING { return "Basic Object"; }); +#define EasyClassReg(clsname, cid, parentCid, strName) \ +CKClassRegister(cid, parentCid, \ + [](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new clsname(ctx, id, name); }, \ + [](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, \ + []() -> CKSTRING { return strName; }); + + EasyClassReg(ObjImpls::CKObject, CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT, "Basic Object"); + EasyClassReg(ObjImpls::CKSceneObject, CK_CLASSID::CKCID_SCENEOBJECT, CK_CLASSID::CKCID_OBJECT, "Scene Object"); + EasyClassReg(ObjImpls::CKBeObject, CK_CLASSID::CKCID_BEOBJECT, CK_CLASSID::CKCID_SCENEOBJECT, "Behavioral Object"); + EasyClassReg(ObjImpls::CKGroup, CK_CLASSID::CKCID_GROUP, CK_CLASSID::CKCID_BEOBJECT, "Group"); + + //CKClassRegister(CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT, + // [](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new ObjImpls::CKObject(ctx, id, name); }, + // [](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, + // []() -> CKSTRING { return "Basic Object"; }); + +#undef EasyClassReg /* // register CKObjects @@ -233,8 +267,6 @@ namespace LibCmo::CK2 { CKERROR CKShutdown() { // free class indo g_CKClassInfo.clear(); - g_CKClassInfoId2Idx.clear(); - g_CKClassInfoMaxID = static_cast(0); return CKERROR::CKERR_OK; } diff --git a/LibCmo/CK2/CKGlobals.hpp b/LibCmo/CK2/CKGlobals.hpp index 53b3c49..cac3f72 100644 --- a/LibCmo/CK2/CKGlobals.hpp +++ b/LibCmo/CK2/CKGlobals.hpp @@ -54,12 +54,13 @@ namespace LibCmo::CK2 { // ========== CKClass Registration ========== + CK_CLASSID CKClassGetNewIdentifier(); void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct); // ========== Class Hierarchy Management ========== - CKINT CKGetClassCount(); + CKDWORD CKGetClassCount(); const CKClassDesc* CKGetClassDesc(CK_CLASSID cid); CKSTRING CKClassIDToString(CK_CLASSID cid); diff --git a/LibCmo/CK2/ObjImpls/CKBeObject.cpp b/LibCmo/CK2/ObjImpls/CKBeObject.cpp index 032fb77..6a664b6 100644 --- a/LibCmo/CK2/ObjImpls/CKBeObject.cpp +++ b/LibCmo/CK2/ObjImpls/CKBeObject.cpp @@ -22,4 +22,9 @@ namespace LibCmo::CK2::ObjImpls { return false; } + void CKBeObject::CKGroup_SetGroups(CKDWORD pos, bool val) { + if (pos >= m_Groups.size()) m_Groups.resize(pos + 1); + m_Groups[pos] = val; + } + } \ No newline at end of file diff --git a/LibCmo/CK2/ObjImpls/CKBeObject.hpp b/LibCmo/CK2/ObjImpls/CKBeObject.hpp index e6129b8..a21e1a2 100644 --- a/LibCmo/CK2/ObjImpls/CKBeObject.hpp +++ b/LibCmo/CK2/ObjImpls/CKBeObject.hpp @@ -22,6 +22,7 @@ namespace LibCmo::CK2::ObjImpls { //virtual void PostLoad() override; bool IsInGroup(CKGroup* group); + void CKGroup_SetGroups(CKDWORD pos, bool val); protected: XContainer::XBitArray m_Groups; diff --git a/LibCmo/CK2/ObjImpls/CKGroup.cpp b/LibCmo/CK2/ObjImpls/CKGroup.cpp index f95f27c..b5920ab 100644 --- a/LibCmo/CK2/ObjImpls/CKGroup.cpp +++ b/LibCmo/CK2/ObjImpls/CKGroup.cpp @@ -1,27 +1,92 @@ -#include "CKSceneObject.hpp" -#include "../CKStateChunk.hpp" #include "CKGroup.hpp" +#include "../CKStateChunk.hpp" +#include "../CKContext.hpp" +#include namespace LibCmo::CK2::ObjImpls { + CKGroup::CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name) : + CKBeObject(ctx, ckid, name), + m_ObjectArray(), + m_GroupIndex(m_Context->AllocateGroupGlobalIndex()) {} + + CKGroup::~CKGroup() { + m_Context->FreeGroupGlobalIndex(m_GroupIndex); + } + bool CKGroup::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) { - return false; + bool suc = CKBeObject::Save(chunk, file, flags); + if (!suc) return false; + + return true; } bool CKGroup::Load(CKStateChunk* chunk, CKFileVisitor* file) { - return false; + bool suc = CKBeObject::Load(chunk, file); + if (!suc) return false; + + return true; } CKDWORD CKGroup::GetGroupIndex() { return m_GroupIndex; } - CKObject* CKGroup::GetObject(CKDWORD pos) { - return nullptr; + CKERROR CKGroup::AddObject(CKBeObject* o) { + if (o == nullptr || o == this || !CKIsChildClassOf(o->GetClassID(), CK_CLASSID::CKCID_BEOBJECT)) { + return CKERROR::CKERR_INVALIDPARAMETER; + } + if (o->IsInGroup(this)) { + return CKERROR::CKERR_ALREADYPRESENT; + } + + // set object + o->CKGroup_SetGroups(m_GroupIndex, true); + // set self + m_ObjectArray.emplace_back(o); + return CKERROR::CKERR_OK; + } + + CKBeObject* CKGroup::RemoveObject(CKDWORD pos) { + // check pos + if (pos >= m_ObjectArray.size()) return nullptr; + + auto it = m_ObjectArray.begin() + pos; + CKBeObject* obj = static_cast(*it); + // set object + obj->CKGroup_SetGroups(m_GroupIndex, false); + // remove self + m_ObjectArray.erase(it); + return obj; + } + + void CKGroup::RemoveObject(CKBeObject* obj) { + // find first + auto finder = std::find(m_ObjectArray.begin(), m_ObjectArray.end(), static_cast(obj)); + if (finder != m_ObjectArray.end()) { + // set object + static_cast(*finder)->CKGroup_SetGroups(m_GroupIndex, false); + // remove self + m_ObjectArray.erase(finder); + } + } + + void CKGroup::Clear() { + for (auto& beobj : m_ObjectArray) { + // set object + static_cast(beobj)->CKGroup_SetGroups(m_GroupIndex, false); + } + + m_ObjectArray.clear(); + } + + CKBeObject* CKGroup::GetObject(CKDWORD pos) { + if (pos >= m_ObjectArray.size()) return nullptr; + else return static_cast(m_ObjectArray[pos]); } CKDWORD CKGroup::GetObjectCount() { - return CKDWORD(); + return static_cast(m_ObjectArray.size()); } } diff --git a/LibCmo/CK2/ObjImpls/CKGroup.hpp b/LibCmo/CK2/ObjImpls/CKGroup.hpp index 97c50ae..7a3531a 100644 --- a/LibCmo/CK2/ObjImpls/CKGroup.hpp +++ b/LibCmo/CK2/ObjImpls/CKGroup.hpp @@ -7,14 +7,8 @@ namespace LibCmo::CK2::ObjImpls { class CKGroup : public CKBeObject { public: - CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name) : - CKBeObject(ctx, ckid, name), - m_ObjectArray(), - m_GroupIndex() // todo: allocate group id - {} - virtual ~CKGroup() { - // todo: free allocated group id - } + CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name); + virtual ~CKGroup(); LIBCMO_DISABLE_COPY_MOVE(CKGroup); virtual CK_CLASSID GetClassID(void) override { @@ -29,20 +23,14 @@ namespace LibCmo::CK2::ObjImpls { // ===== Insert ===== CKERROR AddObject(CKBeObject *o); - CKERROR AddObjectFront(CKBeObject *o); - CKERROR InsertObjectAt(CKBeObject *o, CKDWORD pos); // ===== Remove ===== CKBeObject* RemoveObject(CKDWORD pos); void RemoveObject(CKBeObject *obj); void Clear(); - // ===== Order ===== - void MoveObjectUp(CKBeObject *o); - void MoveObjectDown(CKBeObject *o); - // ===== Access ===== - CKObject* GetObject(CKDWORD pos); + CKBeObject* GetObject(CKDWORD pos); CKDWORD GetObjectCount(); protected: diff --git a/LibCmo/LibCmo.vcxproj b/LibCmo/LibCmo.vcxproj index b9f9b18..55c3b31 100644 --- a/LibCmo/LibCmo.vcxproj +++ b/LibCmo/LibCmo.vcxproj @@ -189,6 +189,7 @@ + @@ -209,6 +210,7 @@ + diff --git a/LibCmo/LibCmo.vcxproj.filters b/LibCmo/LibCmo.vcxproj.filters index cad2ac9..d3245bc 100644 --- a/LibCmo/LibCmo.vcxproj.filters +++ b/LibCmo/LibCmo.vcxproj.filters @@ -87,6 +87,9 @@ Sources\CK2\ObjImpls + + Sources\XContainer + @@ -146,5 +149,8 @@ Headers\CK2\ObjImpls + + Headers\XContainer + \ No newline at end of file diff --git a/LibCmo/XContainer/XBitArray.cpp b/LibCmo/XContainer/XBitArray.cpp new file mode 100644 index 0000000..679bb28 --- /dev/null +++ b/LibCmo/XContainer/XBitArray.cpp @@ -0,0 +1,30 @@ +#include "XBitArray.hpp" + +namespace LibCmo::XContainer::XBitArrayPatch { + + template + bool GeneralGetBitPosition(XBitArray& ba, CK2::CKDWORD n, CK2::CKDWORD& got) { + CK2::CKDWORD counter = 0; + for (size_t i = 0; i < ba.size(); ++i) { + if (ba[i] == _Cond) { + if (counter == n) { + got = static_cast(i); + return true; + } else { + ++counter; + } + } + } + + return false; + } + + bool GetSetBitPosition(XBitArray& ba, CK2::CKDWORD n, CK2::CKDWORD& got) { + return GeneralGetBitPosition(ba, n, got); + } + + bool GetUnsetBitPosition(XBitArray& ba, CK2::CKDWORD n, CK2::CKDWORD& got) { + return GeneralGetBitPosition(ba, n, got); + } + +} diff --git a/LibCmo/XContainer/XBitArray.hpp b/LibCmo/XContainer/XBitArray.hpp new file mode 100644 index 0000000..988aa7b --- /dev/null +++ b/LibCmo/XContainer/XBitArray.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "XTypes.hpp" + +namespace LibCmo::XContainer::XBitArrayPatch { + + /** + * @brief Returns the position of the n-th set(1) bit + * @return false if not found. + */ + bool GetSetBitPosition(XBitArray& ba, CK2::CKDWORD n, CK2::CKDWORD& got); + /** + * @brief Returns the position of the n-th unset(0) bit + * @return false if not found. + */ + bool GetUnsetBitPosition(XBitArray& ba, CK2::CKDWORD n, CK2::CKDWORD& got); + +} diff --git a/Unvirt/StructFormatter.cpp b/Unvirt/StructFormatter.cpp index 8df3cd0..9a6d7df 100644 --- a/Unvirt/StructFormatter.cpp +++ b/Unvirt/StructFormatter.cpp @@ -167,14 +167,28 @@ namespace Unvirt::StructFormatter { void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject* obj) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKObject\n")), stdout); + if (obj == nullptr) { + fputs(UNVIRT_TERMCOL_LIGHT_RED(("No Data\n")), stdout); + return; + } + fputs(UNVIRT_TERMCOL_LIGHT_RED(("Not Implemented.\n")), stdout); } void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKBaseManager\n")), stdout); + if (mgr == nullptr) { + fputs(UNVIRT_TERMCOL_LIGHT_RED(("No Data\n")), stdout); + return; + } + fputs(UNVIRT_TERMCOL_LIGHT_RED(("Not Implemented.\n")), stdout); } void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKStateChunk\n")), stdout); + if (chunk == nullptr) { + fputs(UNVIRT_TERMCOL_LIGHT_RED(("No Data\n")), stdout); + return; + } // hack const state chunk LibCmo::CK2::CKStateChunk* operchunk = const_cast(chunk); diff --git a/Unvirt/UnvirtContext.cpp b/Unvirt/UnvirtContext.cpp index 1cc31c9..cbc7d50 100644 --- a/Unvirt/UnvirtContext.cpp +++ b/Unvirt/UnvirtContext.cpp @@ -127,6 +127,7 @@ namespace Unvirt::Context { m_Help = root->RootHelp(); // create context + LibCmo::CK2::CKStartUp(); m_Ctx = new LibCmo::CK2::CKContext(); m_Ctx->SetOutputCallback(std::bind(&UnvirtContext::PrintContextMsg, this, std::placeholders::_1)); } @@ -134,6 +135,11 @@ namespace Unvirt::Context { UnvirtContext::~UnvirtContext() { if (m_Help != nullptr) delete m_Help; + + // free context + ClearDocument(); + delete m_Ctx; + LibCmo::CK2::CKShutdown(); } bool UnvirtContext::HasOpenedFile() {