From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Dbx_tree/Entities.cpp | 1032 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1032 insertions(+) create mode 100644 plugins/Dbx_tree/Entities.cpp (limited to 'plugins/Dbx_tree/Entities.cpp') diff --git a/plugins/Dbx_tree/Entities.cpp b/plugins/Dbx_tree/Entities.cpp new file mode 100644 index 0000000000..73e9487ac6 --- /dev/null +++ b/plugins/Dbx_tree/Entities.cpp @@ -0,0 +1,1032 @@ +/* + +dbx_tree: tree database driver for Miranda IM + +Copyright 2007-2010 Michael "Protogenes" Kunz, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "Entities.h" + +CVirtuals::CVirtuals(CBlockManager & BlockManager, TNodeRef RootNode) +: CFileBTree::CFileBTree(BlockManager, RootNode, cVirtualNodeSignature) +{ + +} + +CVirtuals::~CVirtuals() +{ + +} + +TDBTEntityHandle CVirtuals::_DeleteRealEntity(TDBTEntityHandle hRealEntity) +{ + TDBTEntityHandle result; + TVirtualKey key; + TEntity * entity; + bool copies = false; + uint32_t size = sizeof(TEntity); + uint32_t sig = cEntitySignature; + + key.RealEntity = hRealEntity; + key.Virtual = 0; + + iterator i = LowerBound(key); + result = i->Virtual; + i.setManaged(); + Delete(*i); + + while ((i) && (i->RealEntity == hRealEntity)) + { + key = *i; + Delete(key); + + key.RealEntity = result; + Insert(key); + + entity = m_BlockManager.ReadBlock(key.Virtual, size, sig); + if (entity) + { + entity->VParent = result; + m_BlockManager.UpdateBlock(key.Virtual); + + copies = true; + } // TODO log + } + + entity = m_BlockManager.ReadBlock(result, size, sig); + if (entity) + { + entity->Flags = entity->Flags & ~(DBT_NF_HasVirtuals | DBT_NF_IsVirtual); + if (copies) + entity->Flags |= DBT_NF_HasVirtuals; + + m_BlockManager.UpdateBlock(result); + } // TODO log + return result; +} + +bool CVirtuals::_InsertVirtual(TDBTEntityHandle hRealEntity, TDBTEntityHandle hVirtual) +{ + TVirtualKey key; + key.RealEntity = hRealEntity; + key.Virtual = hVirtual; + + Insert(key); + + return true; +} +void CVirtuals::_DeleteVirtual(TDBTEntityHandle hRealEntity, TDBTEntityHandle hVirtual) +{ + TVirtualKey key; + key.RealEntity = hRealEntity; + key.Virtual = hVirtual; + + Delete(key); +} +TDBTEntityHandle CVirtuals::getParent(TDBTEntityHandle hVirtual) +{ + TEntity * entity; + uint32_t size = sizeof(TEntity); + uint32_t sig = cEntitySignature; + + CBlockManager::ReadTransaction trans(m_BlockManager); + + entity = m_BlockManager.ReadBlock(hVirtual, size, sig); + if (!entity || ((entity->Flags & DBT_NF_IsVirtual) == 0)) + return DBT_INVALIDPARAM; + + return entity->VParent; +} +TDBTEntityHandle CVirtuals::getFirst(TDBTEntityHandle hRealEntity) +{ + TEntity * entity; + uint32_t size = sizeof(TEntity); + uint32_t sig = cEntitySignature; + + CBlockManager::ReadTransaction trans(m_BlockManager); + + entity = m_BlockManager.ReadBlock(hRealEntity, size, sig); + if (!entity || ((entity->Flags & DBT_NF_HasVirtuals) == 0)) + return DBT_INVALIDPARAM; + + TVirtualKey key; + key.RealEntity = hRealEntity; + key.Virtual = 0; + + iterator i = LowerBound(key); + + if (i && (i->RealEntity == hRealEntity)) + key.Virtual = i->Virtual; + else + key.Virtual = 0; + + return key.Virtual; +} +TDBTEntityHandle CVirtuals::getNext(TDBTEntityHandle hVirtual) +{ + TEntity * entity; + uint32_t size = sizeof(TEntity); + uint32_t sig = cEntitySignature; + + CBlockManager::ReadTransaction trans(m_BlockManager); + + entity = m_BlockManager.ReadBlock(hVirtual, size, sig); + if (!entity || ((entity->Flags & DBT_NF_IsVirtual) == 0)) + return DBT_INVALIDPARAM; + + TVirtualKey key; + key.RealEntity = entity->VParent; + key.Virtual = hVirtual + 1; + + iterator i = LowerBound(key); + + if ((i) && (i->RealEntity == entity->VParent)) + key.Virtual = i->Virtual; + else + key.Virtual = 0; + + return key.Virtual; +} + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +CEntities::CEntities(CBlockManager & BlockManager, TDBTEntityHandle RootEntity, TNodeRef EntityRoot, CVirtuals::TNodeRef VirtualRoot) +: CFileBTree::CFileBTree(BlockManager, EntityRoot, cEntityNodeSignature), + m_Virtuals(BlockManager, VirtualRoot), + + m_sigEntityDelete(), + m_sigInternalDeleteEvents(), + m_sigInternalDeleteSettings(), + m_sigInternalMergeSettings(), + m_sigInternalTransferEvents() +{ + if (RootEntity == 0) + m_RootEntity = _CreateRootEntity(); + else + m_RootEntity = RootEntity; + +} + +CEntities::~CEntities() +{ + +} + +TDBTEntityHandle CEntities::_CreateRootEntity() +{ + TEntity * entity; + TEntityKey key = {0,0,0}; + + CBlockManager::WriteTransaction trans(m_BlockManager); + + entity = m_BlockManager.CreateBlock(key.Entity, cEntitySignature); + entity->Flags = DBT_NF_IsGroup | DBT_NF_IsRoot; + m_BlockManager.UpdateBlock(key.Entity); + Insert(key); + return key.Entity; +} + +void CEntities::_InternalTransferContacts(TDBTEntityHandle OldAccount, TDBTEntityHandle NewAccount) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + TEntityKey key = {0,0,0}; + iterator i = LowerBound(key); + + while (i) + { + sig = cEntitySignature; + TEntity * entity = m_BlockManager.ReadBlock(i->Entity, size, sig); + if (entity && (entity->Account == OldAccount)) + { + entity->Account = NewAccount; + m_BlockManager.UpdateBlock(i->Entity); + } + + ++i; + } +} + +uint32_t CEntities::_getSettingsRoot(TDBTEntityHandle hEntity) +{ + /*CSettingsTree::TNodeRef*/ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return DBT_INVALIDPARAM; + + return entity->Settings; +} +bool CEntities::_setSettingsRoot(TDBTEntityHandle hEntity, /*CSettingsTree::TNodeRef*/ uint32_t NewRoot) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return false; + + entity->Settings = NewRoot; + m_BlockManager.UpdateBlock(hEntity); + + return true; +} + +uint32_t CEntities::_getEventsRoot(TDBTEntityHandle hEntity) +{ + /*CEventsTree::TNodeRef*/ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return DBT_INVALIDPARAM; + + return entity->Events; +} +bool CEntities::_setEventsRoot(TDBTEntityHandle hEntity, /*CEventsTree::TNodeRef*/ uint32_t NewRoot) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return false; + entity->Events = NewRoot; + m_BlockManager.UpdateBlock(hEntity); + + return true; +} + +uint32_t CEntities::_getEventCount(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return DBT_INVALIDPARAM; + + return entity->EventCount; +} + +uint32_t CEntities::_adjustEventCount(TDBTEntityHandle hEntity, int32_t Adjust) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return DBT_INVALIDPARAM; + + if (((Adjust < 0) && ((uint32_t)(-Adjust) <= entity->EventCount)) || + ((Adjust > 0) && ((0xffffffff - entity->EventCount) > (uint32_t)Adjust))) + { + entity->EventCount += Adjust; + m_BlockManager.UpdateBlock(hEntity); + } + + return entity->EventCount; +} + +bool CEntities::_getFirstUnreadEvent(TDBTEntityHandle hEntity, uint32_t & hEvent, uint32_t & Timestamp) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return false; + + Timestamp = entity->FirstUnreadEventTimestamp; + hEvent = entity->FirstUnreadEventHandle; + return true; +} +bool CEntities::_setFirstUnreadEvent(TDBTEntityHandle hEntity, uint32_t hEvent, uint32_t Timestamp) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return false; + entity->FirstUnreadEventTimestamp = Timestamp; + entity->FirstUnreadEventHandle = hEvent; + m_BlockManager.UpdateBlock(hEntity); + + return true; +} + +TDBTEntityHandle CEntities::getParent(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + if (!entity) + return DBT_INVALIDPARAM; + + return entity->ParentEntity; +} +TDBTEntityHandle CEntities::setParent(TDBTEntityHandle hEntity, TDBTEntityHandle hParent) +{ + TEntity *entity, *newparent, *oldparent; + uint32_t size = sizeof(TEntity); + uint32_t sig = cEntitySignature; + + CBlockManager::WriteTransaction trans(m_BlockManager); + + entity = m_BlockManager.ReadBlock(hEntity, size, sig); + newparent = m_BlockManager.ReadBlock(hParent, size, sig); + if (!entity || !newparent) + return DBT_INVALIDPARAM; + + oldparent = m_BlockManager.ReadBlock(entity->ParentEntity, size, sig); + if (!oldparent) + return DBT_INVALIDPARAM; + + // update parents + if (--oldparent->ChildCount == 0) + oldparent->Flags &= ~DBT_NF_HasChildren; + + if (++newparent->ChildCount == 1) + newparent->Flags |= DBT_NF_HasChildren; + + + m_BlockManager.UpdateBlock(entity->ParentEntity); + m_BlockManager.UpdateBlock(hParent); + + // update rest + + TEntityKey key; + int dif = newparent->Level - entity->Level + 1; + + if (dif == 0) // no level difference, update only moved Entity + { + key.Entity = hEntity; + key.Level = entity->Level; + key.Parent = entity->ParentEntity; + Delete(key); + key.Parent = hParent; + Insert(key); + + entity->ParentEntity = hParent; + m_BlockManager.UpdateBlock(hEntity); + + } else { + TDBTEntityIterFilter filter = {0,0,0,0}; + filter.cbSize = sizeof(filter); + filter.Options = DBT_NIFO_OSC_AC | DBT_NIFO_OC_AC; + + TDBTEntityIterationHandle iter = IterationInit(filter, hEntity); + + key.Entity = IterationNext(iter); + + while ((key.Entity != 0) && (key.Entity != DBT_INVALIDPARAM)) + { + size = sizeof(TEntity); + sig = cEntitySignature; + TEntity * child = m_BlockManager.ReadBlock(key.Entity, size, sig); + + if (child) + { + key.Level = child->Level; + key.Parent = child->ParentEntity; + Delete(key); + + if (key.Entity == hEntity) + { + key.Parent = hParent; + entity->ParentEntity = hParent; + } + + child->Level += dif; + key.Level += dif; + m_BlockManager.UpdateBlock(key.Entity); + + Insert(key); + } // TODO log + key.Entity = IterationNext(iter); + } + + IterationClose(iter); + } + + /// TODO raise event + + return entity->ParentEntity; +} + +uint32_t CEntities::getChildCount(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + if (!entity) + return DBT_INVALIDPARAM; + + return entity->ChildCount; +} + +uint32_t CEntities::getFlags(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + if (!entity) + return DBT_INVALIDPARAM; + + return entity->Flags; +} + +uint32_t CEntities::getAccount(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + if (!entity) + return DBT_INVALIDPARAM; + + if (entity->Flags & DBT_NF_IsVirtual) + return getAccount(entity->VParent); + else if (entity->Flags & (DBT_NF_IsAccount | DBT_NF_IsGroup | DBT_NF_IsRoot)) + return 0; + + return entity->Flags; +} + +TDBTEntityHandle CEntities::CreateEntity(const TDBTEntity & Entity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TDBTEntityHandle haccount = 0; + + CBlockManager::WriteTransaction trans(m_BlockManager); + + TEntity * parent = m_BlockManager.ReadBlock(Entity.hParentEntity, size, sig); + + if (!parent) + return DBT_INVALIDPARAM; + + // check account specification + if ((Entity.fFlags == 0) && (Entity.hAccountEntity != m_RootEntity)) // TODO disable root account thing, after conversion + { + TEntity * account = m_BlockManager.ReadBlock(Entity.hAccountEntity, size, sig); + if (!account || !(account->Flags & DBT_NF_IsAccount)) + return DBT_INVALIDPARAM; + + if (account->Flags & DBT_NF_IsVirtual) + { + haccount = VirtualGetParent(Entity.hAccountEntity); + } else { + haccount = Entity.hAccountEntity; + } + } + + TDBTEntityHandle hentity; + TEntity * entityblock = m_BlockManager.CreateBlock(hentity, cEntitySignature); + if (!entityblock) + return DBT_INVALIDPARAM; + + TEntityKey key; + + entityblock->Level = parent->Level + 1; + entityblock->ParentEntity = Entity.hParentEntity; + entityblock->Flags = Entity.fFlags; + entityblock->Account = haccount; + + m_BlockManager.UpdateBlock(hentity); + + key.Level = entityblock->Level; + key.Parent = entityblock->ParentEntity; + key.Entity = hentity; + + Insert(key); + + if (parent->ChildCount == 0) + parent->Flags = parent->Flags | DBT_NF_HasChildren; + + ++parent->ChildCount; + m_BlockManager.UpdateBlock(Entity.hParentEntity); + + return hentity; +} + +unsigned int CEntities::DeleteEntity(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TDBTEntityHandle haccount = 0; + + CBlockManager::WriteTransaction trans(m_BlockManager); + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (!entity) + return DBT_INVALIDPARAM; + + TEntity * parent = m_BlockManager.ReadBlock(entity->ParentEntity, size, sig); + if (!parent) + return DBT_INVALIDPARAM; + + m_sigEntityDelete.emit(this, hEntity); + + if (entity->Flags & DBT_NF_HasVirtuals) + { + // move virtuals and make one of them real + TDBTEntityHandle newreal = m_Virtuals._DeleteRealEntity(hEntity); + + TEntity * realblock = m_BlockManager.ReadBlock(newreal, size, sig); + if (realblock) + { + realblock->EventCount = entity->EventCount; + realblock->Events = entity->Events; + + m_BlockManager.UpdateBlock(newreal); + + m_sigInternalTransferEvents.emit(this, hEntity, newreal); + m_sigInternalMergeSettings.emit(this, hEntity, newreal); + + if (entity->Flags & DBT_NF_IsAccount) + _InternalTransferContacts(hEntity, newreal); + } // TODO log + } else { + m_sigInternalDeleteEvents.emit(this, hEntity); + m_sigInternalDeleteSettings.emit(this, hEntity); + + if ((entity->Flags & DBT_NF_IsAccount) && !(entity->Flags & DBT_NF_IsVirtual)) + _InternalTransferContacts(hEntity, m_RootEntity); + + } + + TEntityKey key; + key.Level = entity->Level; + key.Parent = entity->ParentEntity; + key.Entity = hEntity; + Delete(key); + + if (entity->Flags & DBT_NF_HasChildren) // keep the children + { + parent->Flags |= DBT_NF_HasChildren; + parent->ChildCount += entity->ChildCount; + + TDBTEntityIterFilter filter = {0,0,0,0}; + filter.cbSize = sizeof(filter); + filter.Options = DBT_NIFO_OSC_AC | DBT_NIFO_OC_AC; + + TDBTEntityIterationHandle iter = IterationInit(filter, hEntity); + if (iter != DBT_INVALIDPARAM) + { + IterationNext(iter); + key.Entity = IterationNext(iter); + + while ((key.Entity != 0) && (key.Entity != DBT_INVALIDPARAM)) + { + size = sizeof(TEntity); + sig = cEntitySignature; + TEntity * child = m_BlockManager.ReadBlock(key.Entity, size, sig); + if (child) + { + key.Parent = child->ParentEntity; + key.Level = child->Level; + Delete(key); + + if (key.Parent == hEntity) + { + key.Parent = entity->ParentEntity; + child->ParentEntity = entity->ParentEntity; + } + + key.Level--; + m_BlockManager.UpdateBlock(key.Entity); + + Insert(key); + + } + key.Entity = IterationNext(iter); + } + + IterationClose(iter); + } + } + + if (--parent->ChildCount == 0) + parent->Flags = parent->Flags & (~DBT_NF_HasChildren); + + m_BlockManager.UpdateBlock(entity->ParentEntity); + + m_BlockManager.DeleteBlock(hEntity); // we needed this block, delete it now + + return 0; +} + + + +TDBTEntityIterationHandle CEntities::IterationInit(const TDBTEntityIterFilter & Filter, TDBTEntityHandle hParent) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TDBTEntityHandle haccount = 0; + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntity * parent = m_BlockManager.ReadBlock(hParent, size, sig); + + if (!parent) + return DBT_INVALIDPARAM; + + PEntityIteration iter = new TEntityIteration; + iter->filter = Filter; + iter->q = new std::deque; + iter->parents = new std::deque; + iter->accounts = new std::deque; + #ifdef _MSC_VER + iter->returned = new stdext::hash_set; + #else + iter->returned = new __gnu_cxx::hash_set; + #endif + iter->returned->insert(hParent); + + TEntityIterationItem it; + it.Flags = parent->Flags; + it.Handle = hParent; + it.Level = parent->Level; + it.Options = Filter.Options & 0x000000ff; + it.LookupDepth = 0; + + iter->q->push_back(it); + + return (TDBTEntityIterationHandle)iter; +} +TDBTEntityHandle CEntities::IterationNext(TDBTEntityIterationHandle Iteration) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + PEntityIteration iter = reinterpret_cast(Iteration); + TEntityIterationItem item; + TDBTEntityHandle result = 0; + + if (iter->q->empty()) + { + std::deque * tmp = iter->q; + iter->q = iter->parents; + iter->parents = tmp; + } + + if (iter->q->empty()) + { + std::deque * tmp = iter->q; + iter->q = iter->accounts; + iter->accounts = tmp; + } + + if (iter->q->empty() && + (iter->filter.Options & DBT_NIFO_GF_USEROOT) && + (iter->returned->find(m_RootEntity) == iter->returned->end())) + { + item.Handle = m_RootEntity; + item.Level = 0; + item.Options = 0; + item.Flags = 0; + item.LookupDepth = 255; + + iter->filter.Options = iter->filter.Options & ~DBT_NIFO_GF_USEROOT; + + iter->q->push_back(item); + } + + if (iter->q->empty()) + return 0; + + do { + item = iter->q->front(); + iter->q->pop_front(); + + std::deque tmp; + TEntityIterationItem newitem; + + // children + if ((item.Flags & DBT_NF_HasChildren) && + (item.Options & DBT_NIFO_OSC_AC)) + { + TEntityKey key; + key.Parent = item.Handle; + key.Level = item.Level + 1; + + newitem.Level = item.Level + 1; + newitem.LookupDepth = item.LookupDepth; + newitem.Options = (iter->filter.Options / DBT_NIFO_OC_AC * DBT_NIFO_OSC_AC) & (DBT_NIFO_OSC_AC | DBT_NIFO_OSC_AO | DBT_NIFO_OSC_AOC | DBT_NIFO_OSC_AOP); + + if (iter->filter.Options & DBT_NIFO_GF_DEPTHFIRST) + { + key.Entity = 0xffffffff; + + CEntities::iterator c = UpperBound(key); + while ((c) && (c->Parent == item.Handle)) + { + newitem.Handle = c->Entity; + + if (iter->returned->find(newitem.Handle) == iter->returned->end()) + { + TEntity * tmp = m_BlockManager.ReadBlock(newitem.Handle, size, sig); + if (tmp) + { + newitem.Flags = tmp->Flags; + if (((newitem.Flags & DBT_NF_IsGroup) == 0) || ((DBT_NF_IsGroup & iter->filter.fHasFlags) == 0)) // if we want only groups, we don't need to trace down Entities... + { + iter->q->push_front(newitem); + iter->returned->insert(newitem.Handle); + } + } + } + + --c; + } + } else { + key.Entity = 0; + + CEntities::iterator c = LowerBound(key); + while ((c) && (c->Parent == item.Handle)) + { + newitem.Handle = c->Entity; + + if (iter->returned->find(newitem.Handle) == iter->returned->end()) + { + TEntity * tmp = m_BlockManager.ReadBlock(newitem.Handle, size, sig); + if (tmp) + { + newitem.Flags = tmp->Flags; + if (((newitem.Flags & DBT_NF_IsGroup) == 0) || ((DBT_NF_IsGroup & iter->filter.fHasFlags) == 0)) // if we want only groups, we don't need to trace down Entities... + { + iter->q->push_back(newitem); + iter->returned->insert(newitem.Handle); + } + } + } + + ++c; + } + + } + } + + // parent... + if ((item.Options & DBT_NIFO_OSC_AP) && (item.Handle != m_RootEntity)) + { + newitem.Handle = getParent(item.Handle); + if ((iter->returned->find(newitem.Handle) == iter->returned->end()) && + (newitem.Handle != DBT_INVALIDPARAM)) + { + TEntity * tmp = m_BlockManager.ReadBlock(newitem.Handle, size, sig); + if (tmp) + { + newitem.Level = item.Level - 1; + newitem.LookupDepth = item.LookupDepth; + newitem.Options = (iter->filter.Options / DBT_NIFO_OP_AC * DBT_NIFO_OSC_AC) & (DBT_NIFO_OSC_AC | DBT_NIFO_OSC_AP | DBT_NIFO_OSC_AO | DBT_NIFO_OSC_AOC | DBT_NIFO_OSC_AOP); + newitem.Flags = tmp->Flags; + + if ((newitem.Flags & iter->filter.fDontHasFlags & DBT_NF_IsGroup) == 0) // if we don't want groups, stop it + { + iter->parents->push_back(newitem); + iter->returned->insert(newitem.Handle); + } + } + } + } + + // virtual lookup, original Entity is the next one + if ((item.Flags & DBT_NF_IsVirtual) && + (item.Options & DBT_NIFO_OSC_AO) && + (((iter->filter.Options >> 28) >= item.LookupDepth) || ((iter->filter.Options >> 28) == 0))) + { + newitem.Handle = VirtualGetParent(item.Handle); + + if ((iter->returned->find(newitem.Handle) == iter->returned->end()) && + (newitem.Handle != DBT_INVALIDPARAM)) + { + TEntity * tmp = m_BlockManager.ReadBlock(newitem.Handle, size, sig); + if (tmp) + { + newitem.Level = tmp->Level; + newitem.Options = 0; + newitem.Flags = tmp->Flags; + + if ((item.Options & DBT_NIFO_OSC_AOC) == DBT_NIFO_OSC_AOC) + newitem.Options |= DBT_NIFO_OSC_AC; + if ((item.Options & DBT_NIFO_OSC_AOP) == DBT_NIFO_OSC_AOP) + newitem.Options |= DBT_NIFO_OSC_AP; + + newitem.LookupDepth = item.LookupDepth + 1; + + iter->q->push_front(newitem); + iter->returned->insert(newitem.Handle); + } + } + } + + if (((iter->filter.fHasFlags & item.Flags) == iter->filter.fHasFlags) && + ((iter->filter.fDontHasFlags & item.Flags) == 0)) + { + result = item.Handle; + + // account lookup + if (((item.Flags & (DBT_NF_IsAccount | DBT_NF_IsGroup | DBT_NF_IsRoot)) == 0) && + ((item.Options & DBT_NIFO_OC_USEACCOUNT) == DBT_NIFO_OC_USEACCOUNT)) + { + TDBTEntityHandle acc = item.Handle; + if (item.Flags & DBT_NF_IsVirtual) + acc = VirtualGetParent(item.Handle); + + acc = getAccount(acc); + + std::deque::iterator acci = iter->accounts->begin(); + + while ((acci != iter->accounts->end()) && (acc != 0)) + { + if (acci->Handle == acc) + acc = 0; + acci++; + } + if (acc != 0) + { + TEntity * tmp = m_BlockManager.ReadBlock(acc, size, sig); + if (tmp) + { + newitem.Options = 0; + newitem.LookupDepth = 0; + newitem.Handle = acc; + newitem.Flags = tmp->Flags; + newitem.Level = tmp->Level; + iter->accounts->push_back(newitem); + } + } + } + } + + } while ((result == 0) && !iter->q->empty()); + + if (result == 0) + result = IterationNext(Iteration); + + return result; +} +unsigned int CEntities::IterationClose(TDBTEntityIterationHandle Iteration) +{ + PEntityIteration iter = reinterpret_cast(Iteration); + + delete iter->q; + delete iter->parents; + delete iter->accounts; + delete iter->returned; + delete iter; + + return 0; +} + + +TDBTEntityHandle CEntities::VirtualCreate(TDBTEntityHandle hRealEntity, TDBTEntityHandle hParent) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + TDBTEntityHandle haccount = 0; + + CBlockManager::WriteTransaction trans(m_BlockManager); + + TEntity * realentity = m_BlockManager.ReadBlock(hRealEntity, size, sig); + + if (!realentity || (realentity->Flags & (DBT_NF_IsGroup | DBT_NF_IsRoot))) + return DBT_INVALIDPARAM; + + TDBTEntity entity = {0,0,0,0}; + entity.hParentEntity = hParent; + entity.fFlags = DBT_NF_IsVirtual | (realentity->Flags & DBT_NF_IsAccount); + entity.hAccountEntity = 0; + + TDBTEntityHandle result = CreateEntity(entity); + if (result == DBT_INVALIDPARAM) + return DBT_INVALIDPARAM; + + TEntity * entityblock = m_BlockManager.ReadBlock(result, size, sig); + if (!entityblock) + return DBT_INVALIDPARAM; + + if (realentity->Flags & DBT_NF_IsVirtual) + { + hRealEntity = realentity->VParent; + realentity = m_BlockManager.ReadBlock(hRealEntity, size, sig); + + if (!realentity) + return DBT_INVALIDPARAM; + } + + entityblock->VParent = hRealEntity; + m_BlockManager.UpdateBlock(result); + + if ((realentity->Flags & DBT_NF_HasVirtuals) == 0) + { + realentity->Flags |= DBT_NF_HasVirtuals; + m_BlockManager.UpdateBlock(hRealEntity); + } + + m_Virtuals._InsertVirtual(hRealEntity, result); + return result; +} + + +TDBTEntityHandle CEntities::compFirstContact() +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntityKey key = {0,0,0}; + iterator i = LowerBound(key); + TDBTEntityHandle res = 0; + + while (i && (res == 0)) + { + TEntity * tmp = m_BlockManager.ReadBlock(i->Entity, size, sig); + if (tmp) + { + if ((tmp->Flags & DBT_NFM_SpecialEntity) == 0) + res = i->Entity; + } + if (res == 0) + ++i; + } + + return res; +} +TDBTEntityHandle CEntities::compNextContact(TDBTEntityHandle hEntity) +{ + uint32_t sig = cEntitySignature; + uint32_t size = sizeof(TEntity); + + CBlockManager::ReadTransaction trans(m_BlockManager); + + TEntityKey key; + key.Entity = hEntity; + TDBTEntityHandle res = 0; + + TEntity * entity = m_BlockManager.ReadBlock(hEntity, size, sig); + + if (entity) + { + key.Level = entity->Level; + key.Parent = entity->ParentEntity; + key.Entity++; + iterator i = LowerBound(key); + + while (i && (res == 0)) + { + entity = m_BlockManager.ReadBlock(i->Entity, size, sig); + if (entity) + { + if ((entity->Flags & DBT_NFM_SpecialEntity) == 0) + res = i->Entity; + } + if (res == 0) + ++i; + } + } + + return res; +} -- cgit v1.2.3