summaryrefslogtreecommitdiff
path: root/plugins/Dbx_tree/src
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-10-12 09:56:01 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-10-12 09:56:01 +0000
commit69fe21d6e2262d6fb2b14278b7a20364468cbdcf (patch)
treed7a5c3805ba838e98e1c5288fe06962a3201c694 /plugins/Dbx_tree/src
parentbcc2cdbf65af07f2593577a4c59f93d25c2e3de9 (diff)
Dbx_tree: folders restructurization
git-svn-id: http://svn.miranda-ng.org/main/trunk@1883 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Dbx_tree/src')
-rw-r--r--plugins/Dbx_tree/src/BTree.h1358
-rw-r--r--plugins/Dbx_tree/src/BlockManager.cpp965
-rw-r--r--plugins/Dbx_tree/src/BlockManager.h401
-rw-r--r--plugins/Dbx_tree/src/Compatibility.cpp799
-rw-r--r--plugins/Dbx_tree/src/Compatibility.h30
-rw-r--r--plugins/Dbx_tree/src/DataBase.cpp371
-rw-r--r--plugins/Dbx_tree/src/DataBase.h189
-rw-r--r--plugins/Dbx_tree/src/DatabaseLink.cpp96
-rw-r--r--plugins/Dbx_tree/src/DatabaseLink.h28
-rw-r--r--plugins/Dbx_tree/src/DirectAccess.cpp118
-rw-r--r--plugins/Dbx_tree/src/DirectAccess.h43
-rw-r--r--plugins/Dbx_tree/src/EncryptionManager.cpp241
-rw-r--r--plugins/Dbx_tree/src/EncryptionManager.h107
-rw-r--r--plugins/Dbx_tree/src/Entities.cpp1032
-rw-r--r--plugins/Dbx_tree/src/Entities.h299
-rw-r--r--plugins/Dbx_tree/src/Events.cpp986
-rw-r--r--plugins/Dbx_tree/src/Events.h263
-rw-r--r--plugins/Dbx_tree/src/FileAccess.cpp299
-rw-r--r--plugins/Dbx_tree/src/FileAccess.h191
-rw-r--r--plugins/Dbx_tree/src/FileBTree.h102
-rw-r--r--plugins/Dbx_tree/src/Hash.cpp183
-rw-r--r--plugins/Dbx_tree/src/Hash.h29
-rw-r--r--plugins/Dbx_tree/src/Interface.h55
-rw-r--r--plugins/Dbx_tree/src/IterationHeap.h196
-rw-r--r--plugins/Dbx_tree/src/Logger.cpp124
-rw-r--r--plugins/Dbx_tree/src/Logger.h73
-rw-r--r--plugins/Dbx_tree/src/MREWSync.cpp330
-rw-r--r--plugins/Dbx_tree/src/MREWSync.h55
-rw-r--r--plugins/Dbx_tree/src/MappedMemory.cpp167
-rw-r--r--plugins/Dbx_tree/src/MappedMemory.h47
-rw-r--r--plugins/Dbx_tree/src/SHA256.cpp301
-rw-r--r--plugins/Dbx_tree/src/SHA256.h49
-rw-r--r--plugins/Dbx_tree/src/Services.cpp402
-rw-r--r--plugins/Dbx_tree/src/Services.h69
-rw-r--r--plugins/Dbx_tree/src/Settings.cpp1479
-rw-r--r--plugins/Dbx_tree/src/Settings.h235
-rw-r--r--plugins/Dbx_tree/src/TLS.h161
-rw-r--r--plugins/Dbx_tree/src/Thread.cpp114
-rw-r--r--plugins/Dbx_tree/src/Thread.h77
-rw-r--r--plugins/Dbx_tree/src/dbConfig_rc.h20
-rw-r--r--plugins/Dbx_tree/src/dbVersion_rc.h14
-rw-r--r--plugins/Dbx_tree/src/init.cpp73
-rw-r--r--plugins/Dbx_tree/src/intrinsics.h407
-rw-r--r--plugins/Dbx_tree/src/inttypes.h305
-rw-r--r--plugins/Dbx_tree/src/lockfree_hashmap.h749
-rw-r--r--plugins/Dbx_tree/src/lockfree_hashmultimap.h750
-rw-r--r--plugins/Dbx_tree/src/savestrings_gcc.h127
-rw-r--r--plugins/Dbx_tree/src/sigslot.h2639
-rw-r--r--plugins/Dbx_tree/src/stdint.h247
49 files changed, 17395 insertions, 0 deletions
diff --git a/plugins/Dbx_tree/src/BTree.h b/plugins/Dbx_tree/src/BTree.h
new file mode 100644
index 0000000000..20c2abfd71
--- /dev/null
+++ b/plugins/Dbx_tree/src/BTree.h
@@ -0,0 +1,1358 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <stack>
+#include "lockfree_hashmultimap.h"
+#include "sigslot.h"
+#ifdef _MSC_VER
+#include "stdint.h"
+#else
+#include <stdint.h>
+#endif
+
+#include "Logger.h"
+
+#ifndef _MSC_VER
+#ifdef offsetof
+#undef offsetof
+#endif
+#define offsetof(TYPE, MEMBER) \
+ ( (reinterpret_cast <size_t> \
+ (&reinterpret_cast <const volatile char &> \
+ (static_cast<TYPE *> (0)->MEMBER))))
+#endif
+
+template <typename TKey, uint16_t SizeParam = 4>
+class CBTree
+{
+public:
+ typedef uint32_t TNodeRef; /// 32bit indices (not storing pointers)
+ typedef sigslot::signal2< void *, TNodeRef > TOnRootChanged;
+
+ #pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+ typedef struct TNode {
+ uint16_t Info; /// Node information (IsLeaf and stored KeyCount)
+ uint16_t Signature; /// signature
+ TNodeRef Parent; /// Handle to the parent node
+ TKey Key[SizeParam * 2 - 1]; /// array with Keys
+ TNodeRef Child[SizeParam * 2]; /// array with child node handles
+ } TNode;
+
+ #pragma pack(pop)
+
+ class iterator
+ {
+ public:
+ iterator();
+ iterator(CBTree* Tree, TNodeRef Node, uint16_t Index);
+ iterator(const iterator& Other);
+ ~iterator();
+
+ CBTree * Tree();
+
+ /**
+ \brief Keeps track of changes in the tree and refresh the iterator
+ **/
+ void setManaged();
+ bool wasDeleted();
+
+ operator bool() const;
+ bool operator !() const;
+
+ const TKey & operator *();
+ const TKey * operator->();
+
+
+ bool operator == (iterator & Other);
+ bool operator < (iterator & Other);
+ bool operator > (iterator & Other);
+
+ iterator& operator =(const iterator& Other);
+
+ iterator& operator ++(); //pre ++i
+ iterator& operator --(); //pre --i
+ iterator operator ++(int); //post i++
+ iterator operator --(int); //post i--
+
+
+ protected:
+ friend class CBTree;
+
+ TNodeRef m_Node;
+ uint16_t m_Index;
+ CBTree* m_Tree;
+
+ bool m_Managed;
+ bool m_LoadedKey;
+ TKey m_ManagedKey;
+ bool m_ManagedDeleted;
+
+ void Backup();
+ void Dec();
+ void Inc();
+ void RemoveManaged(TNodeRef FromNode);
+ void InsertManaged();
+ };
+
+
+ CBTree(TNodeRef RootNode = 0);
+ virtual ~CBTree();
+
+ iterator Insert(const TKey & Key);
+ iterator Find(const TKey & Key);
+ iterator LowerBound(const TKey & Key);
+ iterator UpperBound(const TKey & Key);
+ bool Delete(const TKey & Key);
+
+ typedef sigslot::signal3<void *, const TKey &, uint32_t> TDeleteCallback;
+ void DeleteTree(TDeleteCallback * CallBack, uint32_t Param);
+
+ TNodeRef getRoot();
+ void setRoot(TNodeRef NewRoot);
+
+ TOnRootChanged & sigRootChanged() {return m_sigRootChanged;};
+
+
+protected:
+ static const uint16_t cIsLeafMask = 0x8000;
+ static const uint16_t cKeyCountMask = 0x7FFF;
+ static const uint16_t cFullNode = SizeParam * 2 - 1;
+ static const uint16_t cEmptyNode = SizeParam - 1;
+
+ typedef lockfree::hash_multimap<TNodeRef, iterator*> TManagedMap;
+
+ TNodeRef m_Root;
+ TOnRootChanged m_sigRootChanged;
+ TManagedMap m_ManagedIterators;
+
+ bool m_DestroyTree;
+
+ uint32_t m_AllocCount;
+ uint32_t m_Count;
+ uint32_t m_FreeIndex;
+ TNode * m_Alloc;
+
+ virtual void PrepareInsertOperation();
+ virtual TNode * CreateNewNode(TNodeRef & NodeRef);
+ virtual void DeleteNode(TNodeRef Node);
+ virtual TNode * Read(TNodeRef Node);
+ virtual void Write(TNodeRef Node);
+
+ void DestroyTree();
+
+
+private:
+ friend class iterator;
+
+ bool InNodeFind(const TNode * Node, const TKey & Key, uint16_t & GreaterEqual);
+ void SplitNode(TNodeRef Node, TNode * NodeData, TNodeRef & Left, TNodeRef & Right, TKey & UpKey, TNodeRef ParentNode, uint16_t ParentIndex);
+ TNodeRef MergeNodes(TNodeRef Left, TNode * LeftData, TNodeRef Right, TNode * RightData, const TKey & DownKey, TNodeRef ParentNode, uint16_t ParentIndex);
+ void KeyInsert(TNodeRef Node, TNode * NodeData, uint16_t Where);
+ void KeyDelete(TNodeRef Node, TNode * NodeData, uint16_t Where);
+ void KeyMove(TNodeRef Source, uint16_t SourceIndex, const TNode * SourceData, TNodeRef Dest, uint16_t DestIndex, TNode * DestData);
+};
+
+
+
+
+
+
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::CBTree(TNodeRef RootNode = NULL)
+: m_sigRootChanged(),
+ m_ManagedIterators()
+{
+ m_Root = RootNode;
+ m_DestroyTree = true;
+
+ m_AllocCount = 0;
+ m_Count = 0;
+ m_FreeIndex = 0;
+ m_Alloc = NULL;
+}
+
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::~CBTree()
+{
+ typename TManagedMap::iterator i = m_ManagedIterators.begin();
+ while (i != m_ManagedIterators.end())
+ {
+ i->second->m_Tree = NULL;
+ i++;
+ }
+
+ if (m_DestroyTree)
+ DestroyTree();
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline bool CBTree<TKey, SizeParam>::InNodeFind(const TNode * Node, const TKey & Key, uint16_t & GreaterEqual)
+{
+ uint16_t l = 0;
+ uint16_t r = (Node->Info & cKeyCountMask);
+ bool res = false;
+ GreaterEqual = 0;
+ while ((l < r) && !res)
+ {
+ GreaterEqual = (l + r) >> 1;
+ if (Node->Key[GreaterEqual] < Key)
+ {
+ GreaterEqual++;
+ l = GreaterEqual;
+ } else if (Node->Key[GreaterEqual] == Key)
+ {
+ //r = -1;
+ res = true;
+ } else {
+ r = GreaterEqual;
+ }
+ }
+
+ return res;
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::SplitNode(TNodeRef Node, TNode * NodeData, TNodeRef & Left, TNodeRef & Right, TKey & UpKey, TNodeRef ParentNode, uint16_t ParentIndex)
+{
+ const uint16_t upindex = SizeParam - 1;
+ TNode *ldata, *rdata;
+ Left = Node;
+ ldata = NodeData;
+ rdata = CreateNewNode(Right);
+
+ typename TManagedMap::iterator it = m_ManagedIterators.find(Node);
+ while ((it != m_ManagedIterators.end()) && (it->first == Node))
+ {
+ if (it->second->m_Index == upindex)
+ {
+ it->second->m_Index = ParentIndex;
+ it->second->m_Node = ParentNode;
+ m_ManagedIterators.insert(std::make_pair(ParentNode, it->second));
+ it = m_ManagedIterators.erase(it);
+ } else if (it->second->m_Index > upindex)
+ {
+ it->second->m_Index = it->second->m_Index - upindex - 1;
+ it->second->m_Node = Right;
+ m_ManagedIterators.insert(std::make_pair(Right, it->second));
+ it = m_ManagedIterators.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ UpKey = NodeData->Key[upindex];
+
+ memcpy(&(rdata->Key[0]), &(NodeData->Key[upindex+1]), sizeof(TKey) * (cFullNode - upindex));
+ if ((NodeData->Info & cIsLeafMask) == 0)
+ {
+ memcpy(&(rdata->Child[0]), &(NodeData->Child[upindex+1]), sizeof(TNodeRef) * (cFullNode - upindex + 1));
+
+ for (int i = 0; i <= upindex; i++)
+ {
+ TNode * tmp = Read(rdata->Child[i]);
+ tmp->Parent = Right;
+ Write(rdata->Child[i]);
+ }
+ }
+
+ rdata->Info = (NodeData->Info & cIsLeafMask) | upindex;
+ NodeData->Info = rdata->Info;
+ rdata->Parent = NodeData->Parent;
+
+ Write(Left);
+ Write(Right);
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline typename CBTree<TKey, SizeParam>::TNodeRef CBTree<TKey, SizeParam>::MergeNodes(TNodeRef Left, TNode * LeftData, TNodeRef Right, TNode * RightData, const TKey & DownKey, TNodeRef ParentNode, uint16_t ParentIndex)
+{
+ uint16_t downindex = LeftData->Info & cKeyCountMask;
+ LeftData->Key[downindex] = DownKey;
+
+ typename TManagedMap::iterator it = m_ManagedIterators.find(Right);
+ while ((it != m_ManagedIterators.end()) && (it->first == Right))
+ {
+ it->second->m_Index = it->second->m_Index + downindex + 1;
+ it->second->m_Node = Left;
+ m_ManagedIterators.insert(std::make_pair(Left, it->second));
+ it = m_ManagedIterators.erase(it);
+ }
+
+ it = m_ManagedIterators.find(ParentNode);
+ while ((it != m_ManagedIterators.end()) && (it->first == ParentNode))
+ {
+ if (it->second->m_Index == ParentIndex)
+ {
+ it->second->m_Index = downindex;
+ it->second->m_Node = Left;
+ m_ManagedIterators.insert(std::make_pair(Left, it->second));
+ it = m_ManagedIterators.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ memcpy(&(LeftData->Key[downindex+1]), &(RightData->Key[0]), sizeof(TKey) * (RightData->Info & cKeyCountMask));
+ if ((LeftData->Info & cIsLeafMask) == 0)
+ {
+ memcpy(&(LeftData->Child[downindex+1]), &(RightData->Child[0]), sizeof(TNodeRef) * ((RightData->Info & cKeyCountMask) + 1));
+
+ for (int i = 0; i <= (RightData->Info & cKeyCountMask); i++)
+ {
+ TNode * tmp = Read(RightData->Child[i]);
+ tmp->Parent = Left;
+ Write(RightData->Child[i]);
+ }
+ }
+
+ LeftData->Info = ((LeftData->Info & cIsLeafMask) | (downindex + 1 + (RightData->Info & cKeyCountMask)));
+
+ Write(Left);
+ DeleteNode(Right);
+
+ return Left;
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::KeyInsert(TNodeRef Node, TNode * NodeData, uint16_t Where)
+{
+ memcpy(&(NodeData->Key[Where+1]), &(NodeData->Key[Where]), sizeof(TKey) * ((NodeData->Info & cKeyCountMask) - Where));
+
+ if ((NodeData->Info & cIsLeafMask) == 0)
+ memcpy(&(NodeData->Child[Where+1]), &(NodeData->Child[Where]), sizeof(TNodeRef) * ((NodeData->Info & cKeyCountMask) - Where + 1));
+
+ NodeData->Info++;
+
+ typename TManagedMap::iterator it = m_ManagedIterators.find(Node);
+ while ((it != m_ManagedIterators.end()) && (it->first == Node))
+ {
+ if (it->second->m_Index >= Where)
+ it->second->m_Index++;
+
+ ++it;
+ }
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::KeyDelete(TNodeRef Node, TNode * NodeData, uint16_t Where)
+{
+ NodeData->Info--;
+
+ typename TManagedMap::iterator it = m_ManagedIterators.find(Node);
+ while ((it != m_ManagedIterators.end()) && (it->first == Node))
+ {
+ if (it->second->m_Index == Where)
+ {
+ it->second->Backup();
+ } else if (it->second->m_Index > Where)
+ {
+ it->second->m_Index--;
+ }
+
+ ++it;
+ }
+
+ memcpy(&(NodeData->Key[Where]), &(NodeData->Key[Where+1]), sizeof(TKey) * ((NodeData->Info & cKeyCountMask) - Where));
+
+ if ((NodeData->Info & cIsLeafMask) == 0)
+ memcpy(&(NodeData->Child[Where]), &(NodeData->Child[Where+1]), sizeof(TNodeRef) * ((NodeData->Info & cKeyCountMask) - Where + 1));
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::KeyMove(TNodeRef Source, uint16_t SourceIndex, const TNode * SourceData, TNodeRef Dest, uint16_t DestIndex, TNode * DestData)
+{
+ DestData->Key[DestIndex] = SourceData->Key[SourceIndex];
+
+ typename TManagedMap::iterator it = m_ManagedIterators.find(Source);
+ while ((it != m_ManagedIterators.end()) && (it->first == Source))
+ {
+ if (it->second->m_Index == SourceIndex)
+ {
+ it->second->m_Index = DestIndex;
+ it->second->m_Node = Dest;
+ m_ManagedIterators.insert(std::make_pair(Dest, it->second));
+ it = m_ManagedIterators.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::Insert(const TKey & Key)
+{
+ TNode *node, *node2;
+ TNodeRef actnode;
+ TNodeRef nextnode;
+ bool exists;
+ uint16_t ge;
+
+ PrepareInsertOperation();
+
+ if (!m_Root)
+ {
+ node = CreateNewNode(m_Root);
+ node->Info = cIsLeafMask;
+ Write(m_Root);
+ m_sigRootChanged.emit(this, m_Root);
+ }
+
+ actnode = m_Root;
+ node = Read(actnode);
+ if ((node->Info & cKeyCountMask) == cFullNode) // root split
+ {
+ // be a little tricky and let the main code handle the actual splitting.
+ // just assign a new root with keycount to zero and one child = old root
+ // the InNode test will fail with GreaterEqual = 0
+ node2 = CreateNewNode(nextnode);
+ node2->Info = 0;
+ node2->Child[0] = actnode;
+ Write(nextnode);
+
+ node->Parent = nextnode;
+ Write(actnode);
+
+ node = node2;
+ actnode = nextnode;
+
+ m_Root = nextnode;
+ m_sigRootChanged.emit(this, m_Root);
+ }
+
+ while (actnode)
+ {
+ exists = InNodeFind(node, Key, ge);
+ if (exists) // already exists
+ {
+ return iterator(this, actnode, ge);
+ } else {
+ if (node->Info & cIsLeafMask) // direct insert to leaf node
+ {
+ KeyInsert(actnode, node, ge);
+
+ node->Key[ge] = Key;
+
+ Write(actnode);
+
+ return iterator(this, actnode, ge);
+
+ } else { // middle node
+ nextnode = node->Child[ge];
+ node2 = Read(nextnode);
+
+ if ((node2->Info & cKeyCountMask) == cFullNode) // split the childnode
+ {
+ KeyInsert(actnode, node, ge);
+ SplitNode(nextnode, node2, node->Child[ge], node->Child[ge+1], node->Key[ge], actnode, ge);
+
+ Write(actnode);
+ if (node->Key[ge] == Key)
+ {
+ return iterator(this, actnode, ge);
+ } else {
+ if (node->Key[ge] < Key)
+ {
+ nextnode = node->Child[ge+1];
+ } else {
+ nextnode = node->Child[ge];
+ }
+ }
+
+ }
+ actnode = nextnode;
+ node = Read(actnode);
+
+ } // if (node.Info & cIsLeafMask)
+ } // if (exists)
+ } // while (actnode)
+
+ // something went wrong
+ return iterator(this, 0, 0xFFFF);
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::Find(const TKey & Key)
+{
+ TNode * node;
+ TNodeRef actnode = m_Root;
+ uint16_t ge;
+
+ if (!m_Root) return iterator(this, 0, 0xFFFF);
+
+ node = Read(actnode);
+
+ while (actnode)
+ {
+ if (InNodeFind(node, Key, ge))
+ {
+ return iterator(this, actnode, ge);
+ }
+
+ if (!(node->Info & cIsLeafMask))
+ {
+ actnode = node->Child[ge];
+ node = Read(actnode);
+ } else {
+ actnode = 0;
+ }
+ }
+
+ return iterator(this, 0, 0xFFFF);
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::LowerBound(const TKey & Key)
+{
+ TNode * node;
+ TNodeRef actnode = m_Root;
+ uint16_t ge;
+
+ if (!m_Root) return iterator(this, 0, 0xFFFF);
+
+ node = Read(actnode);
+
+ while (actnode)
+ {
+ if (InNodeFind(node, Key, ge))
+ {
+ return iterator(this, actnode, ge);
+ }
+
+ if (node->Info & cIsLeafMask)
+ {
+ if (ge >= (node->Info & cKeyCountMask))
+ {
+ iterator i(this, actnode, ge - 1);
+ ++i;
+ return i;
+ } else {
+ return iterator(this, actnode, ge);
+ }
+ } else {
+ actnode = node->Child[ge];
+ node = Read(actnode);
+ }
+ }
+
+ return iterator(this, 0, 0xFFFF);
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::UpperBound(const TKey & Key)
+{
+ TNode * node;
+ TNodeRef actnode = m_Root;
+ uint16_t ge;
+ if (!m_Root) return iterator(this, 0, 0xFFFF);
+
+ node = Read(actnode);
+
+ while (actnode)
+ {
+ if (InNodeFind(node, Key, ge))
+ {
+ return iterator(this, actnode, ge);
+ }
+
+ if (node->Info & cIsLeafMask)
+ {
+ if (ge == 0)
+ {
+ iterator i(this, actnode, 0);
+ --i;
+ return i;
+ } else {
+ return iterator(this, actnode, ge - 1);
+ }
+ } else {
+ actnode = node->Child[ge];
+ node = Read(actnode);
+ }
+ }
+
+ return iterator(this, 0, 0xFFFF);
+}
+
+template <typename TKey, uint16_t SizeParam>
+bool CBTree<TKey, SizeParam>::Delete(const TKey& Key)
+{
+ if (!m_Root) return false;
+
+ TNode *node, *node2, *lnode, *rnode;
+
+ TNodeRef actnode = m_Root;
+ TNodeRef nextnode, l, r;
+ bool exists, skipread;
+ uint16_t ge;
+
+ bool foundininnernode = false;
+ bool wantleftmost = false;
+ TNodeRef innernode = 0;
+ TNode * innernodedata = NULL;
+ uint16_t innerindex = 0xFFFF;
+
+ node = Read(actnode);
+
+ while (actnode)
+ {
+ skipread = false;
+
+ if (foundininnernode)
+ {
+ exists = false;
+ if (wantleftmost)
+ ge = 0;
+ else
+ ge = node->Info & cKeyCountMask;
+
+ } else {
+ exists = InNodeFind(node, Key, ge);
+ }
+
+ if (exists)
+ {
+ if (node->Info & cIsLeafMask) // delete in leaf
+ {
+ KeyDelete(actnode, node, ge);
+ Write(actnode);
+
+ return true;
+
+ } else { // delete in inner node
+ l = node->Child[ge];
+ r = node->Child[ge+1];
+ lnode = Read(l);
+ rnode = Read(r);
+
+
+ if (((rnode->Info & cKeyCountMask) == cEmptyNode) && ((lnode->Info & cKeyCountMask) == cEmptyNode))
+ { // merge childnodes and keep going
+ nextnode = MergeNodes(l, lnode, r, rnode, node->Key[ge], actnode, ge);
+
+ KeyDelete(actnode, node, ge);
+ node->Child[ge] = nextnode;
+
+ if ((actnode == m_Root) && ((node->Info & cKeyCountMask) == 0))
+ { // root node is empty. delete it
+ DeleteNode(actnode);
+ m_Root = nextnode;
+ m_sigRootChanged.emit(this, m_Root);
+ } else {
+ Write(actnode);
+ }
+
+ } else { // need a key-data-pair from a leaf to replace deleted pair -> save position
+ foundininnernode = true;
+ innernode = actnode;
+ innerindex = ge;
+ innernodedata = node;
+
+ if ((lnode->Info & cKeyCountMask) == cEmptyNode)
+ {
+ wantleftmost = true;
+ nextnode = r;
+ } else {
+ wantleftmost = false;
+ nextnode = l;
+ }
+ }
+ }
+
+ } else if (node->Info & cIsLeafMask) { // we are at the bottom. finish it
+ if (foundininnernode)
+ {
+ if (wantleftmost)
+ {
+ KeyMove(actnode, 0, node, innernode, innerindex, innernodedata);
+ Write(innernode);
+
+ KeyDelete(actnode, node, 0);
+ Write(actnode);
+
+ } else {
+ KeyMove(actnode, (node->Info & cKeyCountMask) - 1, node, innernode, innerindex, innernodedata);
+ Write(innernode);
+
+ //KeyDelete(actnode, node, node.Info & cKeyCountMask);
+ node->Info--;
+ Write(actnode);
+ }
+ }
+ return foundininnernode;
+
+ } else { // inner node. go on and check if moving or merging is neccessary
+ nextnode = node->Child[ge];
+ node2 = Read(nextnode);
+
+ if ((node2->Info & cKeyCountMask) == cEmptyNode) // move or merge
+ {
+ // set l and r for easier access
+ if (ge > 0)
+ {
+ l = node->Child[ge - 1];
+ lnode = Read(l);
+ } else
+ l = 0;
+
+ if (ge < (node->Info & cKeyCountMask))
+ {
+ r = node->Child[ge + 1];
+ rnode = Read(r);
+ } else
+ r = 0;
+
+ if ((r != 0) && ((rnode->Info & cKeyCountMask) > cEmptyNode)) // move a Key-Data-pair from the right
+ {
+ // move key-data-pair down from current to the next node
+ KeyMove(actnode, ge, node, nextnode, node2->Info & cKeyCountMask, node2);
+
+ // move the child from right to next node
+ node2->Child[(node2->Info & cKeyCountMask) + 1] = rnode->Child[0];
+
+ // move key-data-pair up from right to current node
+ KeyMove(r, 0, rnode, actnode, ge, node);
+ Write(actnode);
+
+ // decrement right node key count and remove the first key-data-pair
+ KeyDelete(r, rnode, 0);
+
+ // increment KeyCount of the next node
+ node2->Info++;
+
+ if ((node2->Info & cIsLeafMask) == 0) // update the parent property of moved child
+ {
+ TNode * tmp = Read(node2->Child[node2->Info & cKeyCountMask]);
+ tmp->Parent = nextnode;
+ Write(node2->Child[node2->Info & cKeyCountMask]);
+ }
+
+
+ Write(r);
+ Write(nextnode);
+ node = node2;
+ skipread = true;
+
+ } else if ((l != 0) && ((lnode->Info & cKeyCountMask) > cEmptyNode)) // move a Key-Data-pair from the left
+ {
+ // increment next node key count and make new first key-data-pair
+ KeyInsert(nextnode, node2, 0);
+
+ // move key-data-pair down from current to the next node
+ KeyMove(actnode, ge - 1, node, nextnode, 0, node2);
+
+ // move the child from left to next node
+ node2->Child[0] = lnode->Child[lnode->Info & cKeyCountMask];
+
+ // move key-data-pair up from left to current node
+ KeyMove(l, (lnode->Info & cKeyCountMask) - 1, lnode, actnode, ge - 1, node);
+ Write(actnode);
+
+ // decrement left node key count
+ lnode->Info--;
+ Write(l);
+
+ if ((node2->Info & cIsLeafMask) == 0) // update the parent property of moved child
+ {
+ TNode * tmp = Read(node2->Child[0]);
+ tmp->Parent = nextnode;
+ Write(node2->Child[0]);
+ }
+
+ Write(nextnode);
+ node = node2;
+ skipread = true;
+
+ } else {
+ if (l != 0) // merge with the left node
+ {
+ nextnode = MergeNodes(l, lnode, nextnode, node2, node->Key[ge - 1], actnode, ge - 1);
+ KeyDelete(actnode, node, ge - 1);
+ node->Child[ge - 1] = nextnode;
+
+ } else { // merge with the right node
+ nextnode = MergeNodes(nextnode, node2, r, rnode, node->Key[ge], actnode, ge);
+ KeyDelete(actnode, node, ge);
+ node->Child[ge] = nextnode;
+ }
+
+ if ((actnode == m_Root) && ((node->Info & cKeyCountMask) == 0))
+ {
+ DeleteNode(actnode);
+ m_Root = nextnode;
+ m_sigRootChanged(this, nextnode);
+ } else {
+ Write(actnode);
+ }
+ }
+ }
+ } // if (exists) else if (node.Info & cIsLeafMask)
+
+ actnode = nextnode;
+ if (!skipread)
+ node = Read(actnode);
+
+ } // while(actnode)
+
+ return false;
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::TNodeRef CBTree<TKey, SizeParam>::getRoot()
+{
+ return m_Root;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::setRoot(TNodeRef NewRoot)
+{
+ m_Root = NewRoot;
+ return;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::PrepareInsertOperation()
+{
+ if (m_Count + 64 > m_AllocCount)
+ {
+ m_AllocCount += 64;
+ m_Alloc = (TNode *)realloc(m_Alloc, sizeof(TNode) * m_AllocCount);
+
+ for (TNodeRef i = m_AllocCount - 64; i < m_AllocCount; ++i)
+ m_Alloc[i].Parent = i + 1;
+
+ m_Alloc[m_AllocCount - 1].Parent = 0;
+
+ if (m_FreeIndex)
+ {
+ TNodeRef i = m_FreeIndex;
+ while (m_Alloc[i].Parent)
+ i = m_Alloc[i].Parent;
+
+ m_Alloc[i].Parent = m_AllocCount - 64;
+
+ } else {
+ m_FreeIndex = m_AllocCount - 63;
+ }
+
+ }
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::TNode * CBTree<TKey, SizeParam>::CreateNewNode(TNodeRef & NodeRef)
+{
+ NodeRef = m_FreeIndex;
+ m_FreeIndex = m_Alloc[m_FreeIndex].Parent;
+ m_Count++;
+ memset(m_Alloc + NodeRef, 0, sizeof(TNode));
+ return m_Alloc + NodeRef;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::DeleteNode(TNodeRef Node)
+{
+ CHECK((Node > 0) && (Node < m_AllocCount), logERROR, _T("Invalid Node"));
+ m_Alloc[Node].Parent = m_FreeIndex;
+ m_FreeIndex = Node;
+ m_Count--;
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::TNode * CBTree<TKey, SizeParam>::Read(TNodeRef Node)
+{
+ CHECK((Node > 0) && (Node < m_AllocCount), logERROR, _T("Invalid Node"));
+ return m_Alloc + Node;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::Write(TNodeRef Node)
+{
+ return;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::DestroyTree()
+{
+ std::stack<TNodeRef> s;
+ TNodeRef node;
+ TNode* nodedata;
+ uint16_t i;
+
+ if (m_Root)
+ s.push(m_Root);
+ while (!s.empty())
+ {
+ node = s.top();
+ nodedata = Read(node);
+ s.pop();
+
+ if ((nodedata->Info & cIsLeafMask) == 0)
+ {
+ for (i = 0; i <= (nodedata->Info & cKeyCountMask); i++)
+ s.push(nodedata->Child[i]);
+ }
+
+ DeleteNode(node);
+ }
+
+ if (m_Alloc)
+ free(m_Alloc);
+ m_Alloc = NULL;
+ m_AllocCount = 0;
+ m_Count = 0;
+ m_FreeIndex = 0;
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::DeleteTree(TDeleteCallback * CallBack, uint32_t Param)
+{
+ std::stack<TNodeRef> s;
+ TNodeRef actnode;
+ TNode * node;
+ uint16_t i;
+
+ typename TManagedMap::iterator it = m_ManagedIterators.begin();
+ while (it != m_ManagedIterators.end())
+ {
+ it->second->m_Node = 0;
+ it->second->m_Index = 0xffff;
+ ++it;
+ }
+
+ if (m_Root)
+ s.push(m_Root);
+
+ m_Root = 0;
+ m_sigRootChanged.emit(this, m_Root);
+
+ while (!s.empty())
+ {
+ actnode = s.top();
+ s.pop();
+
+ node = Read(actnode);
+
+ if ((node->Info & cIsLeafMask) == 0)
+ {
+ for (i = 0; i <= (node->Info & cKeyCountMask); i++)
+ s.push(node->Child[i]);
+
+ }
+ if (CallBack)
+ {
+ for (i = 0; i < (node->Info & cKeyCountMask); i++)
+ CallBack->emit(this, node->Key[i], Param);
+ }
+
+ DeleteNode(actnode);
+ }
+}
+
+
+
+
+
+
+
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::iterator::iterator()
+{
+ m_Tree = NULL;
+ m_Node = 0;
+ m_Index = 0xFFFF;
+ m_Managed = false;
+ m_ManagedDeleted = false;
+ m_LoadedKey = false;
+}
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::iterator::iterator(CBTree* Tree, TNodeRef Node, uint16_t Index)
+{
+ m_Tree = Tree;
+ m_Node = Node;
+ m_Index = Index;
+ m_Managed = false;
+ m_ManagedDeleted = false;
+ m_LoadedKey = false;
+}
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::iterator::iterator(const iterator& Other)
+{
+ m_Tree = Other.m_Tree;
+ m_Node = Other.m_Node;
+ m_Index = Other.m_Index;
+ m_ManagedDeleted = Other.m_ManagedDeleted;
+ m_Managed = Other.m_Managed;
+ m_LoadedKey = Other.m_LoadedKey;
+ m_ManagedKey = Other.m_ManagedKey;
+
+ if (m_Managed)
+ InsertManaged();
+}
+
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam>::iterator::~iterator()
+{
+ RemoveManaged(m_Node);
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::iterator::setManaged()
+{
+ if (!m_Managed)
+ InsertManaged();
+
+ m_Managed = true;
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::iterator::RemoveManaged(TNodeRef FromNode)
+{
+ if (m_Managed && m_Tree)
+ {
+ typename TManagedMap::iterator i = m_Tree->m_ManagedIterators.find(FromNode);
+
+ while ((i != m_Tree->m_ManagedIterators.end()) && (i->second != this) && (i->first == FromNode))
+ ++i;
+
+ if ((i != m_Tree->m_ManagedIterators.end()) && (i->second == this))
+ m_Tree->m_ManagedIterators.erase(i);
+ }
+}
+template <typename TKey, uint16_t SizeParam>
+inline void CBTree<TKey, SizeParam>::iterator::InsertManaged()
+{
+ if (m_Tree)
+ m_Tree->m_ManagedIterators.insert(std::make_pair(m_Node, this));
+}
+
+template <typename TKey, uint16_t SizeParam>
+bool CBTree<TKey, SizeParam>::iterator::wasDeleted()
+{
+ return m_ManagedDeleted;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::iterator::Backup()
+{
+ if ((!m_ManagedDeleted) && (*this))
+ {
+ TNode * tmp;
+ if (!m_LoadedKey)
+ {
+ tmp = m_Tree->Read(m_Node);
+ m_ManagedKey = tmp->Key[m_Index];
+ }
+ m_LoadedKey = true;
+ }
+
+ m_ManagedDeleted = true;
+}
+
+template <typename TKey, uint16_t SizeParam>
+CBTree<TKey, SizeParam> * CBTree<TKey, SizeParam>::iterator::Tree()
+{
+ return m_Tree;
+}
+
+template <typename TKey, uint16_t SizeParam>
+const TKey& CBTree<TKey, SizeParam>::iterator::operator *()
+{
+ if (!m_LoadedKey)
+ {
+ TNode * node;
+ node = m_Tree->Read(m_Node);
+ m_ManagedKey = node->Key[m_Index];
+ m_LoadedKey = true;
+ }
+ return m_ManagedKey;
+}
+
+template <typename TKey, uint16_t SizeParam>
+const TKey* CBTree<TKey, SizeParam>::iterator::operator ->()
+{
+ if (!m_LoadedKey)
+ {
+ TNode * node;
+ node = m_Tree->Read(m_Node);
+ m_ManagedKey = node->Key[m_Index];
+ m_LoadedKey = true;
+ }
+ return &m_ManagedKey;
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline CBTree<TKey, SizeParam>::iterator::operator bool() const
+{
+ if (m_Tree && m_Node)
+ {
+ TNode * node;
+ node = m_Tree->Read(m_Node);
+ return (m_Index < (node->Info & cKeyCountMask));
+ } else
+ return false;
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline bool CBTree<TKey, SizeParam>::iterator::operator !() const
+{
+ if (m_Tree && m_Node)
+ {
+ TNode * node;
+ node = m_Tree->Read(m_Node);
+ return (m_Index > (node->Info & cKeyCountMask));
+ } else
+ return true;
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline bool CBTree<TKey, SizeParam>::iterator::operator ==(iterator & Other)
+{
+ //return (m_Tree == Other.m_Tree) && (m_Node == Other.m_Node) && (m_Index == Other.m_Index) && (!m_ManagedDeleted) && (!Other.m_ManagedDeleted);
+ return Key() == Other.Key();
+}
+
+template <typename TKey, uint16_t SizeParam>
+inline bool CBTree<TKey, SizeParam>::iterator::operator < (iterator & Other)
+{
+ return Key() < Other.Key();
+}
+template <typename TKey, uint16_t SizeParam>
+inline bool CBTree<TKey, SizeParam>::iterator::operator > (iterator & Other)
+{
+ return Key() > Other.Key();
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator&
+CBTree<TKey, SizeParam>::iterator::operator =(const iterator& Other)
+{
+ RemoveManaged(m_Node);
+
+ m_Tree = Other.m_Tree;
+ m_Node = Other.m_Node;
+ m_Index = Other.m_Index;
+ m_ManagedDeleted = Other.m_ManagedDeleted;
+ m_Managed = Other.m_Managed;
+ m_LoadedKey = Other.m_LoadedKey;
+ m_ManagedKey = Other.m_ManagedKey;
+
+ if (m_Managed)
+ InsertManaged();
+
+ return *this;
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator&
+CBTree<TKey, SizeParam>::iterator::operator ++() //pre ++i
+{
+ TNodeRef oldnode = m_Node;
+ if (m_Managed && m_ManagedDeleted)
+ {
+ TKey oldkey = m_ManagedKey;
+ m_LoadedKey = false;
+ m_ManagedDeleted = false;
+ iterator other = m_Tree->LowerBound(m_ManagedKey);
+ m_Node = other.m_Node;
+ m_Index = other.m_Index;
+ while (((**this) == oldkey) && (*this))
+ Inc();
+
+ } else
+ Inc();
+
+ if (m_Managed && (oldnode != m_Node))
+ {
+ RemoveManaged(oldnode);
+ InsertManaged();
+ }
+ return *this;
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator&
+CBTree<TKey, SizeParam>::iterator::operator --() //pre --i
+{
+ TNodeRef oldnode = m_Node;
+ if (m_Managed && m_ManagedDeleted)
+ {
+ TKey oldkey = m_ManagedKey;
+ m_LoadedKey = false;
+
+ m_ManagedDeleted = false;
+ iterator other = m_Tree->UpperBound(m_ManagedKey);
+ m_Node = other.m_Node;
+ m_Index = other.m_Index;
+ while (((**this) == oldkey) && (*this))
+ Dec();
+ } else
+ Dec();
+
+ if (m_Managed && (oldnode != m_Node))
+ {
+ RemoveManaged(oldnode);
+ InsertManaged();
+ }
+ return *this;
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::iterator::operator ++(int) //post i++
+{
+ iterator tmp(*this);
+ ++(*this);
+ return tmp;
+}
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::iterator
+CBTree<TKey, SizeParam>::iterator::operator --(int) //post i--
+{
+ iterator tmp(*this);
+ --(*this);
+ return tmp;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::iterator::Inc()
+{
+ TNode * node;
+ TNodeRef nextnode;
+ node = m_Tree->Read(m_Node);
+
+ m_LoadedKey = false;
+
+ if ((node->Info & cIsLeafMask) && ((node->Info & cKeyCountMask) > m_Index + 1)) // leaf
+ {
+ m_Index++;
+ return;
+ }
+
+ if ((node->Info & cIsLeafMask) == 0) // inner node. go down
+ {
+ m_Node = node->Child[m_Index + 1];
+ node = m_Tree->Read(m_Node);
+
+ m_Index = 0;
+
+ while ((node->Info & cIsLeafMask) == 0) // go down to a leaf
+ {
+ m_Node = node->Child[0];
+ node = m_Tree->Read(m_Node);
+ }
+
+ return;
+ }
+
+ while (m_Index >= (node->Info & cKeyCountMask) - 1) // go up
+ {
+ if (m_Node == m_Tree->m_Root) // the root is the top, we cannot go further
+ {
+ m_Index = 0xFFFF;
+ m_Node = 0;
+ return;
+ }
+
+ nextnode = node->Parent;
+ node = m_Tree->Read(nextnode);
+ m_Index = 0;
+
+ while ((m_Index <= (node->Info & cKeyCountMask)) && (node->Child[m_Index] != m_Node))
+ m_Index++;
+
+ m_Node = nextnode;
+
+ if (m_Index < (node->Info & cKeyCountMask))
+ return;
+ }
+
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CBTree<TKey, SizeParam>::iterator::Dec()
+{
+ TNode * node;
+ TNodeRef nextnode;
+ node = m_Tree->Read(m_Node);
+
+ m_LoadedKey = false;
+
+ if ((node->Info & cIsLeafMask) && (m_Index > 0)) // leaf
+ {
+ m_Index--;
+ return;
+ }
+
+ if ((node->Info & cIsLeafMask) == 0) // inner node. go down
+ {
+ m_Node = node->Child[m_Index];
+ node = m_Tree->Read(m_Node);
+ m_Index = (node->Info & cKeyCountMask) - 1;
+
+ while ((node->Info & cIsLeafMask) == 0) // go down to a leaf
+ {
+ m_Node = node->Child[node->Info & cKeyCountMask];
+ node = m_Tree->Read(m_Node);
+ m_Index = (node->Info & cKeyCountMask) - 1;
+ }
+
+ return;
+ }
+
+ while (m_Index == 0) // go up
+ {
+ if (m_Node == m_Tree->m_Root) // the root is the top, we cannot go further
+ {
+ m_Index = 0xFFFF;
+ m_Node = 0;
+ return;
+ }
+
+ nextnode = node->Parent;
+ node = m_Tree->Read(nextnode);
+ m_Index = 0;
+
+ while ((m_Index <= (node->Info & cKeyCountMask)) && (node->Child[m_Index] != m_Node))
+ m_Index++;
+
+ m_Node = nextnode;
+
+ if (m_Index > 0)
+ {
+ m_Index--;
+ return;
+ }
+ }
+}
diff --git a/plugins/Dbx_tree/src/BlockManager.cpp b/plugins/Dbx_tree/src/BlockManager.cpp
new file mode 100644
index 0000000000..b52298602f
--- /dev/null
+++ b/plugins/Dbx_tree/src/BlockManager.cpp
@@ -0,0 +1,965 @@
+/*
+
+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 "BlockManager.h"
+#include "Logger.h"
+
+CBlockManager::CBlockManager(
+ CFileAccess & FileAccess,
+ CEncryptionManager & EncryptionManager
+ )
+: m_BlockSync(),
+ m_FileAccess(FileAccess),
+ m_EncryptionManager(EncryptionManager),
+ m_BlockTable(1024),
+ m_FreeBlocks()
+{
+ m_Optimize.Thread = NULL;
+ m_Optimize.Source = 0;
+ m_Optimize.Dest = 0;
+
+ m_CacheInfo.Growth = 0;
+ m_CacheInfo.Size = 0;
+ m_CacheInfo.LastPurge = time(NULL);
+
+ m_PendingHead = NULL;
+ m_PendingTail = NULL;
+ m_PendingLast = NULL;
+ m_LastFlush = time(NULL);
+ m_BytesPending = 20;
+ m_FirstFreeIndex = 0;
+
+ m_SaveMode = true;
+ m_ReadOnly = m_FileAccess.ReadOnly();
+
+ memset(m_Cache, 0, sizeof(m_Cache));
+}
+
+CBlockManager::~CBlockManager()
+{
+ m_BlockSync.BeginWrite();
+ if (m_Optimize.Thread)
+ {
+ m_Optimize.Thread->FreeOnTerminate(false);
+ m_Optimize.Thread->Terminate();
+
+ m_BlockSync.EndWrite();
+ m_Optimize.Thread->WaitFor();
+
+ delete m_Optimize.Thread;
+ } else {
+ m_BlockSync.EndWrite();
+ }
+
+ _PendingFlush(true);
+
+ for (uint32_t buddy = 0; buddy < cCacheBuddyCount; buddy++)
+ {
+ TCacheEntry * i = m_Cache[buddy];
+ while (i)
+ {
+ free(i->Cache);
+
+ TCacheEntry * tmp = i;
+ i = i->Next;
+ free(tmp);
+ }
+ }
+}
+
+// Optimize File Size
+void CBlockManager::ExecuteOptimize()
+{ /*
+ TBlockHeadFree h = {0,0};
+ uint8_t * buf = (uint8_t*)malloc(1 << 18); // 256kb
+ uint32_t bufuse = 0;
+ uint32_t bufsize = 1 << 18;
+ uint32_t lastflush = 0;
+
+ {
+ int i = 0;
+ while (!m_Optimize.Thread->Terminated() && (i < 600))
+ {
+ ++i;
+ Sleep(100); // wait for Miranda to start
+ }
+ }
+
+ TransactionBeginWrite();
+
+ while (!m_Optimize.Thread->Terminated() && (m_Optimize.Source < m_FileAccess.Size()) && !m_ReadOnly)
+ {
+ m_FileAccess.Read(&h, m_Optimize.Source, sizeof(h));
+ if (h.ID == cFreeBlockID)
+ {
+ _RemoveFreeBlock(m_Optimize.Source, h.Size);
+
+ m_Optimize.Source += h.Size;
+ } else {
+
+ if (bufsize < bufuse + h.Size)
+ {
+ buf = (uint8_t*)realloc(buf, bufuse + h.Size);
+ bufsize = bufuse + h.Size;
+ }
+ m_FileAccess.Read(buf + bufuse, m_Optimize.Source, h.Size);
+
+ m_BlockTable[h.ID >> 2].Addr = (m_Optimize.Dest + bufuse) >> 2;
+
+ m_Optimize.Source += h.Size;
+ bufuse += h.Size;
+ }
+
+ if ((m_BlockSync.Waiting() > 0)
+ || (bufuse + 1024 >= bufsize)
+ || (m_Optimize.Source >= m_FileAccess.Size())) // buffer is nearly full or EOF
+ {
+ if (m_Optimize.Dest != m_Optimize.Source) // move blocks
+ {
+ TBlockHeadFree h = {cFreeBlockID, m_Optimize.Source - m_Optimize.Dest};
+ TBlockTailFree t = {m_Optimize.Source - m_Optimize.Dest, cFreeBlockID};
+
+ m_FileAccess.Write(buf, m_Optimize.Dest, bufuse);
+
+ m_FileAccess.Write(&h, m_Optimize.Dest + bufuse, sizeof(h));
+ m_FileAccess.Invalidate(m_Optimize.Dest + bufuse + sizeof(h), m_Optimize.Source - m_Optimize.Dest - bufuse - sizeof(h) - sizeof(t));
+ m_FileAccess.Write(&t, m_Optimize.Dest + bufuse - sizeof(t), sizeof(t));
+
+ if (m_SaveMode)
+ {
+ m_FileAccess.CloseTransaction();
+ m_FileAccess.Flush();
+ m_FileAccess.UseJournal(false);
+
+ m_FileAccess.Write(buf, m_Optimize.Dest, bufuse);
+
+ m_FileAccess.Write(&h, m_Optimize.Dest + bufuse, sizeof(h));
+ m_FileAccess.Invalidate(m_Optimize.Dest + bufuse + sizeof(h), m_Optimize.Source - m_Optimize.Dest - bufuse - sizeof(h) - sizeof(t));
+ m_FileAccess.Write(&t, m_Optimize.Dest + bufuse - sizeof(t), sizeof(t));
+
+ m_FileAccess.Flush();
+ m_FileAccess.CleanJournal();
+ m_FileAccess.UseJournal(true);
+ }
+
+ m_Optimize.Dest += bufuse;
+ bufuse = 0;
+ }
+
+ if (m_BlockSync.Waiting() > 0)
+ {
+ unsigned int w = m_BlockSync.Waiting();
+ m_BlockSync.EndWrite();
+ Sleep(w * 64 + 1);
+ m_BlockSync.BeginWrite();
+ m_FileAccess.UseJournal(m_SaveMode);
+ }
+ }
+ }
+
+ if (m_Optimize.Source >= m_FileAccess.Size())
+ m_FileAccess.Size(m_Optimize.Dest);
+
+ m_Optimize.Thread = NULL;
+ m_Optimize.Source = 0;
+ m_Optimize.Dest = 0;
+ if (m_SaveMode)
+ TransactionEndWrite();
+ else
+ m_BlockSync.EndWrite();
+
+ free(buf); */
+
+ m_Optimize.Thread = NULL;
+}
+
+inline void CBlockManager::_PendingAdd(uint32_t BlockID, uint32_t Addr, uint32_t Size, TCacheEntry * Cache)
+{
+ TPendingOperation * p = NULL;
+ if (BlockID == cFreeBlockID)
+ {
+ p = (TPendingOperation*)malloc(sizeof(TPendingOperation));
+
+ p->BlockID = cFreeBlockID;
+ p->Addr = Addr;
+ p->Size = Size;
+ p->CacheEntry = NULL;
+ p->EncryptionBuffer = NULL;
+
+ m_BytesPending += 24 + sizeof(TBlockHeadFree) + sizeof(TBlockTailFree);
+ if (Addr & cPendingInvalidate)
+ m_BytesPending += 12;
+
+ } else {
+ if (Cache->Pending)
+ {
+ p = Cache->Pending;
+ _PendingRemove(Cache->Pending, false);
+ } else {
+ p = (TPendingOperation*)malloc(sizeof(TPendingOperation));
+ }
+
+ p->BlockID = BlockID;
+ p->Addr = Addr;
+ p->Size = Size;
+ p->CacheEntry = Cache;
+ p->EncryptionBuffer = NULL;
+
+ m_BytesPending += 12 + Size;
+
+ Cache->Pending = p;
+ }
+
+ p->Next = NULL;
+ p->Prev = m_PendingTail;
+ if (m_PendingTail)
+ m_PendingTail->Next = p;
+
+ m_PendingTail = p;
+ if (!m_PendingHead)
+ m_PendingHead = p;
+}
+
+inline void CBlockManager::_PendingRemove(TPendingOperation * Pending, bool Free)
+{
+ if (Pending->Prev)
+ Pending->Prev->Next = Pending->Next;
+ else
+ m_PendingHead = Pending->Next;
+
+ if (Pending->Next)
+ Pending->Next->Prev = Pending->Prev;
+ else
+ m_PendingTail = Pending->Prev;
+
+ if (Pending->EncryptionBuffer)
+ free(Pending->EncryptionBuffer);
+
+ if (m_PendingLast == Pending)
+ m_PendingLast = Pending->Prev;
+
+ Pending->CacheEntry->Pending = NULL;
+ if (Free)
+ free(Pending);
+}
+
+inline void CBlockManager::_PendingFlush(bool FullFlush)
+{
+ TPendingOperation * i = NULL;
+
+ if (m_ReadOnly)
+ return;
+
+ if (FullFlush)
+ {
+ if (m_SaveMode)
+ {
+ _PendingFlush(false); // write to journal
+ m_FileAccess.Flush();
+ m_FileAccess.UseJournal(false);
+ m_FileAccess.Size(m_FileAccess.Size()); // resize real file
+ } else {
+ m_FileAccess.UseJournal(false);
+ }
+
+ i = m_PendingHead;
+ } else if (m_PendingLast)
+ {
+ i = m_PendingLast->Next;
+ m_FileAccess.UseJournal(m_SaveMode);
+ } else {
+ i = m_PendingHead;
+ m_FileAccess.UseJournal(m_SaveMode);
+ }
+
+ while (i)
+ {
+ if (i->BlockID == cFreeBlockID)
+ {
+ uint32_t addr = i->Addr & ~cPendingInvalidate;
+ if (addr + i->Size <= m_FileAccess.Size())
+ {
+ TBlockHeadFree h = {cFreeBlockID, i->Size};
+ TBlockTailFree t = {i->Size, cFreeBlockID};
+
+ m_FileAccess.Write(&h, addr, sizeof(h));
+ if (i->Addr & cPendingInvalidate)
+ m_FileAccess.Invalidate(addr + sizeof(h), i->Size - sizeof(h) - sizeof(t));
+ m_FileAccess.Write(&t, addr + i->Size - sizeof(t), sizeof(t));
+ }
+
+ } else {
+
+ if (i->BlockID && !i->EncryptionBuffer && m_EncryptionManager.IsEncrypted(i->BlockID))
+ {
+ i->EncryptionBuffer = (TBlockHeadOcc*) malloc(i->Size);
+ memcpy(i->EncryptionBuffer, i->CacheEntry->Cache, i->Size);
+ m_EncryptionManager.Encrypt(i->EncryptionBuffer + 1, i->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc), i->BlockID, 0);
+ }
+
+ if (i->EncryptionBuffer)
+ {
+ m_FileAccess.Write(i->EncryptionBuffer, i->Addr, i->Size);
+ } else {
+ m_FileAccess.Write(i->CacheEntry->Cache, i->Addr, i->Size);
+ }
+ }
+
+ i = i->Next;
+ } // while
+
+ if (FullFlush)
+ {
+ m_FileAccess.Flush();
+ if (m_SaveMode)
+ m_FileAccess.CleanJournal();
+
+ m_BytesPending = 20;
+ m_LastFlush = time(NULL);
+
+ i = m_PendingHead;
+ while (i)
+ {
+ if (i->EncryptionBuffer)
+ free(i->EncryptionBuffer);
+
+ if (i->CacheEntry)
+ i->CacheEntry->Pending = NULL;
+
+ TPendingOperation * tmp = i;
+ i = i->Next;
+ free(tmp);
+ }
+ m_PendingHead = NULL;
+ m_PendingTail = NULL;
+ m_PendingLast = NULL;
+ } else {
+ m_PendingLast = m_PendingTail;
+ m_FileAccess.CloseTransaction();
+ }
+}
+
+inline CBlockManager::TCacheEntry * CBlockManager::_CacheInsert(uint32_t Idx, TBlockHeadOcc * Cache, bool Virtual)
+{
+ TCacheEntry * res;
+ uint32_t myidx = ROR_32(Idx, cCacheBuddyBits);
+
+ res = (TCacheEntry *)malloc(sizeof(TCacheEntry));
+ res->Cache = Cache;
+ res->Pending = NULL;
+ res->Idx = myidx;
+ res->Forced = Virtual;
+
+ TCacheEntry * volatile * last = &m_Cache[Idx % cCacheBuddyCount];
+ TCacheEntry * i;
+ do {
+ i = *last;
+
+ while (i && (i->Idx < myidx))
+ {
+ last = &i->Next;
+ i = i->Next;
+ }
+
+ if (i && (i->Idx == myidx))
+ {
+ free(res);
+ free(Cache);
+
+ i->LastUse = time(NULL) >> 2;
+ return i;
+ }
+
+ res->Next = i;
+
+ } while (i != CMPXCHG_Ptr(*last, res, i));
+
+ res->LastUse = time(NULL) >> 2;
+
+ m_BlockTable[Idx].InCache = true;
+ if (!Virtual)
+ XADD_32(m_CacheInfo.Growth, res->Cache->Size);
+
+ return res;
+}
+
+inline CBlockManager::TCacheEntry * CBlockManager::_CacheFind(uint32_t Idx)
+{
+ TCacheEntry * i = m_Cache[Idx % cCacheBuddyCount];
+ uint32_t myidx = ROR_32(Idx, cCacheBuddyBits);
+ while (i && (i->Idx < myidx))
+ i = i->Next;
+
+ if (i && (i->Idx == myidx))
+ return i;
+ else
+ return NULL;
+}
+
+inline void CBlockManager::_CacheErase(uint32_t Idx)
+{
+ TCacheEntry * i = m_Cache[Idx % cCacheBuddyCount];
+ TCacheEntry * volatile * l = &m_Cache[Idx % cCacheBuddyCount];
+
+ uint32_t myidx = ROR_32(Idx, cCacheBuddyBits);
+
+ while (i->Idx < myidx)
+ {
+ l = &i->Next;
+ i = i->Next;
+ }
+ *l = i->Next;
+
+ if (i->Cache)
+ free(i->Cache);
+ free(i);
+}
+
+inline void CBlockManager::_CachePurge()
+{
+ _PendingFlush(true);
+
+ uint32_t ts = time(NULL);
+ if (m_CacheInfo.Size + m_CacheInfo.Growth > cCachePurgeSize) {
+ ts = ts - (ts - m_CacheInfo.LastPurge) * cCachePurgeSize / (m_CacheInfo.Size + 2 * m_CacheInfo.Growth);
+ } else if (m_CacheInfo.Growth > m_CacheInfo.Size)
+ {
+ ts = ts - (ts - m_CacheInfo.LastPurge) * m_CacheInfo.Size / m_CacheInfo.Growth;
+ } else if (m_CacheInfo.Size > m_CacheInfo.Growth)
+ {
+ ts = ts - (ts - m_CacheInfo.LastPurge) * m_CacheInfo.Growth / m_CacheInfo.Size;
+ } else {
+ ts = m_CacheInfo.LastPurge;
+ }
+
+ m_CacheInfo.Size += m_CacheInfo.Growth;
+ m_CacheInfo.Growth = 0;
+ m_CacheInfo.LastPurge = time(NULL);
+
+ for (uint32_t buddy = 0; buddy < cCacheBuddyCount; buddy++)
+ {
+ TCacheEntry * i = m_Cache[buddy];
+ TCacheEntry * volatile * l = &m_Cache[buddy];
+
+ while (i)
+ {
+ if (!i->Forced && !i->KeepInCache && i->Idx && ((i->LastUse << 2) < ts))
+ {
+ uint32_t idx = ROL_32(i->Idx, cCacheBuddyBits);
+ m_CacheInfo.Size -= i->Cache->Size;
+ m_BlockTable[idx].InCache = false;
+ free(i->Cache);
+
+ *l = i->Next;
+ TCacheEntry * tmp = i;
+ i = i->Next;
+ free(tmp);
+
+ } else {
+ l = &i->Next;
+ i = i->Next;
+ }
+ }
+ }
+}
+
+inline uint32_t CBlockManager::_GetAvailableIndex()
+{
+ uint32_t id;
+ if (m_FirstFreeIndex)
+ {
+ id = m_FirstFreeIndex;
+ m_FirstFreeIndex = m_BlockTable[id].Addr;
+ TBlockTableEntry b = {false, false, 0};
+ m_BlockTable[id] = b;
+ } else {
+ id = static_cast<uint32_t>(m_BlockTable.size());
+ if (id > (1 << 12))
+ m_BlockTable.resize(id + (1 << 12));
+ else
+ m_BlockTable.resize(id * 2);
+
+ for (uint32_t i = static_cast<uint32_t>(m_BlockTable.size() - 1); i > id; --i)
+ {
+ TBlockTableEntry b = {true, true, m_FirstFreeIndex};
+ m_BlockTable[i] = b;
+ m_FirstFreeIndex = i;
+ }
+ }
+ return id;
+}
+
+inline void CBlockManager::_InsertFreeBlock(uint32_t Addr, uint32_t Size, bool InvalidateData, bool Reuse)
+{
+ if (Addr + Size == m_FileAccess.Size())
+ {
+ if (Reuse) // in FindFreePosition we would want to use that block
+ m_FileAccess.Size(Addr);
+ } else {
+
+ if (Reuse)
+ m_FreeBlocks.insert(std::make_pair(Size, Addr));
+
+ if (!m_ReadOnly)
+ _PendingAdd(cFreeBlockID, InvalidateData ? Addr | cPendingInvalidate : Addr, Size, NULL);
+
+ }
+}
+
+inline void CBlockManager::_RemoveFreeBlock(uint32_t Addr, uint32_t Size)
+{
+ TFreeBlockMap::iterator i = m_FreeBlocks.find(Size);
+ while ((i != m_FreeBlocks.end()) && (i->first == Size))
+ {
+ if (i->second == Addr)
+ {
+ m_FreeBlocks.erase(i);
+ i = m_FreeBlocks.end();
+ } else {
+ ++i;
+ }
+ }
+}
+
+inline uint32_t CBlockManager::_FindFreePosition(uint32_t Size)
+{
+ // try to find free block
+ TFreeBlockMap::iterator f;
+ TFreeBlockMap::iterator e = m_FreeBlocks.end();
+
+ if (m_FreeBlocks.size())
+ {
+ f = m_FreeBlocks.find(Size);
+ if (f == e)
+ {
+ if (m_FreeBlocks.rbegin()->first > Size * 2)
+ {
+ f = m_FreeBlocks.end();
+ --f;
+ }
+ }
+ } else {
+ f = e;
+ }
+
+ uint32_t addr = 0;
+
+ if (f == e) // no block found - expand file
+ {
+ addr = m_FileAccess.Size();
+ m_FileAccess.Size(addr + Size);
+
+ } else {
+ addr = f->second;
+
+ if (f->first != Size)
+ {
+ _InsertFreeBlock(addr + Size, f->first - Size, false, true);
+ }
+ _InsertFreeBlock(addr, Size, false, false);
+
+ m_FreeBlocks.erase(f);
+ }
+
+ return addr;
+}
+
+inline bool CBlockManager::_InitOperation(uint32_t BlockID, uint32_t & Addr, TCacheEntry * & Cache)
+{
+ if (!BlockID || (BlockID & 3) || ((BlockID >> 2) >= m_BlockTable.size()))
+ return false;
+
+ uint32_t idx = BlockID >> 2;
+ TBlockTableEntry dat = m_BlockTable[idx];
+
+ if (dat.Deleted) // deleted or FreeIDList item
+ return false;
+
+ Addr = dat.Addr << 2;
+ if (dat.InCache)
+ {
+ Cache = _CacheFind(idx);
+ } else if (Addr)
+ {
+ TBlockHeadOcc h;
+
+ m_FileAccess.Read(&h, Addr, sizeof(h));
+
+ TBlockHeadOcc * block = (TBlockHeadOcc *) malloc(h.Size);
+ m_FileAccess.Read(block, Addr, h.Size);
+
+ m_EncryptionManager.Decrypt(block + 1, h.Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc), BlockID, 0);
+
+ Cache = _CacheInsert(idx, block, false);
+ } else {
+ return false;
+ }
+
+ return Cache != NULL;
+}
+
+inline void CBlockManager::_UpdateBlock(uint32_t BlockID, TCacheEntry * CacheEntry, uint32_t Addr)
+{
+ CacheEntry->KeepInCache = m_ReadOnly;
+
+ if (!CacheEntry->Forced)
+ {
+ if (!m_ReadOnly)
+ _PendingAdd(BlockID, Addr, CacheEntry->Cache->Size, CacheEntry);
+ }
+}
+
+
+uint32_t CBlockManager::ScanFile(uint32_t FirstBlockStart, uint32_t HeaderSignature, uint32_t FileSize)
+{
+ TBlockHeadOcc h, lasth = {0, 0, 0};
+ uint32_t p;
+ uint32_t res = 0;
+ bool invalidateblock = false;
+
+ p = FirstBlockStart;
+ m_FirstBlockStart = FirstBlockStart;
+ m_Optimize.Source = 0;
+ m_Optimize.Dest = 0;
+
+ { // insert header cache element
+ void * header = malloc(FirstBlockStart);
+ m_FileAccess.Read(header, 0, FirstBlockStart);
+ _CacheInsert(0, (TBlockHeadOcc*)header, false);
+ }
+
+ TransactionBeginWrite();
+
+ while (p < FileSize)
+ {
+ m_FileAccess.Read(&h, p, sizeof(h));
+ if (CLogger::Instance().Level() >= CLogger::logERROR || !h.Size)
+ {
+ LOG(logCRITICAL, _T("Block-structure of file is corrupt!"));
+ return 0;
+ }
+
+ if (h.ID == cFreeBlockID)
+ {
+ if (m_Optimize.Dest == 0)
+ m_Optimize.Dest = p;
+
+ if (lasth.ID == cFreeBlockID)
+ {
+ lasth.Size += h.Size;
+ invalidateblock = true;
+ } else {
+ lasth = h;
+ }
+
+ } else {
+
+ if (lasth.ID == cFreeBlockID)
+ {
+ if (m_Optimize.Source == 0)
+ m_Optimize.Source = p;
+
+ _InsertFreeBlock(p - lasth.Size, lasth.Size, invalidateblock, true);
+ }
+ lasth = h;
+ invalidateblock = false;
+
+ while ((h.ID >> 2) >= m_BlockTable.size())
+ m_BlockTable.resize(m_BlockTable.size() << 1);
+
+ m_BlockTable[h.ID >> 2].Addr = p >> 2;
+
+ if (h.Signature == HeaderSignature)
+ res = h.ID;
+ }
+
+ p = p + h.Size;
+ }
+
+ m_FirstFreeIndex = 0;
+ for (uint32_t i = static_cast<uint32_t>(m_BlockTable.size() - 1); i > 0; --i)
+ {
+ if (m_BlockTable[i].Addr == 0)
+ {
+ TBlockTableEntry b = {true, true, m_FirstFreeIndex};
+ m_BlockTable[i] = b;
+ m_FirstFreeIndex = i;
+ }
+ }
+
+ TransactionEndWrite();
+
+ if (m_Optimize.Source && !m_FileAccess.ReadOnly())
+ {
+ m_Optimize.Thread = new COptimizeThread(*this);
+ m_Optimize.Thread->Priority(CThread::tpLowest);
+ m_Optimize.Thread->FreeOnTerminate(true);
+ m_Optimize.Thread->Resume();
+ }
+
+ return res;
+}
+
+void * CBlockManager::_CreateBlock(uint32_t & BlockID, const uint32_t Signature, uint32_t Size)
+{
+ uint32_t idx = _GetAvailableIndex();
+ BlockID = idx << 2;
+
+ Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes
+
+ TBlockHeadOcc h = {BlockID, Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc), Signature};
+ TBlockTailOcc t = {BlockID};
+
+ TBlockHeadOcc * block = (TBlockHeadOcc*) malloc(Size + sizeof(h) + sizeof(t));
+ *block = h;
+ memset(block + 1, 0, Size);
+ *(TBlockTailOcc*)(((uint8_t*)(block + 1)) + Size) = t;
+
+ TCacheEntry * ce = _CacheInsert(idx, block, false);
+
+ if (m_ReadOnly)
+ {
+ TBlockTableEntry b = {false, true, 0};
+ m_BlockTable[idx] = b;
+ } else {
+ uint32_t addr = _FindFreePosition(Size + sizeof(h) + sizeof(t));
+ TBlockTableEntry b = {false, true, addr >> 2 };
+ m_BlockTable[idx] = b;
+
+ _UpdateBlock(BlockID, ce, addr);
+ }
+
+ return ce->Cache + 1;
+}
+
+void * CBlockManager::_CreateBlockVirtual(uint32_t & BlockID, const uint32_t Signature, uint32_t Size)
+{
+ uint32_t idx = _GetAvailableIndex();
+ BlockID = idx << 2;
+
+ Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes
+
+ TBlockHeadOcc h = {BlockID, Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc), Signature};
+ TBlockTailOcc t = {BlockID};
+
+ TBlockHeadOcc * block = (TBlockHeadOcc*) malloc(Size + sizeof(h) + sizeof(t));
+ *block = h;
+ memset(block + 1, 0, Size);
+ *(TBlockTailOcc*)(((uint8_t*)(block + 1)) + Size) = t;
+
+ return _CacheInsert(idx, block, true)->Cache + 1;
+}
+
+bool CBlockManager::DeleteBlock(uint32_t BlockID)
+{
+ uint32_t idx = BlockID >> 2;
+ uint32_t addr;
+ uint32_t size;
+ TCacheEntry * ce;
+ if (!_InitOperation(BlockID, addr, ce))
+ return false;
+
+ if (!ce->Forced)
+ XADD_32(m_CacheInfo.Size, 0 - ce->Cache->Size);
+
+ if (ce->Pending)
+ _PendingRemove(ce->Pending, true);
+
+ size = ce->Cache->Size;
+ _CacheErase(idx);
+
+ if (addr == 0) // Block in memory only
+ {
+ TBlockTableEntry b = {false, false, 0};
+ m_BlockTable[idx] = b;
+
+ } else if (m_ReadOnly)
+ {
+ m_BlockTable[idx].Deleted = true;
+ m_BlockTable[idx].InCache = false;
+ } else {
+ _InsertFreeBlock(addr, size, true, true);
+
+ TBlockTableEntry b = {false, false, 0};
+ m_BlockTable[idx] = b;
+ }
+
+ return true;
+}
+
+uint32_t CBlockManager::_ResizeBlock(uint32_t BlockID, void * & Buffer, uint32_t Size)
+{
+ uint32_t idx = BlockID >> 2;
+ uint32_t addr;
+ TCacheEntry * ce;
+
+ if (Size == 0)
+ return 0;
+
+ if (!_InitOperation(BlockID, addr, ce))
+ return 0;
+
+ Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes
+
+ uint32_t os = ce->Cache->Size;
+ uint32_t ns = Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc);
+ if (ns == ce->Cache->Size)
+ {
+ Buffer = ce->Cache + 1;
+ return Size;
+ }
+
+ ce->Cache = (TBlockHeadOcc*) realloc(ce->Cache, ns);
+ ce->Cache->Size = ns;
+ TBlockTailOcc t = {BlockID};
+ *(TBlockTailOcc*)(((uint8_t*)(ce->Cache + 1)) + Size) = t;
+ XADD_32(m_CacheInfo.Size, ns - os);
+
+ Buffer = ce->Cache + 1;
+ ce->KeepInCache = m_ReadOnly;
+
+ if (!m_ReadOnly && addr)
+ {
+ _InsertFreeBlock(addr, os, true, true);
+ addr = _FindFreePosition(ns);
+ m_BlockTable[idx].Addr = addr >> 2;
+
+ _UpdateBlock(BlockID, ce, addr); // write down
+ }
+
+ return Size;
+}
+
+bool CBlockManager::IsForcedVirtual(uint32_t BlockID)
+{
+ TCacheEntry * ce = _CacheFind(BlockID >> 2);
+ return ce && ce->Forced;
+}
+
+bool CBlockManager::WriteBlockToDisk(uint32_t BlockID)
+{
+ uint32_t addr;
+ TCacheEntry * ce;
+
+ if (!_InitOperation(BlockID, addr, ce))
+ return false;
+
+ if (!ce->Forced)
+ return true;
+
+ ce->Forced = false;
+ XADD_32(m_CacheInfo.Size, ce->Cache->Size);
+
+ if (!m_ReadOnly)
+ {
+ addr = _FindFreePosition(ce->Cache->Size);
+ m_BlockTable[BlockID >> 2].Addr = addr >> 2;
+ _UpdateBlock(BlockID, ce, addr);
+ }
+ return true;
+}
+
+bool CBlockManager::MakeBlockVirtual(uint32_t BlockID)
+{
+ uint32_t addr;
+ TCacheEntry * ce;
+
+ if (!_InitOperation(BlockID, addr, ce))
+ return false;
+
+ if (ce->Forced)
+ return true;
+
+ if (ce->Pending) // don't write down, we kill it anyway
+ _PendingRemove(ce->Pending, true);
+
+ ce->Forced = true;
+ XADD_32(m_CacheInfo.Size, 0 - ce->Cache->Size);
+
+ if (!m_ReadOnly)
+ {
+ _InsertFreeBlock(addr, ce->Cache->Size, true, true);
+ m_BlockTable[BlockID >> 2].Addr = 0;
+ }
+ return true;
+}
+
+void * CBlockManager::_ReadBlock(uint32_t BlockID, uint32_t & Size, uint32_t & Signature)
+{
+ uint32_t addr;
+ TCacheEntry * ce;
+
+ if ((BlockID == 0) && (Signature == -1))
+ {
+ Size = m_FirstBlockStart;
+ return m_Cache[0]->Cache;
+ }
+
+ if (!_InitOperation(BlockID, addr, ce))
+ return NULL;
+
+ if ((Signature != 0) && (Signature != ce->Cache->Signature))
+ {
+ Signature = ce->Cache->Signature;
+ return NULL;
+ }
+ Signature = ce->Cache->Signature;
+
+ if ((Size != 0) && (Size != ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc)))
+ {
+ Size = ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc);
+ return NULL;
+ }
+ Size = ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc);
+
+ return ce->Cache + 1;
+}
+
+bool CBlockManager::UpdateBlock(uint32_t BlockID, uint32_t Signature)
+{
+ uint32_t addr;
+ TCacheEntry * ce;
+
+ if ((BlockID == 0) && (Signature == -1))
+ {
+ if (!m_ReadOnly)
+ _PendingAdd(0, 0, m_FirstBlockStart, m_Cache[0]);
+
+ return true;
+ }
+
+ if (!_InitOperation(BlockID, addr, ce))
+ return false;
+
+ if (Signature)
+ ce->Cache->Signature = Signature;
+
+ _UpdateBlock(BlockID, ce, addr);
+
+ return true;
+}
+
+// make file writeable:
+// write all cached blocks to file and check for the old addresses
+// remove virtual only from file
+// update m_FreeBlocks along the way
+
diff --git a/plugins/Dbx_tree/src/BlockManager.h b/plugins/Dbx_tree/src/BlockManager.h
new file mode 100644
index 0000000000..dcccd4f0b9
--- /dev/null
+++ b/plugins/Dbx_tree/src/BlockManager.h
@@ -0,0 +1,401 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <windows.h>
+#include <map>
+#include <vector>
+
+#include "stdint.h"
+#include "FileAccess.h"
+#include "EncryptionManager.h"
+#include "MREWSync.h"
+#include "Thread.h"
+#include "intrinsics.h"
+
+class CBlockManager
+{
+protected:
+ static const uint32_t cFreeBlockID = 0xFFFFFFFF;
+
+ static const uint32_t cJournalFlushBytes = (1 << 20) - 2048; // flush before reserved journal-space is exhausted
+ static const uint32_t cJournalFlushTimeout = 300; // journal flush every 5 minutes
+
+ static const uint32_t cCacheBuddyBits = 10;
+ static const uint32_t cCacheBuddyCount = 1 << cCacheBuddyBits; // count of static allocated buddy nodes
+ static const uint32_t cCacheBuddyCheck = 0xffffffff << cCacheBuddyBits;
+
+ static const uint32_t cCacheMinimumTimeout = 2; // purge less than every n seconds (high priority)
+ static const uint32_t cCacheMaximumTimeout = 600; // purge every 10 minutes (high priority)
+ static const uint32_t cCachePurgeSize = 1 << 21; // cache up to 2MB
+ static const uint32_t cCacheMinimumGrowthForPurge = 1 << 19; // cache only when 512kb were added
+
+ #pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+ typedef struct TBlockHeadFree {
+ uint32_t ID;
+ uint32_t Size;
+ } TBlockHeadFree;
+ typedef struct TBlockHeadOcc {
+ uint32_t ID;
+ uint32_t Size;
+ uint32_t Signature; /// if occupied block
+ } TBlockHeadOcc;
+
+ typedef struct TBlockTailOcc {
+ uint32_t ID;
+ } TBlockTailOcc;
+
+ typedef struct TBlockTailFree {
+ uint32_t Size; /// if free block
+ uint32_t ID;
+ } TBlockTailFree;
+
+ #pragma pack(pop)
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// <summary> Block table entry. </summary>
+ ///
+ /// Addr Deleted InCache Meaning
+ /// 0 0 0 successfully deleted block
+ /// 0 0 1 virtual only block (either forced virtual or created on a read-only file)
+ /// 0 1 0 invalid
+ /// 0 1 1 FreeID list (last entry)
+ /// set 0 0 Normal in-file block
+ /// set 0 1 in file and cache (normal cache which could differ on a read-only file or forced virtual out of a read-only file - check TCacheEntry)
+ /// set 1 0 deleted block or a read-only file
+ /// set 1 1 FreeID list entry
+ ///
+ /// <remarks> Michael "Protogenes" Kunz, 07.09.2010. </remarks>
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ typedef struct TBlockTableEntry {
+ uint32_t Deleted : 1; ///< Flag is set if the block was deleted but can't be removed, because the file is read-only
+ uint32_t InCache : 1; ///< Flag is set if block is in the cache (either forced virtual or from the file)
+ uint32_t Addr : 30; ///< The Offset in the file div 4, so we can address files up to 4GB
+ } TBlockTableEntry;
+ std::vector<TBlockTableEntry> m_BlockTable;
+
+ struct TPendingOperation;
+ typedef struct TCacheEntry {
+ TCacheEntry * volatile Next;
+ TBlockHeadOcc * volatile Cache;
+ TPendingOperation * Pending;
+
+ uint32_t Idx;
+ uint32_t Forced : 1;
+ uint32_t KeepInCache : 1;
+ uint32_t LastUse : 30;
+ } TCacheEntry;
+
+ TCacheEntry * m_Cache[cCacheBuddyCount];
+
+ struct {
+ uint32_t volatile Size;
+ uint32_t volatile Growth;
+ uint32_t volatile LastPurge;
+ } m_CacheInfo;
+
+ CFileAccess & m_FileAccess;
+ CEncryptionManager & m_EncryptionManager;
+ CMultiReadExclusiveWriteSynchronizer m_BlockSync;
+
+ uint32_t m_FirstBlockStart;
+ bool m_SaveMode;
+ bool m_ReadOnly;
+
+ typedef std::multimap<uint32_t, uint32_t> TFreeBlockMap;
+ TFreeBlockMap m_FreeBlocks;
+ uint32_t m_FirstFreeIndex;
+
+ static const uint32_t cPendingInvalidate = 0x00000001;
+ typedef struct TPendingOperation {
+ TPendingOperation * Next; ///< The next
+ TPendingOperation * Prev; ///< The previous
+ uint32_t BlockID; ///< Identifier for the block
+ uint32_t Addr; ///< The address in the file
+ uint32_t Size; ///< The size of the block
+ TCacheEntry * CacheEntry; ///< The cache entry
+ TBlockHeadOcc * EncryptionBuffer; ///< Buffer for encrypted block
+ } TPendingOperation;
+
+ TPendingOperation * m_PendingHead; ///< The double linked list head
+ TPendingOperation * m_PendingTail; ///< The double linked list tail
+ TPendingOperation * m_PendingLast; ///< The last processed item
+
+ uint32_t m_LastFlush; ///< The last flush timestamp
+ uint32_t m_BytesPending; ///< The bytes pending for write
+
+ class COptimizeThread : public CThread
+ {
+ protected:
+ CBlockManager & m_Owner;
+ void Execute() { m_Owner.ExecuteOptimize(); };
+ public:
+ COptimizeThread(CBlockManager & Owner) : CThread(true), m_Owner(Owner) {};
+ ~COptimizeThread() {};
+ };
+
+ struct {
+ uint32_t Source;
+ uint32_t Dest;
+ COptimizeThread * Thread;
+ } m_Optimize;
+ void ExecuteOptimize();
+
+ uint32_t _GetAvailableIndex();
+ void _InsertFreeBlock(uint32_t Addr, uint32_t Size, bool InvalidateData, bool Reuse);
+ void _RemoveFreeBlock(uint32_t Addr, uint32_t Size);
+ uint32_t _FindFreePosition(uint32_t Size);
+
+ bool _InitOperation(uint32_t BlockID, uint32_t & Addr, TCacheEntry * & Cache);
+ void _UpdateBlock(uint32_t BlockID, TCacheEntry * CacheEntry, uint32_t Addr);
+
+ void * _ReadBlock(uint32_t BlockID, uint32_t & Size, uint32_t & Signature);
+ void * _CreateBlock(uint32_t & BlockID, const uint32_t Signature, uint32_t Size);
+ void * _CreateBlockVirtual(uint32_t & BlockID, const uint32_t Signature, uint32_t Size);
+ uint32_t _ResizeBlock(uint32_t BlockID, void * & Buffer, uint32_t Size);
+
+ TCacheEntry * _CacheInsert(uint32_t Idx, TBlockHeadOcc * Cache, bool Virtual);
+ TCacheEntry * _CacheFind(uint32_t Idx);
+ void _CacheErase(uint32_t Idx);
+
+ void _CachePurge();
+ void _PendingAdd(uint32_t BlockID, uint32_t Addr, uint32_t Size, TCacheEntry * Cache);
+ void _PendingRemove(TPendingOperation * Pending, bool Free);
+ void _PendingFlush(bool FullFlush);
+
+
+
+ void TransactionBeginRead()
+ {
+ m_BlockSync.BeginRead();
+ };
+
+ void TransactionEndRead()
+ {
+ m_BlockSync.EndRead();
+ };
+
+ void TransactionBeginWrite()
+ {
+ m_BlockSync.BeginWrite();
+ m_FileAccess.UseJournal(m_SaveMode);
+ };
+
+ void TransactionEndWrite()
+ {
+ if (m_BlockSync.WriteRecursionCount() == 1)
+ {
+ m_FileAccess.CompleteTransaction();
+ m_BytesPending += 12;
+
+ if ((m_CacheInfo.LastPurge + cCacheMaximumTimeout < time(NULL))
+ || ((m_CacheInfo.Size + m_CacheInfo.Growth > cCachePurgeSize)
+ && (m_CacheInfo.Growth > cCacheMinimumGrowthForPurge)
+ && (m_CacheInfo.LastPurge + cCacheMinimumTimeout < time(NULL))))
+ {
+ _CachePurge();
+ } else if ((m_BytesPending >= cJournalFlushBytes) || (time(NULL) > m_LastFlush + cJournalFlushTimeout))
+ {
+ _PendingFlush(true);
+ } else {
+ _PendingFlush(false);
+ }
+ }
+
+ m_BlockSync.EndWrite();
+ };
+public:
+ CBlockManager(CFileAccess & FileAccess, CEncryptionManager & EncryptionManager);
+ ~CBlockManager();
+
+
+ class ReadTransaction
+ {
+ private:
+ CBlockManager * m_Owner;
+ uint32_t volatile * m_RefCount;
+ bool m_Closed;
+ public:
+ ReadTransaction()
+ : m_Owner(NULL),
+ m_RefCount(NULL),
+ m_Closed(true)
+ {
+
+ };
+ ReadTransaction(CBlockManager & BlockManager)
+ : m_Owner(&BlockManager),
+ m_RefCount(new uint32_t(1)),
+ m_Closed(false)
+ {
+ m_Owner->TransactionBeginRead();
+ };
+ ReadTransaction(const ReadTransaction & Other)
+ : m_Owner(Other.m_Owner),
+ m_RefCount(Other.m_RefCount),
+ m_Closed(Other.m_Closed)
+ {
+ if (!m_Closed)
+ INC_32(*m_RefCount);
+ };
+ ~ReadTransaction()
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndRead();
+ }
+ };
+
+ ReadTransaction & operator =(const ReadTransaction & Other)
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndRead();
+ }
+
+ m_Owner = Other.m_Owner;
+ m_RefCount = Other.m_RefCount;
+ m_Closed = Other.m_Closed;
+ if (!m_Closed)
+ INC_32(*m_RefCount);
+
+ return *this;
+ }
+
+ void Close()
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndRead();
+ }
+ m_Closed = true;
+ }
+
+ };
+ class WriteTransaction
+ {
+ private:
+ CBlockManager * m_Owner;
+ uint32_t volatile * m_RefCount;
+ bool m_Closed;
+ public:
+ WriteTransaction()
+ : m_Owner(NULL),
+ m_RefCount(NULL),
+ m_Closed(true)
+ {
+
+ };
+ WriteTransaction(CBlockManager & BlockManager)
+ : m_Owner(&BlockManager),
+ m_RefCount(new uint32_t(1)),
+ m_Closed(false)
+ {
+ m_Owner->TransactionBeginWrite();
+ };
+ WriteTransaction(const WriteTransaction & Other)
+ : m_Owner(Other.m_Owner),
+ m_RefCount(Other.m_RefCount),
+ m_Closed(Other.m_Closed)
+ {
+ if (!m_Closed)
+ INC_32(*m_RefCount);
+ };
+ ~WriteTransaction()
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndWrite();
+ }
+ };
+
+ WriteTransaction & operator =(const WriteTransaction & Other)
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndWrite();
+ }
+
+ m_Owner = Other.m_Owner;
+ m_RefCount = Other.m_RefCount;
+ m_Closed = Other.m_Closed;
+ if (!m_Closed)
+ INC_32(*m_RefCount);
+
+ return *this;
+ }
+
+ void Close()
+ {
+ if (!m_Closed && (DEC_32(*m_RefCount) == 0))
+ {
+ delete m_RefCount;
+ m_Owner->TransactionEndWrite();
+ }
+ m_Closed = true;
+ }
+
+ };
+
+ uint32_t ScanFile(uint32_t FirstBlockStart, uint32_t HeaderSignature, uint32_t FileSize);
+
+ template <typename BlockType>
+ BlockType * ReadBlock(uint32_t BlockID, uint32_t & Size, uint32_t & Signature)
+ {
+ return reinterpret_cast<BlockType*>(_ReadBlock(BlockID, Size, Signature));
+ };
+
+ template <typename BlockType>
+ BlockType * CreateBlock(uint32_t & BlockID, const uint32_t Signature, uint32_t Size = sizeof(BlockType))
+ {
+ return reinterpret_cast<BlockType*>(_CreateBlock(BlockID, Signature, Size));
+ };
+
+ template <typename BlockType>
+ BlockType * CreateBlockVirtual(uint32_t & BlockID, const uint32_t Signature, uint32_t Size = sizeof(BlockType))
+ {
+ return reinterpret_cast<BlockType*>(_CreateBlockVirtual(BlockID, Signature, Size));
+ };
+
+ template <typename BlockType>
+ uint32_t ResizeBlock(uint32_t BlockID, BlockType * & Buffer, uint32_t Size)
+ {
+ void * tmp = Buffer;
+ uint32_t res = _ResizeBlock(BlockID, tmp, Size);
+ Buffer = reinterpret_cast<BlockType*>(tmp);
+ return res;
+ };
+
+ bool UpdateBlock(uint32_t BlockID, uint32_t Signature = 0);
+ bool DeleteBlock(uint32_t BlockID);
+
+ bool IsForcedVirtual(uint32_t BlockID);
+ bool WriteBlockToDisk(uint32_t BlockID);
+ bool MakeBlockVirtual(uint32_t BlockID);
+};
diff --git a/plugins/Dbx_tree/src/Compatibility.cpp b/plugins/Dbx_tree/src/Compatibility.cpp
new file mode 100644
index 0000000000..759e44012c
--- /dev/null
+++ b/plugins/Dbx_tree/src/Compatibility.cpp
@@ -0,0 +1,799 @@
+/*
+
+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 "Compatibility.h"
+#include "Logger.h"
+#define DB_NOHELPERFUNCTIONS
+#include "m_database.h"
+#include "m_db_int.h"
+#undef DB_NOHELPERFUNCTIONS
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#endif
+
+HANDLE gEvents[6] = {0,0,0,0,0,0};
+
+HANDLE hEventDeletedEvent,
+ hEventAddedEvent,
+ hEventFilterAddedEvent,
+ hSettingChangeEvent,
+ hContactDeletedEvent,
+ hContactAddedEvent;
+
+STDMETHODIMP_(HANDLE) CDataBase::AddContact(void)
+{
+ TDBTEntity entity = {0,0,0,0};
+ entity.hParentEntity = DBEntityGetRoot(0, 0);
+ entity.hAccountEntity = entity.hParentEntity;
+
+ TDBTEntityHandle res = gDataBase->getEntities().CreateEntity(entity);
+ if (res == DBT_INVALIDPARAM)
+ return (HANDLE)1;
+
+ NotifyEventHooks(hContactAddedEvent, res, 0);
+ return (HANDLE)res;
+}
+
+STDMETHODIMP_(LONG) CDataBase::DeleteContact(HANDLE hContact)
+{
+ NotifyEventHooks(hContactDeletedEvent, (WPARAM)hContact, 0);
+
+ int res = DBEntityDelete((WPARAM)hContact, 0);
+ if (res == DBT_INVALIDPARAM)
+ return 1;
+
+ return res;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::IsDbContact(HANDLE hContact)
+{
+ int flags = DBEntityGetFlags((WPARAM)hContact, 0);
+ return (flags != DBT_INVALIDPARAM) &&
+ ((flags & DBT_NFM_SpecialEntity) == 0);
+}
+
+STDMETHODIMP_(LONG) CDataBase::GetContactCount(void)
+{
+ TDBTEntityIterFilter f = {0,0,0,0};
+ f.cbSize = sizeof(f);
+ f.fDontHasFlags = DBT_NF_IsGroup | DBT_NF_IsVirtual | DBT_NF_IsAccount | DBT_NF_IsRoot;
+ f.Options = DBT_NIFO_OSC_AC | DBT_NIFO_OC_AC;
+
+ TDBTEntityIterationHandle hiter = DBEntityIterInit((WPARAM)&f, gDataBase->getEntities().getRootEntity());
+ int c = 0;
+ if ((hiter != 0) && (hiter != DBT_INVALIDPARAM))
+ {
+ TDBTEntityHandle con = DBEntityIterNext(hiter, 0);
+
+ while ((con != DBT_INVALIDPARAM) && (con != 0))
+ {
+ if ((con != 0) && (con != DBT_INVALIDPARAM))
+ c++;
+
+ con = DBEntityIterNext(hiter, 0);
+ }
+ DBEntityIterClose(hiter, 0);
+ }
+ return c;
+}
+
+//!!!!!!!!!!!!!!!!!!!! szProto ignored
+STDMETHODIMP_(HANDLE) CDataBase::FindFirstContact(const char* szProto)
+{
+ return (HANDLE)gDataBase->getEntities().compFirstContact();
+}
+
+//!!!!!!!!!!!!!!!!!!!! szProto ignored
+STDMETHODIMP_(HANDLE) CDataBase::FindNextContact(HANDLE hContact, const char* szProto)
+{
+ return (HANDLE)gDataBase->getEntities().compNextContact((WPARAM)hContact);
+}
+
+STDMETHODIMP_(BOOL) CDataBase::GetContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dbcgs)
+{
+ dbcgs->pValue->type = 0;
+
+ char namebuf[512];
+ namebuf[0] = 0;
+
+ if (!(dbcgs->szModule || dbcgs->szSetting))
+ return -1;
+
+ if (dbcgs->szModule)
+ strcpy_s(namebuf, dbcgs->szModule);
+ strcat_s(namebuf, "/");
+ if (dbcgs->szSetting)
+ strcat_s(namebuf, dbcgs->szSetting);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ TDBTSetting set = {0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+ desc.pszSettingName = namebuf;
+
+ set.cbSize = sizeof(set);
+ set.Descriptor = &desc;
+
+ if (DBSettingRead(reinterpret_cast<WPARAM>(&set), 0) == DBT_INVALIDPARAM)
+ return -1;
+
+ switch (set.Type)
+ {
+ case DBT_ST_ANSI:
+ {
+ dbcgs->pValue->type = DBVT_ASCIIZ;
+ dbcgs->pValue->pszVal = set.Value.pAnsi;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+ } break;
+ case DBT_ST_UTF8:
+ {
+ dbcgs->pValue->type = DBVT_WCHAR;
+ dbcgs->pValue->pwszVal = mir_utf8decodeW(set.Value.pUTF8);
+ if (dbcgs->pValue->pwszVal)
+ dbcgs->pValue->cchVal = static_cast<uint32_t>(wcslen(dbcgs->pValue->pwszVal));
+ else
+ dbcgs->pValue->cchVal = 0;
+ mir_free(set.Value.pUTF8);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ dbcgs->pValue->type = DBVT_WCHAR;
+ dbcgs->pValue->pwszVal = set.Value.pWide;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+ } break;
+ case DBT_ST_BLOB:
+ {
+ dbcgs->pValue->type = DBVT_BLOB;
+ dbcgs->pValue->pbVal = set.Value.pBlob;
+ dbcgs->pValue->cpbVal = set.Value.Length;
+ } break;
+ case DBT_ST_BOOL:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = (uint8_t)set.Value.Bool;
+ } break;
+ case DBT_ST_BYTE: case DBT_ST_CHAR:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = set.Value.Byte;
+ } break;
+ case DBT_ST_SHORT: case DBT_ST_WORD:
+ {
+ dbcgs->pValue->type = DBVT_WORD;
+ dbcgs->pValue->wVal = set.Value.Word;
+ } break;
+ case DBT_ST_INT: case DBT_ST_DWORD:
+ {
+ dbcgs->pValue->type = DBVT_DWORD;
+ dbcgs->pValue->dVal = set.Value.DWord;
+ } break;
+ case DBT_ST_INT64: case DBT_ST_QWORD:
+ case DBT_ST_DOUBLE: case DBT_ST_FLOAT:
+ {
+ dbcgs->pValue->type = DBVT_BLOB;
+ dbcgs->pValue->cpbVal = sizeof(set.Value);
+ dbcgs->pValue->pbVal = reinterpret_cast<BYTE*>(mir_alloc(sizeof(set.Value)));
+ memcpy(dbcgs->pValue->pbVal, &set.Value, sizeof(set.Value));
+ } break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::GetContactSettingStr(HANDLE hContact, DBCONTACTGETSETTING *dbcgs)
+{
+ if ((dbcgs->pValue->type & DBVTF_VARIABLELENGTH) == 0)
+ {
+ FreeVariant(dbcgs->pValue);
+ dbcgs->pValue->type = 0;
+ }
+
+ char namebuf[512];
+ namebuf[0] = 0;
+ if (dbcgs->szModule)
+ strcpy_s(namebuf, dbcgs->szModule);
+ strcat_s(namebuf, "/");
+ if (dbcgs->szSetting)
+ strcat_s(namebuf, dbcgs->szSetting);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ TDBTSetting set = {0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+ desc.pszSettingName = namebuf;
+
+ set.cbSize = sizeof(set);
+ set.Descriptor = &desc;
+
+
+ switch (dbcgs->pValue->type)
+ {
+ case DBVT_ASCIIZ: set.Type = DBT_ST_ANSI; break;
+ case DBVT_BLOB: set.Type = DBT_ST_BLOB; break;
+ case DBVT_UTF8: set.Type = DBT_ST_UTF8; break;
+ case DBVT_WCHAR: set.Type = DBT_ST_WCHAR; break;
+ }
+
+ if (DBSettingRead(reinterpret_cast<WPARAM>(&set), 0) == DBT_INVALIDPARAM)
+ return -1;
+
+ switch (set.Type)
+ {
+ case DBT_ST_ANSI:
+ {
+ dbcgs->pValue->type = DBVT_ASCIIZ;
+ dbcgs->pValue->pszVal = set.Value.pAnsi;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+ } break;
+ case DBT_ST_UTF8:
+ {
+ dbcgs->pValue->type = DBVT_UTF8;
+ dbcgs->pValue->pszVal = set.Value.pUTF8;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ if (dbcgs->pValue->type == DBVT_WCHAR)
+ {
+ dbcgs->pValue->pwszVal = set.Value.pWide;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+ } else {
+ dbcgs->pValue->type = DBVT_UTF8;
+ dbcgs->pValue->pszVal = mir_utf8encodeW(set.Value.pWide);
+ dbcgs->pValue->cchVal = static_cast<uint32_t>(strlen(dbcgs->pValue->pszVal));
+ mir_free(set.Value.pWide);
+ }
+ } break;
+ case DBT_ST_BLOB:
+ {
+ dbcgs->pValue->type = DBVT_BLOB;
+ dbcgs->pValue->pbVal = set.Value.pBlob;
+ dbcgs->pValue->cpbVal = set.Value.Length;
+ } break;
+ case DBT_ST_BOOL:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = (uint8_t)set.Value.Bool;
+ } break;
+ case DBT_ST_BYTE: case DBT_ST_CHAR:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = set.Value.Byte;
+ } break;
+ case DBT_ST_SHORT: case DBT_ST_WORD:
+ {
+ dbcgs->pValue->type = DBVT_WORD;
+ dbcgs->pValue->wVal = set.Value.Word;
+ } break;
+ case DBT_ST_INT: case DBT_ST_DWORD:
+ {
+ dbcgs->pValue->type = DBVT_DWORD;
+ dbcgs->pValue->dVal = set.Value.DWord;
+ } break;
+ case DBT_ST_INT64: case DBT_ST_QWORD:
+ case DBT_ST_DOUBLE: case DBT_ST_FLOAT:
+ {
+ dbcgs->pValue->type = DBVT_BLOB;
+ dbcgs->pValue->cpbVal = sizeof(set.Value);
+ dbcgs->pValue->pbVal = reinterpret_cast<BYTE*>(mir_alloc(sizeof(set.Value)));
+ memcpy(dbcgs->pValue->pbVal, &set.Value, sizeof(set.Value));
+ } break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::GetContactSettingStatic(HANDLE hContact, DBCONTACTGETSETTING *dbcgs)
+{
+ char namebuf[512];
+ namebuf[0] = 0;
+ if (dbcgs->szModule)
+ strcpy_s(namebuf, dbcgs->szModule);
+ strcat_s(namebuf, "/");
+ if (dbcgs->szSetting)
+ strcat_s(namebuf, dbcgs->szSetting);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ TDBTSetting set = {0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+ desc.pszSettingName = namebuf;
+
+ set.cbSize = sizeof(set);
+ set.Descriptor = &desc;
+
+ if (DBSettingRead(reinterpret_cast<WPARAM>(&set), 0) == DBT_INVALIDPARAM)
+ return -1;
+
+ if ((set.Type & DBT_STF_VariableLength) ^ (dbcgs->pValue->type & DBVTF_VARIABLELENGTH))
+ {
+ if (set.Type & DBT_STF_VariableLength)
+ mir_free(set.Value.pBlob);
+ return -1;
+ }
+
+ switch (set.Type)
+ {
+ case DBT_ST_ANSI:
+ {
+ if (dbcgs->pValue->cchVal < set.Value.Length)
+ {
+ memcpy(dbcgs->pValue->pszVal, set.Value.pAnsi, dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[dbcgs->pValue->cchVal - 1] = 0;
+ } else {
+ memcpy(dbcgs->pValue->pszVal, set.Value.pAnsi, set.Value.Length);
+ }
+ dbcgs->pValue->type = DBVT_ASCIIZ;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+
+ mir_free(set.Value.pAnsi);
+ } break;
+ case DBT_ST_UTF8:
+ {
+ set.Value.pUTF8 = mir_utf8decode(set.Value.pUTF8, NULL);
+ set.Value.Length = static_cast<uint32_t>(strlen(set.Value.pUTF8));
+
+ if (dbcgs->pValue->cchVal < set.Value.Length)
+ {
+ memcpy(dbcgs->pValue->pszVal, set.Value.pUTF8, dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[dbcgs->pValue->cchVal - 1] = 0;
+ } else {
+ memcpy(dbcgs->pValue->pszVal, set.Value.pUTF8, set.Value.Length);
+ }
+ dbcgs->pValue->type = DBVT_ASCIIZ;
+ dbcgs->pValue->cchVal = set.Value.Length - 1;
+
+ mir_free(set.Value.pUTF8);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ char * tmp = mir_u2a(set.Value.pWide);
+ WORD l = static_cast<WORD>(strlen(tmp));
+ mir_free(set.Value.pWide);
+
+ if (dbcgs->pValue->cchVal < l + 1)
+ {
+ memcpy(dbcgs->pValue->pszVal, tmp, dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[l] = 0;
+ } else {
+ memcpy(dbcgs->pValue->pszVal, tmp, l + 1);
+ }
+ dbcgs->pValue->type = DBVT_ASCIIZ;
+ dbcgs->pValue->cchVal = l;
+
+ mir_free(tmp);
+ } break;
+ case DBT_ST_BLOB:
+ {
+ if (dbcgs->pValue->cchVal < set.Value.Length)
+ {
+ memcpy(dbcgs->pValue->pbVal, set.Value.pBlob, dbcgs->pValue->cchVal);
+ } else {
+ memcpy(dbcgs->pValue->pbVal, set.Value.pBlob, set.Value.Length);
+ }
+ dbcgs->pValue->type = DBVT_BLOB;
+ dbcgs->pValue->cchVal = set.Value.Length;
+
+ mir_free(set.Value.pBlob);
+ } break;
+ case DBT_ST_BOOL:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = set.Value.Bool ? TRUE : FALSE;
+ } break;
+ case DBT_ST_BYTE: case DBT_ST_CHAR:
+ {
+ dbcgs->pValue->type = DBVT_BYTE;
+ dbcgs->pValue->bVal = set.Value.Byte;
+ } break;
+ case DBT_ST_SHORT: case DBT_ST_WORD:
+ {
+ dbcgs->pValue->type = DBVT_WORD;
+ dbcgs->pValue->wVal = set.Value.Word;
+ } break;
+ case DBT_ST_INT: case DBT_ST_DWORD:
+ {
+ dbcgs->pValue->type = DBVT_DWORD;
+ dbcgs->pValue->dVal = set.Value.DWord;
+ } break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::FreeVariant(DBVARIANT *dbv)
+{
+ if ((dbv->type == DBVT_BLOB) && (dbv->pbVal))
+ {
+ mir_free(dbv->pbVal);
+ dbv->pbVal = 0;
+ } else if ((dbv->type & DBVTF_VARIABLELENGTH) && (dbv->pszVal))
+ {
+ mir_free(dbv->pszVal);
+ dbv->pszVal = NULL;
+ }
+ dbv->type = 0;
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::WriteContactSetting(HANDLE hContact, DBCONTACTWRITESETTING *dbcws)
+{
+ char namebuf[512];
+ namebuf[0] = 0;
+ if (dbcws->szModule)
+ strcpy_s(namebuf, dbcws->szModule);
+ strcat_s(namebuf, "/");
+ if (dbcws->szSetting)
+ strcat_s(namebuf, dbcws->szSetting);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ TDBTSetting set = {0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+ desc.pszSettingName = namebuf;
+
+ set.cbSize = sizeof(set);
+ set.Descriptor = &desc;
+
+ switch (dbcws->value.type)
+ {
+ case DBVT_ASCIIZ:
+ {
+ set.Type = DBT_ST_ANSI;
+ set.Value.pAnsi = dbcws->value.pszVal;
+ } break;
+ case DBVT_UTF8:
+ {
+ wchar_t * tmp = mir_utf8decodeW(dbcws->value.pszVal);
+ if (tmp == 0)
+ {
+ if (IsDebuggerPresent())
+ {
+ DebugBreak();
+#ifdef _DEBUG
+ } else {
+ LOG(logWARNING, _T("Trying to write malformed UTF8 setting \"%hs\" in module \"%hs\""), dbcws->szSetting, dbcws->szModule);
+ CLogger::Instance().ShowMessage();
+#endif
+ }
+ return -1;
+ } else {
+ mir_free(tmp);
+ }
+
+ set.Type = DBT_ST_UTF8;
+ set.Value.pUTF8 = dbcws->value.pszVal;
+ } break;
+ case DBVT_WCHAR:
+ {
+ set.Type = DBT_ST_WCHAR;
+ set.Value.pWide = dbcws->value.pwszVal;
+ } break;
+ case DBVT_BLOB:
+ {
+ set.Type = DBT_ST_BLOB;
+ set.Value.pBlob = dbcws->value.pbVal;
+ set.Value.Length = dbcws->value.cpbVal;
+ } break;
+ case DBVT_BYTE:
+ {
+ set.Type = DBT_ST_BYTE;
+ set.Value.Byte = dbcws->value.bVal;
+ } break;
+ case DBVT_WORD:
+ {
+ set.Type = DBT_ST_WORD;
+ set.Value.Word = dbcws->value.wVal;
+ } break;
+ case DBVT_DWORD:
+ {
+ set.Type = DBT_ST_DWORD;
+ set.Value.DWord = dbcws->value.dVal;
+ } break;
+ default:
+ {
+ return -1;
+ }
+ }
+
+ if (DBSettingWrite(reinterpret_cast<WPARAM>(&set), 0) == DBT_INVALIDPARAM)
+ return -1;
+
+ if (dbcws->value.type == DBVT_WCHAR)
+ {
+ dbcws->value.type = DBVT_UTF8;
+ wchar_t * tmp = dbcws->value.pwszVal;
+ dbcws->value.pszVal = mir_utf8encodeW(dbcws->value.pwszVal);
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (LPARAM)dbcws);
+ mir_free(dbcws->value.pszVal);
+ dbcws->value.type = DBVT_WCHAR;
+ dbcws->value.pwszVal = tmp;
+ } else {
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (LPARAM)dbcws);
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::DeleteContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dbcgs)
+{
+ char namebuf[512];
+ namebuf[0] = 0;
+ if (dbcgs->szModule)
+ strcpy_s(namebuf, dbcgs->szModule);
+ strcat_s(namebuf, "/");
+ if (dbcgs->szSetting)
+ strcat_s(namebuf, dbcgs->szSetting);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+ desc.pszSettingName = namebuf;
+
+ if (DBSettingDelete(reinterpret_cast<WPARAM>(&desc), 0) == DBT_INVALIDPARAM)
+ return -1;
+
+ {
+ DBCONTACTWRITESETTING tmp = {0,0,0,0};
+ tmp.szModule = dbcgs->szModule;
+ tmp.szSetting = dbcgs->szSetting;
+ tmp.value.type = 0;
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (LPARAM)&tmp);
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::EnumContactSettings(HANDLE hContact, DBCONTACTENUMSETTINGS* pces)
+{
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.Entity = (WPARAM)hContact;
+
+ char namebuf[512];
+ namebuf[0] = 0;
+ if (pces->szModule)
+ strcpy_s(namebuf, pces->szModule);
+ strcat_s(namebuf, "/");
+
+ TDBTSettingIterFilter filter = {0,0,0,0,0,0,0,0};
+ filter.cbSize = sizeof(filter);
+ filter.Descriptor = &desc;
+ filter.hEntity = (WPARAM)(WPARAM)hContact;
+ filter.NameStart = namebuf;
+
+ TDBTSettingIterationHandle hiter = DBSettingIterInit(reinterpret_cast<WPARAM>(&filter), 0);
+ if ((hiter == 0) || (hiter == DBT_INVALIDPARAM))
+ return -1;
+
+ int res = 0;
+ TDBTSettingHandle hset = DBSettingIterNext(hiter, 0);
+ while (hset != 0)
+ {
+ char * p = strchr(desc.pszSettingName, '/');
+ if (p) {
+ ++p;
+ } else {
+ p = desc.pszSettingName;
+ }
+
+ res = pces->pfnEnumProc(p, pces->lParam);
+ if (res == 0)
+ {
+ hset = DBSettingIterNext(hiter, 0);
+ } else {
+ hset = 0;
+ }
+ }
+
+ DBSettingIterClose(hiter, 0);
+
+ if (desc.pszSettingName)
+ mir_free(desc.pszSettingName);
+
+ return res;
+}
+
+STDMETHODIMP_(LONG) CDataBase::GetEventCount(HANDLE hContact)
+{
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+
+ return DBEventGetCount((WPARAM)hContact, 0);
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::AddEvent(HANDLE hContact, DBEVENTINFO *dbei)
+{
+ if (dbei->cbSize < sizeof(DBEVENTINFO))
+ return (HANDLE)-1;
+
+ int tmp = NotifyEventHooks(hEventFilterAddedEvent, (WPARAM)hContact, (LPARAM)dbei);
+ if (tmp != 0)
+ return (HANDLE)tmp;
+
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+
+
+ TDBTEvent ev = {0,0,0,0,0,0,0};
+ ev.cbSize = sizeof(ev);
+ ev.ModuleName = dbei->szModule;
+ ev.Timestamp = dbei->timestamp;
+ ev.Flags = dbei->flags;
+ if (ev.Flags & DBEF_SENT)
+ ev.Flags = ev.Flags | DBEF_READ;
+ ev.EventType = dbei->eventType;
+ ev.cbBlob = dbei->cbBlob;
+ ev.pBlob = dbei->pBlob;
+
+ int res = DBEventAdd((WPARAM)hContact, reinterpret_cast<LPARAM>(&ev));
+ if (res != DBT_INVALIDPARAM)
+ {
+ NotifyEventHooks(hEventAddedEvent, (WPARAM)hContact, res);
+ return (HANDLE)res;
+ }
+ return NULL;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::DeleteEvent(HANDLE hContact, HANDLE hDbEvent)
+{
+ int res = NotifyEventHooks(hEventDeletedEvent, (WPARAM)hContact, (WPARAM)hDbEvent);
+
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+
+ if (res == 0)
+ return DBEventDelete((WPARAM)hDbEvent, 0);
+
+ return res;
+}
+
+STDMETHODIMP_(LONG) CDataBase::GetBlobSize(HANDLE hDbEvent)
+{
+ int res = DBEventGetBlobSize((WPARAM)hDbEvent, 0);
+ if (res == DBT_INVALIDPARAM)
+ return -1;
+
+ return res;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::GetEvent(HANDLE hDbEvent, DBEVENTINFO *dbei)
+{
+ if (dbei->cbSize < sizeof(DBEVENTINFO))
+ return -1;
+
+ TDBTEvent ev = {0,0,0,0,0,0,0};
+ ev.cbSize = sizeof(ev);
+ ev.cbBlob = 0;
+ ev.pBlob = NULL;
+
+ int res = DBEventGet((WPARAM)hDbEvent, reinterpret_cast<LPARAM>(&ev));
+
+ dbei->szModule = ev.ModuleName;
+ dbei->timestamp = ev.Timestamp;
+ dbei->flags = ev.Flags;
+ if (dbei->flags & DBEF_SENT)
+ dbei->flags = dbei->flags & ~DBEF_READ;
+ dbei->eventType = ev.EventType;
+
+ if (dbei->cbBlob && dbei->pBlob)
+ {
+ if (dbei->cbBlob >= ev.cbBlob)
+ memcpy(dbei->pBlob, ev.pBlob, ev.cbBlob);
+ else
+ memcpy(dbei->pBlob, ev.pBlob, dbei->cbBlob);
+ }
+ mir_free(ev.pBlob);
+ dbei->cbBlob = ev.cbBlob;
+
+ if (res == DBT_INVALIDPARAM)
+ return 1;
+
+ return res;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::MarkEventRead(HANDLE hContact, HANDLE hDbEvent)
+{
+ int res = DBEventMarkRead((WPARAM)hDbEvent, 0);
+ if ((res != DBT_INVALIDPARAM) && (res & DBEF_SENT))
+ res = res & ~DBEF_READ;
+ return res;
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::GetEventContact(HANDLE hDbEvent)
+{
+ TDBTEntityHandle res = DBEventGetEntity((WPARAM)hDbEvent, 0);
+ if (res == gDataBase->getEntities().getRootEntity())
+ res = 0;
+
+ return (HANDLE)res;
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::FindFirstEvent(HANDLE hContact)
+{
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+
+ return (HANDLE)gDataBase->getEvents().compFirstEvent((WPARAM)hContact);
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::FindFirstUnreadEvent(HANDLE hContact)
+{
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+ return (HANDLE)gDataBase->getEvents().compFirstUnreadEvent((WPARAM)hContact);
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::FindLastEvent(HANDLE hContact)
+{
+ if (hContact == 0)
+ hContact = (HANDLE)gDataBase->getEntities().getRootEntity();
+ return (HANDLE)gDataBase->getEvents().compLastEvent((WPARAM)hContact);
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::FindNextEvent(HANDLE hDbEvent)
+{
+ return (HANDLE)gDataBase->getEvents().compNextEvent((WPARAM)hDbEvent);
+}
+
+STDMETHODIMP_(HANDLE) CDataBase::FindPrevEvent(HANDLE hDbEvent)
+{
+ return (HANDLE)gDataBase->getEvents().compPrevEvent((WPARAM)hDbEvent);
+}
+
+STDMETHODIMP_(BOOL) CDataBase::EnumModuleNames(DBMODULEENUMPROC pCallback, void *pParam)
+{
+ if (!pCallback)
+ return -1;
+
+ return gDataBase->getSettings().CompEnumModules(pCallback, (WPARAM)pParam);
+}
+
+STDMETHODIMP_(BOOL) CDataBase::SetSettingResident(BOOL bIsResident, const char *pszSettingName)
+{
+ return FALSE;
+}
+
+STDMETHODIMP_(BOOL) CDataBase::EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam)
+{
+ return FALSE;
+}
+
+STDMETHODIMP_(void) CDataBase::SetCacheSafetyMode(BOOL) {}
+
+bool CompatibilityRegister()
+{
+ hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED);
+ hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED);
+ hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD);
+ hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED);
+ hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED);
+ hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED);
+ return true;
+}
diff --git a/plugins/Dbx_tree/src/Compatibility.h b/plugins/Dbx_tree/src/Compatibility.h
new file mode 100644
index 0000000000..a23fa9284b
--- /dev/null
+++ b/plugins/Dbx_tree/src/Compatibility.h
@@ -0,0 +1,30 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include "Interface.h"
+#include "DataBase.h"
+#include "Services.h"
+
+bool CompatibilityRegister();
+
diff --git a/plugins/Dbx_tree/src/DataBase.cpp b/plugins/Dbx_tree/src/DataBase.cpp
new file mode 100644
index 0000000000..50fe494b3c
--- /dev/null
+++ b/plugins/Dbx_tree/src/DataBase.cpp
@@ -0,0 +1,371 @@
+/*
+
+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 "DataBase.h"
+#include "newpluginapi.h"
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#endif
+#include "Logger.h"
+
+CDataBase *gDataBase = NULL;
+
+CDataBase::CDataBase(const TCHAR *FileName)
+{
+ InitDbInstance(this);
+
+ size_t len = _tcslen(FileName);
+ m_FileName[0] = new TCHAR[len + 1];
+ _tcsncpy_s(m_FileName[0], len + 1, FileName, len);
+ m_FileName[0][len] = 0;
+
+ TCHAR * tmp = _tcsrchr(m_FileName[0], '.');
+ if (tmp)
+ {
+ m_FileName[1] = new TCHAR[len + 1];
+ _tcsncpy_s(m_FileName[1], len + 1, m_FileName[0], tmp - m_FileName[0]);
+ _tcscat_s(m_FileName[1], len + 1, _T(".pri"));
+ } else {
+ m_FileName[1] = new TCHAR[len + 5];
+ _tcscpy_s(m_FileName[1], len + 5, m_FileName[0]);
+ _tcscat_s(m_FileName[1], len + 5, _T(".pri"));
+ }
+
+ m_Opened = false;
+
+ for (int i = 0; i < DBFileMax; ++i)
+ {
+ m_BlockManager[i] = NULL;
+ m_FileAccess[i] = NULL;
+ m_EncryptionManager[i] = NULL;
+ m_HeaderBlock[i] = 0;
+ }
+
+ m_Entities = NULL;
+ m_Settings = NULL;
+ m_Events = NULL;
+
+}
+CDataBase::~CDataBase()
+{
+ if (m_Events) delete m_Events;
+ if (m_Settings) delete m_Settings;
+ if (m_Entities) delete m_Entities;
+
+ m_Entities = NULL;
+ m_Settings = NULL;
+ m_Events = NULL;
+
+ for (int i = DBFileMax - 1; i >= 0; --i)
+ {
+ if (m_BlockManager[i]) delete m_BlockManager[i];
+ if (m_FileAccess[i]) delete m_FileAccess[i];
+ if (m_EncryptionManager[i]) delete m_EncryptionManager[i];
+
+ m_BlockManager[i] = NULL;
+ m_FileAccess[i] = NULL;
+ m_EncryptionManager[i] = NULL;
+
+ delete [] (m_FileName[i]);
+ }
+ DestroyDbInstance(this);
+}
+
+int CDataBase::CreateDB()
+{
+ /// TODO: create and show wizard
+ if (!CreateNewFile(DBFileSetting) ||
+ !CreateNewFile(DBFilePrivate))
+ return EMKPRF_CREATEFAILED;
+
+ return 0;
+}
+
+
+int CDataBase::CheckFile(TDBFileType Index)
+{
+ TGenericFileHeader h;
+ memset(&h, 0, sizeof(h));
+ DWORD r = 0;
+ HANDLE htmp = CreateFile(m_FileName[Index], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+ if (htmp != INVALID_HANDLE_VALUE)
+ {
+ SetFilePointer(htmp, 0, NULL, FILE_BEGIN);
+ if (ReadFile(htmp, &h, sizeof(h), &r, NULL))
+ {
+ if (0 != memcmp(h.Gen.Signature, cFileSignature[Index], sizeof(cFileSignature[Index])))
+ {
+ CloseHandle(htmp);
+ return EGROKPRF_UNKHEADER;
+ }
+
+ if (cDBVersion < h.Gen.Version)
+ {
+ CloseHandle(htmp);
+ return EGROKPRF_VERNEWER;
+ }
+
+ CloseHandle(htmp);
+ return EGROKPRF_NOERROR;
+ }
+ CloseHandle(htmp);
+ }
+
+ return EGROKPRF_CANTREAD;
+}
+
+int CDataBase::CheckDB()
+{
+ int res = CheckFile(DBFileSetting);
+
+ if (res != EGROKPRF_NOERROR)
+ return res;
+
+ if (PrivateFileExists())
+ res = CheckFile(DBFilePrivate);
+
+ return res;
+}
+
+int CDataBase::LoadFile(TDBFileType Index)
+{
+ TGenericFileHeader h;
+ m_EncryptionManager[Index] = new CEncryptionManager;
+
+ if (CMappedMemory::InitMMAP())
+ m_FileAccess[Index] = new CMappedMemory(m_FileName[Index]);
+ else
+ m_FileAccess[Index] = new CDirectAccess(m_FileName[Index]);
+
+ m_FileAccess[Index]->Read(&h, 0, sizeof(h));
+ m_EncryptionManager[Index]->InitEncryption(h.Gen.FileEncryption);
+
+ m_FileAccess[Index]->Size(h.Gen.FileSize);
+ m_FileAccess[Index]->sigFileSizeChanged().connect(this, &CDataBase::onFileSizeChanged);
+
+ m_BlockManager[Index] = new CBlockManager(*m_FileAccess[Index], *m_EncryptionManager[Index]);
+
+ CBlockManager::WriteTransaction trans(*m_BlockManager[Index]); // don't fire size event until header is loaded
+
+ m_HeaderBlock[Index] = m_BlockManager[Index]->ScanFile(sizeof(h), cHeaderBlockSignature, h.Gen.FileSize);
+
+ if (m_HeaderBlock[Index] == 0)
+ {
+ LOG(logCRITICAL, _T("Header Block not found! File damaged: \"%s\""), m_FileName[Index]);
+ return -1;
+ }
+
+ uint32_t size = sizeof(h);
+ uint32_t sig = -1;
+ m_Header[Index] = m_BlockManager[Index]->ReadBlock<TGenericFileHeader>(0, size, sig);
+
+ sig = cHeaderBlockSignature;
+ TGenericFileHeader * buf = m_BlockManager[Index]->ReadBlock<TGenericFileHeader>(m_HeaderBlock[Index], size, sig);
+ if (!buf)
+ {
+ LOG(logCRITICAL, _T("Header Block cannot be read! File damaged: \"%s\""), m_FileName[Index]);
+ return -1;
+ }
+
+ buf->Gen.Obscure = 0;
+
+ if (memcmp(m_Header[Index], buf, size))
+ {
+ LOG(logCRITICAL, _T("Header Block in \"%s\" damaged!"), m_FileName[Index]);
+ return -1;
+ }
+
+ return 0;
+}
+
+int CDataBase::OpenDB()
+{
+ if (!PrivateFileExists())
+ {
+ // TODO WIZARD
+ if (!CreateNewFile(DBFilePrivate))
+ return -1;
+ }
+
+ int res = LoadFile(DBFileSetting);
+ if ((res != 0) && (CLogger::logERROR <= CLogger::Instance().ShowMessage()))
+ {
+ return res;
+ }
+
+ res = LoadFile(DBFilePrivate);
+
+ if ((res != 0) && (CLogger::logERROR <= CLogger::Instance().ShowMessage()))
+ {
+ return res;
+ }
+ if (CLogger::logERROR <= CLogger::Instance().ShowMessage())
+ return -1;
+
+ m_Entities = new CEntities(*m_BlockManager[DBFilePrivate],
+ m_Header[DBFilePrivate]->Pri.RootEntity,
+ m_Header[DBFilePrivate]->Pri.Entities,
+ m_Header[DBFilePrivate]->Pri.Virtuals);
+
+ m_Entities->sigRootChanged().connect(this, &CDataBase::onEntitiesRootChanged);
+ m_Entities->sigVirtualRootChanged().connect(this, &CDataBase::onVirtualsRootChanged);
+
+ if (m_Entities->getRootEntity() != m_Header[DBFilePrivate]->Pri.RootEntity)
+ {
+ m_Header[DBFilePrivate]->Pri.RootEntity = m_Entities->getRootEntity();
+ ReWriteHeader(DBFilePrivate);
+ }
+
+ m_Settings = new CSettings(*m_BlockManager[DBFileSetting],
+ *m_BlockManager[DBFilePrivate],
+ m_Header[DBFileSetting]->Set.Settings,
+ *m_Entities);
+
+ m_Settings->sigRootChanged().connect(this, &CDataBase::onSettingsRootChanged);
+
+ m_Events = new CEvents(*m_BlockManager[DBFilePrivate],
+ *m_EncryptionManager[DBFilePrivate],
+ *m_Entities,
+ *m_Settings);
+
+ return 0;
+}
+
+bool CDataBase::PrivateFileExists()
+{
+ HANDLE htmp = CreateFile(m_FileName[DBFilePrivate], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+ if (htmp != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(htmp);
+ return true;
+ }
+
+ return false;
+}
+
+
+bool CDataBase::CreateNewFile(TDBFileType File)
+{
+ CEncryptionManager enc;
+ CDirectAccess fa(m_FileName[File]);
+ fa.Size(sizeof(TGenericFileHeader));
+ CBlockManager bm(fa, enc);
+ bm.ScanFile(sizeof(TGenericFileHeader), 0, sizeof(TGenericFileHeader));
+
+ CBlockManager::WriteTransaction trans(bm);
+
+ uint32_t block;
+ TGenericFileHeader * buf = bm.CreateBlock<TGenericFileHeader>(block, cHeaderBlockSignature);
+ uint32_t size = 0;
+ uint32_t sig = -1;
+ TGenericFileHeader * h = bm.ReadBlock<TGenericFileHeader>(0, size, sig);
+
+ memset(h, 0, sizeof(TGenericFileHeader));
+ memcpy(&h->Gen.Signature, &cFileSignature[File], sizeof(h->Gen.Signature));
+ h->Gen.Version = cDBVersion;
+ h->Gen.FileSize = fa.Size();
+
+ memcpy(buf, h, sizeof(TGenericFileHeader));
+ bm.UpdateBlock(block, 0);
+ bm.UpdateBlock(0, -1);
+
+ return true;
+}
+
+inline void CDataBase::ReWriteHeader(TDBFileType Index)
+{
+ m_BlockManager[Index]->UpdateBlock(0, -1);
+ uint32_t size = 0, sig = 0;
+ TGenericFileHeader * h = m_BlockManager[Index]->ReadBlock<TGenericFileHeader>(m_HeaderBlock[Index], size, sig);
+
+ *h = *m_Header[Index];
+ h->Gen.Obscure = GetTickCount();
+ m_BlockManager[Index]->UpdateBlock(m_HeaderBlock[Index], 0);
+}
+
+
+void CDataBase::onSettingsRootChanged(CSettings* Settings, CSettingsTree::TNodeRef NewRoot)
+{
+ m_Header[DBFileSetting]->Set.Settings = NewRoot;
+ ReWriteHeader(DBFileSetting);
+}
+void CDataBase::onVirtualsRootChanged(void* Virtuals, CVirtuals::TNodeRef NewRoot)
+{
+ m_Header[DBFilePrivate]->Pri.Virtuals = NewRoot;
+ ReWriteHeader(DBFilePrivate);
+}
+void CDataBase::onEntitiesRootChanged(void* Entities, CEntities::TNodeRef NewRoot)
+{
+ m_Header[DBFilePrivate]->Pri.Entities = NewRoot;
+ ReWriteHeader(DBFilePrivate);
+}
+void CDataBase::onFileSizeChanged(CFileAccess * File, uint32_t Size)
+{
+ if (File == m_FileAccess[DBFileSetting])
+ {
+ m_Header[DBFileSetting]->Gen.FileSize = Size;
+ ReWriteHeader(DBFileSetting);
+ } else {
+ m_Header[DBFilePrivate]->Gen.FileSize = Size;
+ ReWriteHeader(DBFilePrivate);
+ }
+}
+
+int CDataBase::getProfileName(int BufferSize, char * Buffer)
+{
+ TCHAR * slash = _tcsrchr(m_FileName[DBFileSetting], '\\');
+ if (slash)
+ slash++;
+ else
+ slash = m_FileName[DBFileSetting];
+
+ int l = static_cast<int>(_tcslen(slash));
+ if (BufferSize < l + 1)
+ return -1;
+
+ char * tmp = mir_t2a(slash);
+ strcpy_s(Buffer, BufferSize, tmp);
+ mir_free(tmp);
+
+ return 0;
+}
+int CDataBase::getProfilePath(int BufferSize, char * Buffer)
+{
+ TCHAR * slash = _tcsrchr(m_FileName[DBFileSetting], '\\');
+ if (!slash)
+ return -1;
+
+ int l = slash - m_FileName[DBFileSetting];
+
+ if (BufferSize < l + 1)
+ {
+ return -1;
+ }
+
+ *slash = 0;
+ char * tmp = mir_t2a(m_FileName[DBFileSetting]);
+ strcpy_s(Buffer, BufferSize, tmp);
+ mir_free(tmp);
+ *slash = '\\';
+
+ return 0;
+}
diff --git a/plugins/Dbx_tree/src/DataBase.h b/plugins/Dbx_tree/src/DataBase.h
new file mode 100644
index 0000000000..124fee4f9d
--- /dev/null
+++ b/plugins/Dbx_tree/src/DataBase.h
@@ -0,0 +1,189 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "stdint.h"
+#endif
+#include "MREWSync.h"
+
+#include "Events.h"
+#include "Settings.h"
+#include "Entities.h"
+
+#include "FileAccess.h"
+#include "MappedMemory.h"
+#include "DirectAccess.h"
+#include "Blockmanager.h"
+
+#include "sigslot.h"
+
+#include "EncryptionManager.h"
+
+typedef enum TDBFileType {
+ DBFileSetting = 0,
+ DBFilePrivate = 1,
+ DBFileMax = 2
+} TDBFileType;
+
+static const uint8_t cFileSignature[DBFileMax][20] = {"Miranda IM Settings", "Miranda IM DataTree"};
+static const uint32_t cDBVersion = 0x00000001;
+
+static const uint32_t cHeaderBlockSignature = 0x7265491E;
+
+#pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+typedef struct TSettingsHeader {
+ uint8_t Signature[20]; /// signature must be cSettingsHeader
+ uint32_t Version; /// internal DB version cDataBaseVersion
+ uint32_t Obscure;
+ TFileEncryption FileEncryption; /// Encryption Method
+ uint32_t FileStructureBlock; /// Offset of CBlockManager master block
+ uint32_t FileSize; /// Offset to the last used byte + 1
+ uint32_t Settings; /// Offset to the SettingsBTree RootNode
+ uint8_t Reserved[256 - sizeof(TFileEncryption) - 20 - 5*sizeof(uint32_t)]; /// reserved storage
+} TSettingsHeader;
+
+typedef struct TPrivateHeader {
+ uint8_t Signature[20]; /// signature must be CDataHeader
+ uint32_t Version; /// internal DB version cDataBaseVersion
+ uint32_t Obscure;
+ TFileEncryption FileEncryption; /// Encryption Method
+ uint32_t FileStructureBlock; /// Offset of CBlockManager master block
+ uint32_t FileSize; /// Offset to the last used byte + 1
+ uint32_t RootEntity; /// Offset to the Root CList Entity
+ uint32_t Entities; /// Offset to the EntityBTree RootNode
+ uint32_t Virtuals; /// Offset to the VirtualsBTree RootNode
+ uint8_t Reserved[256 - sizeof(TFileEncryption) - 20 - 7*sizeof(uint32_t)]; /// reserved storage
+} TPrivateHeader;
+
+
+typedef union TGenericFileHeader {
+ struct {
+ uint8_t Signature[20]; /// signature must be cSettingsHeader
+ uint32_t Version; /// internal DB version cDataBaseVersion
+ uint32_t Obscure;
+ TFileEncryption FileEncryption; /// Encryption Method
+ uint32_t FileStructureBlock; /// Offset of CBlockManager master block
+ uint32_t FileSize; /// Offset to the last used byte + 1
+ uint8_t Reserved[256 - sizeof(TFileEncryption) - 20 - 4*sizeof(uint32_t)]; /// reserved storage
+ } Gen;
+ TSettingsHeader Set;
+ TPrivateHeader Pri;
+} TGenericFileHeader;
+
+#pragma pack(pop)
+
+class CDataBase : public sigslot::has_slots<>, public MIDatabase
+{
+private:
+ TCHAR* m_FileName[DBFileMax];
+ bool m_Opened;
+
+ CBlockManager *m_BlockManager[DBFileMax];
+ CFileAccess *m_FileAccess[DBFileMax];
+ TGenericFileHeader * m_Header[DBFileMax];
+ CEncryptionManager *m_EncryptionManager[DBFileMax];
+
+ uint32_t m_HeaderBlock[DBFileMax];
+
+ void onSettingsRootChanged(CSettings* Settings, CSettingsTree::TNodeRef NewRoot);
+ void onVirtualsRootChanged(void* Virtuals, CVirtuals::TNodeRef NewRoot);
+ void onEntitiesRootChanged(void* Entities, CEntities::TNodeRef NewRoot);
+ void onFileSizeChanged(CFileAccess * File, uint32_t Size);
+
+ bool PrivateFileExists();
+ bool CreateNewFile(TDBFileType File);
+
+ int CheckFile(TDBFileType Index);
+ int LoadFile(TDBFileType Index);
+protected:
+ CEntities *m_Entities;
+ CSettings *m_Settings;
+ CEvents *m_Events;
+
+ void ReWriteHeader(TDBFileType Index);
+
+public:
+ CDataBase(const TCHAR* FileName);
+ virtual ~CDataBase();
+
+ int CreateDB();
+ int CheckDB();
+ int OpenDB();
+
+ CEntities & getEntities()
+ {
+ return *m_Entities;
+ }
+ CSettings & getSettings()
+ {
+ return *m_Settings;
+ }
+ CEvents & getEvents()
+ {
+ return *m_Events;
+ }
+
+ int getProfileName(int BufferSize, char * Buffer);
+ int getProfilePath(int BufferSize, char * Buffer);
+
+protected: // to be compatible with the standard Miranda databases
+ STDMETHODIMP_(void) SetCacheSafetyMode(BOOL);
+
+ STDMETHODIMP_(LONG) GetContactCount(void);
+ STDMETHODIMP_(HANDLE) FindFirstContact(const char* szProto = NULL);
+ STDMETHODIMP_(HANDLE) FindNextContact(HANDLE hContact, const char* szProto = NULL);
+ STDMETHODIMP_(LONG) DeleteContact(HANDLE hContact);
+ STDMETHODIMP_(HANDLE) AddContact(void);
+ STDMETHODIMP_(BOOL) IsDbContact(HANDLE hContact);
+
+ STDMETHODIMP_(LONG) GetEventCount(HANDLE hContact);
+ STDMETHODIMP_(HANDLE) AddEvent(HANDLE hContact, DBEVENTINFO *dbe);
+ STDMETHODIMP_(BOOL) DeleteEvent(HANDLE hContact, HANDLE hDbEvent);
+ STDMETHODIMP_(LONG) GetBlobSize(HANDLE hDbEvent);
+ STDMETHODIMP_(BOOL) GetEvent(HANDLE hDbEvent, DBEVENTINFO *dbe);
+ STDMETHODIMP_(BOOL) MarkEventRead(HANDLE hContact, HANDLE hDbEvent);
+ STDMETHODIMP_(HANDLE) GetEventContact(HANDLE hDbEvent);
+ STDMETHODIMP_(HANDLE) FindFirstEvent(HANDLE hContact);
+ STDMETHODIMP_(HANDLE) FindFirstUnreadEvent(HANDLE hContact);
+ STDMETHODIMP_(HANDLE) FindLastEvent(HANDLE hContact);
+ STDMETHODIMP_(HANDLE) FindNextEvent(HANDLE hDbEvent);
+ STDMETHODIMP_(HANDLE) FindPrevEvent(HANDLE hDbEvent);
+
+ STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam);
+
+ STDMETHODIMP_(BOOL) GetContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dbcgs);
+ STDMETHODIMP_(BOOL) GetContactSettingStr(HANDLE hContact, DBCONTACTGETSETTING *dbcgs);
+ STDMETHODIMP_(BOOL) GetContactSettingStatic(HANDLE hContact, DBCONTACTGETSETTING *dbcgs);
+ STDMETHODIMP_(BOOL) FreeVariant(DBVARIANT *dbv);
+ STDMETHODIMP_(BOOL) WriteContactSetting(HANDLE hContact, DBCONTACTWRITESETTING *dbcws);
+ STDMETHODIMP_(BOOL) DeleteContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dbcgs);
+ STDMETHODIMP_(BOOL) EnumContactSettings(HANDLE hContact, DBCONTACTENUMSETTINGS* dbces);
+ STDMETHODIMP_(BOOL) SetSettingResident(BOOL bIsResident, const char *pszSettingName);
+ STDMETHODIMP_(BOOL) EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam);
+};
+
+extern CDataBase *gDataBase;
diff --git a/plugins/Dbx_tree/src/DatabaseLink.cpp b/plugins/Dbx_tree/src/DatabaseLink.cpp
new file mode 100644
index 0000000000..cc944cc305
--- /dev/null
+++ b/plugins/Dbx_tree/src/DatabaseLink.cpp
@@ -0,0 +1,96 @@
+/*
+
+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 "DatabaseLink.h"
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#endif
+
+
+/*
+ profile: pointer to a string which contains full path + name
+ Affect: The database plugin should create the profile, the filepath will not exist at
+ the time of this call, profile will be C:\..\<name>.dat
+ Note: Do not prompt the user in anyway about this operation.
+ Note: Do not initialise internal data structures at this point!
+ Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_*
+*/
+
+static int makeDatabase(const TCHAR *profile)
+{
+ std::auto_ptr<CDataBase> db( new CDataBase(profile));
+ return db->CreateDB();
+}
+
+/*
+ profile: [in] a null terminated string to file path of selected profile
+ error: [in/out] pointer to an int to set with error if any
+ Affect: Ask the database plugin if it supports the given profile, if it does it will
+ return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error
+ condition, most common error would be [EGROKPRF_UNKHEADER]
+ Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged
+ etc.
+ Returns: 0 on success, non zero on failure
+*/
+static int grokHeader(const TCHAR *profile)
+{
+ std::auto_ptr<CDataBase> db( new CDataBase(profile));
+ return db->CheckDB();
+}
+
+/*
+Affect: Tell the database to create all services/hooks that a 3.xx legecy database might support into link,
+ which is a PLUGINLINK structure
+Returns: 0 on success, nonzero on failure
+*/
+
+static MIDatabase* LoadDatabase(const TCHAR *profile)
+{
+ gDataBase = new CDataBase(profile);
+ gDataBase->OpenDB();
+ return gDataBase;
+}
+
+/*
+Affect: The database plugin should shutdown, unloading things from the core and freeing internal structures
+Returns: 0 on success, nonzero on failure
+Note: Unload() might be called even if Load(void) was never called, wasLoaded is set to 1 if Load(void) was ever called.
+*/
+
+static int UnloadDatabase(MIDatabase* db)
+{
+ if (gDataBase == db)
+ gDataBase = NULL;
+ delete (CDataBase*)db;
+ return 0;
+}
+
+DATABASELINK gDBLink = {
+ sizeof(DATABASELINK),
+ gInternalName,
+ _T(gInternalNameLong),
+ makeDatabase,
+ grokHeader,
+ LoadDatabase,
+ UnloadDatabase,
+ NULL // does not support file checking
+};
diff --git a/plugins/Dbx_tree/src/DatabaseLink.h b/plugins/Dbx_tree/src/DatabaseLink.h
new file mode 100644
index 0000000000..c0c20b7fa0
--- /dev/null
+++ b/plugins/Dbx_tree/src/DatabaseLink.h
@@ -0,0 +1,28 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+#include <windows.h>
+#include "Interface.h"
+#include "Database.h"
+#include "Services.h"
+#include "Compatibility.h" \ No newline at end of file
diff --git a/plugins/Dbx_tree/src/DirectAccess.cpp b/plugins/Dbx_tree/src/DirectAccess.cpp
new file mode 100644
index 0000000000..33785af7c4
--- /dev/null
+++ b/plugins/Dbx_tree/src/DirectAccess.cpp
@@ -0,0 +1,118 @@
+/*
+
+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 "DirectAccess.h"
+#include "Logger.h"
+
+CDirectAccess::CDirectAccess(const TCHAR* FileName)
+: CFileAccess(FileName)
+{
+ m_File = CreateFile(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
+ CHECKSYS(m_File != INVALID_HANDLE_VALUE,
+ logCRITICAL, _T("CreateFile failed"));
+
+ m_MinAllocGranularity = 0x00001000; // 4kb to avoid heavy fragmentation
+ m_AllocGranularity = 0x00008000; // 32kb
+ m_MaxAllocGranularity = 0x00100000; // 1mb for fast increasing
+
+ uint32_t size = GetFileSize(m_File, NULL);
+ size = (size + m_AllocGranularity - 1) & ~(m_AllocGranularity - 1);
+
+ if (size == 0)
+ size = m_AllocGranularity;
+
+ m_AllocSize = size;
+
+ InitJournal();
+}
+
+CDirectAccess::~CDirectAccess()
+{
+ if (m_File)
+ {
+ if (INVALID_SET_FILE_POINTER != SetFilePointer(m_File, m_Size, NULL, FILE_BEGIN))
+ SetEndOfFile(m_File);
+
+ CloseHandle(m_File);
+ }
+}
+
+uint32_t CDirectAccess::_Read(void* Buf, uint32_t Source, uint32_t Size)
+{
+ DWORD read = 0;
+
+ CHECKSYS(INVALID_SET_FILE_POINTER != SetFilePointer(m_File, Source, NULL, FILE_BEGIN),
+ logERROR, _T("SetFilePointer failed"));
+
+ CHECKSYS(ReadFile(m_File, Buf, Size, &read, NULL),
+ logERROR, _T("ReadFile failed"));
+
+ return read;
+}
+uint32_t CDirectAccess::_Write(void* Buf, uint32_t Dest, uint32_t Size)
+{
+ DWORD written = 0;
+
+ CHECKSYS(INVALID_SET_FILE_POINTER != SetFilePointer(m_File, Dest, NULL, FILE_BEGIN),
+ logERROR, _T("SetFilePointer failed"));
+
+ CHECKSYS(WriteFile(m_File, Buf, Size, &written, NULL),
+ logERROR, _T("WriteFile failed"));
+
+ return written;
+}
+
+uint32_t CDirectAccess::_SetSize(uint32_t Size)
+{
+ CHECKSYS(INVALID_SET_FILE_POINTER != SetFilePointer(m_File, Size, NULL, FILE_BEGIN),
+ logERROR, _T("SetFilePointer failed"));
+
+ CHECKSYS(SetEndOfFile(m_File),
+ logERROR, _T("SetEndOfFile failed"));
+
+ return Size;
+}
+
+void CDirectAccess::_Invalidate(uint32_t Dest, uint32_t Size)
+{
+ DWORD written;
+ uint8_t buf[4096];
+ memset(buf, 0, sizeof(buf));
+
+ CHECKSYS(INVALID_SET_FILE_POINTER != SetFilePointer(m_File, Dest, NULL, FILE_BEGIN),
+ logERROR, _T("SetFilePointer failed"));
+
+ while (Size > sizeof(buf))
+ {
+ Size -= sizeof(buf);
+ CHECKSYS(WriteFile(m_File, buf, sizeof(buf), &written, NULL),
+ logERROR, _T("WriteFile failed"));
+ }
+ CHECKSYS(WriteFile(m_File, buf, Size, &written, NULL),
+ logERROR, _T("WriteFile failed"));
+}
+
+void CDirectAccess::_Flush()
+{
+ CHECKSYS(FlushFileBuffers(m_File),
+ logERROR, _T("FlushFileBuffers failed"));
+}
diff --git a/plugins/Dbx_tree/src/DirectAccess.h b/plugins/Dbx_tree/src/DirectAccess.h
new file mode 100644
index 0000000000..cc4241c235
--- /dev/null
+++ b/plugins/Dbx_tree/src/DirectAccess.h
@@ -0,0 +1,43 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <windows.h>
+#include "FileAccess.h"
+
+class CDirectAccess : public CFileAccess
+{
+private:
+
+ HANDLE m_File;
+protected:
+ uint32_t _Read(void* Buf, uint32_t Source, uint32_t Size);
+ uint32_t _Write(void* Buf, uint32_t Dest, uint32_t Size);
+ void _Invalidate(uint32_t Dest, uint32_t Size);
+ uint32_t _SetSize(uint32_t Size);
+ void _Flush();
+public:
+ CDirectAccess(const TCHAR* FileName);
+ virtual ~CDirectAccess();
+
+};
diff --git a/plugins/Dbx_tree/src/EncryptionManager.cpp b/plugins/Dbx_tree/src/EncryptionManager.cpp
new file mode 100644
index 0000000000..7afdcb248f
--- /dev/null
+++ b/plugins/Dbx_tree/src/EncryptionManager.cpp
@@ -0,0 +1,241 @@
+/*
+
+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 "EncryptionManager.h"
+#include <tchar.h>
+
+uint32_t CEncryptionManager::CipherListRefCount = 0;
+CEncryptionManager::TCipherList* CEncryptionManager::CipherList = NULL;
+
+static const uint32_t cFileBlockMask = 0xfffff000;
+
+void CEncryptionManager::LoadCipherList()
+{
+ if (CipherList)
+ return;
+
+ CipherList = new TCipherList;
+ CipherListRefCount++;
+
+ WIN32_FIND_DATA search;
+ TCHAR path[MAX_PATH * 8];
+ GetModuleFileName(NULL, path, sizeof(path));
+ TCHAR * file = _tcsrchr(path, '\\');
+ if (!file)
+ file = path;
+
+ _tcscpy_s(file, sizeof(path) / sizeof(path[0]) - (file - path), _T("\\plugins\\encryption\\*.dll"));
+ file += 20;
+
+ HANDLE hfinder = FindFirstFile(path, &search);
+ if (hfinder != INVALID_HANDLE_VALUE)
+ {
+ TCipherItem item;
+ TCipherInfo* (__cdecl *CipherInfoProc)(void *);
+ do {
+ _tcscpy_s(file, sizeof(path) / sizeof(path[0]) - (file - path), search.cFileName);
+ HMODULE hmod = LoadLibrary(path);
+ if (hmod)
+ {
+ CipherInfoProc = (TCipherInfo*(__cdecl*)(void*)) GetProcAddress(hmod, "CipherInfo");
+ if (CipherInfoProc)
+ {
+ TCipherInfo* info = CipherInfoProc(NULL);
+ if (info && (info->cbSize == sizeof(TCipherInfo)) && (CipherList->find(info->ID) == CipherList->end()))
+ {
+ item.ID = info->ID;
+ item.Name = _wcsdup(info->Name);
+ item.Description = _wcsdup(info->Description);
+ item.FilePath = _tcsdup(path);
+ item.FileName = item.FilePath + (file - path);
+
+ CipherList->insert(std::make_pair(item.ID, item));
+ }
+ }
+
+ FreeLibrary(hmod);
+
+ }
+ } while (FindNextFile(hfinder, &search));
+
+ FindClose(hfinder);
+ }
+}
+
+CEncryptionManager::CEncryptionManager()
+{
+ m_Ciphers[CURRENT].Cipher = NULL;
+ m_Ciphers[OLD].Cipher = NULL;
+ m_Changing = false;
+ m_ChangingProcess = 0;
+
+ LoadCipherList();
+}
+CEncryptionManager::~CEncryptionManager()
+{
+ if (m_Ciphers[CURRENT].Cipher)
+ delete m_Ciphers[CURRENT].Cipher;
+ m_Ciphers[CURRENT].Cipher = NULL;
+ if (m_Ciphers[OLD].Cipher)
+ delete m_Ciphers[OLD].Cipher;
+ m_Ciphers[OLD].Cipher = NULL;
+
+ CipherListRefCount--;
+ if (!CipherListRefCount)
+ {
+ TCipherList::iterator i = CipherList->begin();
+ while (i != CipherList->end())
+ {
+ free(i->second.Description);
+ free(i->second.Name);
+ free(i->second.FilePath);
+ // do not free Filename... it's a substring of FilePath
+ ++i;
+ }
+
+ delete CipherList;
+ CipherList = NULL;
+ }
+}
+
+bool CEncryptionManager::InitEncryption(TFileEncryption & Enc)
+{
+ if (Enc.ConversionProcess)
+ {
+ m_Changing = true;
+ m_ChangingProcess = Enc.ConversionProcess;
+ }
+
+ for (int c = (int)CURRENT; c < (int)COUNT; c++)
+ {
+ TCipherList::iterator i = CipherList->find(Enc.CipherID);
+ if (i != CipherList->end())
+ {
+ m_Ciphers[c].CipherDLL = LoadLibrary(i->second.FilePath);
+ if (m_Ciphers[c].CipherDLL)
+ {
+ TCipherInfo* (__cdecl *cipherinfoproc)(void *);
+ cipherinfoproc = (TCipherInfo*(__cdecl*)(void*)) GetProcAddress(m_Ciphers[c].CipherDLL, "CipherInfo");
+ if (cipherinfoproc)
+ {
+ TCipherInfo* info = cipherinfoproc(NULL);
+ if (info && (info->cbSize == sizeof(TCipherInfo)))
+ m_Ciphers[c].Cipher = new CCipher(info->Create());
+
+ }
+
+ if (!m_Ciphers[c].Cipher)
+ {
+ FreeLibrary(m_Ciphers[c].CipherDLL);
+ m_Ciphers[c].CipherDLL = NULL;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool CEncryptionManager::AlignData(uint32_t ID, uint32_t & Start, uint32_t & End)
+{
+ if (m_Ciphers[CURRENT].Cipher && (!m_Changing || (ID < m_ChangingProcess)))
+ {
+ if (m_Ciphers[CURRENT].Cipher->IsStreamCipher())
+ {
+ Start = 0;
+ End = End - End % m_Ciphers[CURRENT].Cipher->BlockSizeBytes() + m_Ciphers[CURRENT].Cipher->BlockSizeBytes();
+ } else {
+ Start = Start - Start % m_Ciphers[CURRENT].Cipher->BlockSizeBytes();
+ if (End % m_Ciphers[CURRENT].Cipher->BlockSizeBytes())
+ End = End - End % m_Ciphers[CURRENT].Cipher->BlockSizeBytes() + m_Ciphers[CURRENT].Cipher->BlockSizeBytes();
+ }
+
+ return true;
+ } else if (m_Ciphers[OLD].Cipher && m_Changing && (ID >= m_ChangingProcess))
+ {
+ if (m_Ciphers[OLD].Cipher->IsStreamCipher())
+ {
+ Start = 0;
+ End = End - End % m_Ciphers[OLD].Cipher->BlockSizeBytes() + m_Ciphers[OLD].Cipher->BlockSizeBytes();
+ } else {
+ Start = Start - Start % m_Ciphers[OLD].Cipher->BlockSizeBytes();
+ if (End % m_Ciphers[OLD].Cipher->BlockSizeBytes())
+ End = End - End % m_Ciphers[OLD].Cipher->BlockSizeBytes() + m_Ciphers[OLD].Cipher->BlockSizeBytes();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+uint32_t CEncryptionManager::AlignSize(uint32_t ID, uint32_t Size)
+{
+ if (m_Ciphers[CURRENT].Cipher && (!m_Changing || (ID < m_ChangingProcess)))
+ {
+ if (Size % m_Ciphers[CURRENT].Cipher->BlockSizeBytes())
+ return Size - Size % m_Ciphers[CURRENT].Cipher->BlockSizeBytes() + m_Ciphers[CURRENT].Cipher->BlockSizeBytes();
+
+ } else if (m_Ciphers[OLD].Cipher && m_Changing && (ID >= m_ChangingProcess))
+ {
+ if (Size % m_Ciphers[OLD].Cipher->BlockSizeBytes())
+ return Size - Size % m_Ciphers[OLD].Cipher->BlockSizeBytes() + m_Ciphers[OLD].Cipher->BlockSizeBytes();
+
+ }
+
+ return Size;
+}
+
+bool CEncryptionManager::IsEncrypted(uint32_t ID)
+{
+ return (m_Ciphers[CURRENT].Cipher && (!m_Changing || (ID < m_ChangingProcess))) ||
+ (m_Ciphers[OLD].Cipher && m_Changing && (ID >= m_ChangingProcess));
+}
+
+void CEncryptionManager::Encrypt(void* Data, uint32_t DataLength, uint32_t ID, uint32_t StartByte)
+{
+ if (m_Ciphers[CURRENT].Cipher && (!m_Changing || (ID < m_ChangingProcess)))
+ {
+ m_Ciphers[CURRENT].Cipher->Encrypt(Data, DataLength, ID, StartByte);
+ } else if (m_Ciphers[OLD].Cipher && m_Changing && (ID >= m_ChangingProcess))
+ {
+ m_Ciphers[OLD].Cipher->Encrypt(Data, DataLength, ID, StartByte);
+ }
+}
+void CEncryptionManager::Decrypt(void* Data, uint32_t DataLength, uint32_t ID, uint32_t StartByte)
+{
+ if (m_Ciphers[CURRENT].Cipher && (!m_Changing || (ID < m_ChangingProcess)))
+ {
+ m_Ciphers[CURRENT].Cipher->Decrypt(Data, DataLength, ID, StartByte);
+ } else if (m_Ciphers[OLD].Cipher && m_Changing && (ID >= m_ChangingProcess))
+ {
+ m_Ciphers[OLD].Cipher->Decrypt(Data, DataLength, ID, StartByte);
+ }
+}
+
+bool CEncryptionManager::CanChangeCipher()
+{
+ return false;
+}
+bool CEncryptionManager::ChangeCipher(TEncryption & Encryption)
+{
+ return false;
+}
diff --git a/plugins/Dbx_tree/src/EncryptionManager.h b/plugins/Dbx_tree/src/EncryptionManager.h
new file mode 100644
index 0000000000..768ea19efa
--- /dev/null
+++ b/plugins/Dbx_tree/src/EncryptionManager.h
@@ -0,0 +1,107 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "stdint.h"
+#endif
+#include "sigslot.h"
+
+#define __INTERFACE_ONLY__
+#include "../encryption/Common/Cipher.h"
+#undef __INTERFACE_ONLY__
+
+#include "SHA256.h"
+#include "Interface.h"
+//#include "Thread.h"
+#include <map>
+#include <windows.h>
+
+static const uint32_t cEncryptionChangingFlag = 0x80000000;
+
+#pragma pack(push, 1)
+
+typedef struct TFileEncryption {
+ uint32_t CipherID;
+ uint32_t CipherOldID;
+ uint32_t ConversionProcess;
+ uint8_t SHA[32];
+ uint8_t SHAOld[32];
+ uint32_t Reserved[2];
+} TFileEncryption, *PFileEncryption;
+
+#pragma pack(pop)
+
+typedef struct TEncryption {
+ uint32_t CipherID;
+ wchar_t * Password;
+} TEncryption, *PEncryption;
+
+class CEncryptionManager
+{
+public:
+ CEncryptionManager();
+ ~CEncryptionManager();
+
+ typedef struct {
+ TCHAR * FilePath;
+ TCHAR * FileName;
+ uint32_t ID;
+ wchar_t * Name;
+ wchar_t * Description;
+ } TCipherItem;
+ typedef std::map<uint32_t, TCipherItem> TCipherList;
+
+ static TCipherList* CipherList; // = NULL; see cpp
+ static uint32_t CipherListRefCount; // = 0; see cpp
+ static void LoadCipherList();
+
+ bool InitEncryption(TFileEncryption & Enc);
+
+ bool AlignData(uint32_t ID, uint32_t & Start, uint32_t & End);
+ uint32_t AlignSize(uint32_t ID, uint32_t Size);
+ bool IsEncrypted(uint32_t ID);
+ void Encrypt(void* Data, uint32_t DataLength, uint32_t ID, uint32_t StartByte);
+ void Decrypt(void* Data, uint32_t DataLength, uint32_t ID, uint32_t StartByte);
+
+ bool CanChangeCipher();
+ bool ChangeCipher(TEncryption & Encryption);
+private:
+ bool m_Changing;
+ uint32_t m_ChangingProcess;
+
+ typedef enum TUsedCiphers {
+ CURRENT = 0,
+ OLD = 1,
+ COUNT = 2
+ } TUsedCiphers;
+
+ struct
+ {
+ CCipher * Cipher;
+ HMODULE CipherDLL;
+ } m_Ciphers[COUNT];
+
+};
diff --git a/plugins/Dbx_tree/src/Entities.cpp b/plugins/Dbx_tree/src/Entities.cpp
new file mode 100644
index 0000000000..73e9487ac6
--- /dev/null
+++ b/plugins/Dbx_tree/src/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<TVirtualKey, 4>::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<TEntity>(key.Virtual, size, sig);
+ if (entity)
+ {
+ entity->VParent = result;
+ m_BlockManager.UpdateBlock(key.Virtual);
+
+ copies = true;
+ } // TODO log
+ }
+
+ entity = m_BlockManager.ReadBlock<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntityKey, 6>::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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(hEntity, size, sig);
+ newparent = m_BlockManager.ReadBlock<TEntity>(hParent, size, sig);
+ if (!entity || !newparent)
+ return DBT_INVALIDPARAM;
+
+ oldparent = m_BlockManager.ReadBlock<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(hEntity, size, sig);
+
+ if (!entity)
+ return DBT_INVALIDPARAM;
+
+ TEntity * parent = m_BlockManager.ReadBlock<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(hParent, size, sig);
+
+ if (!parent)
+ return DBT_INVALIDPARAM;
+
+ PEntityIteration iter = new TEntityIteration;
+ iter->filter = Filter;
+ iter->q = new std::deque<TEntityIterationItem>;
+ iter->parents = new std::deque<TEntityIterationItem>;
+ iter->accounts = new std::deque<TEntityIterationItem>;
+ #ifdef _MSC_VER
+ iter->returned = new stdext::hash_set<TDBTEntityHandle>;
+ #else
+ iter->returned = new __gnu_cxx::hash_set<TDBTEntityHandle>;
+ #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<PEntityIteration>(Iteration);
+ TEntityIterationItem item;
+ TDBTEntityHandle result = 0;
+
+ if (iter->q->empty())
+ {
+ std::deque <TEntityIterationItem> * tmp = iter->q;
+ iter->q = iter->parents;
+ iter->parents = tmp;
+ }
+
+ if (iter->q->empty())
+ {
+ std::deque <TEntityIterationItem> * 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<TEntityIterationItem> 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<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(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<TEntityIterationItem>::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<TEntity>(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<PEntityIteration>(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<TEntity>(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<TEntity>(result, size, sig);
+ if (!entityblock)
+ return DBT_INVALIDPARAM;
+
+ if (realentity->Flags & DBT_NF_IsVirtual)
+ {
+ hRealEntity = realentity->VParent;
+ realentity = m_BlockManager.ReadBlock<TEntity>(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<TEntity>(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<TEntity>(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<TEntity>(i->Entity, size, sig);
+ if (entity)
+ {
+ if ((entity->Flags & DBT_NFM_SpecialEntity) == 0)
+ res = i->Entity;
+ }
+ if (res == 0)
+ ++i;
+ }
+ }
+
+ return res;
+}
diff --git a/plugins/Dbx_tree/src/Entities.h b/plugins/Dbx_tree/src/Entities.h
new file mode 100644
index 0000000000..579383d15f
--- /dev/null
+++ b/plugins/Dbx_tree/src/Entities.h
@@ -0,0 +1,299 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include "Interface.h"
+#include "FileBTree.h"
+#include "MREWSync.h"
+#include <deque>
+#ifdef _MSC_VER
+#include <hash_set>
+#else
+#include <ext/hash_set>
+#endif
+
+#pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+
+/**
+ \brief Key Type of the VirtualsBTree
+
+ This BTree don't hold data itself, it's just for organisation
+ The virtual Entities are sorted first based on their real Entity.
+ That is for enumeration of one Entity's virtual copies, which are all stored in one block in the BTree
+**/
+typedef struct TVirtualKey {
+ TDBTEntityHandle RealEntity; /// hEntity of the duplicated RealEntity
+ TDBTEntityHandle Virtual; /// hEntity of the virtual duplicate
+
+ bool operator < (const TVirtualKey & Other) const
+ {
+ if (RealEntity != Other.RealEntity) return RealEntity < Other.RealEntity;
+ if (Virtual != Other.Virtual) return Virtual < Other.Virtual;
+ return false;
+ }
+ //bool operator <= (const TVirtualKey & Other);
+ bool operator == (const TVirtualKey & Other) const
+ {
+ return (RealEntity == Other.RealEntity) && (Virtual == Other.Virtual);
+ }
+ //bool operator >= (const TVirtualKey & Other);
+ bool operator > (const TVirtualKey & Other) const
+ {
+ if (RealEntity != Other.RealEntity) return RealEntity > Other.RealEntity;
+ if (Virtual != Other.Virtual) return Virtual > Other.Virtual;
+ return false;
+ }
+} TVirtualKey;
+
+/**
+ \brief Key Type of the EntityBTree
+
+ The Entities are sorted first based on their level. (root is first node, followed by its children)
+ That is for enumeration of one Entity's children, which are all stored in one block in the BTree
+**/
+typedef struct TEntityKey {
+ uint16_t Level; /// Level where Entity is located or parent-steps to root. Root.Level == 0, root children have level 1 etc.
+ TDBTEntityHandle Parent; /// hEntity of the Parent. Root.Parent == 0
+ TDBTEntityHandle Entity; /// hEntity of the stored Entity itself
+
+ bool operator < (const TEntityKey & Other) const
+ {
+ if (Level != Other.Level) return Level < Other.Level;
+ if (Parent != Other.Parent) return Parent < Other.Parent;
+ if (Entity != Other.Entity) return Entity < Other.Entity;
+ return false;
+ }
+ //bool operator <= (const TEntityKey & Other);
+ bool operator == (const TEntityKey & Other) const
+ {
+ return (Level == Other.Level) && (Parent == Other.Parent) && (Entity == Other.Entity);
+ }
+ //bool operator >= (const TEntityKey & Other);
+ bool operator > (const TEntityKey & Other) const
+ {
+ if (Level != Other.Level) return Level > Other.Level;
+ if (Parent != Other.Parent) return Parent > Other.Parent;
+ if (Entity != Other.Entity) return Entity > Other.Entity;
+ return false;
+ }
+} TEntityKey;
+
+/**
+ \brief The data of an Entity
+**/
+typedef struct TEntity {
+ uint16_t Level; /// Level where Entity is located or parent-steps to root. Root.Level == 0, root children have level 1 etc. !used in the BTreeKey!
+ uint16_t ChildCount; /// Count of the children !invalid for Virtual Entity!
+ TDBTEntityHandle ParentEntity; /// hEntity of the Parent. Root.Parent == 0 !used in the BTreeKey!
+ union {
+ TDBTEntityHandle VParent; /// if the Entity is Virtual this is the hEntity of the related Realnode
+ TDBTEntityHandle Account; /// if the Entity's account, only for real real normal Entities
+ };
+ uint32_t Flags; /// flags, see cEF_*
+ /*CSettingsTree::TNodeRef*/
+ uint32_t Settings; /// Offset to the SettingsBTree RootNode of this Entity, NULL if no settings are present
+ /*CEventsTree::TNodeRef*/
+ uint32_t Events; /// Offset to the EventsBTree RootNode of this Entity, NULL if no events are present !invalid for Virtal Entity!
+ uint32_t EventCount; /// Count of the stored events !invalid for Virtual Entity!
+ uint32_t FirstUnreadEventTimestamp; /// timestamp of the first unread event
+ uint32_t FirstUnreadEventHandle;/// ID of the first unread event
+ uint8_t Reserved[4]; /// reserved storage
+} TEntity;
+
+#pragma pack(pop) // pop the alignment from stack
+
+
+
+
+/**
+ \brief Manages the Virtual Entities in the Database
+
+ A virtual Entity is stored as normal Entity in the database-structure, but doesn't hold own settings/events.
+ Such an Entity has the virtual flag set and refers its original duplicate.
+ All copies are stored in this BTree sorted to the RealEntity.
+ If the RealEntity should be deleted take the first virtual duplicate and make it real. Also change the relation of other copies.
+**/
+class CVirtuals : public CFileBTree<TVirtualKey, 4>
+{
+private:
+
+protected:
+
+public:
+ CVirtuals(CBlockManager & BlockManager, TNodeRef Root);
+ virtual ~CVirtuals();
+
+ /**
+ \brief Changes reference for all copies to the first Virtual in list
+
+ \return New Original (previously first Virtual) to associate data with
+ **/
+ TDBTEntityHandle _DeleteRealEntity(TDBTEntityHandle hRealEntity);
+
+ bool _InsertVirtual(TDBTEntityHandle hRealEntity, TDBTEntityHandle hVirtual);
+ void _DeleteVirtual(TDBTEntityHandle hRealEntity, TDBTEntityHandle hVirtual);
+
+ // services:
+ TDBTEntityHandle getParent(TDBTEntityHandle hVirtual);
+ TDBTEntityHandle getFirst(TDBTEntityHandle hRealEntity);
+ TDBTEntityHandle getNext(TDBTEntityHandle hVirtual);
+};
+
+
+static const uint32_t cEntitySignature = 0x9A6B3C0D;
+static const uint16_t cEntityNodeSignature = 0x65A9;
+static const uint16_t cVirtualNodeSignature = 0x874E;
+/**
+ \brief Manages the Entities in the Database
+
+ A hEntity is equivalent to the fileoffset of its related TEntity structure
+**/
+class CEntities : public CFileBTree<TEntityKey, 6>
+{
+
+public:
+ CEntities(CBlockManager & BlockManager, TDBTEntityHandle RootEntity, TNodeRef EntityRoot, CVirtuals::TNodeRef VirtualRoot);
+ virtual ~CEntities();
+
+ typedef sigslot::signal2<CEntities *, TDBTEntityHandle> TOnEntityDelete;
+ typedef sigslot::signal2<CEntities *, TDBTEntityHandle> TOnInternalDeleteSettings;
+ typedef sigslot::signal2<CEntities *, TDBTEntityHandle> TOnInternalDeleteEvents;
+
+ typedef sigslot::signal3<CEntities *, TDBTEntityHandle, TDBTEntityHandle> TOnInternalMergeSettings;
+ typedef sigslot::signal3<CEntities *, TDBTEntityHandle, TDBTEntityHandle> TOnInternalTransferEvents;
+
+ CVirtuals::TOnRootChanged & sigVirtualRootChanged()
+ {
+ return m_Virtuals.sigRootChanged();
+ };
+
+ TOnEntityDelete & sigEntityDelete()
+ {
+ return m_sigEntityDelete;
+ };
+ TOnInternalDeleteEvents & _sigDeleteEvents()
+ {
+ return m_sigInternalDeleteEvents;
+ };
+ TOnInternalDeleteSettings & _sigDeleteSettings()
+ {
+ return m_sigInternalDeleteSettings;
+ };
+ TOnInternalMergeSettings & _sigMergeSettings()
+ {
+ return m_sigInternalMergeSettings;
+ };
+ TOnInternalTransferEvents & _sigTransferEvents()
+ {
+ return m_sigInternalTransferEvents;
+ };
+
+ //internal helpers:
+ /*CSettingsTree::TNodeRef*/
+ uint32_t _getSettingsRoot(TDBTEntityHandle hEntity);
+ bool _setSettingsRoot(TDBTEntityHandle hEntity, /*CSettingsTree::TNodeRef*/ uint32_t NewRoot);
+ uint32_t _getEventsRoot(TDBTEntityHandle hEntity);
+ bool _setEventsRoot(TDBTEntityHandle hEntity, /*CSettingsTree::TNodeRef*/ uint32_t NewRoot);
+ uint32_t _getEventCount(TDBTEntityHandle hEntity);
+ uint32_t _adjustEventCount(TDBTEntityHandle hEntity, int32_t Adjust);
+ bool _getFirstUnreadEvent(TDBTEntityHandle hEntity, uint32_t & hEvent, uint32_t & Timestamp);
+ bool _setFirstUnreadEvent(TDBTEntityHandle hEntity, uint32_t hEvent, uint32_t Timestamp);
+
+ CVirtuals & _getVirtuals()
+ {
+ return m_Virtuals;
+ };
+
+ //compatibility:
+ TDBTEntityHandle compFirstContact();
+ TDBTEntityHandle compNextContact(TDBTEntityHandle hEntity);
+ //Services:
+ TDBTEntityHandle CEntities::getRootEntity()
+ {
+ return m_RootEntity;
+ };
+
+ TDBTEntityHandle getParent(TDBTEntityHandle hEntity);
+ TDBTEntityHandle setParent(TDBTEntityHandle hEntity, TDBTEntityHandle hParent);
+ uint32_t getChildCount(TDBTEntityHandle hEntity);
+ uint32_t getFlags(TDBTEntityHandle hEntity);
+ uint32_t getAccount(TDBTEntityHandle hEntity);
+
+ TDBTEntityHandle CreateEntity(const TDBTEntity & Entity);
+ unsigned int DeleteEntity(TDBTEntityHandle hEntity);
+
+ TDBTEntityIterationHandle IterationInit(const TDBTEntityIterFilter & Filter, TDBTEntityHandle hParent);
+ TDBTEntityHandle IterationNext(TDBTEntityIterationHandle Iteration);
+ unsigned int IterationClose(TDBTEntityIterationHandle Iteration);
+
+ TDBTEntityHandle VirtualCreate(TDBTEntityHandle hRealEntity, TDBTEntityHandle hParent);
+ TDBTEntityHandle VirtualGetParent(TDBTEntityHandle hVirtual)
+ {
+ return m_Virtuals.getParent(hVirtual);
+ };
+ TDBTEntityHandle VirtualGetFirst(TDBTEntityHandle hRealEntity)
+ {
+ return m_Virtuals.getFirst(hRealEntity);
+ };
+ TDBTEntityHandle VirtualGetNext(TDBTEntityHandle hVirtual)
+ {
+ return m_Virtuals.getNext(hVirtual);
+ };
+private:
+
+protected:
+
+ typedef struct TEntityIterationItem {
+ uint8_t Options;
+ uint8_t LookupDepth;
+ uint16_t Level;
+ TDBTEntityHandle Handle;
+ uint32_t Flags;
+ } TEntityIterationItem;
+
+ typedef struct TEntityIteration {
+ TDBTEntityIterFilter filter;
+ std::deque<TEntityIterationItem> * q;
+ std::deque<TEntityIterationItem> * parents;
+ std::deque<TEntityIterationItem> * accounts;
+ #ifdef _MSC_VER
+ stdext::hash_set<TDBTEntityHandle> * returned;
+ #else
+ __gnu_cxx::hash_set<TDBTEntityHandle> * returned;
+ #endif
+ } TEntityIteration, *PEntityIteration;
+
+ TDBTEntityHandle m_RootEntity;
+ CVirtuals m_Virtuals;
+
+ TDBTEntityHandle _CreateRootEntity();
+ void _InternalTransferContacts(TDBTEntityHandle OldAccount, TDBTEntityHandle NewAccount);
+
+ TOnEntityDelete m_sigEntityDelete;
+ TOnInternalDeleteEvents m_sigInternalDeleteEvents;
+ TOnInternalDeleteSettings m_sigInternalDeleteSettings;
+ TOnInternalMergeSettings m_sigInternalMergeSettings;
+ TOnInternalTransferEvents m_sigInternalTransferEvents;
+
+};
diff --git a/plugins/Dbx_tree/src/Events.cpp b/plugins/Dbx_tree/src/Events.cpp
new file mode 100644
index 0000000000..732f6241c2
--- /dev/null
+++ b/plugins/Dbx_tree/src/Events.cpp
@@ -0,0 +1,986 @@
+/*
+
+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 "Events.h"
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#endif
+
+
+CEventsTypeManager::CEventsTypeManager(CEntities & Entities, CSettings & Settings)
+: m_Entities(Entities),
+ m_Settings(Settings),
+ m_Map()
+{
+ m_Settings._EnsureModuleExists("$EventTypes");
+}
+CEventsTypeManager::~CEventsTypeManager()
+{
+ TTypeMap::iterator it = m_Map.begin();
+
+ while (it != m_Map.end())
+ {
+ delete [] it->second->ModuleName;
+ delete it->second;
+ ++it;
+ }
+}
+
+uint32_t CEventsTypeManager::MakeGlobalID(char* Module, uint32_t EventType)
+{
+ uint32_t l = static_cast<uint32_t>(strlen(Module));
+ void * buf = malloc(l + sizeof(uint32_t));
+ memcpy(buf, Module, l);
+ memcpy(((char*)buf) + l, &EventType, sizeof(uint32_t));
+
+ uint32_t h = Hash(buf, l + sizeof(uint32_t));
+ free(buf);
+
+ char * m;
+ uint32_t t;
+ while (GetType(h, m, t) && ((t != EventType) || (strcmp(m, Module) != 0)))
+ {
+ ++h;
+ }
+
+ return h;
+}
+bool CEventsTypeManager::GetType(uint32_t GlobalID, char * & Module, uint32_t & EventType)
+{
+ TTypeMap::iterator it = m_Map.find(GlobalID);
+
+ if (it == m_Map.end())
+ {
+ char n[256];
+
+ TDBTSettingDescriptor d = {0,0,0,0,0,0,0,0};
+ d.cbSize = sizeof(d);
+ d.Entity = m_Entities.getRootEntity();
+ d.pszSettingName = n;
+
+ TDBTSetting sid = {0,0,0,0};
+ TDBTSetting sname = {0,0,0,0};
+
+ sid.cbSize = sizeof(sid);
+ sid.Descriptor = &d;
+ sid.Type = DBT_ST_INT;
+
+ sname.cbSize = sizeof(sname);
+ sname.Descriptor = &d;
+ sname.Type = DBT_ST_ANSI;
+
+ sprintf_s(n, "$EventTypes/%08x/ModuleID", GlobalID);
+ TDBTSettingHandle h = m_Settings.ReadSetting(sid);
+
+ if ((h != DBT_INVALIDPARAM) && (h != 0))
+ {
+ sprintf_s(n, "$EventTypes/%08x/ModuleName", GlobalID);
+ d.Flags = 0;
+ h = m_Settings.ReadSetting(sname);
+
+ if ((h != DBT_INVALIDPARAM) && (h != 0))
+ {
+ PEventType t = new TEventType;
+
+ t->EventType = sid.Value.Int;
+
+ t->ModuleName = new char[sname.Value.Length];
+ strcpy_s(t->ModuleName, sname.Value.Length, sname.Value.pAnsi);
+
+ m_Map.insert(std::make_pair(GlobalID, t));
+
+ mir_free(sname.Value.pAnsi);
+
+ Module = t->ModuleName;
+ EventType = t->EventType;
+
+ return true;
+ }
+ }
+ } else {
+ Module = it->second->ModuleName;
+ EventType = it->second->EventType;
+
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t CEventsTypeManager::EnsureIDExists(char* Module, uint32_t EventType)
+{
+ uint32_t res = MakeGlobalID(Module, EventType);
+ char * m;
+ uint32_t t;
+ if (!GetType(res, m, t))
+ {
+ char n[256];
+
+ TDBTSettingDescriptor d = {0,0,0,0,0,0,0,0};
+ d.cbSize = sizeof(d);
+ d.pszSettingName = n;
+ d.Entity = m_Entities.getRootEntity();
+
+ TDBTSetting s = {0,0,0,0};
+ s.cbSize = sizeof(s);
+ s.Descriptor = &d;
+
+ sprintf_s(n, "$EventTypes/%08x/ModuleID", res);
+ s.Type = DBT_ST_INT;
+ s.Value.Int = EventType;
+ m_Settings.WriteSetting(s);
+
+ sprintf_s(n, "$EventTypes/%08x/ModuleName", res);
+ d.Flags = 0;
+ s.Type = DBT_ST_ANSI;
+ s.Value.Length = static_cast<uint32_t>(strlen(Module) + 1);
+ s.Value.pAnsi = Module;
+ m_Settings.WriteSetting(s);
+
+ m_Settings._EnsureModuleExists(Module);
+ }
+
+ return res;
+}
+
+
+CEvents::CEvents(
+ CBlockManager & BlockManager,
+ CEncryptionManager & EncryptionManager,
+ CEntities & Entities,
+ CSettings & Settings
+)
+: m_BlockManager(BlockManager),
+ m_EncryptionManager(EncryptionManager),
+ m_Entities(Entities),
+ m_Types(Entities, Settings),
+ m_EntityEventsMap()
+{
+ m_Entities._sigDeleteEvents().connect(this, &CEvents::onDeleteEvents);
+ m_Entities._sigTransferEvents().connect(this, &CEvents::onTransferEvents);
+}
+
+CEvents::~CEvents()
+{
+ TEntityEventsMap::iterator i = m_EntityEventsMap.begin();
+ while (i != m_EntityEventsMap.end())
+ {
+ delete i->second->RealTree;
+ delete i->second->VirtualTree;
+ delete i->second;
+ ++i;
+ }
+}
+
+void CEvents::onRootChanged(void* EventsTree, CEventsTree::TNodeRef NewRoot)
+{
+ m_Entities._setEventsRoot(reinterpret_cast<CEventsTree*>(EventsTree)->Entity(), NewRoot);
+}
+
+void CEvents::onDeleteEventCallback(void * Tree, const TEventKey & Key, uint32_t Param)
+{
+ m_BlockManager.DeleteBlock(Key.Event);
+}
+
+void CEvents::onDeleteVirtualEventCallback(void * Tree, const TEventKey & Key, uint32_t Param)
+{
+ m_BlockManager.DeleteBlock(Key.Event);
+}
+void CEvents::onDeleteEvents(CEntities * Entities, TDBTEntityHandle hEntity)
+{
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+
+ if (record == NULL)
+ return;
+
+ m_Entities._setEventsRoot(hEntity, 0);
+
+ if (record->VirtualCount)
+ {
+ CVirtualEventsTree::TDeleteCallback callback;
+ callback.connect(this, &CEvents::onDeleteVirtualEventCallback);
+
+ record->VirtualTree->DeleteTree(&callback, hEntity);
+ }
+ delete record->VirtualTree;
+
+ CEventsTree::TDeleteCallback callback;
+ callback.connect(this, &CEvents::onDeleteEventCallback);
+ record->RealTree->DeleteTree(&callback, hEntity);
+ delete record->RealTree;
+ m_EntityEventsMap.erase(hEntity);
+}
+void CEvents::onTransferEvents(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest)
+{
+ PEntityEventsRecord record = getEntityRecord(Source);
+
+ if (record == NULL)
+ return;
+
+ if (record->VirtualCount)
+ {
+ TEventKey key = {0,0};
+
+ CVirtualEventsTree::iterator i = record->VirtualTree->LowerBound(key);
+
+ while (i)
+ {
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+ TEvent * tmp = m_BlockManager.ReadBlock<TEvent>(i->Event, size, sig);
+ if (tmp)
+ {
+ tmp->Entity = Dest;
+ m_BlockManager.UpdateBlock(i->Event);
+ }
+ ++i;
+ }
+ }
+
+ {
+ TEventKey key = {0,0};
+
+ CEventsTree::iterator i = record->RealTree->LowerBound(key);
+ while (i)
+ {
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+ TEvent * tmp = m_BlockManager.ReadBlock<TEvent>(i->Event, size, sig);
+ if (tmp)
+ {
+ tmp->Entity = Dest;
+ m_BlockManager.UpdateBlock(i->Event);
+ }
+ ++i;
+ }
+
+ m_Entities._setEventsRoot(Source, 0);
+ m_Entities._setEventsRoot(Dest, record->RealTree->getRoot());
+ m_Entities._adjustEventCount(Dest, m_Entities._getEventCount(Source));
+ m_Entities._getFirstUnreadEvent(Source, key.Event, key.TimeStamp);
+ m_Entities._setFirstUnreadEvent(Dest, key.Event, key.TimeStamp);
+ }
+
+ record->VirtualTree->Entity(Dest);
+ record->RealTree->Entity(Dest);
+ m_EntityEventsMap.erase(Source);
+ m_EntityEventsMap.insert(std::make_pair(Dest, record));
+}
+
+CEvents::PEntityEventsRecord CEvents::getEntityRecord(TDBTEntityHandle hEntity)
+{
+ TEntityEventsMap::iterator i = m_EntityEventsMap.find(hEntity);
+ if (i != m_EntityEventsMap.end())
+ return i->second;
+
+ uint32_t root = m_Entities._getEventsRoot(hEntity);
+ if (root == DBT_INVALIDPARAM)
+ return NULL;
+
+ PEntityEventsRecord res = new TEntityEventsRecord;
+ res->RealTree = new CEventsTree(m_BlockManager, root, hEntity);
+ res->RealTree->sigRootChanged().connect(this, &CEvents::onRootChanged);
+ res->VirtualTree = new CVirtualEventsTree(hEntity);
+ res->VirtualCount = 0;
+ res->FirstVirtualUnread.TimeStamp = 0;
+ res->FirstVirtualUnread.Event = 0;
+ m_EntityEventsMap.insert(std::make_pair(hEntity, res));
+
+ return res;
+}
+
+inline uint32_t CEvents::adjustVirtualEventCount(PEntityEventsRecord Record, int32_t Adjust)
+{
+ if (((Adjust < 0) && ((uint32_t)(-Adjust) <= Record->VirtualCount)) ||
+ ((Adjust > 0) && ((0xffffffff - Record->VirtualCount) > (uint32_t)Adjust)))
+ {
+ Record->VirtualCount += Adjust;
+ }
+
+ return Record->VirtualCount;
+}
+
+inline bool CEvents::MarkEventsTree(TEventBase::iterator Iterator, TDBTEventHandle FirstUnread)
+{
+ uint32_t sig, size;
+ bool b = true;
+ bool res = false;
+ while (Iterator && b)
+ {
+ sig = cEventSignature;
+ size = 0;
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(Iterator->Event, size, sig);
+ if (event)
+ {
+ if (Iterator->Event == FirstUnread)
+ res = true;
+
+ if ((event->Flags & DBT_EF_READ) == 0)
+ {
+ event->Flags |= DBT_EF_READ;
+ m_BlockManager.UpdateBlock(Iterator->Event);
+ --Iterator;
+ } else {
+ b = false;
+ }
+ } else {
+ --Iterator;
+ }
+ }
+ return res;
+}
+inline void CEvents::FindNextUnreadEvent(TEventBase::iterator & Iterator)
+{
+ uint32_t sig, size;
+ while (Iterator)
+ {
+ sig = cEventSignature;
+ size = 0;
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(Iterator->Event, size, sig);
+ if (event)
+ {
+ if (event->Flags & DBT_EF_READ)
+ ++Iterator;
+ else
+ return;
+ } else {
+ ++Iterator;
+ }
+ }
+}
+
+unsigned int CEvents::GetBlobSize(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ return event->DataLength;
+}
+
+unsigned int CEvents::Get(TDBTEventHandle hEvent, TDBTEvent & Event)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ uint8_t * blob = reinterpret_cast<uint8_t *>(event + 1);
+
+ if (!m_Types.GetType(event->Type, Event.ModuleName, Event.EventType))
+ {
+ Event.EventType = event->Type;
+ Event.ModuleName = "???";
+ }
+
+ Event.Flags = event->Flags;
+ if (m_BlockManager.IsForcedVirtual(hEvent))
+ Event.Flags |= DBT_EF_VIRTUAL;
+
+ Event.Timestamp = event->TimeStamp;
+
+ if (Event.cbBlob < event->DataLength)
+ Event.pBlob = (uint8_t*) mir_realloc(Event.pBlob, event->DataLength);
+
+ memcpy(Event.pBlob, blob, event->DataLength);
+ Event.cbBlob = event->DataLength;
+
+ return 0;
+}
+
+unsigned int CEvents::GetCount(TDBTEntityHandle hEntity)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ uint32_t res = m_Entities._getEventCount(hEntity);
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+
+ if ((res == DBT_INVALIDPARAM) || !record)
+ return DBT_INVALIDPARAM;
+
+ res = res + record->VirtualCount; // access to Virtual Count need sync, too
+
+ return res;
+}
+
+unsigned int CEvents::Delete(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+ TEventKey key = {0, hEvent};
+
+ CBlockManager::WriteTransaction trans(m_BlockManager);
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ key.TimeStamp = event->TimeStamp;
+
+ PEntityEventsRecord record = getEntityRecord(event->Entity);
+ if (!record)
+ return DBT_INVALIDPARAM;
+
+ if (m_BlockManager.IsForcedVirtual(hEvent))
+ {
+ if (record->VirtualTree->Delete(key))
+ {
+ adjustVirtualEventCount(record, -1);
+
+ if (record->FirstVirtualUnread.Event == hEvent)
+ {
+ CVirtualEventsTree::iterator vi = record->VirtualTree->LowerBound(key);
+ FindNextUnreadEvent(vi);
+ if (vi)
+ {
+ record->FirstVirtualUnread = *vi;
+ } else {
+ record->FirstVirtualUnread.TimeStamp = 0;
+ record->FirstVirtualUnread.Event = 0;
+ }
+ }
+ }
+ } else { // real event
+ if (record->RealTree->Delete(key))
+ {
+ m_Entities._adjustEventCount(event->Entity, -1);
+ TEventKey unreadkey;
+ m_Entities._getFirstUnreadEvent(event->Entity, unreadkey.Event, unreadkey.TimeStamp);
+ if (unreadkey.Event == hEvent)
+ {
+ CEventsTree::iterator it = record->VirtualTree->LowerBound(key);
+ FindNextUnreadEvent(it);
+ if (it)
+ {
+ m_Entities._setFirstUnreadEvent(event->Entity, it->Event, it->TimeStamp);
+ } else {
+ m_Entities._setFirstUnreadEvent(event->Entity, 0, 0);
+ }
+ }
+ }
+ }
+ m_BlockManager.DeleteBlock(hEvent);
+
+ return 0;
+}
+
+TDBTEventHandle CEvents::Add(TDBTEntityHandle hEntity, TDBTEvent & Event)
+{
+ TDBTEventHandle res = 0;
+ TEvent * event;
+
+ CBlockManager::WriteTransaction trans(m_BlockManager);
+
+ uint32_t eflags = m_Entities.getFlags(hEntity);
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+
+ if ((eflags == DBT_INVALIDPARAM) ||
+ ((eflags & (DBT_NF_IsGroup | DBT_NF_IsRoot)) == DBT_NF_IsGroup) || // forbid events in groups. but allow root to have system history
+ !record)
+ {
+ return DBT_INVALIDPARAM;
+ }
+
+ if (eflags & DBT_NF_IsVirtual)
+ hEntity = m_Entities.VirtualGetParent(hEntity);
+
+ uint8_t *blobdata = Event.pBlob;
+ bool bloballocated = false;
+
+ if (Event.Flags & DBT_EF_VIRTUAL)
+ {
+ event = m_BlockManager.CreateBlockVirtual<TEvent>(res, cEventSignature, sizeof(TEvent) + Event.cbBlob);
+ } else {
+ event = m_BlockManager.CreateBlock<TEvent>(res, cEventSignature, sizeof(TEvent) + Event.cbBlob);
+ }
+
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ TEventKey key = {0,0};
+
+ event->TimeStamp = Event.Timestamp;
+ event->Flags = Event.Flags & ~DBT_EF_VIRTUAL;
+ event->Type = m_Types.EnsureIDExists(Event.ModuleName, Event.EventType);
+ event->DataLength = Event.cbBlob;
+ event->Entity = hEntity;
+
+ key.TimeStamp = event->TimeStamp;
+ key.Event = res;
+ memcpy(event + 1, Event.pBlob, Event.cbBlob);
+
+ m_BlockManager.UpdateBlock(res);
+
+ if (Event.Flags & DBT_EF_VIRTUAL)
+ {
+ record->VirtualTree->Insert(key);
+ adjustVirtualEventCount(record, +1);
+ if (!(Event.Flags & DBT_EF_READ) && ((record->FirstVirtualUnread.Event == 0) || (key < record->FirstVirtualUnread)))
+ {
+ record->FirstVirtualUnread = key;
+ }
+ } else {
+ record->RealTree->Insert(key);
+ m_Entities._adjustEventCount(hEntity, +1);
+
+ if (!(Event.Flags & DBT_EF_READ))
+ {
+ TEventKey unreadkey;
+ if (m_Entities._getFirstUnreadEvent(hEntity, unreadkey.Event, unreadkey.TimeStamp) &&
+ ((unreadkey.Event == 0) || (key < unreadkey)))
+ {
+ m_Entities._setFirstUnreadEvent(hEntity, key.Event, key.TimeStamp);
+ }
+ }
+ }
+
+ return res;
+}
+unsigned int CEvents::MarkRead(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+ TEventKey key = {0, hEvent};
+
+ CBlockManager::WriteTransaction trans(m_BlockManager);
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ key.TimeStamp = event->TimeStamp;
+
+ if (event->Flags & DBT_EF_READ)
+ return event->Flags;
+
+ PEntityEventsRecord record = getEntityRecord(event->Entity);
+ if (!record)
+ return DBT_INVALIDPARAM;
+
+ CEventsTree::iterator it = record->RealTree->UpperBound(key);
+ CVirtualEventsTree::iterator vi = record->VirtualTree->UpperBound(key);
+
+ m_Entities._getFirstUnreadEvent(event->Entity, key.Event, key.TimeStamp);
+ if (MarkEventsTree(it, key.Event))
+ {
+ FindNextUnreadEvent(++it);
+ if (it)
+ {
+ m_Entities._setFirstUnreadEvent(event->Entity, it->Event, it->TimeStamp);
+ } else {
+ m_Entities._setFirstUnreadEvent(event->Entity, 0, 0);
+ }
+ }
+ if (MarkEventsTree(vi, record->FirstVirtualUnread.Event))
+ {
+ FindNextUnreadEvent(++vi);
+ if (vi)
+ {
+ record->FirstVirtualUnread = *it;
+ } else {
+ record->FirstVirtualUnread.TimeStamp = 0;
+ record->FirstVirtualUnread.Event = 0;
+ }
+ }
+
+ return event->Flags | DBT_EF_READ;
+}
+unsigned int CEvents::WriteToDisk(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+ TEventKey key;
+ key.Event = hEvent;
+
+ CBlockManager::WriteTransaction trans(m_BlockManager);
+
+ if (!m_BlockManager.IsForcedVirtual(hEvent))
+ return DBT_INVALIDPARAM;
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+ if (!event || (size < sizeof(TEvent)))
+ return DBT_INVALIDPARAM;
+
+ PEntityEventsRecord record = getEntityRecord(event->Entity);
+ if (!record)
+ return DBT_INVALIDPARAM;
+
+ key.TimeStamp = event->TimeStamp;
+ key.Event = hEvent;
+
+ if (record->VirtualTree->Delete(key))
+ adjustVirtualEventCount(record, -1);
+
+ if (record->RealTree->Insert(key))
+ m_Entities._adjustEventCount(event->Entity, +1);
+ m_BlockManager.WriteBlockToDisk(hEvent);
+
+ return 0;
+}
+
+TDBTEntityHandle CEvents::getEntity(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+ if (!event)
+ return DBT_INVALIDPARAM;
+
+ return event->Entity;
+}
+
+TDBTEventIterationHandle CEvents::IterationInit(TDBTEventIterFilter & Filter)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ PEntityEventsRecord record = getEntityRecord(Filter.hEntity);
+
+ if (!record)
+ return DBT_INVALIDPARAM;
+
+ std::queue<TEventBase * > q;
+ q.push(record->RealTree);
+ q.push(record->VirtualTree);
+
+ TDBTEntityIterFilter f = {0,0,0,0};
+ f.cbSize = sizeof(f);
+ f.Options = Filter.Options;
+
+ TDBTEntityIterationHandle citer = m_Entities.IterationInit(f, Filter.hEntity);
+ if (citer != DBT_INVALIDPARAM)
+ {
+ m_Entities.IterationNext(citer);
+ TDBTEntityHandle c = m_Entities.IterationNext(citer);
+ while (c != 0)
+ {
+ record = getEntityRecord(c);
+ if (record)
+ {
+ q.push(record->RealTree);
+ q.push(record->VirtualTree);
+ }
+
+ c = m_Entities.IterationNext(citer);
+ }
+
+ m_Entities.IterationClose(citer);
+ }
+
+ for (unsigned j = 0; j < Filter.ExtraCount; ++j)
+ {
+ record = getEntityRecord(Filter.ExtraEntities[j]);
+ if (record)
+ {
+ q.push(record->RealTree);
+ q.push(record->VirtualTree);
+ }
+ }
+
+ PEventIteration iter = new TEventIteration;
+ iter->Filter = Filter;
+ iter->LastEvent = 0;
+ iter->Heap = NULL;
+
+ TEventKey key;
+ key.TimeStamp = Filter.tSince;
+ key.Event = 0;
+
+ while (!q.empty())
+ {
+ TEventBase * b = q.front();
+ q.pop();
+
+ TEventBase::iterator it = b->LowerBound(key);
+ if (it)
+ {
+ TEventBase::iterator * it2 = new TEventBase::iterator(it);
+ it2->setManaged();
+ if (iter->Heap)
+ {
+ iter->Heap->Insert(*it2);
+ } else {
+ iter->Heap = new TEventsHeap(*it2, TEventsHeap::ITForward, true);
+ }
+ }
+ }
+
+ if (iter->Heap == NULL)
+ {
+ delete iter;
+ iter = (PEventIteration)DBT_INVALIDPARAM;
+ }
+
+ return reinterpret_cast<TDBTEventIterationHandle>(iter);
+}
+
+TDBTEventHandle CEvents::IterationNext(TDBTEventIterationHandle Iteration)
+{
+ PEventIteration iter = reinterpret_cast<PEventIteration>(Iteration);
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TDBTEventHandle res = 0;
+ TEventBase::iterator it = iter->Heap->Top();
+
+ while ((it) && (it.wasDeleted() || ((it->TimeStamp <= iter->Filter.tTill) && (it->Event == iter->LastEvent))))
+ {
+ iter->Heap->Pop();
+ it = iter->Heap->Top();
+ }
+
+ if ((it) && !it.wasDeleted() && (it->TimeStamp <= iter->Filter.tTill))
+ {
+ res = it->Event;
+ iter->Heap->Pop();
+ }
+
+ if (res)
+ {
+ iter->LastEvent = res;
+ if (iter->Filter.Event)
+ {
+ iter->Filter.Event->EventType = 0;
+ Get(res, *iter->Filter.Event);
+ }
+ }
+
+ return res;
+}
+
+unsigned int CEvents::IterationClose(TDBTEventIterationHandle Iteration)
+{
+ PEventIteration iter = reinterpret_cast<PEventIteration>(Iteration);
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+ delete iter->Heap;
+ delete iter;
+ return 0;
+}
+
+
+TDBTEventHandle CEvents::compFirstEvent(TDBTEntityHandle hEntity)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TDBTEventHandle res = 0;
+
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+ if (!record)
+ return 0;
+
+ TEventKey key = {0,0};
+ CEventsTree::iterator i = record->RealTree->LowerBound(key);
+ CVirtualEventsTree::iterator vi = record->VirtualTree->LowerBound(key);
+
+ if (i && vi)
+ {
+ if (*i < *vi)
+ {
+ res = i->Event;
+ } else {
+ res = vi->Event;
+ }
+ } else if (i)
+ {
+ res = i->Event;
+ } else if (vi)
+ {
+ res = vi->Event;
+ }
+
+ return res;
+}
+TDBTEventHandle CEvents::compFirstUnreadEvent(TDBTEntityHandle hEntity)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TDBTEventHandle res = 0;
+
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+ if (!record)
+ return 0;
+
+ TEventKey key;
+ m_Entities._getFirstUnreadEvent(hEntity, key.Event, key.TimeStamp);
+ if (key.Event)
+ {
+ if (record->FirstVirtualUnread.Event && (record->FirstVirtualUnread < key))
+ {
+ res = record->FirstVirtualUnread.Event;
+ } else {
+ res = key.Event;
+ }
+ } else if (record->FirstVirtualUnread.Event)
+ {
+ res = record->FirstVirtualUnread.Event;
+ }
+
+ return res;
+}
+TDBTEventHandle CEvents::compLastEvent(TDBTEntityHandle hEntity)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+ TDBTEventHandle res = 0;
+
+ PEntityEventsRecord record = getEntityRecord(hEntity);
+ if (!record)
+ return 0;
+
+ TEventKey key = {0xffffffff, 0xffffffff};
+
+ CEventsTree::iterator i = record->RealTree->UpperBound(key);
+ CVirtualEventsTree::iterator vi = record->VirtualTree->UpperBound(key);
+
+ if (i && vi)
+ {
+ if (*i > *vi)
+ {
+ res = i->Event;
+ } else {
+ res = vi->Event;
+ }
+ } else if (i)
+ {
+ res = i->Event;
+ } else if (vi)
+ {
+ res = vi->Event;
+ }
+
+ return res;
+}
+TDBTEventHandle CEvents::compNextEvent(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+
+ if (!event)
+ return 0;
+
+ TEventKey key = {event->TimeStamp, hEvent};
+
+ PEntityEventsRecord record = getEntityRecord(event->Entity);
+
+ if (!record)
+ return 0;
+
+ if (key.Event == 0xffffffff)
+ {
+ if (key.TimeStamp == 0xffffffff)
+ {
+ return 0;
+ } else {
+ ++key.TimeStamp;
+ }
+ } else {
+ ++key.Event;
+ }
+
+ CEventsTree::iterator i = record->RealTree->LowerBound(key);
+ CVirtualEventsTree::iterator vi = record->VirtualTree->LowerBound(key);
+
+ TDBTEventHandle res = 0;
+ if (i && vi)
+ {
+ if (*i < *vi)
+ {
+ res = i->Event;
+ } else {
+ res = vi->Event;
+ }
+ } else if (i)
+ {
+ res = i->Event;
+ } else if (vi)
+ {
+ res = vi->Event;
+ }
+
+ return res;
+}
+TDBTEventHandle CEvents::compPrevEvent(TDBTEventHandle hEvent)
+{
+ uint32_t sig = cEventSignature;
+ uint32_t size = 0;
+
+ CBlockManager::ReadTransaction trans(m_BlockManager);
+
+ TEvent * event = m_BlockManager.ReadBlock<TEvent>(hEvent, size, sig);
+
+ if (!event)
+ return 0;
+
+ TEventKey key = {event->TimeStamp, hEvent};
+
+ PEntityEventsRecord record = getEntityRecord(event->Entity);
+ if (!record)
+ return 0;
+
+ if (key.Event == 0)
+ {
+ if (key.TimeStamp == 0)
+ {
+ return 0;
+ } else {
+ --key.TimeStamp;
+ }
+ } else {
+ --key.Event;
+ }
+
+ CEventsTree::iterator i = record->RealTree->UpperBound(key);
+ CVirtualEventsTree::iterator vi = record->VirtualTree->UpperBound(key);
+
+ TDBTEventHandle res = 0;
+ if (i && vi)
+ {
+ if (*i > *vi)
+ {
+ res = i->Event;
+ } else {
+ res = vi->Event;
+ }
+ } else if (i)
+ {
+ res = i->Event;
+ } else if (vi)
+ {
+ res = vi->Event;
+ }
+
+ return res;
+}
diff --git a/plugins/Dbx_tree/src/Events.h b/plugins/Dbx_tree/src/Events.h
new file mode 100644
index 0000000000..7a3d50ff19
--- /dev/null
+++ b/plugins/Dbx_tree/src/Events.h
@@ -0,0 +1,263 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include "Interface.h"
+#include "BTree.h"
+#include "FileBTree.h"
+#include "BlockManager.h"
+#include "IterationHeap.h"
+#include "Entities.h"
+#include "Settings.h"
+#include "Hash.h"
+#include "EncryptionManager.h"
+#include "sigslot.h"
+
+#ifdef _MSC_VER
+#include <hash_map>
+#include <hash_set>
+#else
+#include <ext/hash_map>
+#include <ext/hash_set>
+#endif
+#include <queue>
+#include <time.h>
+#include <windows.h>
+
+#pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+/**
+ \brief Key Type of the EventsBTree
+
+ The Key consists of a timestamp, seconds elapsed since 1.1.1970
+ and an Index, which makes it possible to store multiple events with the same timestamp
+**/
+typedef struct TEventKey {
+ uint32_t TimeStamp; /// timestamp at which the event occoured
+ TDBTEventHandle Event;
+
+ bool operator < (const TEventKey & Other) const
+ {
+ if (TimeStamp != Other.TimeStamp) return TimeStamp < Other.TimeStamp;
+ if (Event != Other.Event) return Event < Other.Event;
+ return false;
+ }
+ //bool operator <= (const TEventKey & Other);
+ bool operator == (const TEventKey & Other) const
+ {
+ return (TimeStamp == Other.TimeStamp) && (Event == Other.Event);
+ }
+
+ //bool operator >= (const TEventKey & Other);
+ bool operator > (const TEventKey & Other) const
+ {
+ if (TimeStamp != Other.TimeStamp) return TimeStamp > Other.TimeStamp;
+ if (Event != Other.Event) return Event > Other.Event;
+ return false;
+ }
+
+} TEventKey;
+
+/**
+ \brief The data of an Event
+
+ A event's data is variable length. The data is a TDBTEvent-structure followed by varaible length data.
+ - fixed data
+ - blob data (mostly UTF8 message body)
+**/
+typedef struct TEvent {
+ uint32_t Flags; /// Flags
+ uint32_t TimeStamp; /// Timestamp of the event (seconds elapsed since 1.1.1970) used as key element
+ uint32_t Type; /// Eventtype
+ TDBTEntityHandle Entity; /// hEntity which owns this event
+ uint32_t DataLength; /// Length of the stored data in bytes
+
+ uint8_t Reserved[8]; /// reserved storage
+} TEvent;
+
+#pragma pack(pop)
+
+
+static const uint32_t cEventSignature = 0x365A7E92;
+static const uint16_t cEventNodeSignature = 0x195C;
+
+/**
+ \brief Manages the Events Index in the Database
+**/
+class CEventsTree : public CFileBTree<TEventKey, 16>
+{
+private:
+ TDBTEntityHandle m_Entity;
+
+public:
+ CEventsTree(CBlockManager & BlockManager, TNodeRef RootNode, TDBTEntityHandle Entity)
+ : CFileBTree<TEventKey, 16>::CFileBTree(BlockManager, RootNode, cEventNodeSignature),
+ m_Entity(Entity)
+ { };
+ ~CEventsTree()
+ { };
+
+ TDBTEntityHandle Entity()
+ {
+ return m_Entity;
+ };
+ void Entity(TDBTEntityHandle NewEntity)
+ {
+ m_Entity = NewEntity;
+ };
+};
+
+/**
+ \brief Manages the Virtual Events Index
+ Sorry for duplicating code...
+**/
+class CVirtualEventsTree : public CBTree<TEventKey, 16>
+{
+private:
+ TDBTEntityHandle m_Entity;
+
+public:
+ CVirtualEventsTree(TDBTEntityHandle Entity)
+ : CBTree<TEventKey, 16>::CBTree(0),
+ m_Entity(Entity)
+ { };
+
+ ~CVirtualEventsTree()
+ { };
+
+ TDBTEntityHandle Entity()
+ {
+ return m_Entity;
+ };
+ void Entity(TDBTEntityHandle NewEntity)
+ {
+ m_Entity = NewEntity;
+ };
+};
+
+
+class CEventsTypeManager
+{
+public:
+ CEventsTypeManager(CEntities & Entities, CSettings & Settings);
+ ~CEventsTypeManager();
+
+ uint32_t MakeGlobalID(char* Module, uint32_t EventType);
+ bool GetType(uint32_t GlobalID, char * & Module, uint32_t & EventType);
+ uint32_t EnsureIDExists(char* Module, uint32_t EventType);
+
+private:
+ typedef struct TEventType {
+ char * ModuleName;
+ uint32_t EventType;
+ } TEventType, *PEventType;
+ #ifdef _MSC_VER
+ typedef stdext::hash_map<uint32_t, PEventType> TTypeMap;
+ #else
+ typedef __gnu_cxx::hash_map<uint32_t, PEventType> TTypeMap;
+ #endif
+
+ CEntities & m_Entities;
+ CSettings & m_Settings;
+ TTypeMap m_Map;
+
+};
+
+
+class CEvents : public sigslot::has_slots<>
+{
+public:
+
+ CEvents(
+ CBlockManager & BlockManager,
+ CEncryptionManager & EncryptionManager,
+ CEntities & Entities,
+ CSettings & Settings
+ );
+ ~CEvents();
+
+ //compatibility
+ TDBTEventHandle compFirstEvent(TDBTEntityHandle hEntity);
+ TDBTEventHandle compFirstUnreadEvent(TDBTEntityHandle hEntity);
+ TDBTEventHandle compLastEvent(TDBTEntityHandle hEntity);
+ TDBTEventHandle compNextEvent(TDBTEventHandle hEvent);
+ TDBTEventHandle compPrevEvent(TDBTEventHandle hEvent);
+
+ //services
+ unsigned int GetBlobSize(TDBTEventHandle hEvent);
+ unsigned int Get(TDBTEventHandle hEvent, TDBTEvent & Event);
+ unsigned int GetCount(TDBTEntityHandle hEntity);
+ unsigned int Delete(TDBTEventHandle hEvent);
+ TDBTEventHandle Add(TDBTEntityHandle hEntity, TDBTEvent & Event);
+ unsigned int MarkRead(TDBTEventHandle hEvent);
+ unsigned int WriteToDisk(TDBTEventHandle hEvent);
+
+ TDBTEntityHandle getEntity(TDBTEventHandle hEvent);
+
+ TDBTEventIterationHandle IterationInit(TDBTEventIterFilter & Filter);
+ TDBTEventHandle IterationNext(TDBTEventIterationHandle Iteration);
+ unsigned int IterationClose(TDBTEventIterationHandle Iteration);
+
+
+private:
+ typedef CBTree<TEventKey, 16> TEventBase;
+ typedef struct
+ {
+ CEventsTree * RealTree;
+ CVirtualEventsTree * VirtualTree;
+ uint32_t VirtualCount;
+ TEventKey FirstVirtualUnread;
+ } TEntityEventsRecord, *PEntityEventsRecord;
+ #ifdef _MSC_VER
+ typedef stdext::hash_map<TDBTEntityHandle, TEntityEventsRecord*> TEntityEventsMap;
+ #else
+ typedef __gnu_cxx::hash_map<TDBTEntityHandle, TEntityEventsRecord*> TEntityEventsMap;
+ #endif
+ typedef CIterationHeap<TEventBase::iterator> TEventsHeap;
+
+ CBlockManager & m_BlockManager;
+ CEncryptionManager & m_EncryptionManager;
+
+ CEntities & m_Entities;
+ CEventsTypeManager m_Types;
+
+ TEntityEventsMap m_EntityEventsMap;
+
+ typedef struct TEventIteration {
+ TDBTEventIterFilter Filter;
+ TEventsHeap * Heap;
+ TDBTEventHandle LastEvent;
+ } TEventIteration, *PEventIteration;
+
+ void onRootChanged(void* EventsTree, CEventsTree::TNodeRef NewRoot);
+
+ void onDeleteEventCallback(void * Tree, const TEventKey & Key, uint32_t Param);
+ void onDeleteVirtualEventCallback(void * Tree, const TEventKey & Key, uint32_t Param);
+ void onDeleteEvents(CEntities * Entities, TDBTEntityHandle hEntity);
+ void onTransferEvents(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest);
+
+ PEntityEventsRecord getEntityRecord(TDBTEntityHandle hEntity);
+ uint32_t adjustVirtualEventCount(PEntityEventsRecord Record, int32_t Adjust);
+ bool MarkEventsTree(TEventBase::iterator Iterator, TDBTEventHandle FirstUnread);
+ void FindNextUnreadEvent(TEventBase::iterator & Iterator);
+};
diff --git a/plugins/Dbx_tree/src/FileAccess.cpp b/plugins/Dbx_tree/src/FileAccess.cpp
new file mode 100644
index 0000000000..a0aa85aecb
--- /dev/null
+++ b/plugins/Dbx_tree/src/FileAccess.cpp
@@ -0,0 +1,299 @@
+/*
+
+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 "FileAccess.h"
+#include <vector>
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#define _time32 time
+#endif
+#include "Logger.h"
+
+const uint8_t CFileAccess::cJournalSignature[20] = "Miranda IM Journal!";
+
+CFileAccess::CFileAccess(const TCHAR* FileName)
+{
+ m_FileName = new TCHAR[_tcslen(FileName) + 1];
+ m_Journal.FileName = new TCHAR[_tcslen(FileName) + 5];
+ _tcscpy_s(m_FileName, _tcslen(FileName) + 1, FileName);
+ _tcscpy_s(m_Journal.FileName, _tcslen(FileName) + 5, FileName);
+ _tcscat_s(m_Journal.FileName, _tcslen(FileName) + 5, _T(".jrn"));
+
+ m_ReadOnly = false;
+ m_LastSize = 0;
+ m_Size = 0;
+ m_Journal.Use = false;
+ m_Journal.hFile = 0;
+ m_Journal.BufUse = 0;
+
+ m_LastAllocTime = _time32(NULL);
+}
+
+CFileAccess::~CFileAccess()
+{
+ CloseHandle(m_Journal.hFile);
+ DeleteFile(m_Journal.FileName);
+
+ delete [] m_FileName;
+ delete [] m_Journal.FileName;
+}
+
+uint32_t CFileAccess::Size(uint32_t NewSize)
+{
+ m_Size = NewSize;
+ if (!m_Journal.Use)
+ {
+ NewSize = (NewSize + m_AllocGranularity - 1) & ~(m_AllocGranularity - 1);
+
+ if (NewSize == 0)
+ NewSize = m_AllocGranularity;
+
+ if (NewSize != m_AllocSize)
+ {
+ m_AllocSize = _SetSize(NewSize);
+
+ // adapt Alloc Granularity
+ uint32_t t = _time32(NULL);
+ uint32_t d = t - m_LastAllocTime;
+ m_LastAllocTime = t;
+
+ if (d < 30) // increase alloc stepping
+ {
+ if (m_AllocGranularity < m_MaxAllocGranularity)
+ m_AllocGranularity = m_AllocGranularity << 1;
+ } else if (d > 120) // decrease alloc stepping
+ {
+ if (m_AllocGranularity > m_MinAllocGranularity)
+ m_AllocGranularity = m_AllocGranularity >> 1;
+ }
+ }
+ }
+ return NewSize;
+}
+
+
+void CFileAccess::CleanJournal()
+{
+ SetFilePointer(m_Journal.hFile, 0, NULL, FILE_BEGIN);
+ SetEndOfFile(m_Journal.hFile);
+
+ DWORD written;
+ WriteFile(m_Journal.hFile, cJournalSignature, sizeof(cJournalSignature), &written, NULL);
+}
+
+void CFileAccess::ProcessJournal()
+{
+ uint32_t filesize = GetFileSize(m_Journal.hFile, NULL) - sizeof(cJournalSignature);
+ SetFilePointer(m_Journal.hFile, sizeof(cJournalSignature), NULL, FILE_BEGIN);
+
+ uint8_t* buf = (uint8_t*)malloc(filesize);
+ TJournalEntry* e = (TJournalEntry*)buf;
+ DWORD read = 0;
+ if (!ReadFile(m_Journal.hFile, buf, filesize, &read, NULL) || (read != filesize))
+ {
+ free(buf);
+ LOGSYS(logCRITICAL, _T("Couldn't flush the journal because ReadFile failed!"));
+ return;
+ }
+
+ m_Journal.Use = false;
+ std::vector<TJournalEntry*> currentops;
+
+ while (filesize >= sizeof(TJournalEntry))
+ {
+ switch (e->Signature)
+ {
+ case 'fini':
+ {
+ Size(e->Size);
+
+ std::vector<TJournalEntry*>::iterator i = currentops.begin();
+ while (i != currentops.end())
+ {
+ switch ((*i)->Signature)
+ {
+ case 'writ':
+ {
+ if ((*i)->Address + (*i)->Size <= m_AllocSize)
+ {
+ _Write(*i + 1, (*i)->Address, (*i)->Size);
+ } else if ((*i)->Address < m_AllocSize)
+ {
+ _Write(*i + 1, (*i)->Address, m_AllocSize - (*i)->Address);
+ }
+ } break;
+ case 'inva':
+ {
+ if ((*i)->Address + (*i)->Size <= m_AllocSize)
+ {
+ _Invalidate((*i)->Address, (*i)->Size);
+ } else if ((*i)->Address < m_AllocSize)
+ {
+ _Invalidate((*i)->Address, m_AllocSize - (*i)->Address);
+ }
+ } break;
+ }
+ ++i;
+ }
+ currentops.clear();
+
+ e++;
+ filesize = filesize - sizeof(TJournalEntry);
+ } break;
+ case 'writ':
+ {
+ if (filesize < sizeof(e) + e->Size)
+ {
+ filesize = 0;
+ } else {
+ currentops.push_back(e);
+ filesize = filesize - sizeof(TJournalEntry) - e->Size;
+ e = (TJournalEntry*)((uint8_t*)e + sizeof(TJournalEntry) + e->Size);
+ }
+ } break;
+ case 'inva':
+ {
+ if (filesize < sizeof(e))
+ {
+ filesize = 0;
+ } else {
+ currentops.push_back(e);
+ e++;
+ filesize = filesize - sizeof(TJournalEntry);
+ }
+ } break;
+ default:
+ {
+ filesize = 0;
+ if (currentops.size())
+ LOG(logWARNING, _T("Your database journal wasn't completely written to disk."));
+ } break;
+ }
+ }
+
+ _Flush();
+
+ CleanJournal();
+
+ free(buf);
+ m_Journal.Use = true;
+}
+
+void CFileAccess::InitJournal()
+{
+ m_Journal.hFile = CreateFile(m_Journal.FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (m_Journal.hFile == INVALID_HANDLE_VALUE)
+ {
+ LOGSYS(logCRITICAL, _T("CreateFile failed on Journal %s"), m_Journal.FileName);
+ return;
+ }
+
+ uint8_t h[sizeof(cJournalSignature)];
+ DWORD read;
+ if (ReadFile(m_Journal.hFile, &h, sizeof(h), &read, NULL) && (read == sizeof(h)) && (0 == memcmp(h, cJournalSignature, sizeof(h))))
+ {
+ TCHAR * bckname = new TCHAR[_tcslen(m_FileName) + 12];
+ _tcscpy_s(bckname, _tcslen(m_FileName) + 12, m_FileName);
+ _tcscat_s(bckname, _tcslen(m_FileName) + 12, _T(".autobackup"));
+
+ TCHAR * bckjrnname = new TCHAR[_tcslen(m_Journal.FileName) + 12];
+ _tcscpy_s(bckjrnname, _tcslen(m_Journal.FileName) + 12, m_Journal.FileName);
+ _tcscat_s(bckjrnname, _tcslen(m_Journal.FileName) + 12, _T(".autobackup"));
+
+ char buf[4096];
+ HANDLE hfilebackup = CreateFile(bckname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (hfilebackup)
+ {
+ uint32_t i = 0;
+ while (i + sizeof(buf) <= m_AllocSize)
+ {
+ DWORD w;
+ _Read(buf, i, sizeof(buf));
+ i += sizeof(buf);
+ WriteFile(hfilebackup, buf, sizeof(buf), &w, NULL);
+ }
+ if (i < m_AllocSize)
+ {
+ DWORD w;
+ _Read(buf, i, m_AllocSize - i);
+ WriteFile(hfilebackup, buf, m_AllocSize - i, &w, NULL);
+ }
+
+ CloseHandle(hfilebackup);
+ }
+
+ HANDLE hjrnfilebackup = CreateFile(bckjrnname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (hjrnfilebackup)
+ {
+ uint32_t i = 0;
+
+ uint32_t filesize = GetFileSize(m_Journal.hFile, NULL);
+ SetFilePointer(m_Journal.hFile, 0, NULL, FILE_BEGIN);
+
+ while (i + sizeof(buf) <= filesize)
+ {
+ DWORD w, r;
+ ReadFile(m_Journal.hFile, buf, sizeof(buf), &r, NULL);
+ i += sizeof(buf);
+ WriteFile(hjrnfilebackup, buf, sizeof(buf), &w, NULL);
+ }
+ if (i < filesize)
+ {
+ DWORD w, r;
+ ReadFile(m_Journal.hFile, buf, filesize - i, &r, NULL);
+ WriteFile(hjrnfilebackup, buf, filesize - i, &w, NULL);
+ }
+ CloseHandle(hjrnfilebackup);
+ }
+
+ TCHAR* path = bckname;
+ TCHAR* fn = _tcsrchr(m_Journal.FileName, _T('\\'));
+ TCHAR* bfn = _tcsrchr(bckname, _T('\\'));
+ TCHAR* jrn = _tcsrchr(bckjrnname, _T('\\'));
+ if (bfn) // truncate path var
+ *bfn = 0;
+
+ if (hfilebackup || hjrnfilebackup)
+ {
+ LOG(logWARNING,
+ _T("Journal \"%s\" was found on start.\nBackup \"%s\"%s created and backup \"%s\"%s created.\nYou may delete these file(s) after successful start from \"%s\"."),
+ fn?fn+1:m_Journal.FileName,
+ bfn?bfn+1:bckname, (hfilebackup!=INVALID_HANDLE_VALUE)?_T(" was successfully"):_T(" could not be"),
+ jrn?jrn+1:bckjrnname, (hjrnfilebackup!=INVALID_HANDLE_VALUE)?_T(" was successfully"):_T(" could not be"),
+ path);
+ } else {
+ LOG(logWARNING,
+ _T("Journal \"%s\" was found on start.\nBackups \"%s\"and \"%s\" could not be created in \"%s\"."),
+ fn?fn+1:m_Journal.FileName,
+ bfn?bfn+1:bckname,
+ jrn?jrn+1:bckjrnname,
+ path);
+ }
+
+ delete [] bckname;
+ delete [] bckjrnname;
+
+ ProcessJournal();
+ }
+
+ CleanJournal();
+}
diff --git a/plugins/Dbx_tree/src/FileAccess.h b/plugins/Dbx_tree/src/FileAccess.h
new file mode 100644
index 0000000000..f49643e2a3
--- /dev/null
+++ b/plugins/Dbx_tree/src/FileAccess.h
@@ -0,0 +1,191 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <windows.h>
+#include <time.h>
+#include "stdint.h"
+#include "sigslot.h"
+
+class CFileAccess
+{
+public:
+ static const uint8_t cJournalSignature[20];
+
+ CFileAccess(const TCHAR* FileName);
+ virtual ~CFileAccess();
+
+
+ uint32_t Read(void* Buf, uint32_t Source, uint32_t Size)
+ {
+ return _Read(Buf, Source, Size);
+ };
+
+ bool Write(void* Buf, uint32_t Dest, uint32_t Size)
+ {
+ if (m_Journal.Use)
+ {
+ DWORD written;
+
+ TJournalEntry * data = reinterpret_cast<TJournalEntry*>(m_Journal.Buffer + m_Journal.BufUse);
+ data->Signature = 'writ';
+ data->Address = Dest;
+ data->Size = Size;
+ m_Journal.BufUse += 12;
+ if (Size + m_Journal.BufUse < sizeof(m_Journal.Buffer) - 12) // one journal header has always to fit in
+ {
+ memcpy(m_Journal.Buffer + m_Journal.BufUse, Buf, Size);
+ m_Journal.BufUse += Size;
+ } else {
+ WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL);
+ WriteFile(m_Journal.hFile, Buf, Size, &written, NULL);
+
+ m_Journal.BufUse = 0;
+ }
+ } else {
+ _Write(Buf, Dest, Size);
+ }
+
+ return true;
+ };
+
+ void Invalidate(uint32_t Dest, uint32_t Size)
+ {
+ if (m_Journal.Use)
+ {
+ DWORD written;
+
+ TJournalEntry * data = reinterpret_cast<TJournalEntry*>(m_Journal.Buffer + m_Journal.BufUse);
+ data->Signature = 'inva';
+ data->Address = Dest;
+ data->Size = Size;
+ m_Journal.BufUse += 12;
+ if (m_Journal.BufUse > sizeof(m_Journal.Buffer) - 12)
+ {
+ WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL);
+ m_Journal.BufUse = 0;
+ }
+ } else {
+ _Invalidate(Dest, Size);
+ }
+ };
+
+ void Flush()
+ {
+ if (m_Journal.Use)
+ {
+ if (m_Journal.BufUse)
+ {
+ DWORD written;
+ WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL);
+ m_Journal.BufUse = 0;
+ }
+ FlushFileBuffers(m_Journal.hFile);
+ } else {
+ _Flush();
+ }
+ };
+
+ void UseJournal(bool UseIt)
+ {
+ m_Journal.Use = UseIt;
+ };
+
+ void CompleteTransaction()
+ {
+ if (m_Size != m_LastSize)
+ {
+ m_sigFileSizeChanged.emit(this, m_Size);
+ m_LastSize = m_Size;
+ }
+ };
+ void CloseTransaction()
+ {
+ if (m_Journal.Use)
+ {
+ DWORD written;
+
+ TJournalEntry * data = reinterpret_cast<TJournalEntry*>(m_Journal.Buffer + m_Journal.BufUse);
+ data->Signature = 'fini';
+ data->Address = 0;
+ data->Size = m_Size;
+
+ WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse + 12, &written, NULL);
+ m_Journal.BufUse = 0;
+ }
+ };
+
+ void CleanJournal();
+
+ uint32_t Size(uint32_t NewSize);
+ uint32_t Size()
+ { return m_Size; };
+ void ReadOnly(bool ReadOnly)
+ { m_ReadOnly = ReadOnly; };
+ bool ReadOnly()
+ { return m_ReadOnly; };
+
+ typedef sigslot::signal2<CFileAccess *, uint32_t> TOnFileSizeChanged;
+
+ TOnFileSizeChanged & sigFileSizeChanged()
+ { return m_sigFileSizeChanged; };
+
+protected:
+ TCHAR* m_FileName;
+ struct {
+ bool Use;
+ TCHAR* FileName;
+ HANDLE hFile;
+
+ uint8_t Buffer[4096];
+ uint32_t BufUse;
+ } m_Journal;
+
+ uint32_t m_Size;
+ uint32_t m_AllocSize;
+ uint32_t m_AllocGranularity;
+ uint32_t m_MinAllocGranularity;
+ uint32_t m_MaxAllocGranularity;
+ uint32_t m_LastAllocTime;
+ bool m_ReadOnly;
+ uint32_t m_LastSize;
+
+ TOnFileSizeChanged m_sigFileSizeChanged;
+ virtual uint32_t _Read(void* Buf, uint32_t Source, uint32_t Size) = 0;
+ virtual uint32_t _Write(void* Buf, uint32_t Dest, uint32_t Size) = 0;
+ virtual void _Invalidate(uint32_t Dest, uint32_t Size) = 0;
+ virtual uint32_t _SetSize(uint32_t Size) = 0;
+ virtual void _Flush() = 0;
+
+#pragma pack (push, 1)
+ typedef struct TJournalEntry
+ {
+ uint32_t Signature;
+ uint32_t Address;
+ uint32_t Size;
+ } TJournalEntry;
+#pragma pack (pop)
+
+ void InitJournal();
+ void ProcessJournal();
+};
diff --git a/plugins/Dbx_tree/src/FileBTree.h b/plugins/Dbx_tree/src/FileBTree.h
new file mode 100644
index 0000000000..3a9e58a43e
--- /dev/null
+++ b/plugins/Dbx_tree/src/FileBTree.h
@@ -0,0 +1,102 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+#include "BTree.h"
+#include "BlockManager.h"
+#include "Logger.h"
+
+template <typename TKey, uint16_t SizeParam = 4>
+class CFileBTree : public CBTree<TKey, SizeParam>
+{
+private:
+
+protected:
+ CBlockManager & m_BlockManager;
+ uint16_t cSignature;
+
+ virtual void PrepareInsertOperation();
+ virtual TNode * CreateNewNode(TNodeRef & NodeRef);
+ virtual void DeleteNode(TNodeRef Node);
+ virtual TNode * Read(TNodeRef Node);
+ virtual void Write(TNodeRef Node);
+public:
+ CFileBTree(CBlockManager & BlockManager, typename CBTree<TKey, SizeParam>::TNodeRef RootNode, uint16_t Signature);
+ virtual ~CFileBTree();
+};
+
+
+
+
+template <typename TKey, uint16_t SizeParam>
+CFileBTree<TKey, SizeParam>::CFileBTree(CBlockManager & BlockManager, typename CBTree<TKey, SizeParam>::TNodeRef RootNode, uint16_t Signature)
+: CBTree<TKey, SizeParam>::CBTree(RootNode),
+ m_BlockManager(BlockManager)
+{
+ cSignature = Signature;
+ CBTree<TKey, SizeParam>::m_DestroyTree = false;
+}
+
+template <typename TKey, uint16_t SizeParam>
+CFileBTree<TKey, SizeParam>::~CFileBTree()
+{
+ CBTree<TKey, SizeParam>::m_DestroyTree = false;
+}
+
+
+template <typename TKey, uint16_t SizeParam>
+void CFileBTree<TKey, SizeParam>::PrepareInsertOperation()
+{
+
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::TNode * CFileBTree<TKey, SizeParam>::CreateNewNode(typename CBTree<TKey, SizeParam>::TNodeRef & NodeRef)
+{
+ return reinterpret_cast<TNode*>( m_BlockManager.CreateBlock<uint32_t>(NodeRef, cSignature << 16, sizeof(typename CBTree<TKey, SizeParam>::TNode) - 4) - 1);
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CFileBTree<TKey, SizeParam>::DeleteNode(typename CBTree<TKey, SizeParam>::TNodeRef Node)
+{
+ m_BlockManager.DeleteBlock(Node);
+}
+
+template <typename TKey, uint16_t SizeParam>
+typename CBTree<TKey, SizeParam>::TNode * CFileBTree<TKey, SizeParam>::Read(typename CBTree<TKey, SizeParam>::TNodeRef Node)
+{
+ uint32_t sig = 0;
+ uint32_t size = 0;
+ TNode * res = reinterpret_cast<TNode*>( m_BlockManager.ReadBlock<uint32_t>(Node, size, sig) - 1); /// HACK using knowledge about the blockmanager here
+
+ CHECK(res->Signature == cSignature,
+ logCRITICAL, _T("Signature check failed"));
+
+ return res;
+}
+
+template <typename TKey, uint16_t SizeParam>
+void CFileBTree<TKey, SizeParam>::Write(typename CBTree<TKey, SizeParam>::TNodeRef Node)
+{
+ m_BlockManager.UpdateBlock(Node, 0);
+}
+
diff --git a/plugins/Dbx_tree/src/Hash.cpp b/plugins/Dbx_tree/src/Hash.cpp
new file mode 100644
index 0000000000..f0541c2da0
--- /dev/null
+++ b/plugins/Dbx_tree/src/Hash.cpp
@@ -0,0 +1,183 @@
+/*
+
+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 "Hash.h"
+
+
+/// lookup3, by Bob Jenkins, May 2006, Public Domain.
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+#define HASHmix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+#define HASHfinal(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c, 4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+
+uint32_t Hash(const void * Data, uint32_t Length)
+{
+ register uint32_t a,b,c; // internal state
+ union { const void *ptr; uint32_t i; } u; // needed for Mac Powerbook G4
+
+ // Set up the internal state
+ a = b = c = 0xdeadbeef + Length; // + initval = 0
+
+ u.ptr = Data;
+ if ((u.i & 0x3) == 0)
+ {
+ const uint32_t *k = (const uint32_t *)Data; // read 32-bit chunks
+
+ // all but last block: aligned reads and affect 32 bits of (a,b,c)
+ while (Length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ HASHmix(a,b,c);
+ Length -= 12;
+ k += 3;
+ }
+
+ switch(Length)
+ {
+ case 12: c += k[2]; b += k[1]; a += k[0]; break;
+ case 11: c += k[2] & 0xffffff; b += k[1]; a += k[0]; break;
+ case 10: c += k[2] & 0xffff; b += k[1]; a += k[0]; break;
+ case 9 : c += k[2] & 0xff; b += k[1]; a += k[0]; break;
+ case 8 : b += k[1]; a += k[0]; break;
+ case 7 : b += k[1] & 0xffffff; a += k[0]; break;
+ case 6 : b += k[1] & 0xffff; a += k[0]; break;
+ case 5 : b += k[1] & 0xff; a += k[0]; break;
+ case 4 : a += k[0]; break;
+ case 3 : a += k[0] & 0xffffff; break;
+ case 2 : a += k[0] & 0xffff; break;
+ case 1 : a += k[0] & 0xff; break;
+ case 0 : return c; // zero length strings require no mixing
+ }
+
+ } else if ((u.i & 0x1) == 0) {
+ const uint16_t *k = (const uint16_t *)Data; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ // all but last block: aligned reads and different mixing
+ while (Length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1]) << 16);
+ b += k[2] + (((uint32_t)k[3]) << 16);
+ c += k[4] + (((uint32_t)k[5]) << 16);
+ HASHmix(a,b,c);
+ Length -= 12;
+ k += 6;
+ }
+
+ // handle the last (probably partial) block
+ k8 = (const uint8_t *)k;
+ switch(Length)
+ {
+ case 12: c += k[4] + (((uint32_t)k[5]) << 16);
+ b += k[2] + (((uint32_t)k[3]) << 16);
+ a += k[0] + (((uint32_t)k[1]) << 16);
+ break;
+ case 11: c += ((uint32_t)k8[10]) << 16; // fall through
+ case 10: c += k[4];
+ b += k[2] + (((uint32_t)k[3]) << 16);
+ a += k[0] + (((uint32_t)k[1]) << 16);
+ break;
+ case 9 : c += k8[8]; // fall through
+ case 8 : b += k[2] + (((uint32_t)k[3]) << 16);
+ a += k[0] + (((uint32_t)k[1]) << 16);
+ break;
+ case 7 : b += ((uint32_t)k8[6]) << 16; // fall through
+ case 6 : b += k[2];
+ a += k[0] + (((uint32_t)k[1]) << 16);
+ break;
+ case 5 : b += k8[4]; // fall through
+ case 4 : a += k[0] + (((uint32_t)k[1]) << 16);
+ break;
+ case 3 : a += ((uint32_t)k8[2]) << 16; // fall through
+ case 2 : a += k[0];
+ break;
+ case 1 : a += k8[0];
+ break;
+ case 0 : return c; // zero length requires no mixing
+ }
+
+ } else { // need to read the key one byte at a time
+ const uint8_t *k = (const uint8_t *)Data;
+
+ // all but the last block: affect some 32 bits of (a,b,c)
+ while (Length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1] ) << 8;
+ a += ((uint32_t)k[2] ) << 16;
+ a += ((uint32_t)k[3] ) << 24;
+ b += k[4];
+ b += ((uint32_t)k[5] ) << 8;
+ b += ((uint32_t)k[6] ) << 16;
+ b += ((uint32_t)k[7] ) << 24;
+ c += k[8];
+ c += ((uint32_t)k[9] ) << 8;
+ c += ((uint32_t)k[10]) << 16;
+ c += ((uint32_t)k[11]) << 24;
+ HASHmix(a,b,c);
+ Length -= 12;
+ k += 12;
+ }
+
+ // last block: affect all 32 bits of (c)
+ switch(Length) // all the case statements fall through
+ {
+ case 12: c += ((uint32_t)k[11]) << 24;
+ case 11: c += ((uint32_t)k[10]) << 16;
+ case 10: c += ((uint32_t)k[9] ) << 8;
+ case 9 : c += k[8];
+ case 8 : b += ((uint32_t)k[7] ) << 24;
+ case 7 : b += ((uint32_t)k[6] ) << 16;
+ case 6 : b += ((uint32_t)k[5] ) << 8;
+ case 5 : b += k[4];
+ case 4 : a += ((uint32_t)k[3] ) << 24;
+ case 3 : a += ((uint32_t)k[2] ) << 16;
+ case 2 : a += ((uint32_t)k[1] ) << 8;
+ case 1 : a += k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ HASHfinal(a,b,c);
+ return c;
+}
diff --git a/plugins/Dbx_tree/src/Hash.h b/plugins/Dbx_tree/src/Hash.h
new file mode 100644
index 0000000000..886e8b1485
--- /dev/null
+++ b/plugins/Dbx_tree/src/Hash.h
@@ -0,0 +1,29 @@
+/*
+
+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.
+
+*/
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "stdint.h"
+#endif
+
+uint32_t Hash(const void * Data, uint32_t Length);
diff --git a/plugins/Dbx_tree/src/Interface.h b/plugins/Dbx_tree/src/Interface.h
new file mode 100644
index 0000000000..bde0a74511
--- /dev/null
+++ b/plugins/Dbx_tree/src/Interface.h
@@ -0,0 +1,55 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#ifndef INTERFACE_VERSION_ONLY
+
+#define MIRANDA_VER 0x0A00
+#include <windows.h>
+#include "newpluginapi.h"
+#include "m_system.h"
+#include "m_system_cpp.h"
+#include "m_database.h"
+#include "m_db_int.h"
+#include "m_utils.h"
+#include "win2k.h"
+
+#include "m_langpack.h"
+
+#include "m_dbx_tree.h"
+
+extern HINSTANCE hInstance;
+
+extern DATABASELINK gDBLink;
+#endif
+
+
+#define gVersion 0x00000012
+#define gResVersion 0,0,0,18
+#define gResVersionString "0.0.0.18"
+#define gInternalName "dbx_tree"
+#define gInternalNameLong "Miranda dbx_tree database driver"
+#define gDescription "Provides extended Miranda database support"
+#define gAutor "Michael 'Protogenes' Kunz"
+#define gAutorEmail "Michael.Kunz@s2005.TU-Chemnitz.de"
+#define gCopyright "2007 - 2010 Michael 'Protogenes' Kunz"
diff --git a/plugins/Dbx_tree/src/IterationHeap.h b/plugins/Dbx_tree/src/IterationHeap.h
new file mode 100644
index 0000000000..db06f7e695
--- /dev/null
+++ b/plugins/Dbx_tree/src/IterationHeap.h
@@ -0,0 +1,196 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <vector>
+
+template <class TType>
+class CIterationHeap
+{
+public:
+ enum TIterationType {ITForward, ITBackward};
+
+ CIterationHeap(TType & InitialItem, TIterationType ForBack, bool DeleteItems = true);
+ ~CIterationHeap();
+
+ bool Insert(TType & Item);
+ TType & Top();
+ void Pop();
+
+protected:
+ typedef struct THeapElement {
+ TType * Elem;
+ size_t Index;
+ } THeapElement, * PHeapElement;
+
+ std::vector <PHeapElement> m_Heap;
+ TIterationType m_Type;
+ bool m_DeleteItems;
+
+ bool A_b4_B(PHeapElement a, PHeapElement b);
+private:
+
+};
+
+
+template <class TType>
+inline bool CIterationHeap<TType>::A_b4_B(PHeapElement a, PHeapElement b)
+{
+ if (m_Type == ITForward)
+ {
+ if ((**a->Elem) == (**b->Elem)) return a->Index < b->Index;
+ return (**a->Elem) < (**b->Elem);
+ } else {
+ if ((**a->Elem) == (**b->Elem)) return a->Index > b->Index;
+ return (**a->Elem) > (**b->Elem);
+ }
+}
+
+template <class TType>
+CIterationHeap<TType>::CIterationHeap(TType & InitialItem, TIterationType MinMax, bool DeleteItems)
+: m_Heap()
+{
+ m_Heap.resize(1);
+ m_Heap.reserve(1 << 1);
+ m_Type = MinMax;
+
+ m_Heap[0] = new THeapElement;
+ m_Heap[0]->Elem = &InitialItem;
+ m_Heap[0]->Index = m_Heap.size();
+ m_DeleteItems = DeleteItems;
+}
+
+template <class TType>
+CIterationHeap<TType>::~CIterationHeap()
+{
+ unsigned int i = 0;
+ while ((i < m_Heap.size()) && (m_Heap[i]))
+ {
+ if (m_DeleteItems && m_Heap[i]->Elem)
+ delete m_Heap[i]->Elem;
+
+ delete m_Heap[i];
+ ++i;
+ }
+}
+
+template <class TType>
+bool CIterationHeap<TType>::Insert(TType & Item)
+{
+ if (!Item)
+ return false;
+
+ if (m_Heap.capacity() == m_Heap.size() + 1)
+ m_Heap.reserve(m_Heap.capacity() << 1);
+
+ m_Heap.push_back(NULL);
+
+ size_t way = m_Heap.capacity() >> 2;
+ size_t index = 0;
+ PHeapElement ins = new THeapElement;
+ ins->Elem = &Item;
+ ins->Index = m_Heap.size();
+
+ PHeapElement next;
+
+ while ((way > 0) && (index + 1 < m_Heap.size()))
+ {
+ next = m_Heap[index];
+ if ((!(*next->Elem)) || A_b4_B(ins, next))
+ {
+ m_Heap[index] = ins;
+ ins = next;
+ }
+
+ if (way & m_Heap.size()) //right
+ {
+ index = (index << 1) + 2;
+ } else { // left
+ index = (index << 1) + 1;
+ }
+ way = way >> 1;
+ }
+
+ m_Heap[index] = ins;
+
+ return true;
+}
+
+template <class TType>
+TType & CIterationHeap<TType>::Top()
+{
+ return *m_Heap[0]->Elem;
+}
+
+template <class TType>
+void CIterationHeap<TType>::Pop()
+{
+ if (m_Type == ITForward)
+ ++(*m_Heap[0]->Elem);
+ else
+ --(*m_Heap[0]->Elem);
+
+ size_t index = 0;
+ PHeapElement ins = m_Heap[0];
+ size_t big = 1;
+
+ while ((big > 0) && (index < (m_Heap.size() >> 1)))
+ {
+ big = 0;
+
+ if ((((index << 1) + 2) < m_Heap.size()) && (*m_Heap[(index << 1) + 2]->Elem))
+ {
+ if (*ins->Elem)
+ {
+ if (A_b4_B(m_Heap[(index << 1) + 2], m_Heap[(index << 1) + 1]))
+ big = (index << 1) + 2;
+ else
+ big = (index << 1) + 1;
+
+ } else {
+ m_Heap[index] = m_Heap[(index << 1) + 2];
+ index = (index << 1) + 2;
+ m_Heap[index] = ins;
+ }
+ } else if ((((index << 1) + 1) < m_Heap.size()) && (*m_Heap[(index << 1) + 1]->Elem))
+ {
+ if (*ins->Elem)
+ {
+ big = (index << 1) + 1;
+ } else {
+ m_Heap[index] = m_Heap[(index << 1) + 1];
+ index = (index << 1) + 1;
+ m_Heap[index] = ins;
+ }
+ }
+
+ if ((big > 0) && A_b4_B(m_Heap[big], ins))
+ {
+ m_Heap[index] = m_Heap[big];
+ index = big;
+ m_Heap[big] = ins;
+ } else {
+ big = 0;
+ }
+ }
+}
diff --git a/plugins/Dbx_tree/src/Logger.cpp b/plugins/Dbx_tree/src/Logger.cpp
new file mode 100644
index 0000000000..551824d905
--- /dev/null
+++ b/plugins/Dbx_tree/src/Logger.cpp
@@ -0,0 +1,124 @@
+/*
+
+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 "Logger.h"
+#include <process.h>
+
+CLogger CLogger::_Instance;
+
+CLogger::CLogger()
+ : m_Length(0),
+ m_Level(logNOTICE)
+{
+
+}
+
+CLogger::~CLogger()
+{
+ for (std::vector<TCHAR *>::iterator it = m_Messages.begin(); it != m_Messages.end(); ++it)
+ delete [] *it;
+}
+
+void CLogger::Append(const TCHAR * File, const TCHAR * Function, const int Line, DWORD SysState, TLevel Level, const TCHAR * Message, ...)
+{
+ if (m_Level < Level)
+ m_Level = Level;
+
+ time_t rawtime = time(NULL);
+ tm timeinfo;
+ TCHAR timebuf[80];
+ localtime_s(&timeinfo, &rawtime);
+ size_t len = _tcsftime(timebuf, sizeof(timebuf) / sizeof(*timebuf), _T("%c"), &timeinfo);
+
+ TCHAR msgbuf[4096];
+ va_list va;
+ va_start(va, Message);
+ len += _vstprintf_s(msgbuf, Message, va);
+ va_end(va);
+
+ TCHAR * message;
+ if (SysState)
+ {
+ TCHAR syserror[2048];
+ len += FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, SysState, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), syserror, 2048, NULL);
+
+ len += /*_tcslen(File) + 10 +*/ _tcslen(Function) + 32 + 12 + 1;
+
+ message = new TCHAR[len];
+ m_Length += _stprintf_s(message, len, _T("[%s - %s]\n%s\n\nSystem Error Code: %d\n%s\n\n"), timebuf, /*File, Line, */ Function, msgbuf, SysState, syserror) + 1;
+ } else {
+ len += /*_tcslen(File) + 10 +*/ _tcslen(Function) + 12 + 1;
+
+ message = new TCHAR[len];
+ m_Length += _stprintf_s(message, len, _T("[%s - %s]\n%s\n\n"), timebuf, /*File, Line, */Function, msgbuf) + 1;
+ }
+ m_Messages.push_back(message);
+}
+
+CLogger::TLevel CLogger::ShowMessage(TLevel CanAsyncTill)
+{
+ if (m_Messages.size() == 0)
+ return logNOTICE;
+
+ TCHAR * msg = new TCHAR[m_Length];
+ *msg = 0;
+
+ for (std::vector<TCHAR *>::iterator it = m_Messages.begin(); it != m_Messages.end(); ++it)
+ {
+ _tcscat_s(msg, m_Length, *it);
+ delete [] *it;
+ }
+ m_Messages.clear();
+
+ if (m_Level <= CanAsyncTill)
+ {
+ MSGBOXPARAMS * p = new MSGBOXPARAMS;
+ p->cbSize = sizeof(*p);
+ p->hwndOwner = 0;
+ p->hInstance = NULL;
+ p->lpszText = msg;
+ p->lpszCaption = _T(gInternalNameLong);
+ p->dwStyle = MB_OK | (m_Level >= logERROR)?MB_ICONHAND:((m_Level == logWARNING)?MB_ICONWARNING:MB_ICONINFORMATION);
+ p->lpszIcon = NULL;
+ p->dwContextHelpId = 0;
+ p->lpfnMsgBoxCallback = NULL;
+ p->dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+
+ _beginthread(&CLogger::MessageBoxAsync, 0, p);
+ } else {
+ MessageBox(0, msg, _T(gInternalNameLong), MB_OK | (m_Level >= logERROR)?MB_ICONHAND:((m_Level == logWARNING)?MB_ICONWARNING:MB_ICONINFORMATION));
+ delete [] msg;
+ }
+
+ TLevel tmp = m_Level;
+ m_Level = logNOTICE;
+ return tmp;
+}
+
+void CLogger::MessageBoxAsync(void * MsgBoxParams)
+{
+ MSGBOXPARAMS* p = reinterpret_cast<MSGBOXPARAMS*>(MsgBoxParams);
+ MessageBoxIndirect(p);
+ if (p->lpszText)
+ delete [] p->lpszText;
+ delete p;
+} \ No newline at end of file
diff --git a/plugins/Dbx_tree/src/Logger.h b/plugins/Dbx_tree/src/Logger.h
new file mode 100644
index 0000000000..a97b928555
--- /dev/null
+++ b/plugins/Dbx_tree/src/Logger.h
@@ -0,0 +1,73 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <vector>
+#include <time.h>
+#include "Interface.h"
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#define __WFILE__ WIDEN(__FILE__)
+#define __WFUNCTION__ WIDEN(__FUNCTION__)
+
+
+#define LOG(Level, Message, ...) CLogger::Instance().Append(__WFILE__, __WFUNCTION__, __LINE__, 0, CLogger:: ## Level, Message, __VA_ARGS__)
+#define LOGSYS(Level, Message, ...) CLogger::Instance().Append(__WFILE__, __WFUNCTION__, __LINE__, GetLastError(), CLogger:: ## Level, Message, __VA_ARGS__)
+
+
+#define CHECK(Assertion, Level, Message, ...) if (!(Assertion)) LOG(Level, Message, __VA_ARGS__)
+#define CHECKSYS(Assertion, Level, Message, ...) if (!(Assertion)) LOGSYS(Level, Message, __VA_ARGS__)
+
+class CLogger
+{
+ public:
+ enum TLevel
+ {
+ logNOTICE,
+ logWARNING,
+ logERROR,
+ logCRITICAL
+ };
+
+ CLogger();
+ ~CLogger();
+
+ void Append(const TCHAR * File, const TCHAR * Function, const int Line, DWORD SysState, TLevel Level, const TCHAR * Message, ...);
+ TLevel ShowMessage(TLevel CanAsyncTill = logERROR);
+
+ static CLogger & Instance()
+ { return _Instance; };
+
+ TLevel Level()
+ { return m_Level; };
+ protected:
+ std::vector<TCHAR *> m_Messages;
+ size_t m_Length;
+ TLevel m_Level;
+
+ static void MessageBoxAsync(void * MsgBoxParams);
+ private:
+ static CLogger _Instance;
+
+};
diff --git a/plugins/Dbx_tree/src/MREWSync.cpp b/plugins/Dbx_tree/src/MREWSync.cpp
new file mode 100644
index 0000000000..6e08be6475
--- /dev/null
+++ b/plugins/Dbx_tree/src/MREWSync.cpp
@@ -0,0 +1,330 @@
+/*
+
+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 "MREWSync.h"
+#include <assert.h>
+#include "intrinsics.h"
+
+#if defined(MREW_DO_DEBUG_LOGGING) && (defined(DEBUG) || defined(_DEBUG))
+ #include <stdio.h>
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// +------------+---------------+---------------+------------+---------------+
+// | ReaderBusy | ReaderWaiting | WriterWaiting | WriterBusy | UseOddReader? |
+// +------------+---------------+---------------+------------+---------------+
+// 63..44 43..24 23..4 3 0
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#define isWriterBusy(Sentinel) ((Sentinel) & 0x0000000000000008ui64)
+#define isWriterWaiting(Sentinel) ((Sentinel) & 0x0000000000fffff0ui64)
+#define isReaderWaiting(Sentinel) ((Sentinel) & 0x00000fffff000000ui64)
+#define isReaderBusy(Sentinel) ((Sentinel) & 0xfffff00000000000ui64)
+
+#define countWriterWaiting(Sentinel) (((Sentinel) & 0x0000000000fffff0ui64) >> 4)
+#define countReaderWaiting(Sentinel) (((Sentinel) & 0x00000fffff000000ui64) >> 24)
+#define countReaderBusy(Sentinel) (((Sentinel) & 0xfffff00000000000ui64) >> 44)
+
+#define WriterBusy (1ui64 << 3)
+#define WriterWaiting (1ui64 << 4)
+#define ReaderWaiting (1ui64 << 24)
+#define ReaderBusy (1ui64 << 44)
+
+#define isUseOddReader(Sentinel) ((Sentinel) & 1)
+#define useOddReader (1ui64)
+
+CMultiReadExclusiveWriteSynchronizer::CMultiReadExclusiveWriteSynchronizer(void)
+: tls(),
+ m_Sentinel(0)
+{
+ m_ReadSignal[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_ReadSignal[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_WriteSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
+ m_WriterID = 0;
+ m_WriteRecursion = 0;
+ m_Revision = 0;
+}
+
+CMultiReadExclusiveWriteSynchronizer::~CMultiReadExclusiveWriteSynchronizer(void)
+{
+ BeginWrite();
+ CloseHandle(m_WriteSignal);
+ CloseHandle(m_ReadSignal[0]);
+ CloseHandle(m_ReadSignal[1]);
+}
+
+void CMultiReadExclusiveWriteSynchronizer::BeginRead()
+{
+ unsigned long id = GetCurrentThreadId();
+ unsigned & reccount(tls.Open(this, 0));
+
+ reccount++;
+ if ((m_WriterID != id) && (reccount == 1))
+ {
+ int64_t old;
+ int64_t newvalue;
+
+ do {
+ old = m_Sentinel;
+ if (isWriterBusy(old))
+ newvalue = old + ReaderBusy; // writer has lock -> we are going to enter after he leaves -> we are busy but have to wait
+ else if (isWriterWaiting(old))
+ newvalue = old + ReaderWaiting; // writer is waiting for lock -> don't set myself busy as he waits for all readers to leave lock
+ else
+ newvalue = old + ReaderBusy; // no writer in sight, just take lock
+
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+
+ if (isWriterBusy(old) || isWriterWaiting(old))
+ {
+ if (isUseOddReader(old))
+ WaitForSingleObject(m_ReadSignal[1], INFINITE);
+ else
+ WaitForSingleObject(m_ReadSignal[0], INFINITE);
+ }
+ }
+}
+void CMultiReadExclusiveWriteSynchronizer::EndRead()
+{
+ unsigned long id = GetCurrentThreadId();
+ unsigned & reccount(tls.Open(this, 1));
+ reccount--;
+
+ if ((reccount == 0) && (m_WriterID != id))
+ {
+ int64_t old;
+ int64_t newvalue;
+
+ do {
+ old = m_Sentinel;
+ if ((countReaderBusy(old) == 1) && isWriterWaiting(old))
+ { // give control to the writer... move waiting readers to busy (but blocked)
+ newvalue = old - WriterWaiting + WriterBusy - ReaderBusy + countReaderWaiting(old) * (ReaderBusy - ReaderWaiting);
+ } else {
+ newvalue = old - ReaderBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ if ((countReaderBusy(old) == 1) && isWriterWaiting(old))
+ {
+ SetEvent(m_WriteSignal);
+ }
+ }
+
+ if (reccount == 0)
+ tls.Remove(this);
+}
+bool CMultiReadExclusiveWriteSynchronizer::BeginWrite()
+{
+ unsigned long id = GetCurrentThreadId();
+ unsigned * reccount = tls.Find(this);
+ bool res = true;
+
+ if (m_WriterID != id)
+ {
+ int64_t old;
+ int64_t newvalue;
+ unsigned int oldrevision = m_Revision;
+
+ if (reccount) // upgrade our readlock
+ {
+ do {
+ old = m_Sentinel;
+ // isWriterBusy cannot happen because we have a readlock, so we ignore it
+ if (countReaderBusy(old) > 1) // there is another reader.. we have to wait for him. set arriving readers to waiting state
+ {
+ newvalue = old + WriterWaiting - ReaderBusy;
+ } else if (isWriterWaiting(old)) // there is another writer waiting, who arrived earlier. we will sign him in and wait. we are the last reader, so we have to update the sentinel
+ {
+ newvalue = old + WriterBusy - ReaderBusy + countReaderWaiting(old) * (ReaderBusy - ReaderWaiting);
+ } else { // nobody is busy, we want the lock
+ newvalue = old + WriterBusy - ReaderBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ if (countReaderBusy(old) > 1)
+ {
+ WaitForSingleObject(m_WriteSignal, INFINITE); // someone woke me up... he had to take care of all state changes of the sentinel
+ } else if (isWriterWaiting(old)) // we will wait for the other writer, as we are the last reader, we have to wake him up
+ {
+ SetEvent(m_WriteSignal);
+ Sleep(0); // yield thread trying to keep FIFO order
+ WaitForSingleObject(m_WriteSignal, INFINITE); // someone woke me up... he had to take care of all state changes of the sentinel
+ }
+ } else { // gain write lock
+ do {
+ old = m_Sentinel;
+ if (isWriterBusy(old)) // there is a writer.. we have to wait for him
+ {
+ newvalue = old + WriterWaiting;
+ } else if (isReaderBusy(old)) // there is a reader.. we have to wait for him. set arriving readers to waiting state
+ {
+ newvalue = old + WriterWaiting;
+ } else if (isWriterWaiting(old)) // there is another writer waiting, who arrived earlier. we will wait
+ {
+ newvalue = old + WriterWaiting;
+ } else { // nobody is busy, we want the lock
+ newvalue = old + WriterBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ if (isWriterBusy(old) || isReaderBusy(old) || isWriterWaiting(old))
+ {
+ WaitForSingleObject(m_WriteSignal, INFINITE); // someone woke me up... he had to take care of all state changes of the sentinel
+ }
+ }
+ res = (oldrevision == (INC_32(m_Revision) - 1));
+
+ m_WriterID = id;
+ }
+ m_WriteRecursion++;
+
+ return res;
+}
+
+bool CMultiReadExclusiveWriteSynchronizer::EndWrite()
+{
+ unsigned long id = GetCurrentThreadId();
+ unsigned * reccount = tls.Find(this);
+
+ m_WriteRecursion--;
+
+ if (m_WriteRecursion == 0)
+ {
+ int64_t old;
+ int64_t newvalue;
+
+ m_WriterID = 0;
+
+ if (isUseOddReader(m_Sentinel)) // reset upcoming signal
+ ResetEvent(m_ReadSignal[0]);
+ else
+ ResetEvent(m_ReadSignal[1]);
+
+ if (reccount) // downgrade to reader lock
+ {
+ do {
+ old = m_Sentinel;
+ newvalue = (old ^ useOddReader) - WriterBusy + ReaderBusy; // single case... we are a waiting reader and we will keep control of the lock
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ if (isUseOddReader(old)) // allow additional readers to pass
+ SetEvent(m_ReadSignal[1]);
+ else
+ SetEvent(m_ReadSignal[0]);
+
+ } else {
+
+ do {
+ old = m_Sentinel;
+ if (isReaderBusy(old)) // give control to waiting readers
+ {
+ newvalue = (old ^ useOddReader) - WriterBusy;
+ } else if (isWriterWaiting(old)) // no reader arrived while i was working... give control to next writer
+ {
+ newvalue = (old ^ useOddReader) - WriterWaiting;
+ } else { // nobody else is there... just close lock
+ newvalue = (old ^ useOddReader) - WriterBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ if (isReaderBusy(old)) // release waiting readers
+ {
+ if (isUseOddReader(old))
+ SetEvent(m_ReadSignal[1]);
+ else
+ SetEvent(m_ReadSignal[0]);
+ } else if (isWriterWaiting(old))
+ {
+ SetEvent(m_WriteSignal);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool CMultiReadExclusiveWriteSynchronizer::TryBeginWrite()
+{
+ unsigned long id = GetCurrentThreadId();
+ unsigned * reccount = tls.Find(this);
+
+ if (m_WriterID != id)
+ {
+ int64_t old;
+ int64_t newvalue;
+ unsigned int oldrevision = m_Revision;
+
+ if (reccount) // upgrade our readlock
+ {
+ do {
+ old = m_Sentinel;
+ // isWriterBusy cannot happen because we have a readlock, so we ignore it
+ if (countReaderBusy(old) > 1) // there is another reader.. we have to wait for him. set arriving readers to waiting state
+ {
+ return false;
+ } else if (isWriterWaiting(old)) // there is another writer waiting, who arrived earlier. we will sign him in and wait. we are the last reader, so we have to update the sentinel
+ {
+ return false;
+ } else { // nobody is busy, we want the lock
+ newvalue = old + WriterBusy - ReaderBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+
+ } else { // gain write lock
+ do {
+ old = m_Sentinel;
+ if (isWriterBusy(old)) // there is a writer.. we have to wait for him
+ {
+ return false;
+ } else if (isReaderBusy(old)) // there is a reader.. we have to wait for him. set arriving readers to waiting state
+ {
+ return false;
+ } else if (isWriterWaiting(old)) // there is another writer waiting, who arrived earlier. we will wait
+ {
+ return false;
+ } else { // nobody is busy, we want the lock
+ newvalue = old + WriterBusy;
+ }
+ } while (CMPXCHG_64(m_Sentinel, newvalue, old) != old);
+ }
+ INC_32(m_Revision);
+
+ m_WriterID = id;
+ }
+ m_WriteRecursion++;
+
+ return true;
+}
+
+unsigned int CMultiReadExclusiveWriteSynchronizer::Waiting()
+{
+ int64_t old = m_Sentinel;
+ if (isWriterBusy(old))
+ { // cast is safe, we don't loose data because these fields are max 20 bits
+ return static_cast<unsigned int>(countReaderBusy(old) + countReaderWaiting(old) + countWriterWaiting(old));
+ } else {
+ return static_cast<unsigned int>(countReaderWaiting(old) + countWriterWaiting(old));
+ }
+};
diff --git a/plugins/Dbx_tree/src/MREWSync.h b/plugins/Dbx_tree/src/MREWSync.h
new file mode 100644
index 0000000000..2ffcbc08d7
--- /dev/null
+++ b/plugins/Dbx_tree/src/MREWSync.h
@@ -0,0 +1,55 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <windows.h>
+#include "TLS.h"
+#include "stdint.h"
+
+class CMultiReadExclusiveWriteSynchronizer
+{
+private:
+ uint64_t volatile m_Sentinel;
+ HANDLE m_ReadSignal[2];
+ HANDLE m_WriteSignal;
+
+ volatile uint32_t m_Revision;
+ unsigned int m_WriterID;
+ unsigned int m_WriteRecursion;
+
+ CThreadLocalStorage<CMultiReadExclusiveWriteSynchronizer, unsigned> tls;
+
+public:
+ CMultiReadExclusiveWriteSynchronizer();
+ virtual ~CMultiReadExclusiveWriteSynchronizer();
+
+ void BeginRead();
+ void EndRead();
+ bool BeginWrite();
+ bool TryBeginWrite();
+ bool EndWrite();
+
+ unsigned int Waiting();
+ unsigned int WriteRecursionCount() {return m_WriteRecursion;};
+
+};
diff --git a/plugins/Dbx_tree/src/MappedMemory.cpp b/plugins/Dbx_tree/src/MappedMemory.cpp
new file mode 100644
index 0000000000..09a1471a90
--- /dev/null
+++ b/plugins/Dbx_tree/src/MappedMemory.cpp
@@ -0,0 +1,167 @@
+/*
+
+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 "MappedMemory.h"
+#include "Logger.h"
+
+typedef BOOL (WINAPI *TUnmapViewOfFile)(LPCVOID);
+typedef BOOL (WINAPI *TFlushViewOfFile)(LPCVOID, SIZE_T);
+typedef HANDLE (WINAPI *TCreateFileMappingA)(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR);
+typedef LPVOID (WINAPI *TMapViewOfFile)(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
+
+HMODULE myKernelLib = NULL;
+TUnmapViewOfFile myUnmapViewOfFile = NULL;
+TFlushViewOfFile myFlushViewOfFile = NULL;
+TCreateFileMappingA myCreateFileMappingA = NULL;
+TMapViewOfFile myMapViewOfFile = NULL;
+
+bool CMappedMemory::InitMMAP()
+{
+ if (!myKernelLib)
+ myKernelLib = GetModuleHandleA("kernel32.dll"); // is always loaded
+
+ if (myKernelLib)
+ {
+ myUnmapViewOfFile = (TUnmapViewOfFile) GetProcAddress(myKernelLib, "UnmapViewOfFile");
+ myFlushViewOfFile = (TFlushViewOfFile) GetProcAddress(myKernelLib, "FlushViewOfFile");
+ myCreateFileMappingA = (TCreateFileMappingA) GetProcAddress(myKernelLib, "CreateFileMappingA");
+ myMapViewOfFile = (TMapViewOfFile) GetProcAddress(myKernelLib, "MapViewOfFile");
+ }
+
+ return myUnmapViewOfFile && myFlushViewOfFile && myCreateFileMappingA && myMapViewOfFile;
+}
+CMappedMemory::CMappedMemory(const TCHAR* FileName)
+: CFileAccess(FileName)
+{
+ SYSTEM_INFO sysinfo;
+
+ m_AllocSize = 0;
+ m_DirectFile = 0;
+ m_FileMapping = 0;
+ m_Base = NULL;
+
+ GetSystemInfo(&sysinfo);
+ m_AllocGranularity = sysinfo.dwAllocationGranularity; // usually 64kb
+ m_MinAllocGranularity = m_AllocGranularity; // must be at least one segment
+ m_MaxAllocGranularity = m_AllocGranularity << 4; // usually 1mb for fast increasing
+
+ m_DirectFile = CreateFile(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
+ if (m_DirectFile == INVALID_HANDLE_VALUE)
+ LOGSYS(logCRITICAL, _T("CreateFile failed"));
+
+ uint32_t size = GetFileSize(m_DirectFile, NULL);
+ size = (size + m_AllocGranularity - 1) & ~(m_AllocGranularity - 1);
+
+ if (size == 0)
+ size = m_AllocGranularity;
+
+ _SetSize(size);
+ m_AllocSize = size;
+
+ InitJournal();
+}
+
+CMappedMemory::~CMappedMemory()
+{
+ if (m_Base)
+ {
+ myFlushViewOfFile(m_Base, NULL);
+ myUnmapViewOfFile(m_Base);
+ }
+ if (m_FileMapping)
+ CloseHandle(m_FileMapping);
+
+ if (m_DirectFile)
+ {
+ if (INVALID_SET_FILE_POINTER != SetFilePointer(m_DirectFile, m_Size, NULL, FILE_BEGIN))
+ SetEndOfFile(m_DirectFile);
+
+ FlushFileBuffers(m_DirectFile);
+ CloseHandle(m_DirectFile);
+ }
+}
+
+
+uint32_t CMappedMemory::_Read(void* Buf, uint32_t Source, uint32_t Size)
+{
+ memcpy(Buf, m_Base + Source, Size);
+ return Size;
+}
+uint32_t CMappedMemory::_Write(void* Buf, uint32_t Dest, uint32_t Size)
+{
+ memcpy(m_Base + Dest, Buf, Size);
+ return Size;
+}
+
+uint32_t CMappedMemory::_SetSize(uint32_t Size)
+{
+ if (m_Base)
+ {
+ myFlushViewOfFile(m_Base, 0);
+ myUnmapViewOfFile(m_Base);
+ }
+ if (m_FileMapping)
+ CloseHandle(m_FileMapping);
+
+ m_Base = NULL;
+ m_FileMapping = NULL;
+
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(m_DirectFile, Size, NULL, FILE_BEGIN))
+ {
+ LOGSYS(logERROR, _T("SetFilePointer failed"));
+ return 0;
+ }
+
+ if (!SetEndOfFile(m_DirectFile))
+ {
+ LOGSYS(logERROR, _T("Cannot set end of file"));
+ return 0;
+ }
+
+ m_FileMapping = myCreateFileMappingA(m_DirectFile, NULL, PAGE_READWRITE, 0, Size, NULL);
+
+ if (!m_FileMapping)
+ {
+ LOGSYS(logERROR, _T("CreateFileMapping failed"));
+ return 0;
+ }
+
+ m_Base = (uint8_t*) myMapViewOfFile(m_FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+ if (!m_Base)
+ {
+ LOGSYS(logERROR, _T("MapViewOfFile failed"));
+ return 0;
+ }
+
+ return Size;
+}
+
+void CMappedMemory::_Invalidate(uint32_t Dest, uint32_t Size)
+{
+ memset(m_Base + Dest, 0, Size);
+}
+
+void CMappedMemory::_Flush()
+{
+ myFlushViewOfFile(m_Base, NULL);
+ FlushFileBuffers(m_DirectFile);
+}
diff --git a/plugins/Dbx_tree/src/MappedMemory.h b/plugins/Dbx_tree/src/MappedMemory.h
new file mode 100644
index 0000000000..e66862836e
--- /dev/null
+++ b/plugins/Dbx_tree/src/MappedMemory.h
@@ -0,0 +1,47 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <windows.h>
+#include "FileAccess.h"
+
+class CMappedMemory : public CFileAccess
+{
+private:
+ uint8_t* m_Base;
+
+ HANDLE m_DirectFile;
+ HANDLE m_FileMapping;
+protected:
+
+ uint32_t _Read(void* Buf, uint32_t Source, uint32_t Size);
+ uint32_t _Write(void* Buf, uint32_t Dest, uint32_t Size);
+ void _Invalidate(uint32_t Dest, uint32_t Size);
+ uint32_t _SetSize(uint32_t Size);
+ void _Flush();
+public:
+ CMappedMemory(const TCHAR* FileName);
+ virtual ~CMappedMemory();
+
+ static bool InitMMAP();
+};
diff --git a/plugins/Dbx_tree/src/SHA256.cpp b/plugins/Dbx_tree/src/SHA256.cpp
new file mode 100644
index 0000000000..9ca7df329c
--- /dev/null
+++ b/plugins/Dbx_tree/src/SHA256.cpp
@@ -0,0 +1,301 @@
+/*
+
+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 "SHA256.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(_MSC_VER) || !defined(_M_IX86)
+#define NO_ASM
+#endif
+#define SHA_LOOPUNROLL
+
+#ifndef _MSC_VER
+ #define rotr(x,n) (((x)>>(n))|((x)<<(32-(n))))
+#else
+ #define rotr(x,n) _lrotr(x,n)
+#endif
+
+
+// table of round constants
+// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
+static const uint32_t cKey[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+// initialisation vector
+// (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
+static const SHA256::THash cHashInit = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+
+
+SHA256::SHA256()
+{
+ SHAInit();
+}
+SHA256::~SHA256()
+{
+
+}
+void SHA256::SHAInit()
+{
+ memcpy(m_Hash, cHashInit, sizeof(m_Hash));
+ m_Length = 0;
+}
+void SHA256::SHAUpdate(void * Data, uint32_t Length)
+{
+ uint8_t * dat = (uint8_t *)Data;
+ uint32_t len = Length;
+
+ if (m_Length & 63)
+ {
+ uint32_t p = (m_Length & 63);
+ uint32_t pl = 64 - p;
+ if (pl > len)
+ pl = len;
+
+ memcpy(&(m_Block[p]), dat, pl);
+ len -= pl;
+ dat += pl;
+
+ if (p + pl == 64)
+ SHABlock();
+ }
+
+ while (len >= 64)
+ {
+ memcpy(m_Block, dat, sizeof(m_Block));
+ SHABlock();
+ len -= 64;
+ dat += 64;
+ }
+
+ if (len > 0)
+ {
+ memcpy(m_Block, dat, len);
+ }
+
+ m_Length += Length;
+}
+
+void SHA256::SHAFinal(SHA256::THash & Hash)
+{
+ uint8_t pad[128] = {
+ 0x80, 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0
+ };
+
+ uint32_t padlen = 0;
+ if ((m_Length & 63) < 55) // 64 - 9 -> short padding
+ {
+ padlen = 64 - (m_Length & 63);
+ } else {
+ padlen = 128 - (m_Length & 63);
+ }
+
+ uint64_t l = m_Length << 3;
+ {
+ uint8_t * p = (uint8_t *) &l;
+#ifdef NO_ASM
+ pad[padlen - 1] = (uint8_t)(p[0]);
+ pad[padlen - 2] = (uint8_t)(p[1]);
+ pad[padlen - 3] = (uint8_t)(p[2]);
+ pad[padlen - 4] = (uint8_t)(p[3]);
+ pad[padlen - 5] = (uint8_t)(p[4]);
+ pad[padlen - 6] = (uint8_t)(p[5]);
+ pad[padlen - 7] = (uint8_t)(p[6]);
+ pad[padlen - 8] = (uint8_t)(p[7]);
+#else
+ uint8_t * p2 = (uint8_t *) &(pad[padlen - 8]);
+ __asm {
+ MOV ebx, p
+ MOV eax, [ebx]
+ BSWAP eax
+ MOV edx, [ebx + 4]
+ MOV ebx, p2
+ BSWAP edx
+ MOV [ebx + 4], eax
+ MOV [ebx], edx
+ }
+#endif
+ }
+
+ SHAUpdate((uint32_t *)pad, padlen);
+
+ {
+ uint8_t * h = (uint8_t *)Hash;
+ uint8_t * m = (uint8_t *)m_Hash;
+#ifdef NO_ASM
+ for (int i = 0; i < 32; i += 4)
+ {
+ h[i] = m[i + 3];
+ h[i + 1] = m[i + 2];
+ h[i + 2] = m[i + 1];
+ h[i + 3] = m[i];
+ }
+#else
+ __asm {
+ MOV esi, m
+ MOV edi, h
+ MOV ecx, 8
+ loop_label:
+ LODSD
+ BSWAP eax
+ STOSD
+ dec ecx
+ jnz loop_label
+ }
+#endif
+ }
+
+ SHAInit();
+}
+
+#define SHA256_ROUND(a,b,c,d,e,f,g,h, i) { \
+t1 = (h) + (rotr((e), 6) ^ rotr((e), 11) ^ rotr((e), 25)) + \
+ (((e) & (f)) ^ ((~(e)) & (g))) + cKey[i] + w[i]; \
+t2 = (rotr((a), 2) ^ rotr((a), 13) ^ rotr((a), 22)) + \
+ (((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c))); \
+d += t1; \
+h = t1 + t2; \
+}
+
+void SHA256::SHABlock()
+{
+ uint32_t w[64];
+
+ // make Big Endian
+ {
+ uint8_t * d = (uint8_t *)w;
+ uint8_t * s = (uint8_t *)m_Block;
+#ifdef NO_ASM
+ for (int i = 0; i < 64; i += 4)
+ {
+ d[i] = s[i + 3];
+ d[i + 1] = s[i + 2];
+ d[i + 2] = s[i + 1];
+ d[i + 3] = s[i];
+ }
+#else
+ __asm {
+ MOV esi, s
+ MOV edi, d
+ MOV ecx, 16
+ loop_label:
+ LODSD
+ BSWAP eax
+ STOSD
+ dec ecx
+ jnz loop_label
+ }
+#endif
+ }
+
+ uint32_t t1, t2, a,b,c,d,e,f,g,h;
+ for (uint32_t i = 16; i < 64; ++i)
+ {
+ t1 = w[i-15];
+ t2 = w[i-2];
+ w[i] = w[i-16] + (rotr(t1, 7) ^ rotr(t1, 18) ^ (t1 >> 3)) + w[i-7] + (rotr(t2, 17) ^ rotr(t2, 19) ^ (t2 >> 10));
+ }
+
+ a = m_Hash[0];
+ b = m_Hash[1];
+ c = m_Hash[2];
+ d = m_Hash[3];
+ e = m_Hash[4];
+ f = m_Hash[5];
+ g = m_Hash[6];
+ h = m_Hash[7];
+
+#ifdef SHA_LOOPUNROLL
+ for (uint32_t i = 0; i < 64; ++i)
+ {
+ SHA256_ROUND(a,b,c,d,e,f,g,h,i); ++i;
+ SHA256_ROUND(h,a,b,c,d,e,f,g,i); ++i;
+ SHA256_ROUND(g,h,a,b,c,d,e,f,i); ++i;
+ SHA256_ROUND(f,g,h,a,b,c,d,e,i); ++i;
+ SHA256_ROUND(e,f,g,h,a,b,c,d,i); ++i;
+ SHA256_ROUND(d,e,f,g,h,a,b,c,i); ++i;
+ SHA256_ROUND(c,d,e,f,g,h,a,b,i); ++i;
+ SHA256_ROUND(b,c,d,e,f,g,h,a,i);
+ }
+#else
+ for (uint32_t i = 0; i < 64; ++i)
+ {
+ t1 = h + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + //s1
+ ((e & f) ^ ((~e) & g)) + cKey[i] + w[i]; //ch
+
+ t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + //s0
+ ((a & b) ^ (a & c) ^ (b & c)); //maj
+
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+#endif
+
+ m_Hash[0] += a;
+ m_Hash[1] += b;
+ m_Hash[2] += c;
+ m_Hash[3] += d;
+ m_Hash[4] += e;
+ m_Hash[5] += f;
+ m_Hash[6] += g;
+ m_Hash[7] += h;
+}
diff --git a/plugins/Dbx_tree/src/SHA256.h b/plugins/Dbx_tree/src/SHA256.h
new file mode 100644
index 0000000000..a9629e6a2a
--- /dev/null
+++ b/plugins/Dbx_tree/src/SHA256.h
@@ -0,0 +1,49 @@
+/*
+
+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.
+
+*/
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "stdint.h"
+#endif
+
+
+class SHA256
+{
+public:
+ typedef uint32_t THash[8];
+
+ SHA256();
+ ~SHA256();
+
+ void SHAInit();
+ void SHAUpdate(void * Data, uint32_t Length);
+ void SHAFinal(THash & Hash);
+private:
+ THash m_Hash;
+ uint64_t m_Length; /// Datalength in byte
+
+ uint8_t m_Block[64];
+
+ void SHABlock();
+ void Swap64(void * Addr);
+};
diff --git a/plugins/Dbx_tree/src/Services.cpp b/plugins/Dbx_tree/src/Services.cpp
new file mode 100644
index 0000000000..d8b734795d
--- /dev/null
+++ b/plugins/Dbx_tree/src/Services.cpp
@@ -0,0 +1,402 @@
+/*
+
+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 "Services.h"
+
+HANDLE gServices[40] = {0};
+
+INT_PTR DBEntityGetRoot(WPARAM wParam, LPARAM lParam)
+{
+ return gDataBase->getEntities().getRootEntity();
+}
+INT_PTR DBEntityChildCount(WPARAM hEntity, LPARAM lParam)
+{
+ if (hEntity == 0)
+ hEntity = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().getChildCount(hEntity);
+}
+INT_PTR DBEntityGetParent(WPARAM hEntity, LPARAM lParam)
+{
+ if (hEntity == 0)
+ hEntity = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().getParent(hEntity);
+}
+INT_PTR DBEntityMove(WPARAM hEntity, LPARAM hParent)
+{
+ if ((hEntity == 0) || (hEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ if (hParent == 0)
+ hParent = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().setParent(hEntity, hParent);
+}
+INT_PTR DBEntityGetFlags(WPARAM hEntity, LPARAM lParam)
+{
+ if (hEntity == 0)
+ hEntity = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().getFlags(hEntity);
+}
+INT_PTR DBEntityIterInit(WPARAM pFilter, LPARAM hParent)
+{
+ TDBTEntityIterFilter fil = {0,0,0,0};
+ if (pFilter == NULL)
+ {
+ pFilter = reinterpret_cast<WPARAM>(&fil);
+ fil.cbSize = sizeof(fil);
+ }
+
+ if (reinterpret_cast<PDBTEntityIterFilter>(pFilter)->cbSize != sizeof(TDBTEntityIterFilter))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTEntityIterFilter>(pFilter)->fDontHasFlags & ((PDBTEntityIterFilter)pFilter)->fHasFlags)
+ return DBT_INVALIDPARAM;
+
+ if (hParent == 0)
+ hParent = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().IterationInit(*reinterpret_cast<PDBTEntityIterFilter>(pFilter), hParent);
+}
+INT_PTR DBEntityIterNext(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getEntities().IterationNext(hIteration);
+}
+INT_PTR DBEntityIterClose(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getEntities().IterationClose(hIteration);
+}
+INT_PTR DBEntityDelete(WPARAM hEntity, LPARAM lParam)
+{
+ if ((hEntity == 0) || (hEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEntities().DeleteEntity(hEntity);
+}
+INT_PTR DBEntityCreate(WPARAM pEntity, LPARAM lParam)
+{
+ if (reinterpret_cast<PDBTEntity>(pEntity)->bcSize != sizeof(TDBTEntity))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTEntity>(pEntity)->hParentEntity == 0)
+ reinterpret_cast<PDBTEntity>(pEntity)->hParentEntity = gDataBase->getEntities().getRootEntity();
+
+ reinterpret_cast<PDBTEntity>(pEntity)->fFlags = reinterpret_cast<PDBTEntity>(pEntity)->fFlags & ~(DBT_NF_IsRoot | DBT_NF_HasChildren | DBT_NF_IsVirtual | DBT_NF_HasVirtuals); // forbidden flags...
+ return gDataBase->getEntities().CreateEntity(*reinterpret_cast<PDBTEntity>(pEntity));
+}
+
+INT_PTR DBEntityGetAccount(WPARAM hEntity, LPARAM lParam)
+{
+ return gDataBase->getEntities().getAccount(hEntity);
+}
+
+INT_PTR DBVirtualEntityCreate(WPARAM hEntity, LPARAM hParent)
+{
+ if ((hEntity == 0) || (hEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ if (hParent == 0)
+ hParent = gDataBase->getEntities().getRootEntity();
+
+ return gDataBase->getEntities().VirtualCreate(hEntity, hParent);
+}
+INT_PTR DBVirtualEntityGetParent(WPARAM hVirtualEntity, LPARAM lParam)
+{
+ if ((hVirtualEntity == 0) || (hVirtualEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEntities().VirtualGetParent(hVirtualEntity);
+}
+INT_PTR DBVirtualEntityGetFirst(WPARAM hEntity, LPARAM lParam)
+{
+ if ((hEntity == 0) || (hEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEntities().VirtualGetFirst(hEntity);
+}
+INT_PTR DBVirtualEntityGetNext(WPARAM hVirtualEntity, LPARAM lParam)
+{
+ if ((hVirtualEntity == 0) || (hVirtualEntity == gDataBase->getEntities().getRootEntity()))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEntities().VirtualGetNext(hVirtualEntity);
+}
+
+
+INT_PTR DBSettingFind(WPARAM pSettingDescriptor, LPARAM lParam)
+{
+ if (pSettingDescriptor == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor)->cbSize != sizeof(TDBTSettingDescriptor))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor)->pszSettingName == NULL)
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().FindSetting(*reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor));
+}
+INT_PTR DBSettingDelete(WPARAM pSettingDescriptor, LPARAM lParam)
+{
+ if (pSettingDescriptor == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor)->cbSize != sizeof(TDBTSettingDescriptor))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor)->pszSettingName == NULL)
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().DeleteSetting(*reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor));
+}
+INT_PTR DBSettingDeleteHandle(WPARAM hSetting, LPARAM lParam)
+{
+ if (hSetting == 0)
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().DeleteSetting(hSetting);
+}
+INT_PTR DBSettingWrite(WPARAM pSetting, LPARAM lParam)
+{
+ if (pSetting == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->cbSize != sizeof(TDBTSetting))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor->cbSize != sizeof(TDBTSettingDescriptor))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor->pszSettingName == NULL)
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTSetting>(pSetting)->Type & DBT_STF_VariableLength) && (reinterpret_cast<PDBTSetting>(pSetting)->Value.pBlob == NULL))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().WriteSetting(*reinterpret_cast<PDBTSetting>(pSetting));
+}
+INT_PTR DBSettingWriteHandle(WPARAM pSetting, LPARAM hSetting)
+{
+ if (pSetting == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->cbSize != sizeof(TDBTSetting))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().WriteSetting(*reinterpret_cast<PDBTSetting>(pSetting), hSetting);
+}
+INT_PTR DBSettingRead(WPARAM pSetting, LPARAM lParam)
+{
+ if (pSetting == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->cbSize != sizeof(TDBTSetting))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor->cbSize != sizeof(TDBTSettingDescriptor))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor->pszSettingName == NULL)
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().ReadSetting(*reinterpret_cast<PDBTSetting>(pSetting));
+}
+INT_PTR DBSettingReadHandle(WPARAM pSetting, LPARAM hSetting)
+{
+ if ((pSetting == NULL) || (hSetting == 0))
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSetting>(pSetting)->cbSize != sizeof(TDBTSetting))
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTSetting>(pSetting)->Descriptor != NULL) && (reinterpret_cast<PDBTSetting>(pSetting)->Descriptor->cbSize != sizeof(TDBTSettingDescriptor)))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().ReadSetting(*((PDBTSetting)pSetting), hSetting);
+}
+INT_PTR DBSettingIterInit(WPARAM pFilter, LPARAM lParam)
+{
+ if (pFilter == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (reinterpret_cast<PDBTSettingIterFilter>(pFilter)->cbSize != sizeof(TDBTSettingIterFilter))
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Descriptor != NULL) && (reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Descriptor->cbSize != sizeof(TDBTSettingDescriptor)))
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Setting != NULL) && (reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Setting->cbSize != sizeof(TDBTSetting)))
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Setting != NULL) && (reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Setting->Descriptor != NULL) && (reinterpret_cast<PDBTSettingIterFilter>(pFilter)->Setting->Descriptor->cbSize != sizeof(TDBTSettingIterFilter)))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getSettings().IterationInit(*reinterpret_cast<PDBTSettingIterFilter>(pFilter));
+}
+INT_PTR DBSettingIterNext(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getSettings().IterationNext(hIteration);
+}
+INT_PTR DBSettingIterClose(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getSettings().IterationClose(hIteration);
+}
+
+INT_PTR DBEventGetBlobSize(WPARAM hEvent, LPARAM lParam)
+{
+ return gDataBase->getEvents().GetBlobSize(hEvent);
+}
+
+INT_PTR DBEventGet(WPARAM hEvent, LPARAM pEvent)
+{
+ if ((pEvent == NULL) || (reinterpret_cast<PDBTEvent>(pEvent)->cbSize != sizeof(TDBTEvent)))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEvents().Get(hEvent, *reinterpret_cast<PDBTEvent>(pEvent));
+}
+
+INT_PTR DBEventGetCount(WPARAM hEntity, LPARAM lParam)
+{
+ return gDataBase->getEvents().GetCount(hEntity);
+}
+
+INT_PTR DBEventDelete(WPARAM hEvent, LPARAM lParam)
+{
+ return gDataBase->getEvents().Delete(hEvent);
+}
+
+INT_PTR DBEventAdd(WPARAM hEntity, LPARAM pEvent)
+{
+ if ((pEvent == NULL) || (reinterpret_cast<PDBTEvent>(pEvent)->cbSize != sizeof(TDBTEvent)) || (reinterpret_cast<PDBTEvent>(pEvent)->pBlob == NULL) || (reinterpret_cast<PDBTEvent>(pEvent)->cbBlob == 0))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEvents().Add(hEntity, *((PDBTEvent)pEvent));
+}
+
+INT_PTR DBEventMarkRead(WPARAM hEvent, LPARAM lParam)
+{
+ return gDataBase->getEvents().MarkRead(hEvent);
+}
+
+INT_PTR DBEventWriteToDisk(WPARAM hEvent, LPARAM lParam)
+{
+ return gDataBase->getEvents().WriteToDisk(hEvent);
+}
+
+INT_PTR DBEventGetEntity(WPARAM hEvent, LPARAM lParam)
+{
+ return gDataBase->getEvents().getEntity(hEvent);
+}
+
+INT_PTR DBEventIterInit(WPARAM pFilter, LPARAM lParam)
+{
+ if ((pFilter == NULL) || (reinterpret_cast<PDBTEventIterFilter>(pFilter)->cbSize != sizeof(TDBTEventIterFilter)))
+ return DBT_INVALIDPARAM;
+
+ if ((reinterpret_cast<PDBTEventIterFilter>(pFilter)->Event != NULL) && (reinterpret_cast<PDBTEventIterFilter>(pFilter)->Event->cbSize != sizeof(TDBTEvent)))
+ return DBT_INVALIDPARAM;
+
+ return gDataBase->getEvents().IterationInit(*reinterpret_cast<PDBTEventIterFilter>(pFilter));
+}
+
+INT_PTR DBEventIterNext(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getEvents().IterationNext(hIteration);
+}
+
+INT_PTR DBEventIterClose(WPARAM hIteration, LPARAM lParam)
+{
+ if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
+ return hIteration;
+
+ return gDataBase->getEvents().IterationClose(hIteration);
+}
+
+
+bool RegisterServices()
+{
+ gServices[ 0] = CreateServiceFunction(MS_DBT_ENTITY_GETROOT, DBEntityGetRoot);
+ gServices[ 1] = CreateServiceFunction(MS_DBT_ENTITY_CHILDCOUNT, DBEntityChildCount);
+ gServices[ 2] = CreateServiceFunction(MS_DBT_ENTITY_GETPARENT, DBEntityGetParent);
+ gServices[ 3] = CreateServiceFunction(MS_DBT_ENTITY_MOVE, DBEntityMove);
+ gServices[ 8] = CreateServiceFunction(MS_DBT_ENTITY_GETFLAGS, DBEntityGetFlags);
+ gServices[ 9] = CreateServiceFunction(MS_DBT_ENTITY_ITER_INIT, DBEntityIterInit);
+ gServices[10] = CreateServiceFunction(MS_DBT_ENTITY_ITER_NEXT, DBEntityIterNext);
+ gServices[11] = CreateServiceFunction(MS_DBT_ENTITY_ITER_CLOSE, DBEntityIterClose);
+ gServices[12] = CreateServiceFunction(MS_DBT_ENTITY_DELETE, DBEntityDelete);
+ gServices[13] = CreateServiceFunction(MS_DBT_ENTITY_CREATE, DBEntityCreate);
+ gServices[13] = CreateServiceFunction(MS_DBT_ENTITY_GETACCOUNT, DBEntityGetAccount);
+
+ gServices[14] = CreateServiceFunction(MS_DBT_VIRTUALENTITY_CREATE, DBVirtualEntityCreate);
+ gServices[15] = CreateServiceFunction(MS_DBT_VIRTUALENTITY_GETPARENT, DBVirtualEntityGetParent);
+ gServices[16] = CreateServiceFunction(MS_DBT_VIRTUALENTITY_GETFIRST, DBVirtualEntityGetFirst);
+ gServices[17] = CreateServiceFunction(MS_DBT_VIRTUALENTITY_GETNEXT, DBVirtualEntityGetNext);
+
+ gServices[18] = CreateServiceFunction(MS_DBT_SETTING_FIND, DBSettingFind);
+ gServices[19] = CreateServiceFunction(MS_DBT_SETTING_DELETE, DBSettingDelete);
+ gServices[20] = CreateServiceFunction(MS_DBT_SETTING_DELETEHANDLE, DBSettingDeleteHandle);
+ gServices[21] = CreateServiceFunction(MS_DBT_SETTING_WRITE, DBSettingWrite);
+ gServices[22] = CreateServiceFunction(MS_DBT_SETTING_WRITEHANDLE, DBSettingWriteHandle);
+ gServices[23] = CreateServiceFunction(MS_DBT_SETTING_READ, DBSettingRead);
+ gServices[24] = CreateServiceFunction(MS_DBT_SETTING_READHANDLE, DBSettingReadHandle);
+ gServices[25] = CreateServiceFunction(MS_DBT_SETTING_ITER_INIT, DBSettingIterInit);
+ gServices[26] = CreateServiceFunction(MS_DBT_SETTING_ITER_NEXT, DBSettingIterNext);
+ gServices[27] = CreateServiceFunction(MS_DBT_SETTING_ITER_CLOSE, DBSettingIterClose);
+
+ gServices[28] = CreateServiceFunction(MS_DBT_EVENT_GETBLOBSIZE, DBEventGetBlobSize);
+ gServices[29] = CreateServiceFunction(MS_DBT_EVENT_GET, DBEventGet);
+ gServices[30] = CreateServiceFunction(MS_DBT_EVENT_GETCOUNT, DBEventGetCount);
+ gServices[31] = CreateServiceFunction(MS_DBT_EVENT_DELETE, DBEventDelete);
+ gServices[32] = CreateServiceFunction(MS_DBT_EVENT_ADD, DBEventAdd);
+ gServices[33] = CreateServiceFunction(MS_DBT_EVENT_MARKREAD, DBEventMarkRead);
+ gServices[34] = CreateServiceFunction(MS_DBT_EVENT_WRITETODISK, DBEventWriteToDisk);
+ gServices[35] = CreateServiceFunction(MS_DBT_EVENT_GETENTITY, DBEventGetEntity);
+ gServices[36] = CreateServiceFunction(MS_DBT_EVENT_ITER_INIT, DBEventIterInit);
+ gServices[37] = CreateServiceFunction(MS_DBT_EVENT_ITER_NEXT, DBEventIterNext);
+ gServices[38] = CreateServiceFunction(MS_DBT_EVENT_ITER_CLOSE, DBEventIterClose);
+
+
+ return true;
+}
diff --git a/plugins/Dbx_tree/src/Services.h b/plugins/Dbx_tree/src/Services.h
new file mode 100644
index 0000000000..0d75552fd4
--- /dev/null
+++ b/plugins/Dbx_tree/src/Services.h
@@ -0,0 +1,69 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include "Interface.h"
+#include "DataBase.h"
+
+bool RegisterServices();
+
+
+INT_PTR DBEntityGetRoot(WPARAM wParam, LPARAM lParam);
+INT_PTR DBEntityChildCount(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBEntityGetParent(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBEntityMove(WPARAM hEntity, LPARAM hParent);
+INT_PTR DBEntityGetFlags(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBEntityIterInit(WPARAM pFilter, LPARAM hParent);
+INT_PTR DBEntityIterNext(WPARAM hIteration, LPARAM lParam);
+INT_PTR DBEntityIterClose(WPARAM hIteration, LPARAM lParam);
+INT_PTR DBEntityDelete(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBEntityCreate(WPARAM pEntity, LPARAM lParam);
+INT_PTR DBEntityGetAccount(WPARAM hEntity, LPARAM lParam);
+
+INT_PTR DBVirtualEntityCreate(WPARAM hEntity, LPARAM hParent);
+INT_PTR DBVirtualEntityGetParent(WPARAM hVirtualEntity, LPARAM lParam);
+INT_PTR DBVirtualEntityGetFirst(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBVirtualEntityGetNext(WPARAM hVirtualEntity, LPARAM lParam);
+
+INT_PTR DBSettingFind(WPARAM pSettingDescriptor, LPARAM lParam);
+INT_PTR DBSettingDelete(WPARAM pSettingDescriptor, LPARAM lParam);
+INT_PTR DBSettingDeleteHandle(WPARAM hSetting, LPARAM lParam);
+INT_PTR DBSettingWrite(WPARAM pSetting, LPARAM lParam);
+INT_PTR DBSettingWriteHandle(WPARAM pSetting, LPARAM hSetting);
+INT_PTR DBSettingRead(WPARAM pSetting, LPARAM lParam);
+INT_PTR DBSettingReadHandle(WPARAM pSetting, LPARAM hSetting);
+INT_PTR DBSettingIterInit(WPARAM pFilter, LPARAM lParam);
+INT_PTR DBSettingIterNext(WPARAM hIteration, LPARAM lParam);
+INT_PTR DBSettingIterClose(WPARAM hIteration, LPARAM lParam);
+
+INT_PTR DBEventGetBlobSize(WPARAM hEvent, LPARAM lParam);
+INT_PTR DBEventGet(WPARAM hEvent, LPARAM pEvent);
+INT_PTR DBEventGetCount(WPARAM hEntity, LPARAM lParam);
+INT_PTR DBEventDelete(WPARAM hEvent, LPARAM lParam);
+INT_PTR DBEventAdd(WPARAM hEntity, LPARAM pEvent);
+INT_PTR DBEventMarkRead(WPARAM hEvent, LPARAM lParam);
+INT_PTR DBEventWriteToDisk(WPARAM hEvent, LPARAM lParam);
+INT_PTR DBEventGetEntity(WPARAM hEvent, LPARAM lParam);
+INT_PTR DBEventIterInit(WPARAM pFilter, LPARAM lParam);
+INT_PTR DBEventIterNext(WPARAM hIteration, LPARAM lParam);
+INT_PTR DBEventIterClose(WPARAM hIteration, LPARAM lParam);
diff --git a/plugins/Dbx_tree/src/Settings.cpp b/plugins/Dbx_tree/src/Settings.cpp
new file mode 100644
index 0000000000..b4ba799c55
--- /dev/null
+++ b/plugins/Dbx_tree/src/Settings.cpp
@@ -0,0 +1,1479 @@
+/*
+
+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 "Settings.h"
+#include <math.h> // floor function
+#include "Hash.h"
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#endif
+
+TDBTSettingHandle CSettingsTree::_FindSetting(const uint32_t Hash, const char * Name, const uint32_t Length)
+{
+ TSettingKey key = {0,0};
+ key.Hash = Hash;
+ iterator i = LowerBound(key);
+ uint16_t l;
+
+ TDBTSettingHandle res = 0;
+
+ char * str = NULL;
+
+ while ((res == 0) && (i) && (i->Hash == Hash))
+ {
+ l = Length;
+ if (m_Owner._ReadSettingName(m_BlockManager, i->Setting, l, str) &&
+ (strncmp(str, Name, Length) == 0))
+ {
+ res = i->Setting;
+ } else {
+ ++i;
+ }
+ }
+
+ if (str)
+ free(str);
+
+ return res;
+}
+
+bool CSettingsTree::_DeleteSetting(const uint32_t Hash, const TDBTSettingHandle hSetting)
+{
+ TSettingKey key = {0,0};
+ key.Hash = Hash;
+ iterator i = LowerBound(key);
+
+ while ((i) && (i->Hash == Hash) && (i->Setting != hSetting))
+ ++i;
+
+ if ((i) && (i->Hash == Hash))
+ {
+ Delete(*i);
+ return true;
+ }
+
+ return false;
+}
+
+bool CSettingsTree::_AddSetting(const uint32_t Hash, const TDBTSettingHandle hSetting)
+{
+ TSettingKey key;
+ key.Hash = Hash;
+ key.Setting = hSetting;
+ Insert(key);
+ return true;
+}
+
+CSettings::CSettings(
+ CBlockManager & BlockManagerSet,
+ CBlockManager & BlockManagerPri,
+ CSettingsTree::TNodeRef SettingsRoot,
+ CEntities & Entities
+)
+: m_BlockManagerSet(BlockManagerSet),
+ m_BlockManagerPri(BlockManagerPri),
+ m_Entities(Entities),
+ m_SettingsMap(),
+ m_sigRootChanged(),
+ m_Modules()
+{
+ CSettingsTree * settree = new CSettingsTree(*this, m_BlockManagerSet, SettingsRoot, 0);
+
+ settree->sigRootChanged().connect(this, &CSettings::onRootChanged);
+ m_SettingsMap.insert(std::make_pair(0, settree));
+
+ m_Entities._sigDeleteSettings().connect(this, &CSettings::onDeleteSettings);
+ m_Entities._sigMergeSettings().connect (this, &CSettings::onMergeSettings);
+
+ _LoadModules();
+ _EnsureModuleExists("$Modules");
+}
+
+CSettings::~CSettings()
+{
+ TSettingsTreeMap::iterator it = m_SettingsMap.begin();
+
+ while (it != m_SettingsMap.end())
+ {
+ delete it->second;
+ ++it;
+ }
+
+ TModulesMap::iterator it2 = m_Modules.begin();
+ while (it2 != m_Modules.end())
+ {
+ if (it2->second)
+ delete [] it2->second;
+ ++it2;
+ }
+}
+
+
+CSettingsTree * CSettings::getSettingsTree(TDBTEntityHandle hEntity)
+{
+ TSettingsTreeMap::iterator i = m_SettingsMap.find(hEntity);
+ if (i != m_SettingsMap.end())
+ return i->second;
+
+ uint32_t root = m_Entities._getSettingsRoot(hEntity);
+ if (root == DBT_INVALIDPARAM)
+ return NULL;
+
+ CSettingsTree * tree = new CSettingsTree(*this, m_BlockManagerPri, root, hEntity);
+ tree->sigRootChanged().connect(this, &CSettings::onRootChanged);
+ m_SettingsMap.insert(std::make_pair(hEntity, tree));
+
+ return tree;
+}
+
+// TODO check if we need to copy the name or if we can just use the cache
+inline bool CSettings::_ReadSettingName(CBlockManager & BlockManager, TDBTSettingHandle Setting, uint16_t & NameLength, char *& NameBuf)
+{
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+
+ TSetting * setting = BlockManager.ReadBlock<TSetting>(Setting, size, sig);
+ if (!setting)
+ return false;
+
+ if ((NameLength != 0) && (NameLength != setting->NameLength))
+ return false;
+
+ NameLength = setting->NameLength;
+ NameBuf = (char*) realloc(NameBuf, NameLength + 1);
+
+ memcpy(NameBuf, setting + 1, NameLength + 1);
+ NameBuf[NameLength] = 0;
+
+ return true;
+}
+
+void CSettings::_EnsureModuleExists(char * Module)
+{
+ if ((Module == NULL) || (*Module == 0))
+ return;
+
+ char * e = strchr(Module, '/');
+ if (e)
+ *e = 0;
+
+ TModulesMap::iterator i = m_Modules.find(*((uint16_t*)Module));
+ while ((i != m_Modules.end()) && (i->first == *((uint16_t*)Module)) && (strcmp(i->second, Module) != 0))
+ {
+ ++i;
+ }
+
+ if ((i == m_Modules.end()) || (i->first != *reinterpret_cast<uint16_t*>(Module)))
+ {
+ size_t l = strlen(Module);
+ char * tmp = new char [l + 1];
+ memcpy(tmp, Module, l + 1);
+ m_Modules.insert(std::make_pair(*reinterpret_cast<uint16_t*>(tmp), tmp));
+
+ char namebuf[512];
+ strcpy_s(namebuf, "$Modules/");
+ strcat_s(namebuf, Module);
+
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ desc.cbSize = sizeof(desc);
+ desc.pszSettingName = namebuf;
+
+ TDBTSetting set = {0,0,0,0};
+ set.cbSize = sizeof(set);
+ set.Descriptor = &desc;
+ set.Type = DBT_ST_DWORD;
+
+ WriteSetting(set, cSettingsFileFlag);
+ }
+
+ if (e)
+ *e = '/';
+}
+
+void CSettings::_LoadModules()
+{
+ TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
+ desc.cbSize = sizeof(desc);
+
+ TDBTSettingIterFilter f = {0,0,0,0,0,0,0,0};
+ f.cbSize = sizeof(f);
+ f.Descriptor = &desc;
+ f.NameStart = "$Modules/";
+
+ TDBTSettingIterationHandle hiter = IterationInit(f);
+
+ if ((hiter != 0) && (hiter != DBT_INVALIDPARAM))
+ {
+ TDBTSettingHandle res = IterationNext(hiter);
+ while ((res != 0) && (res != DBT_INVALIDPARAM))
+ {
+ size_t l = strlen(desc.pszSettingName);
+ char * tmp = new char [l - 9 + 1];
+ memcpy(tmp, desc.pszSettingName + 9, l - 9 + 1);
+ m_Modules.insert(std::make_pair(*reinterpret_cast<uint16_t*>(tmp), tmp));
+ res = IterationNext(hiter);
+ }
+
+ IterationClose(hiter);
+ }
+}
+
+void CSettings::onRootChanged(void* SettingsTree, CSettingsTree::TNodeRef NewRoot)
+{
+ if (((CSettingsTree*)SettingsTree)->Entity() == 0)
+ m_sigRootChanged.emit(this, NewRoot);
+ else
+ m_Entities._setSettingsRoot(((CSettingsTree*)SettingsTree)->Entity(), NewRoot);
+}
+
+void CSettings::onDeleteSettingCallback(void * Tree, const TSettingKey & Key, uint32_t Param)
+{
+ if (Param == 0)
+ {
+ m_BlockManagerSet.DeleteBlock(Key.Setting);
+ } else {
+ m_BlockManagerPri.DeleteBlock(Key.Setting);
+ }
+}
+void CSettings::onDeleteSettings(CEntities * Entities, TDBTEntityHandle hEntity)
+{
+ CSettingsTree * tree = getSettingsTree(hEntity);
+
+ m_Entities._setSettingsRoot(hEntity, 0);
+
+ if (tree)
+ {
+ CSettingsTree::TDeleteCallback callback;
+ callback.connect(this, &CSettings::onDeleteSettingCallback);
+
+ tree->DeleteTree(&callback, hEntity);
+
+ TSettingsTreeMap::iterator i = m_SettingsMap.find(hEntity);
+ delete i->second; // tree
+ m_SettingsMap.erase(i);
+ }
+}
+
+
+typedef struct TSettingMergeHelper
+{
+ TDBTEntityHandle Source;
+ TDBTEntityHandle Dest;
+ CSettingsTree * SourceTree;
+
+} TSettingMergeHelper, *PSettingMergeHelper;
+
+
+void CSettings::onMergeSettingCallback(void * Tree, const TSettingKey & Key,uint32_t Param)
+{
+ PSettingMergeHelper hlp = (PSettingMergeHelper)Param;
+
+ uint16_t dnl = 0;
+ char * dnb = NULL;
+
+ _ReadSettingName(m_BlockManagerPri, Key.Setting, dnl, dnb);
+
+ TSettingKey k = {0,0};
+ k.Hash = Key.Hash;
+
+ CSettingsTree::iterator i = hlp->SourceTree->LowerBound(k);
+ TDBTSettingHandle res = 0;
+ while ((res == 0) && i && (i->Hash == Key.Hash))
+ {
+ uint16_t snl = dnl;
+ char * snb = NULL;
+
+ if (_ReadSettingName(m_BlockManagerPri, i->Setting, snl, snb)
+ && (strcmp(dnb, snb) == 0)) // found it
+ {
+ res = i->Setting;
+ }
+ }
+
+ if (res == 0)
+ {
+ hlp->SourceTree->Insert(Key);
+ } else {
+ hlp->SourceTree->Delete(*i);
+ hlp->SourceTree->Insert(Key);
+ m_BlockManagerPri.DeleteBlock(res);
+ }
+}
+
+void CSettings::onMergeSettings(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest)
+{
+
+ if ((Source != 0) && (Dest != 0))
+ {
+ LOG(logERROR, _T("Cannot Merge with global settings!\nSource %d Dest %d"), Source, Dest);
+ return;
+ }
+
+ CSettingsTree * stree = getSettingsTree(Source);
+ CSettingsTree * dtree = getSettingsTree(Dest);
+
+ if (stree && dtree)
+ {
+ m_Entities._setSettingsRoot(Source, 0);
+
+ stree->Entity(Dest);
+ m_Entities._setSettingsRoot(Dest, stree->getRoot());
+
+ TSettingKey key = {0,0};
+ CSettingsTree::iterator it = stree->LowerBound(key);
+
+ while (it) // transfer all source settings to new Entity
+ {
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+ TSetting * tmp = m_BlockManagerPri.ReadBlock<TSetting>(it->Setting, size, sig);
+ if (tmp)
+ {
+ tmp->Entity = Dest;
+ m_BlockManagerPri.UpdateBlock(it->Setting);
+ }
+ ++it;
+ }
+
+ // merge the dest tree into the source tree. override existing items
+ // do it this way, because source tree should be much larger
+ TSettingMergeHelper hlp;
+ hlp.Source = Source;
+ hlp.Dest = Dest;
+ hlp.SourceTree = stree;
+
+ CSettingsTree::TDeleteCallback callback;
+ callback.connect(this, &CSettings::onMergeSettingCallback);
+ dtree->DeleteTree(&callback, (uint32_t)&hlp);
+
+ TSettingsTreeMap::iterator i = m_SettingsMap.find(Dest);
+ delete i->second; // dtree
+ i->second = stree;
+ m_SettingsMap.erase(Source);
+
+ }
+}
+
+
+
+
+TDBTSettingHandle CSettings::FindSetting(TDBTSettingDescriptor & Descriptor)
+{
+ if (Descriptor.Flags & DBT_SDF_FoundValid)
+ return Descriptor.FoundHandle;
+
+ uint32_t namelength = static_cast<uint32_t>( strlen(Descriptor.pszSettingName));
+ uint32_t namehash;
+
+ if (Descriptor.Flags & DBT_SDF_HashValid)
+ {
+ namehash = Descriptor.Hash;
+ } else {
+ namehash = Hash(Descriptor.pszSettingName, namelength);
+ Descriptor.Hash = namehash;
+ Descriptor.Flags = Descriptor.Flags | DBT_SDF_HashValid;
+ }
+
+ Descriptor.Flags = Descriptor.Flags & ~DBT_SDF_FoundValid;
+
+ CSettingsTree * tree;
+ TDBTSettingHandle res = 0;
+ CBlockManager * file = &m_BlockManagerPri;
+ if (Descriptor.Entity == 0)
+ file = &m_BlockManagerSet;
+
+ CBlockManager::ReadTransaction trans(*file);
+
+ if ((Descriptor.Entity == 0) || (Descriptor.Options == 0))
+ {
+ tree = getSettingsTree(Descriptor.Entity);
+ if (tree == NULL)
+ return DBT_INVALIDPARAM;
+
+ res = tree->_FindSetting(namehash, Descriptor.pszSettingName, namelength);
+
+ if (res)
+ {
+ Descriptor.FoundInEntity = Descriptor.Entity;
+ Descriptor.FoundHandle = res;
+ Descriptor.Flags = Descriptor.Flags | DBT_SDF_FoundValid;
+ }
+
+ if (Descriptor.Entity == 0)
+ res = res | cSettingsFileFlag;
+
+ return res;
+ }
+
+ uint32_t cf = m_Entities.getFlags(Descriptor.Entity);
+ if (cf == DBT_INVALIDPARAM)
+ return DBT_INVALIDPARAM;
+
+ // search the setting
+ res = 0;
+
+ TDBTEntityIterFilter f;
+ f.cbSize = sizeof(f);
+ if (cf & DBT_NF_IsGroup)
+ {
+ f.fDontHasFlags = 0;
+ f.fHasFlags = DBT_NF_IsGroup;
+ } else {
+ f.fDontHasFlags = DBT_NF_IsGroup;
+ f.fHasFlags = 0;
+ }
+ f.Options = Descriptor.Options;
+
+ TDBTEntityIterationHandle i = m_Entities.IterationInit(f, Descriptor.Entity);
+ if ((i == DBT_INVALIDPARAM) || (i == 0))
+ return DBT_INVALIDPARAM;
+
+ TDBTEntityHandle e = m_Entities.IterationNext(i);
+ TDBTEntityHandle found = 0;
+ while ((res == 0) && (e != 0))
+ {
+ tree = getSettingsTree(e);
+ if (tree)
+ {
+ res = tree->_FindSetting(namehash, Descriptor.pszSettingName, namelength);
+ found = e;
+ }
+
+ e = m_Entities.IterationNext(i);
+ }
+
+ m_Entities.IterationClose(i);
+
+ if (res)
+ {
+ Descriptor.FoundInEntity = found;
+ Descriptor.FoundHandle = res;
+ Descriptor.Flags = Descriptor.Flags | DBT_SDF_FoundValid;
+ }
+
+ return res;
+}
+
+unsigned int CSettings::DeleteSetting(TDBTSettingDescriptor & Descriptor)
+{
+ TDBTSettingHandle hset = FindSetting(Descriptor);
+ if ((hset == 0) || (hset == DBT_INVALIDPARAM))
+ {
+ return DBT_INVALIDPARAM;
+ }
+
+ unsigned int res = 0;
+ if ((Descriptor.Flags & DBT_SDF_FoundValid) && (Descriptor.Flags & DBT_SDF_HashValid))
+ {
+ CBlockManager * file = &m_BlockManagerPri;
+
+ if (Descriptor.FoundInEntity == 0)
+ {
+ file = &m_BlockManagerSet;
+ hset = hset & ~cSettingsFileFlag;
+ }
+
+ CBlockManager::WriteTransaction trans(*file);
+
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+ TSetting * setting = file->ReadBlock<TSetting>(hset, size, sig);
+ if (setting && (setting->Entity == Descriptor.FoundInEntity))
+ {
+ CSettingsTree * tree = getSettingsTree(setting->Entity);
+ if (tree)
+ {
+ tree->_DeleteSetting(Descriptor.Hash, hset);
+ file->DeleteBlock(hset);
+ }
+ }
+
+ } else {
+ res = DeleteSetting(hset);
+ }
+
+ return res;
+}
+unsigned int CSettings::DeleteSetting(TDBTSettingHandle hSetting)
+{
+ CBlockManager * file = &m_BlockManagerPri;
+
+ if (hSetting & cSettingsFileFlag)
+ {
+ file = &m_BlockManagerSet;
+ hSetting = hSetting & ~cSettingsFileFlag;
+ }
+
+ CBlockManager::WriteTransaction trans(*file);
+
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+ TSetting * setting = file->ReadBlock<TSetting>(hSetting, size, sig);
+
+ if (!setting)
+ return DBT_INVALIDPARAM;
+
+ CSettingsTree * tree = getSettingsTree(setting->Entity);
+ if (tree == NULL)
+ return DBT_INVALIDPARAM;
+
+ char * str = reinterpret_cast<char*>(setting + 1);
+ tree->_DeleteSetting(Hash(str, setting->NameLength), hSetting);
+
+ file->DeleteBlock(hSetting);
+
+ return 0;
+}
+TDBTSettingHandle CSettings::WriteSetting(TDBTSetting & Setting)
+{
+ CBlockManager * file = &m_BlockManagerPri;
+ if (Setting.Descriptor->Entity == 0)
+ file = &m_BlockManagerSet;
+
+ CBlockManager::WriteTransaction trans(*file);
+
+ TDBTSettingHandle hset = FindSetting(*Setting.Descriptor);
+ if (hset == DBT_INVALIDPARAM)
+ return hset;
+
+ hset = WriteSetting(Setting, hset);
+
+ return hset;
+}
+
+TDBTSettingHandle CSettings::WriteSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting)
+{
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+ TSetting * setting = NULL;
+
+ if (!hSetting && !(Setting.Descriptor && Setting.Descriptor->Entity))
+ return DBT_INVALIDPARAM;
+
+ CBlockManager * file = &m_BlockManagerPri;
+ bool fileflag = false;
+
+ if (hSetting & cSettingsFileFlag)
+ {
+ file = &m_BlockManagerSet;
+ hSetting = hSetting & ~cSettingsFileFlag;
+ fileflag = true;
+ }
+
+ CSettingsTree * tree = NULL;
+
+ if (hSetting == 0)
+ {
+ if (Setting.Descriptor->Entity == 0)
+ {
+ file = &m_BlockManagerSet;
+ fileflag = true;
+ }
+
+ CBlockManager::WriteTransaction trans(*file);
+
+ if ((Setting.Descriptor) && (Setting.Descriptor->pszSettingName)) // setting needs a name
+ {
+ tree = getSettingsTree(Setting.Descriptor->Entity);
+ _EnsureModuleExists(Setting.Descriptor->pszSettingName);
+ }
+
+ } else {
+ CBlockManager::WriteTransaction trans(*file);
+
+ setting = file->ReadBlock<TSetting>(hSetting, size, sig);
+
+ if (setting) // check if hSetting is valid
+ tree = getSettingsTree(setting->Entity);
+ }
+
+ if (tree == NULL)
+ return DBT_INVALIDPARAM;
+
+ uint32_t blobsize = 0;
+
+ if (Setting.Type & DBT_STF_VariableLength)
+ {
+ switch (Setting.Type)
+ {
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ if (Setting.Value.Length == 0)
+ blobsize = static_cast<uint32_t>(strlen(Setting.Value.pAnsi) + 1);
+ else
+ blobsize = Setting.Value.Length;
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ if (Setting.Value.Length == 0)
+ blobsize = sizeof(wchar_t) * static_cast<uint32_t>(wcslen(Setting.Value.pWide) + 1);
+ else
+ blobsize = sizeof(wchar_t) * (Setting.Value.Length);
+ } break;
+ default:
+ blobsize = Setting.Value.Length;
+ break;
+ }
+ }
+
+ size = sizeof(TSetting) + static_cast<uint32_t>(strlen(Setting.Descriptor->pszSettingName)) + 1 + blobsize;
+
+ if (hSetting == 0) // create new setting
+ {
+ setting = file->CreateBlock<TSetting>(hSetting, cSettingSignature, size);
+
+ setting->Entity = Setting.Descriptor->Entity;
+ setting->Flags = 0;
+ setting->AllocSize = blobsize;
+
+ if (Setting.Descriptor && (Setting.Descriptor->Flags & DBT_SDF_HashValid))
+ {
+ tree->_AddSetting(Setting.Descriptor->Hash, hSetting);
+ } else {
+ tree->_AddSetting(Hash(Setting.Descriptor->pszSettingName, static_cast<uint32_t>(strlen(Setting.Descriptor->pszSettingName))), hSetting);
+ }
+
+ } else {
+ uint32_t tmp = 0;
+ setting = file->ReadBlock<TSetting>(hSetting, tmp, sig);
+
+ if (((Setting.Type & DBT_STF_VariableLength) == 0) && (setting->Type & DBT_STF_VariableLength))
+ { // shrink setting (variable size->fixed size)
+ file->ResizeBlock(hSetting, setting, size);
+ }
+
+ if ((Setting.Type & DBT_STF_VariableLength) && ((setting->Type & DBT_STF_VariableLength) == 0))
+ { // trick it
+ setting->AllocSize = 0;
+ }
+ }
+
+ setting->Type = Setting.Type;
+ setting->NameLength = static_cast<uint32_t>(strlen(Setting.Descriptor->pszSettingName));
+ memcpy(setting + 1, Setting.Descriptor->pszSettingName, setting->NameLength + 1);
+
+ if (Setting.Type & DBT_STF_VariableLength)
+ {
+ setting->AllocSize = file->ResizeBlock(hSetting, setting, size) -
+ (sizeof(TSetting) + setting->NameLength + 1);
+
+ setting->BlobLength = blobsize;
+
+ memcpy(reinterpret_cast<uint8_t*>(setting + 1) + setting->NameLength + 1, Setting.Value.pBlob, blobsize);
+ } else {
+ memset(&(setting->Value), 0, sizeof(setting->Value));
+ switch (Setting.Type)
+ {
+ case DBT_ST_BOOL:
+ setting->Value.Bool = Setting.Value.Bool; break;
+ case DBT_ST_BYTE: case DBT_ST_CHAR:
+ setting->Value.Byte = Setting.Value.Byte; break;
+ case DBT_ST_SHORT: case DBT_ST_WORD:
+ setting->Value.Short = Setting.Value.Short; break;
+ case DBT_ST_INT: case DBT_ST_DWORD:
+ setting->Value.Int = Setting.Value.Int; break;
+ default:
+ setting->Value.QWord = Setting.Value.QWord; break;
+ }
+ }
+
+ file->UpdateBlock(hSetting);
+
+ if (fileflag)
+ hSetting = hSetting | cSettingsFileFlag;
+
+ return hSetting;
+}
+
+unsigned int CSettings::ReadSetting(TDBTSetting & Setting)
+{
+ CBlockManager * file = &m_BlockManagerPri;
+ if (Setting.Descriptor->Entity == 0)
+ file = &m_BlockManagerSet;
+
+ CBlockManager::ReadTransaction trans(*file);
+
+ TDBTSettingHandle hset = FindSetting(*Setting.Descriptor);
+ if ((hset == 0) || (hset == DBT_INVALIDPARAM))
+ return DBT_INVALIDPARAM;
+
+ PDBTSettingDescriptor back = Setting.Descriptor;
+ Setting.Descriptor = NULL;
+
+ if (ReadSetting(Setting, hset) == DBT_INVALIDPARAM)
+ hset = DBT_INVALIDPARAM;
+
+ Setting.Descriptor = back;
+
+ return hset;
+}
+
+unsigned int CSettings::ReadSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting)
+{
+ CBlockManager * file = &m_BlockManagerPri;
+
+ if (hSetting & cSettingsFileFlag)
+ {
+ file = &m_BlockManagerSet;
+ hSetting = hSetting & ~cSettingsFileFlag;
+ }
+
+ uint32_t sig = cSettingSignature;
+ uint32_t size = 0;
+
+ if (hSetting == 0)
+ return DBT_INVALIDPARAM;
+
+ CBlockManager::ReadTransaction trans(*file);
+
+ TSetting * setting = file->ReadBlock<TSetting>(hSetting, size, sig);
+
+ if (!setting)
+ return DBT_INVALIDPARAM;
+
+ uint8_t* str = reinterpret_cast<uint8_t*>(setting + 1) + setting->NameLength + 1;
+
+ if (Setting.Type == 0)
+ {
+ Setting.Type = setting->Type;
+ if (setting->Type & DBT_STF_VariableLength)
+ {
+ Setting.Value.Length = setting->BlobLength;
+ switch (setting->Type)
+ {
+ case DBT_ST_WCHAR:
+ {
+ Setting.Value.Length = setting->BlobLength / sizeof(wchar_t);
+ Setting.Value.pWide = (wchar_t*) mir_realloc(Setting.Value.pWide, sizeof(wchar_t) * Setting.Value.Length);
+ memcpy(Setting.Value.pWide, str, setting->BlobLength);
+ Setting.Value.pWide[Setting.Value.Length - 1] = 0;
+
+ } break;
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ Setting.Value.Length = setting->BlobLength;
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, setting->BlobLength);
+ memcpy(Setting.Value.pAnsi, str, setting->BlobLength);
+ Setting.Value.pAnsi[Setting.Value.Length - 1] = 0;
+
+ } break;
+ default:
+ {
+ Setting.Value.Length = setting->BlobLength;
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength);
+ memcpy(Setting.Value.pBlob, str, setting->BlobLength);
+ } break;
+ }
+ } else {
+ Setting.Value.QWord = setting->Value.QWord;
+ }
+ } else {
+ switch (setting->Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD:
+ {
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) setting->Value.QWord; break;
+ case DBT_ST_WORD: Setting.Value.Word = (uint16_t) setting->Value.QWord; break;
+ case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) setting->Value.QWord; break;
+ case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) setting->Value.QWord; break;
+ case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) setting->Value.QWord; break;
+ case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) setting->Value.QWord; break;
+ case DBT_ST_INT: Setting.Value.Int = ( int32_t) setting->Value.QWord; break;
+ case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) setting->Value.QWord; break;
+ case DBT_ST_BOOL: Setting.Value.Bool = setting->Value.QWord != 0; break;
+
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ char buffer[24];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + sprintf_s(buffer, "%llu", setting->Value.QWord);
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length);
+ memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length);
+
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ wchar_t buffer[24];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + swprintf_s(buffer, L"%llu", setting->Value.QWord);
+ Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t));
+ memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t));
+
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.Length = 0;
+ switch (setting->Type)
+ {
+ case DBT_ST_BYTE: Setting.Value.Length = 1; break;
+ case DBT_ST_WORD: Setting.Value.Length = 2; break;
+ case DBT_ST_DWORD: Setting.Value.Length = 4; break;
+ case DBT_ST_QWORD: Setting.Value.Length = 8; break;
+ }
+
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, Setting.Value.Length);
+ memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length);
+
+
+ } break;
+ }
+
+ } break;
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ int64_t val = 0;
+ switch (setting->Type)
+ {
+ case DBT_ST_CHAR: val = setting->Value.Char; break;
+ case DBT_ST_SHORT: val = setting->Value.Short; break;
+ case DBT_ST_INT: val = setting->Value.Int; break;
+ case DBT_ST_INT64: val = setting->Value.Int64; break;
+ }
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) val; break;
+ case DBT_ST_WORD: Setting.Value.Word = (uint16_t) val; break;
+ case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) val; break;
+ case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) val; break;
+ case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) val; break;
+ case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) val; break;
+ case DBT_ST_INT: Setting.Value.Int = ( int32_t) val; break;
+ case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) val; break;
+ case DBT_ST_BOOL: Setting.Value.Bool = val != 0; break;
+
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ char buffer[24];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + sprintf_s(buffer, "%lli", val);
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length);
+ memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length);
+
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ wchar_t buffer[24];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + swprintf_s(buffer, L"%lli", val);
+ Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t));
+ memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t));
+
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.Length = 0;
+ switch (setting->Type)
+ {
+ case DBT_ST_CHAR: Setting.Value.Length = 1; break;
+ case DBT_ST_SHORT: Setting.Value.Length = 2; break;
+ case DBT_ST_INT: Setting.Value.Length = 4; break;
+ case DBT_ST_INT64: Setting.Value.Length = 8; break;
+ }
+
+ Setting.Value.pBlob = (unsigned char *) mir_realloc(Setting.Value.pBlob, Setting.Value.Length);
+ memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length);
+
+ } break;
+ }
+
+ } break;
+ case DBT_ST_FLOAT: case DBT_ST_DOUBLE:
+ {
+ double val = 0;
+ if (setting->Type == DBT_ST_DOUBLE)
+ val = setting->Value.Double;
+ else
+ val = setting->Value.Float;
+
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) floor(val); break;
+ case DBT_ST_WORD: Setting.Value.Word = (uint16_t) floor(val); break;
+ case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) floor(val); break;
+ case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) floor(val); break;
+ case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) floor(val); break;
+ case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) floor(val); break;
+ case DBT_ST_INT: Setting.Value.Int = ( int32_t) floor(val); break;
+ case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) floor(val); break;
+ case DBT_ST_BOOL: Setting.Value.Bool = val != 0; break;
+
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ char buffer[128];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + sprintf_s(buffer, "%lf", setting->Value.QWord);
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length);
+ memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ wchar_t buffer[128];
+ buffer[0] = 0;
+ Setting.Value.Length = 1 + swprintf_s(buffer, L"%lf", setting->Value.QWord);
+ Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t));
+ memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t));
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.Length = 4;
+ if (setting->Type == DBT_ST_DOUBLE)
+ Setting.Value.Length = 8;
+
+ Setting.Value.pBlob = (uint8_t*) mir_realloc(Setting.Value.pBlob, Setting.Value.Length);
+ memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length);
+
+ } break;
+ }
+
+ } break;
+ case DBT_ST_BOOL:
+ {
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD:
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ if (setting->Value.Bool)
+ Setting.Value.QWord = 1;
+ else
+ Setting.Value.QWord = 0;
+ } break;
+ case DBT_ST_FLOAT:
+ {
+ if (setting->Value.Bool)
+ Setting.Value.Float = 1;
+ else
+ Setting.Value.Float = 0;
+ } break;
+ case DBT_ST_DOUBLE:
+ {
+ if (setting->Value.Bool)
+ Setting.Value.Double = 1;
+ else
+ Setting.Value.Double = 0;
+ } break;
+ case DBT_ST_ANSI: case DBT_ST_UTF8:
+ {
+ char * buffer = "false";
+ Setting.Value.Length = 5;
+ if (setting->Value.Bool)
+ {
+ buffer = "true";
+ Setting.Value.Length = 4;
+ }
+
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length);
+ memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ wchar_t * buffer = L"false";
+ Setting.Value.Length = 5;
+ if (setting->Value.Bool)
+ {
+ buffer = L"true";
+ Setting.Value.Length = 4;
+ }
+
+ Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t));
+ memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t));
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.pBlob = (uint8_t*) mir_realloc(Setting.Value.pBlob, sizeof(bool));
+ (*((bool*)Setting.Value.pBlob)) = setting->Value.Bool;
+ Setting.Value.Length = sizeof(bool);
+ } break;
+ }
+ } break;
+ case DBT_ST_ANSI:
+ {
+ str[setting->BlobLength - 1] = 0;
+
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL:
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ Setting.Value.QWord = 0;
+ } break;
+ case DBT_ST_ANSI:
+ {
+ Setting.Value.Length = setting->BlobLength;
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, setting->BlobLength);
+ memcpy(Setting.Value.pAnsi, str, setting->BlobLength);
+ } break;
+ case DBT_ST_UTF8:
+ {
+ Setting.Value.pUTF8 = mir_utf8encode((char*)str);
+ Setting.Value.Length = static_cast<uint32_t>(strlen(Setting.Value.pUTF8) + 1);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ Setting.Value.pWide = mir_a2u((char*)str);
+ Setting.Value.Length = static_cast<uint32_t>(wcslen(Setting.Value.pWide) + 1);
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.Length = setting->BlobLength;
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength);
+ memcpy(Setting.Value.pBlob, str, setting->BlobLength);
+ } break;
+ }
+ } break;
+ case DBT_ST_UTF8:
+ {
+ str[setting->BlobLength - 1] = 0;
+
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL:
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ Setting.Value.QWord = 0;
+ } break;
+ case DBT_ST_ANSI:
+ {
+ mir_utf8decode((char*)str, NULL);
+ Setting.Value.Length = static_cast<uint32_t>(strlen((char*)str) + 1);
+ Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length);
+ memcpy(Setting.Value.pAnsi, str, Setting.Value.Length);
+ } break;
+ case DBT_ST_UTF8:
+ {
+ Setting.Value.Length = setting->BlobLength;
+ Setting.Value.pUTF8 = (char *) mir_realloc(Setting.Value.pUTF8, setting->BlobLength);
+ memcpy(Setting.Value.pUTF8, str, setting->BlobLength);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ Setting.Value.pWide = mir_utf8decodeW((char*)str);
+ if (Setting.Value.pWide)
+ {
+ Setting.Value.Length = static_cast<uint32_t>(wcslen(Setting.Value.pWide) + 1);
+ } else {
+ Setting.Value.Length = 0;
+ Setting.Type = 0;
+ }
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength);
+ memcpy(Setting.Value.pBlob, str, setting->BlobLength);
+ Setting.Value.Length = setting->BlobLength;
+ } break;
+ }
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ ((wchar_t*)str)[setting->BlobLength / sizeof(wchar_t) - 1] = 0;
+
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL:
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ Setting.Value.QWord = 0;
+ } break;
+ case DBT_ST_ANSI:
+ {
+ Setting.Value.pAnsi = mir_u2a((wchar_t*)str);
+ Setting.Value.Length = static_cast<uint32_t>(strlen(Setting.Value.pAnsi) + 1);
+ } break;
+ case DBT_ST_UTF8:
+ {
+ Setting.Value.pUTF8 = mir_utf8encodeW((wchar_t*)str);
+ Setting.Value.Length = static_cast<uint32_t>(strlen(Setting.Value.pUTF8) + 1);
+ } break;
+ case DBT_ST_WCHAR:
+ {
+ Setting.Value.Length = setting->BlobLength / sizeof(wchar_t);
+ Setting.Value.pWide = (wchar_t*) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t));
+ memcpy(Setting.Value.pWide, str, Setting.Value.Length * sizeof(wchar_t));
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength);
+ memcpy(Setting.Value.pBlob, str, setting->BlobLength);
+ Setting.Value.Length = setting->BlobLength;
+ } break;
+ }
+ } break;
+ case DBT_ST_BLOB:
+ {
+ switch (Setting.Type)
+ {
+ case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL:
+ case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64:
+ {
+ Setting.Value.QWord = 0;
+ } break;
+ case DBT_ST_ANSI: case DBT_ST_WCHAR: case DBT_ST_UTF8:
+ {
+ Setting.Value.Length = 0;
+ if (Setting.Value.pBlob)
+ mir_free(Setting.Value.pBlob);
+
+ Setting.Value.pBlob = NULL;
+ } break;
+ case DBT_ST_BLOB:
+ {
+ Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength);
+ memcpy(Setting.Value.pBlob, str, setting->BlobLength);
+ Setting.Value.Length = setting->BlobLength;
+ } break;
+ }
+ } break;
+
+ }
+ }
+
+
+ if (Setting.Descriptor)
+ {
+ Setting.Descriptor->Entity = setting->Entity;
+ Setting.Descriptor->FoundInEntity = setting->Entity;
+
+ Setting.Descriptor->pszSettingName = (char *) mir_realloc(Setting.Descriptor->pszSettingName, setting->NameLength + 1);
+ memcpy(Setting.Descriptor->pszSettingName, setting + 1, setting->NameLength + 1);
+ Setting.Descriptor->pszSettingName[setting->NameLength] = 0;
+ }
+
+ return setting->Type;
+}
+
+
+
+
+TDBTSettingIterationHandle CSettings::IterationInit(TDBTSettingIterFilter & Filter)
+{
+ CBlockManager::ReadTransaction transset(m_BlockManagerSet);
+ CBlockManager::ReadTransaction transpri(m_BlockManagerPri);
+
+ std::queue<TDBTEntityHandle> Entities;
+ Entities.push(Filter.hEntity);
+
+ CSettingsTree * tree = getSettingsTree(Filter.hEntity);
+
+ if (tree == NULL)
+ return DBT_INVALIDPARAM;
+
+ if (Filter.hEntity != 0)
+ {
+ uint32_t cf = m_Entities.getFlags(Filter.hEntity);
+
+ if (cf == DBT_INVALIDPARAM)
+ return DBT_INVALIDPARAM;
+
+ TDBTEntityIterFilter f = {0,0,0,0};
+ f.cbSize = sizeof(f);
+ if (cf & DBT_NF_IsGroup)
+ {
+ f.fHasFlags = DBT_NF_IsGroup;
+ } else {
+ f.fDontHasFlags = DBT_NF_IsGroup;
+ }
+ f.Options = Filter.Options;
+
+ TDBTEntityIterationHandle citer = m_Entities.IterationInit(f, Filter.hEntity);
+ if (citer != DBT_INVALIDPARAM)
+ {
+ m_Entities.IterationNext(citer); // the initial Entity was already added
+ TDBTEntityHandle e = m_Entities.IterationNext(citer);
+ while (e != 0)
+ {
+ Entities.push(e);
+ e = m_Entities.IterationNext(citer);
+ }
+
+ m_Entities.IterationClose(citer);
+ }
+ }
+
+ for (unsigned int j = 0; j < Filter.ExtraCount; ++j)
+ Entities.push(Filter.ExtraEntities[j]);
+
+
+ PSettingIteration iter = new TSettingIteration;
+ iter->Filter = Filter;
+ iter->FilterNameStartLength = 0;
+ iter->LockSetting = (Filter.hEntity == 0);
+ iter->LockPrivate = (Filter.hEntity != 0);
+ if (Filter.NameStart)
+ {
+ uint16_t l = static_cast<uint32_t>(strlen(Filter.NameStart));
+ iter->Filter.NameStart = new char[l + 1];
+ memcpy(iter->Filter.NameStart, Filter.NameStart, l + 1);
+ iter->FilterNameStartLength = l;
+ }
+
+ TSettingKey key = {0, 0};
+
+ // pop first Entity. we have always one and always its tree
+ Entities.pop();
+
+ CSettingsTree::iterator * tmp = new CSettingsTree::iterator(tree->LowerBound(key));
+ tmp->setManaged();
+ iter->Heap = new TSettingsHeap(*tmp, TSettingsHeap::ITForward, true);
+
+ while (!Entities.empty())
+ {
+ TDBTEntityHandle e = Entities.front();
+ Entities.pop();
+
+ tree = getSettingsTree(e);
+ if (tree != NULL)
+ {
+ tmp = new CSettingsTree::iterator(tree->LowerBound(key));
+ tmp->setManaged();
+ iter->Heap->Insert(*tmp);
+
+ iter->LockSetting = iter->LockSetting || (e == 0);
+ iter->LockPrivate = iter->LockPrivate || (e != 0);
+ }
+ }
+
+ iter->Frame = new std::queue<TSettingIterationResult>;
+
+ return reinterpret_cast<TDBTSettingIterationHandle>(iter);
+}
+
+
+typedef struct TSettingIterationHelper {
+ TDBTSettingHandle Handle;
+ CSettingsTree * Tree;
+ uint16_t NameLen;
+ char * Name;
+ } TSettingIterationHelper;
+
+TDBTSettingHandle CSettings::IterationNext(TDBTSettingIterationHandle Iteration)
+{
+ PSettingIteration iter = reinterpret_cast<PSettingIteration>(Iteration);
+ CBlockManager::ReadTransaction transset;
+ CBlockManager::ReadTransaction transpri;
+
+ if (iter->LockSetting)
+ transset = CBlockManager::ReadTransaction(m_BlockManagerSet);
+ if (iter->LockPrivate)
+ transpri = CBlockManager::ReadTransaction(m_BlockManagerPri);
+
+ while (iter->Frame->empty() && iter->Heap->Top())
+ {
+ while (iter->Heap->Top() && iter->Heap->Top().wasDeleted())
+ iter->Heap->Pop();
+
+ if (iter->Heap->Top())
+ {
+ uint32_t h = iter->Heap->Top()->Hash;
+ std::queue<TSettingIterationHelper> q;
+ TSettingIterationHelper help;
+ help.NameLen = 0;
+ help.Name = NULL;
+
+ help.Handle = iter->Heap->Top()->Setting;
+ help.Tree = (CSettingsTree *) iter->Heap->Top().Tree();
+ if (help.Tree)
+ q.push(help);
+
+ iter->Heap->Pop();
+
+ // add all candidates
+ while (iter->Heap->Top() && (iter->Heap->Top()->Hash == h))
+ {
+ if (!iter->Heap->Top().wasDeleted())
+ {
+ help.Handle = iter->Heap->Top()->Setting;
+ help.Tree = (CSettingsTree *) iter->Heap->Top().Tree();
+ q.push(help);
+ }
+ iter->Heap->Pop();
+ }
+
+ while (!q.empty())
+ {
+ help = q.front();
+ q.pop();
+
+ if (help.Name == NULL)
+ {
+ if (help.Tree->Entity() == 0)
+ _ReadSettingName(m_BlockManagerSet, help.Handle, help.NameLen, help.Name);
+ else
+ _ReadSettingName(m_BlockManagerPri, help.Handle, help.NameLen, help.Name);
+ }
+
+
+ q.push(help);
+ while (q.front().Handle != help.Handle) // remove all queued settings with same name
+ {
+ bool namereadres = false;
+
+ TSettingIterationHelper tmp;
+ tmp = q.front();
+ q.pop();
+
+ if (tmp.Name == NULL)
+ {
+ if (tmp.Tree->Entity() == 0)
+ namereadres = _ReadSettingName(m_BlockManagerSet, tmp.Handle, tmp.NameLen, tmp.Name);
+ else
+ namereadres = _ReadSettingName(m_BlockManagerPri, tmp.Handle, tmp.NameLen, tmp.Name);
+ }
+
+ if (!namereadres)
+ {
+ q.push(tmp);
+ } else {
+ if (strcmp(tmp.Name, help.Name) != 0)
+ {
+ q.push(tmp);
+ } else {
+ free(tmp.Name);
+ }
+ }
+ }
+
+ // namefilter
+ if ((iter->Filter.NameStart == NULL) || ((iter->FilterNameStartLength <= help.NameLen) && (memcmp(iter->Filter.NameStart, help.Name, iter->FilterNameStartLength) == 0)))
+ {
+ TSettingIterationResult tmp;
+ if (help.Tree->Entity() == 0)
+ help.Handle |= cSettingsFileFlag;
+
+ tmp.Handle = help.Handle;
+ tmp.Entity = help.Tree->Entity();
+ tmp.Name = help.Name;
+ tmp.NameLen = help.NameLen;
+ iter->Frame->push(tmp);
+ } else {
+ free(help.Name);
+ }
+
+ q.pop();
+ }
+ }
+ }
+
+
+ TSettingIterationResult res = {0,0,0,0};
+ if (!iter->Frame->empty())
+ {
+ res = iter->Frame->front();
+ iter->Frame->pop();
+
+ if ((iter->Filter.Descriptor) && ((iter->Filter.Setting == NULL) || (iter->Filter.Setting->Descriptor != iter->Filter.Descriptor)))
+ {
+ iter->Filter.Descriptor->Entity = res.Entity;
+ iter->Filter.Descriptor->pszSettingName = (char *) mir_realloc(iter->Filter.Descriptor->pszSettingName, res.NameLen + 1);
+ memcpy(iter->Filter.Descriptor->pszSettingName, res.Name, res.NameLen + 1);
+ iter->Filter.Descriptor->FoundInEntity = res.Entity;
+ }
+ if (iter->Filter.Setting)
+ {
+ if ((iter->Filter.Setting->Type & DBT_STF_VariableLength) && (iter->Filter.Setting->Value.pBlob))
+ {
+ mir_free(iter->Filter.Setting->Value.pBlob);
+ iter->Filter.Setting->Value.pBlob = NULL;
+ }
+ iter->Filter.Setting->Type = 0;
+
+ ReadSetting(*iter->Filter.Setting, res.Handle);
+ }
+
+ free(res.Name);
+ }
+
+ return res.Handle;
+}
+unsigned int CSettings::IterationClose(TDBTSettingIterationHandle Iteration)
+{
+ PSettingIteration iter = reinterpret_cast<PSettingIteration>(Iteration);
+ {
+ CBlockManager::ReadTransaction transset;
+ CBlockManager::ReadTransaction transpri;
+
+ if (iter->LockSetting)
+ transset = CBlockManager::ReadTransaction(m_BlockManagerSet);
+ if (iter->LockPrivate)
+ transpri = CBlockManager::ReadTransaction(m_BlockManagerPri);
+
+ delete iter->Heap; // only this needs synchronization
+ }
+
+ if (iter->Filter.NameStart)
+ delete [] iter->Filter.NameStart;
+
+ if (iter->Filter.Descriptor && iter->Filter.Descriptor->pszSettingName)
+ {
+ mir_free(iter->Filter.Descriptor->pszSettingName);
+ iter->Filter.Descriptor->pszSettingName = NULL;
+ }
+ if (iter->Filter.Setting)
+ {
+ if (iter->Filter.Setting->Descriptor)
+ {
+ mir_free(iter->Filter.Setting->Descriptor->pszSettingName);
+ iter->Filter.Setting->Descriptor->pszSettingName = NULL;
+ }
+
+ if (iter->Filter.Setting->Type & DBT_STF_VariableLength)
+ {
+ mir_free(iter->Filter.Setting->Value.pBlob);
+ iter->Filter.Setting->Value.pBlob = NULL;
+ }
+ }
+
+ while (!iter->Frame->empty())
+ {
+ if (iter->Frame->front().Name)
+ free(iter->Frame->front().Name);
+
+ iter->Frame->pop();
+ }
+ delete iter->Frame;
+ delete iter;
+
+ return 0;
+}
+
+
+int CSettings::CompEnumModules(DBMODULEENUMPROC CallBack, LPARAM lParam)
+{
+ CBlockManager::ReadTransaction trans(m_BlockManagerSet);
+
+ TModulesMap::iterator i = m_Modules.begin();
+ int res = 0;
+ while ((i != m_Modules.end()) && (res == 0))
+ {
+ char * tmp = i->second;
+ trans.Close();
+
+ res = CallBack(tmp, 0, lParam);
+
+ trans = CBlockManager::ReadTransaction(m_BlockManagerSet);
+ ++i;
+ }
+
+ return res;
+}
diff --git a/plugins/Dbx_tree/src/Settings.h b/plugins/Dbx_tree/src/Settings.h
new file mode 100644
index 0000000000..28be10603e
--- /dev/null
+++ b/plugins/Dbx_tree/src/Settings.h
@@ -0,0 +1,235 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include "Interface.h"
+#include "FileBTree.h"
+#include "MREWSync.h"
+#include "sigslot.h"
+#include "IterationHeap.h"
+#include <queue>
+#include "lockfree_hashmap.h"
+
+class CSettings;
+class CSettingsTree;
+
+#include "Entities.h"
+
+#pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary
+
+/**
+ \brief Key Type of the SettingsBTree
+
+ The setting names (ASCII) are hashed, so that they can easily be accessed.
+**/
+
+typedef struct TSettingKey {
+ uint32_t Hash; /// 32 bit hash of the Setting name
+ TDBTSettingHandle Setting;
+
+ bool operator < (const TSettingKey & Other) const
+ {
+ if (Hash != Other.Hash) return Hash < Other.Hash;
+ if (Setting != Other.Setting) return Setting < Other.Setting;
+ return false;
+ }
+ //bool operator <= (const TSettingKey & Other);
+ bool operator == (const TSettingKey & Other) const
+ {
+ return (Hash == Other.Hash) && (Setting == Other.Setting);
+ }
+ //bool operator >= (const TSettingKey & Other);
+ bool operator > (const TSettingKey & Other) const
+ {
+ if (Hash != Other.Hash) return Hash > Other.Hash;
+ if (Setting != Other.Setting) return Setting > Other.Setting;
+ return false;
+ }
+} TSettingKey;
+
+static const uint32_t cSettingSignature = 0xF5B87A3D;
+static const uint16_t cSettingNodeSignature = 0xBA12;
+
+/**
+ \brief The data of a setting
+
+ A setting's data is variable length. The data is a TSetting-structure followed by variable length data.
+ - fixed data
+ - SettingName (ASCII)
+ - maybe blob data
+**/
+typedef struct TSetting {
+ TDBTEntityHandle Entity; /// Settings' Entity
+ uint32_t Flags; /// flags
+ uint16_t Type; /// setting type
+ uint16_t NameLength; /// settingname length
+ union {
+ union {
+ bool Bool;
+ int8_t Char; uint8_t Byte;
+ int16_t Short; uint16_t Word;
+ uint32_t Int; uint32_t DWord;
+ int64_t Int64; uint64_t QWord;
+ float Float;
+ double Double;
+ } Value; /// if type is fixed length, the data is stored right here
+
+ struct {
+ uint32_t BlobLength; /// if type is variable length this describes the length of the data in bytes
+ uint32_t AllocSize; /// this is the allocated space for the blob ALWAYS in byte! this prevents us to realloc it too often
+ };
+ };
+ uint8_t Reserved[8];
+ // settingname with terminating NULL
+ // blob
+} TSetting;
+
+#pragma pack(pop)
+
+/**
+ \brief Manages the Settings in the Database
+**/
+class CSettingsTree : public CFileBTree<TSettingKey, 8>
+{
+protected:
+ TDBTEntityHandle m_Entity;
+ CSettings & m_Owner;
+public:
+ CSettingsTree(CSettings & Owner, CBlockManager & BlockManager, TNodeRef RootNode, TDBTEntityHandle Entity)
+ : CFileBTree<TSettingKey, 8>(BlockManager, RootNode, cSettingNodeSignature),
+ m_Owner(Owner),
+ m_Entity(Entity)
+ {
+
+ };
+ ~CSettingsTree()
+ {
+
+ };
+
+ TDBTEntityHandle Entity()
+ {
+ return m_Entity;
+ };
+ void Entity(TDBTEntityHandle NewEntity)
+ {
+ m_Entity = NewEntity;
+ };
+
+ TDBTSettingHandle _FindSetting(const uint32_t Hash, const char * Name, const uint32_t Length);
+ bool _DeleteSetting(const uint32_t Hash, const TDBTSettingHandle hSetting);
+ bool _AddSetting(const uint32_t Hash, const TDBTSettingHandle hSetting);
+};
+
+
+/**
+ \brief Manages all Settings and provides access to them
+**/
+class CSettings : public sigslot::has_slots<>
+{
+public:
+ typedef sigslot::signal2<CSettings*, CSettingsTree::TNodeRef> TOnRootChanged;
+
+ static const uint32_t cSettingsFileFlag = 0x00000001;
+
+ CSettings(
+ CBlockManager & BlockManagerSet,
+ CBlockManager & BlockManagerPri,
+ CSettingsTree::TNodeRef SettingsRoot,
+ CEntities & Entities
+ );
+ virtual ~CSettings();
+
+
+ TOnRootChanged & sigRootChanged()
+ {
+ return m_sigRootChanged;
+ };
+
+ bool _ReadSettingName(CBlockManager & BlockManager, TDBTSettingHandle Setting, uint16_t & NameLength, char *& NameBuf);
+ void _EnsureModuleExists(char * Module);
+
+ // compatibility:
+ typedef int (*DBMODULEENUMPROC)(const char *szModuleName,DWORD ofsModuleName,LPARAM lParam);
+
+ int CompEnumModules(DBMODULEENUMPROC CallBack, LPARAM lParam);
+ // services:
+ TDBTSettingHandle FindSetting(TDBTSettingDescriptor & Descriptor);
+ unsigned int DeleteSetting(TDBTSettingDescriptor & Descriptor);
+ unsigned int DeleteSetting(TDBTSettingHandle hSetting);
+ TDBTSettingHandle WriteSetting(TDBTSetting & Setting);
+ TDBTSettingHandle WriteSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting);
+ unsigned int ReadSetting(TDBTSetting & Setting);
+ unsigned int ReadSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting);
+
+
+ TDBTSettingIterationHandle IterationInit(TDBTSettingIterFilter & Filter);
+ TDBTSettingHandle IterationNext(TDBTSettingIterationHandle Iteration);
+ unsigned int IterationClose(TDBTSettingIterationHandle Iteration);
+
+
+private:
+
+ typedef lockfree::hash_map<TDBTEntityHandle, CSettingsTree*> TSettingsTreeMap;
+
+ typedef CIterationHeap<CSettingsTree::iterator> TSettingsHeap;
+
+ CBlockManager & m_BlockManagerSet;
+ CBlockManager & m_BlockManagerPri;
+
+ CEntities & m_Entities;
+
+ TSettingsTreeMap m_SettingsMap;
+
+ typedef struct TSettingIterationResult {
+ TDBTSettingHandle Handle;
+ TDBTEntityHandle Entity;
+ char * Name;
+ uint16_t NameLen;
+ } TSettingIterationResult;
+
+ typedef struct TSettingIteration {
+ TDBTSettingIterFilter Filter;
+ uint16_t FilterNameStartLength;
+ TSettingsHeap * Heap;
+ std::queue<TSettingIterationResult> * Frame;
+ bool LockSetting;
+ bool LockPrivate;
+ } TSettingIteration, *PSettingIteration;
+
+ TOnRootChanged m_sigRootChanged;
+ void onRootChanged(void* SettingsTree, CSettingsTree::TNodeRef NewRoot);
+
+ void onDeleteSettingCallback(void * Tree, const TSettingKey & Key, uint32_t Param);
+ void onDeleteSettings(CEntities * Entities, TDBTEntityHandle hEntity);
+ void onMergeSettingCallback(void * Tree, const TSettingKey & Key, uint32_t Param);
+ void onMergeSettings(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest);
+
+ CSettingsTree * getSettingsTree(TDBTEntityHandle hEntity);
+ typedef lockfree::hash_multimap<uint16_t, char *> TModulesMap;
+
+ TModulesMap m_Modules;
+
+ void _LoadModules();
+
+};
diff --git a/plugins/Dbx_tree/src/TLS.h b/plugins/Dbx_tree/src/TLS.h
new file mode 100644
index 0000000000..d309090a34
--- /dev/null
+++ b/plugins/Dbx_tree/src/TLS.h
@@ -0,0 +1,161 @@
+/*
+
+dbx_tree: tree database driver for Miranda IM
+
+Copyright 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.
+
+*/
+
+#pragma once
+
+#include "lockfree_hashmap.h"
+
+template <typename TAdministrator, typename TData>
+class CThreadLocalStorage
+{
+ private:
+ typedef struct TListElem
+ {
+ TListElem * Next;
+ TAdministrator * Admin;
+ TData Data;
+ TListElem(TListElem * ANext, TAdministrator * AAdmin, const TData & AData)
+ : Next(ANext), Admin(AAdmin), Data(AData)
+ { };
+
+ } TListElem, *PListElem;
+ static __declspec(thread) PListElem m_Head;
+
+ static inline uint32_t DummyHash(const void * Data, uint32_t Length)
+ {
+ return *reinterpret_cast<const uint32_t *>(Data);
+ }
+
+ lockfree::hash_map<DWORD, TData, DummyHash> * m_LockfreeList;
+ typedef typename lockfree::hash_map<DWORD, TData, DummyHash>::iterator TThreadStorage;
+
+ public:
+ CThreadLocalStorage();
+ ~CThreadLocalStorage();
+
+ TData & Open(TAdministrator * Admin, const TData & Default);
+ TData * Find(TAdministrator * Admin);
+ void Remove(TAdministrator * Admin);
+};
+
+const bool _CanUseTLS = ((LOBYTE(LOWORD(GetVersion()))) >= 6);
+
+template <typename TAdministrator, typename TData>
+typename CThreadLocalStorage<TAdministrator, TData>::PListElem CThreadLocalStorage<TAdministrator, TData>::m_Head = NULL;
+
+
+template <typename TAdministrator, typename TData>
+CThreadLocalStorage<TAdministrator, TData>::CThreadLocalStorage()
+{
+ m_LockfreeList = NULL;
+ if (!_CanUseTLS)
+ m_LockfreeList = new lockfree::hash_map<DWORD, TData, DummyHash>();
+}
+template <typename TAdministrator, typename TData>
+CThreadLocalStorage<TAdministrator, TData>::~CThreadLocalStorage()
+{
+ if (m_LockfreeList)
+ delete m_LockfreeList;
+}
+
+
+template <typename TAdministrator, typename TData>
+typename TData & CThreadLocalStorage<TAdministrator, TData>::Open(typename TAdministrator * Admin, const TData & Default)
+{
+ if (_CanUseTLS)
+ {
+ PListElem * last = &m_Head;
+ PListElem i = m_Head;
+ while (i && (i->Admin != Admin))
+ {
+ last = &i->Next;
+ i = i->Next;
+ }
+
+ if (i)
+ {
+ *last = i->Next;
+ i->Next = m_Head;
+ m_Head = i;
+ } else {
+ m_Head = new TListElem(m_Head, Admin, Default);
+ }
+ return m_Head->Data;
+ } else {
+ TThreadStorage & res = m_LockfreeList->insert(std::make_pair(GetCurrentThreadId(), Default)).first;
+ return res->second;
+ }
+}
+
+template <typename TAdministrator, typename TData>
+typename TData * CThreadLocalStorage<TAdministrator, TData>::Find(typename TAdministrator * Admin)
+{
+ if (_CanUseTLS)
+ {
+ PListElem * last = &m_Head;
+ PListElem i = m_Head;
+ while (i && (i->Admin != Admin))
+ {
+ last = &i->Next;
+ i = i->Next;
+ }
+
+ if (i)
+ {
+ *last = i->Next;
+ i->Next = m_Head;
+ m_Head = i;
+ } else {
+ return NULL;
+ }
+ return &m_Head->Data;
+ } else {
+ TThreadStorage & res = m_LockfreeList->find(GetCurrentThreadId());
+ if (res != m_LockfreeList->end())
+ return &res->second;
+ else
+ return NULL;
+ }
+}
+
+template <typename TAdministrator, typename TData>
+void CThreadLocalStorage<TAdministrator, TData>::Remove(typename TAdministrator * Admin)
+{
+ if (_CanUseTLS)
+ {
+ PListElem * last = &m_Head;
+ PListElem i = m_Head;
+ while (i && (i->Admin != Admin))
+ {
+ last = &i->Next;
+ i = i->Next;
+ }
+
+ if (i)
+ {
+ *last = i->Next;
+ delete i;
+ }
+ } else {
+ m_LockfreeList->erase(GetCurrentThreadId());
+ }
+}
diff --git a/plugins/Dbx_tree/src/Thread.cpp b/plugins/Dbx_tree/src/Thread.cpp
new file mode 100644
index 0000000000..bdb01f18aa
--- /dev/null
+++ b/plugins/Dbx_tree/src/Thread.cpp
@@ -0,0 +1,114 @@
+/*
+
+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 "Thread.h"
+#include "intrinsics.h"
+
+unsigned int __stdcall ThreadDistributor(void* Param)
+{
+ CThread * thread = static_cast<CThread *>(Param);
+ DWORD result = thread->Wrapper();
+ _endthreadex(result);
+ return result; // to make the compiler happy
+}
+
+CThread::CThread(bool CreateSuspended)
+{
+ m_Handle = NULL;
+ m_Terminated = 0;
+ m_FreeOnTerminate = false;
+ m_Finished = false;
+ m_Suspended = CreateSuspended;
+ m_ReturnValue = 0;
+ unsigned int flags = 0;
+ if (CreateSuspended)
+ flags = CREATE_SUSPENDED;
+
+ m_Handle = reinterpret_cast<HANDLE> (_beginthreadex(NULL, 0, &ThreadDistributor, this, flags, &m_ThreadID));
+}
+CThread::~CThread()
+{
+ if (!m_Finished && !m_Suspended)
+ {
+ Terminate();
+ WaitFor();
+ }
+ if (m_Handle)
+ CloseHandle(m_Handle);
+}
+DWORD CThread::Wrapper()
+{
+ Execute();
+
+ bool dofree = FreeOnTerminate();
+ DWORD result = ReturnValue();
+ m_Finished = true;
+
+ m_sigTerminate(this);
+ if (dofree)
+ delete this;
+
+ return result;
+}
+
+void CThread::Resume()
+{
+ if (ResumeThread(m_Handle) == 1)
+ XCHG_32(m_Suspended, 0);
+}
+void CThread::Suspend()
+{
+ SuspendThread(m_Handle);
+ XCHG_32(m_Suspended, 1);
+}
+void CThread::Terminate()
+{
+ XCHG_32(m_Terminated, 1);
+}
+DWORD CThread::WaitFor()
+{
+ HANDLE tmp = m_Handle;
+ DWORD result = WAIT_FAILED;
+
+ if (WaitForSingleObject(m_Handle, INFINITE) != WAIT_FAILED)
+ GetExitCodeThread(tmp, &result);
+
+ return result;
+}
+
+void CThread::FreeOnTerminate(bool Terminate)
+{
+ XCHG_32(m_FreeOnTerminate, Terminate);
+}
+void CThread::ReturnValue(DWORD Value)
+{
+ XCHG_32(m_ReturnValue, Value);
+}
+
+void CThread::Priority(TPriority NewPriority)
+{
+ SetThreadPriority(m_Handle, NewPriority);
+}
+CThread::TPriority CThread::Priority()
+{
+ return static_cast<TPriority> (GetThreadPriority(m_Handle) & 0xffff);
+}
diff --git a/plugins/Dbx_tree/src/Thread.h b/plugins/Dbx_tree/src/Thread.h
new file mode 100644
index 0000000000..09b0b6c016
--- /dev/null
+++ b/plugins/Dbx_tree/src/Thread.h
@@ -0,0 +1,77 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+#include <process.h>
+#include <windows.h>
+#include "sigslot.h"
+#include "stdint.h"
+
+class CThread
+{
+private:
+ uint32_t volatile m_Terminated;
+ uint32_t volatile m_FreeOnTerminate;
+ uint32_t volatile m_Finished;
+ uint32_t volatile m_Suspended;
+ uint32_t volatile m_ReturnValue;
+protected:
+ HANDLE m_Handle;
+ unsigned int m_ThreadID;
+
+ void ReturnValue(DWORD Value);
+ virtual void Execute() = 0;
+public:
+ CThread(bool CreateSuspended);
+ virtual ~CThread();
+
+ DWORD Wrapper();
+
+ void Resume();
+ void Suspend();
+ void Terminate();
+ DWORD WaitFor();
+
+ bool Suspended() {return m_Suspended != 0;};
+ bool Terminated() {return m_Terminated != 0;};
+ bool FreeOnTerminate() {return m_FreeOnTerminate != 0;};
+ void FreeOnTerminate(bool Terminate);
+ DWORD ReturnValue() {return m_ReturnValue;};
+
+ typedef enum TPriority {
+ tpIdle = THREAD_PRIORITY_IDLE,
+ tpLowest = THREAD_PRIORITY_LOWEST,
+ tpLower = THREAD_PRIORITY_BELOW_NORMAL,
+ tpNormal = THREAD_PRIORITY_NORMAL,
+ tpHigher = THREAD_PRIORITY_ABOVE_NORMAL,
+ tpHighest = THREAD_PRIORITY_HIGHEST,
+ tpRealTime = THREAD_PRIORITY_TIME_CRITICAL
+ } TPriority;
+
+ void Priority(TPriority NewPriority);
+ TPriority Priority();
+
+ typedef sigslot::signal1<CThread *> TOnTerminate;
+ TOnTerminate m_sigTerminate;
+ TOnTerminate & sigTerminate() {return m_sigTerminate;};
+};
diff --git a/plugins/Dbx_tree/src/dbConfig_rc.h b/plugins/Dbx_tree/src/dbConfig_rc.h
new file mode 100644
index 0000000000..099067d3ec
--- /dev/null
+++ b/plugins/Dbx_tree/src/dbConfig_rc.h
@@ -0,0 +1,20 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by dbConfig.rc
+//
+#define IDD_DIALOGBAR 103
+#define IDC_BUTTON1 1001
+#define IDC_BUTTON2 1002
+#define IDC_BUTTON3 1003
+#define IDC_LIST1 1004
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1005
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Dbx_tree/src/dbVersion_rc.h b/plugins/Dbx_tree/src/dbVersion_rc.h
new file mode 100644
index 0000000000..24a3ae4cf4
--- /dev/null
+++ b/plugins/Dbx_tree/src/dbVersion_rc.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by dbVersion.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Dbx_tree/src/init.cpp b/plugins/Dbx_tree/src/init.cpp
new file mode 100644
index 0000000000..3e1f4cc6a6
--- /dev/null
+++ b/plugins/Dbx_tree/src/init.cpp
@@ -0,0 +1,73 @@
+/*
+
+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 "Interface.h"
+#include "DatabaseLink.h"
+
+HINSTANCE hInstance = NULL;
+int hLangpack;
+
+static const DWORD gMinMirVer = 0x00080000;
+// {28F45248-8C9C-4bee-9307-7BCF3E12BF99}
+static const MUUID gGUID =
+{ 0x28f45248, 0x8c9c, 0x4bee, { 0x93, 0x07, 0x7b, 0xcf, 0x3e, 0x12, 0xbf, 0x99 } };
+
+static PLUGININFOEX gPluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ gInternalNameLong,
+ gVersion,
+ gDescription,
+ gAutor,
+ gAutorEmail,
+ gCopyright,
+ "http://miranda-ng.org/",
+ UNICODE_AWARE,
+ gGUID
+};
+
+extern "C" __declspec(dllexport) PLUGININFOEX * MirandaPluginInfoEx(DWORD MirandaVersion)
+{
+ return &gPluginInfoEx;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_DATABASE, MIID_LAST};
+
+extern "C" __declspec(dllexport) int Load(void)
+{
+ mir_getLP(&gPluginInfoEx);
+
+ RegisterDatabasePlugin(&gDBLink);
+ RegisterServices();
+ CompatibilityRegister();
+ return 0;
+}
+
+extern "C" __declspec(dllexport) int Unload(void)
+{
+ return 0;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID reserved)
+{
+ hInstance = hInstDLL;
+ return TRUE;
+}
diff --git a/plugins/Dbx_tree/src/intrinsics.h b/plugins/Dbx_tree/src/intrinsics.h
new file mode 100644
index 0000000000..7cb8af18f3
--- /dev/null
+++ b/plugins/Dbx_tree/src/intrinsics.h
@@ -0,0 +1,407 @@
+#pragma once
+
+#ifdef _MSC_VER
+
+#include <intrin.h>
+#include "stdint.h"
+
+#ifdef _M_X64
+
+inline uint32_t XCHG_32(uint32_t volatile & Dest, uint32_t Exchange)
+{
+ return (uint32_t)_InterlockedExchange((long volatile*)&(Dest), (long)(Exchange));
+}
+inline int32_t XCHG_32(int32_t volatile & Dest, int32_t Exchange)
+{
+ return (int32_t)_InterlockedExchange((long volatile*)&(Dest), (long)(Exchange));
+}
+
+inline uint64_t XCHG_64(uint64_t volatile & Dest, uint64_t Exchange)
+{
+ return (uint64_t)_InterlockedExchange64((__int64 volatile*)&Dest, (__int64)Exchange);
+}
+inline int64_t XCHG_64(int64_t volatile & Dest, int64_t Exchange)
+{
+ return (int64_t)_InterlockedExchange64((__int64 volatile*)&Dest, (__int64)Exchange);
+}
+
+template <typename T>
+inline T * XCHG_Ptr(T * volatile & Dest, T * Exchange)
+{
+ return (T*)_InterlockedExchangePointer((void*volatile*)&Dest, (void*)Exchange);
+}
+
+
+inline uint32_t CMPXCHG_32(uint32_t volatile & Dest, uint32_t Exchange, uint32_t Comperand)
+{
+ return (uint64_t)_InterlockedCompareExchange((long volatile*)&(Dest), (long)(Exchange), (long)Comperand);
+}
+inline int32_t CMPXCHG_32(int32_t volatile & Dest, int32_t Exchange, int32_t Comperand)
+{
+ return (int32_t)_InterlockedCompareExchange((long volatile*)&(Dest), (long)(Exchange), (long)Comperand);
+}
+
+inline uint64_t CMPXCHG_64(uint64_t volatile & Dest, uint64_t Exchange, uint64_t Comperand)
+{
+ return (uint64_t)_InterlockedCompareExchange64((__int64 volatile*)&Dest, (__int64)Exchange, (__int64)Comperand);
+}
+inline int64_t CMPXCHG_64(int64_t volatile & Dest, int64_t Exchange, int64_t Comperand)
+{
+ return (int64_t)_InterlockedCompareExchange64((__int64 volatile*)&Dest, (__int64)Exchange, (__int64)Comperand);
+}
+
+template <typename T>
+inline T * CMPXCHG_Ptr(T * volatile & Dest, T * Exchange, T * Comperand)
+{
+ return (T*)_InterlockedCompareExchangePointer((void*volatile*)&Dest, (void*)Exchange, (void*)Comperand);
+}
+
+inline uint32_t XADD_32(uint32_t volatile & Dest, int32_t Addend)
+{
+ return (uint32_t)_InterlockedExchangeAdd((long volatile*)&Dest, (long)Addend);
+}
+inline int32_t XADD_32(int32_t volatile & Dest, int32_t Addend)
+{
+ return (int32_t)_InterlockedExchangeAdd((long volatile*)&Dest, (long)Addend);
+}
+
+inline uint64_t XADD_64(uint64_t volatile & Dest, int64_t Addend)
+{
+ return (uint64_t)_InterlockedExchangeAdd64((__int64 volatile*)&Dest, (__int64)Addend);
+}
+inline int64_t XADD_64(int64_t volatile & Dest, int64_t Addend)
+{
+ return (int64_t)_InterlockedExchangeAdd64((__int64 volatile*)&Dest, (__int64)Addend);
+}
+
+inline uint32_t DEC_32(uint32_t volatile & Dest)
+{
+ return (uint32_t)_InterlockedDecrement((long volatile*)&Dest);
+}
+inline int32_t DEC_32(int32_t volatile & Dest)
+{
+ return (int32_t)_InterlockedDecrement((long volatile*)&Dest);
+}
+
+inline uint64_t DEC_64(uint64_t volatile & Dest)
+{
+ return (uint64_t)_InterlockedDecrement64((__int64 volatile*)&Dest);
+}
+inline int64_t DEC_64(int64_t volatile & Dest)
+{
+ return (int64_t)_InterlockedDecrement64((__int64 volatile*)&Dest);
+}
+
+inline uint32_t INC_32(uint32_t volatile & Dest)
+{
+ return (uint32_t)_InterlockedIncrement((long volatile*)&Dest);
+}
+inline int32_t INC_32(int32_t volatile & Dest)
+{
+ return (int32_t)_InterlockedIncrement((long volatile*)&Dest);
+}
+
+inline uint64_t INC_64(uint64_t volatile & Dest)
+{
+ return (uint64_t)_InterlockedIncrement64((__int64 volatile*)&Dest);
+}
+inline int64_t INC_64(int64_t volatile & Dest)
+{
+ return (int64_t)_InterlockedIncrement64((__int64 volatile*)&Dest);
+}
+
+inline bool BTS_32(uint32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+}
+inline bool BTS_32(int32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+}
+inline bool BTS_64(uint64_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset64((__int64 volatile*)&Dest, Offset);
+}
+inline bool BTS_64(int64_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset64((__int64 volatile*)&Dest, Offset);
+}
+
+
+inline bool BTR_32(uint32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+}
+inline bool BTR_32(int32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+}
+inline bool BTR_64(uint64_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset64((__int64 volatile*)&Dest, Offset);
+}
+inline bool BTR_64(int64_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset64((__int64 volatile*)&Dest, Offset);
+}
+
+
+inline uint32_t OR_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedOr((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t OR_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedOr((long volatile*)&Value, (long)Operator);
+}
+
+inline uint64_t OR_64(uint64_t volatile & Value, uint64_t Operator)
+{
+ return (uint64_t)_InterlockedOr64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+inline int64_t OR_64(int64_t volatile & Value, int64_t Operator)
+{
+ return (int64_t)_InterlockedOr64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+inline uint32_t AND_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedAnd((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t AND_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedAnd((long volatile*)&Value, (long)Operator);
+}
+
+inline uint64_t AND_64(uint64_t volatile & Value, uint64_t Operator)
+{
+ return (uint64_t)_InterlockedAnd64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+inline int64_t AND_64(int64_t volatile & Value, int64_t Operator)
+{
+ return (int64_t)_InterlockedAnd64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+
+inline uint32_t XOR_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedXor((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t XOR_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedXor((long volatile*)&Value, (long)Operator);
+}
+inline uint64_t XOR_64(uint64_t volatile & Value, uint64_t Operator)
+{
+ return (uint64_t)_InterlockedXor64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+inline int64_t XOR_64(int64_t volatile & Value, int64_t Operator)
+{
+ return (int64_t)_InterlockedXor64((__int64 volatile*)&Value, (__int64)Operator);
+}
+
+
+inline uint32_t BSWAP_32(uint32_t Value)
+{
+ return _byteswap_ulong(Value);
+}
+
+inline uint32_t ROL_32(uint32_t Value, uint8_t Shift)
+{
+ return _rotl(Value, Shift);
+}
+
+inline uint32_t ROR_32(uint32_t Value, uint8_t Shift)
+{
+ return _rotr(Value, Shift);
+}
+
+#elif defined(_M_IX86)
+
+inline uint32_t XCHG_32(uint32_t volatile & Dest, uint32_t Exchange)
+{
+ return (uint32_t)_InterlockedExchange((long volatile*)&(Dest), (long)(Exchange));
+}
+inline int32_t XCHG_32(int32_t volatile & Dest, int32_t Exchange)
+{
+ return (int32_t)_InterlockedExchange((long volatile*)&(Dest), (long)(Exchange));
+}
+/*
+inline uint64_t XCHG_64(uint64_t volatile & Dest, uint64_t Exchange)
+{
+ return (uint64_t)_InterlockedExchange64((__int64 volatile*)&Dest, (__int64)Exchange);
+}
+inline int64_t XCHG_64(int64_t volatile & Dest, int64_t Exchange)
+{
+ return (int64_t)_InterlockedExchange64((__int64 volatile*)&Dest, (__int64)Exchange);
+}
+*/
+template <typename T>
+inline T * XCHG_Ptr(T * volatile & Dest, T * Exchange)
+{
+ return (T*)_InterlockedExchange((long volatile*)&Dest, (long)Exchange);
+}
+
+
+inline uint32_t CMPXCHG_32(uint32_t volatile & Dest, uint32_t Exchange, uint32_t Comperand)
+{
+ return (uint64_t)_InterlockedCompareExchange((long volatile*)&(Dest), (long)(Exchange), (long)Comperand);
+}
+inline int32_t CMPXCHG_32(int32_t volatile & Dest, int32_t Exchange, int32_t Comperand)
+{
+ return (int32_t)_InterlockedCompareExchange((long volatile*)&(Dest), (long)(Exchange), (long)Comperand);
+}
+
+inline uint64_t CMPXCHG_64(uint64_t volatile & Dest, uint64_t Exchange, uint64_t Comperand)
+{
+ return (uint64_t)_InterlockedCompareExchange64((__int64 volatile*)&Dest, (__int64)Exchange, (__int64)Comperand);
+}
+inline int64_t CMPXCHG_64(int64_t volatile & Dest, int64_t Exchange, int64_t Comperand)
+{
+ return (int64_t)_InterlockedCompareExchange64((__int64 volatile*)&Dest, (__int64)Exchange, (__int64)Comperand);
+}
+
+template <typename T>
+inline T * CMPXCHG_Ptr(T * volatile & Dest, T * Exchange, T * Comperand)
+{
+ return (T*)_InterlockedCompareExchange((long volatile *)&Dest, (long)Exchange, (long)Comperand);
+}
+
+inline uint32_t XADD_32(uint32_t volatile & Dest, int32_t Addend)
+{
+ return (uint32_t)_InterlockedExchangeAdd((long volatile*)&Dest, (long)Addend);
+}
+inline int32_t XADD_32(int32_t volatile & Dest, int32_t Addend)
+{
+ return (int32_t)_InterlockedExchangeAdd((long volatile*)&Dest, (long)Addend);
+}
+
+inline uint32_t DEC_32(uint32_t volatile & Dest)
+{
+ return (uint32_t)_InterlockedDecrement((long volatile*)&Dest);
+}
+inline int32_t DEC_32(int32_t volatile & Dest)
+{
+ return (int32_t)_InterlockedDecrement((long volatile*)&Dest);
+}
+
+inline uint32_t INC_32(uint32_t volatile & Dest)
+{
+ return (uint32_t)_InterlockedIncrement((long volatile*)&Dest);
+}
+inline int32_t INC_32(int32_t volatile & Dest)
+{
+ return (int32_t)_InterlockedIncrement((long volatile*)&Dest);
+}
+
+inline bool BTS_32(uint32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+}
+inline bool BTS_32(int32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+}
+inline bool BTS_64(uint64_t volatile & Dest, uint8_t Offset)
+{
+ if (Offset > 31)
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+ else
+ return !!_interlockedbittestandset(((long volatile*)&Dest) + 1, Offset - 32);
+}
+inline bool BTS_64(int64_t volatile & Dest, uint8_t Offset)
+{
+ if (Offset > 31)
+ return !!_interlockedbittestandset((long volatile*)&Dest, Offset);
+ else
+ return !!_interlockedbittestandset(((long volatile*)&Dest) + 1, Offset - 32);
+}
+
+
+inline bool BTR_32(uint32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+}
+inline bool BTR_32(int32_t volatile & Dest, uint8_t Offset)
+{
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+}
+inline bool BTR_64(uint64_t volatile & Dest, uint8_t Offset)
+{
+ if (Offset > 31)
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+ else
+ return !!_interlockedbittestandreset(((long volatile*)&Dest) + 1, Offset - 32);
+}
+inline bool BTR_64(int64_t volatile & Dest, uint8_t Offset)
+{
+ if (Offset > 31)
+ return !!_interlockedbittestandreset((long volatile*)&Dest, Offset);
+ else
+ return !!_interlockedbittestandreset(((long volatile*)&Dest) + 1, Offset - 32);
+}
+
+inline uint32_t OR_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedOr((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t OR_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedOr((long volatile*)&Value, (long)Operator);
+}
+
+inline uint32_t AND_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedAnd((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t AND_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedAnd((long volatile*)&Value, (long)Operator);
+}
+
+inline uint32_t XOR_32(uint32_t volatile & Value, uint32_t Operator)
+{
+ return (uint32_t)_InterlockedXor((long volatile*)&Value, (long)Operator);
+}
+
+inline int32_t XOR_32(int32_t volatile & Value, int32_t Operator)
+{
+ return (int32_t)_InterlockedXor((long volatile*)&Value, (long)Operator);
+}
+
+
+inline uint32_t BSWAP_32(uint32_t Value)
+{
+ return _byteswap_ulong(Value);
+}
+
+inline uint32_t ROL_32(uint32_t Value, uint8_t Shift)
+{
+ return _rotl(Value, Shift);
+}
+inline uint32_t ROR_32(uint32_t Value, uint8_t Shift)
+{
+ return _rotr(Value, Shift);
+}
+
+
+
+#else
+
+#error unsupported architecture
+
+#endif
+
+#else
+
+#error unsupported compiler
+
+#endif
diff --git a/plugins/Dbx_tree/src/inttypes.h b/plugins/Dbx_tree/src/inttypes.h
new file mode 100644
index 0000000000..25542771f5
--- /dev/null
+++ b/plugins/Dbx_tree/src/inttypes.h
@@ -0,0 +1,305 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/plugins/Dbx_tree/src/lockfree_hashmap.h b/plugins/Dbx_tree/src/lockfree_hashmap.h
new file mode 100644
index 0000000000..7ec2df3ce4
--- /dev/null
+++ b/plugins/Dbx_tree/src/lockfree_hashmap.h
@@ -0,0 +1,749 @@
+#pragma once
+
+/*
+
+lockfree hash-multi_map based on Ori Shalev and Nir Shavit
+
+implementation
+Copyright 2009-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.
+
+*/
+
+#pragma once
+
+#include <utility>
+#include "Hash.h"
+#include "intrinsics.h"
+
+#define NodePointer(listitem) ((PListItem)(((uintptr_t)(listitem)) & ~1))
+#define NodeMark(listitem) ((bool) (((uintptr_t)(listitem)) & 1))
+
+#define HashTablePtr(hashtable) ((PHashTable)(((uintptr_t)(hashtable)) & ~31))
+#define HashTableSize(hashtable) ((uint32_t)(((uintptr_t)(hashtable)) & 31))
+#define HashTable(tableptr, tablesize) ((void*)(((uintptr_t)(tableptr)) | ((tablesize) & 31)))
+
+#define GCSelection(Sentinel) ((Sentinel) >> 63)
+#define GCRefCount0(Sentinel) ((Sentinel) & 0x7fffffff)
+#define GCRefCount1(Sentinel) (((Sentinel) >> 32) & 0x7fffffff)
+#define GCMakeSentinel(Sel, RefCount0, RefCount1) ((((uint64_t)(Sel) & 1) << 63) | (((uint64_t)(RefCount1)) << 32) | ((uint64_t)(RefCount0)))
+
+#define GCRef0 (1)
+#define GCRef1 (0x0000000100000000)
+
+namespace lockfree
+{
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t) = Hash>
+ class hash_map
+ {
+ public:
+ typedef std::pair<TKey, TData> value_type;
+
+ private:
+ typedef struct TListItem
+ {
+ TListItem * volatile Next;
+ TListItem * volatile NextPurge;
+ volatile uint32_t Hash;
+ value_type Value;
+ } TListItem, *PListItem;
+
+ typedef struct THashTable
+ {
+ volatile PListItem Table[256];
+ } THashTable, *PHashTable;
+
+ typedef struct {
+ volatile uint64_t Sentinel;
+ volatile PListItem Purge0;
+ volatile PListItem Purge1;
+ } THashTableReferences;
+
+ THashTableReferences m_GarbageCollector;
+
+ volatile uint32_t m_Count;
+ void * volatile m_HashTableData;
+
+ PListItem listInsert(PListItem BucketNode, PListItem Node);
+ PListItem listDelete(PListItem BucketNode, uint32_t Hash, const TKey & Key);
+
+ PListItem listDelete(PListItem BucketNode, PListItem Node);
+
+ bool listFind(const PListItem BucketNode, const uint32_t Hash, const TKey & Key, const PListItem Node, volatile PListItem * & Prev, PListItem & Curr, PListItem & Next);
+
+ uint32_t getMask(uint32_t Size)
+ {
+ const uint32_t mask[32] = {
+ 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
+ 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
+ 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
+ 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
+ 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
+ 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
+ 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
+ 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
+ };
+ return mask[Size - 1];
+ };
+
+ PHashTable makeNewTable()
+ {
+ void * block = malloc(sizeof(THashTable) + 32 + sizeof(void*));
+ PHashTable result = reinterpret_cast<PHashTable>((reinterpret_cast<uintptr_t>(block) + 31 + sizeof(void*)) & (~(uintptr_t)31));
+ *(reinterpret_cast<void**>(result)-1) = block;
+ memset(reinterpret_cast<void*>(result), 0, sizeof(THashTable));
+ return reinterpret_cast<PHashTable>(result);
+ };
+
+ void destroyTable(PHashTable Table)
+ {
+ free(*(reinterpret_cast<void**>(Table) - 1));
+ };
+
+ PListItem makeDummyNode(uint32_t Hash)
+ {
+ PListItem result = new TListItem;
+ result->Hash = Hash;
+ result->Next = NULL;
+ result->NextPurge = NULL;
+ return result;
+ };
+
+ bool DisposeNode(volatile PListItem * Prev, PListItem Curr, PListItem Next);
+
+ PListItem initializeBucket(uint32_t Bucket, uint32_t Mask);
+
+ PListItem getBucket(uint32_t Bucket);
+
+ void setBucket(uint32_t Bucket, PListItem Dummy);
+
+ void DeleteTable(void * Table, uint32_t Size)
+ {
+ if (Size > 8)
+ {
+ for (uint32_t i = 0; i < 256; ++i)
+ {
+ if (HashTablePtr(Table)->Table[i])
+ DeleteTable(HashTablePtr(Table)->Table[i], Size - 8);
+ }
+ }
+
+ destroyTable(HashTablePtr(Table));
+ };
+
+
+ int addRef(int GC = -1);
+ void delRef(int GC);
+
+ public:
+
+
+ class iterator
+ {
+ protected:
+ friend class hash_map<TKey, TData, FHash>;
+ PListItem m_Item;
+ typename hash_map<TKey, TData, FHash> * m_Owner;
+ int m_GC;
+
+ iterator(hash_map<TKey, TData, FHash> * Owner, PListItem Item, int GC)
+ : m_Owner(Owner)
+ {
+ m_GC = GC;
+ m_Item = Item;
+
+ while (m_Item && (!(m_Item->Hash & 1) || NodeMark(m_Item->Next)))
+ m_Item = NodePointer(m_Item->Next);
+
+ if (!m_Item && (m_GC != -1))
+ {
+ m_Owner->delRef(m_GC);
+ m_GC = -1;
+ }
+
+ };
+ public:
+ iterator(const iterator & Other)
+ : m_Owner(Other.m_Owner),
+ m_Item(Other.m_Item)
+ {
+ m_GC = -1;
+ if (Other.m_GC != -1)
+ m_GC = m_Owner->addRef(Other.m_GC);
+ };
+ ~iterator()
+ {
+ if (m_GC != -1)
+ m_Owner->delRef(m_GC);
+ };
+
+ operator bool() const
+ {
+ return m_Item != NULL;
+ };
+ bool operator !() const
+ {
+ return m_Item == NULL;
+ };
+
+ value_type * operator ->()
+ {
+ return &m_Item->Value;
+ };
+ value_type & operator *()
+ {
+ return m_Item->Value;
+ };
+
+ bool operator ==(iterator& Other)
+ {
+ return m_Item->Value.first == Other.m_Item->Value.first;
+ };
+ bool operator < (iterator & Other)
+ {
+ return m_Item->Value.first < Other.m_Item->Value.first;
+ };
+ bool operator > (iterator & Other)
+ {
+ return m_Item->Value.first > Other.m_Item->Value.first;
+ };
+
+ iterator& operator =(const iterator& Other)
+ {
+ m_Owner = Other.m_Owner;
+ m_Item = Other.m_Item;
+
+ if (Other.m_GC != m_GC)
+ {
+ if (m_GC != -1)
+ m_Owner->delRef(m_GC);
+
+ m_GC = Other.m_GC;
+
+ if (Other.m_GC != -1)
+ m_GC = m_Owner->addRef(Other.m_GC);
+
+ }
+
+ return *this;
+ };
+
+ iterator& operator ++() //pre ++i
+ {
+ if (!m_Item)
+ return *this;
+
+ int gc = m_GC;
+ m_GC = m_Owner->addRef();
+ do
+ {
+ m_Item = NodePointer(m_Item->Next);
+ } while (m_Item && (!(m_Item->Hash & 1) || NodeMark(m_Item->Next)));
+
+ m_Owner->delRef(gc);
+ if (!m_Item)
+ {
+ m_Owner->delRef(m_GC);
+ m_GC = -1;
+ }
+ return *this;
+ };
+ iterator operator ++(int) //post i++
+ {
+ iterator bak(*this);
+ ++(*this);
+ return bak;
+ };
+ };
+
+ iterator begin()
+ {
+ return iterator(this, getBucket(0), addRef());
+ };
+
+ iterator end()
+ {
+ return iterator(this, NULL, -1);
+ };
+
+ hash_map();
+ ~hash_map();
+
+ std::pair<iterator, bool> insert(const value_type & Val);
+
+ iterator find(const TKey & Key);
+
+ iterator erase(const iterator & Where);
+
+ size_t erase(const TKey & Key);
+
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ int hash_map<TKey, TData, FHash>::addRef(int GC = -1)
+ {
+ uint64_t old;
+ uint64_t newvalue;
+ int res;
+ do {
+ old = m_GarbageCollector.Sentinel;
+ if (GC == 0) // this is safe because refcount will never fall to zero because of the original reference
+ {
+ newvalue = old + GCRef0;
+ res = 0;
+ } else if (GC == 1)
+ {
+ newvalue = old + GCRef1;
+ res = 1;
+ } else {
+ if (GCSelection(old))
+ {
+ newvalue = old + GCRef1;
+ res = 1;
+ } else {
+ newvalue = old + GCRef0;
+ res = 0;
+ }
+ }
+ }
+ while (CMPXCHG_64(m_GarbageCollector.Sentinel, newvalue, old) != old);
+
+ return res;
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ void hash_map<TKey, TData, FHash>::delRef(int GC)
+ {
+ uint64_t old;
+ uint64_t newvalue;
+ PListItem purge = NULL;
+ do {
+ old = m_GarbageCollector.Sentinel;
+ if (GC)
+ {
+ newvalue = old - GCRef1;
+
+ if (!GCSelection(old) && (GCRefCount1(old) == 1)) // the other gc is activated and we are the last one
+ {
+ if (!purge) // check if we had to loop...
+ purge = m_GarbageCollector.Purge1;
+
+ m_GarbageCollector.Purge1 = NULL;
+ }
+
+ } else {
+ newvalue = old - GCRef0;
+
+ if (GCSelection(old) && (GCRefCount0(old) == 1)) // the other gc is activated and we are the last one
+ {
+ if (!purge) // check if we had to loop...
+ purge = m_GarbageCollector.Purge0;
+
+ m_GarbageCollector.Purge0 = NULL;
+ }
+
+ }
+ } while (CMPXCHG_64(m_GarbageCollector.Sentinel, newvalue, old) != old);
+
+ purge = NodePointer(purge);
+ while (purge)
+ {
+ PListItem tmp = purge;
+ purge = purge->NextPurge;
+ delete tmp;
+ };
+ };
+
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ bool hash_map<TKey, TData, FHash>::DisposeNode(volatile PListItem * Prev, PListItem Curr, PListItem Next)
+ {
+ if (NodePointer(Curr) == CMPXCHG_Ptr(*Prev, NodePointer(Next), NodePointer(Curr)))
+ {
+ uint64_t old = m_GarbageCollector.Sentinel;
+ PListItem del = NodePointer(Curr);
+
+ if (GCSelection(old))
+ {
+ del->NextPurge = (PListItem)XCHG_Ptr(m_GarbageCollector.Purge1, del);
+
+ if (!GCRefCount0(old))
+ BTR_64(m_GarbageCollector.Sentinel, 63); // switch
+
+ } else {
+
+ del->NextPurge = (PListItem)XCHG_Ptr(m_GarbageCollector.Purge0, del);
+
+ if (!GCRefCount1(old))
+ BTS_64(m_GarbageCollector.Sentinel, 63); // switch
+
+ }
+ return true;
+ }
+
+ return false;
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::PListItem hash_map<TKey, TData, FHash>::listInsert(PListItem BucketNode, PListItem Node)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+ do
+ {
+ if (listFind(BucketNode, Node->Hash, Node->Value.first, NULL, prev, curr, next))
+ return NodePointer(curr);
+
+ Node->Next = NodePointer(curr);
+
+ } while (NodePointer(curr) != CMPXCHG_Ptr(*prev, Node, NodePointer(curr)));
+ return Node;
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::PListItem hash_map<TKey, TData, FHash>::listDelete(PListItem BucketNode, uint32_t Hash, const TKey & Key)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+
+ if (!listFind(BucketNode, Hash, Key, NULL, prev, curr, next))
+ return NodePointer(curr);
+
+ do
+ {
+ if (!listFind(BucketNode, Hash, Key, NULL, prev, curr, next))
+ return NodePointer(curr);
+
+ } while (NodePointer(next) != CMPXCHG_Ptr(curr->Next, (PListItem)((uintptr_t)next | 1), NodePointer(next)));
+
+ if (!DisposeNode(prev, curr, next))
+ listFind(BucketNode, Hash, Key, NULL, prev, curr, next); // cleanup
+
+ return NodePointer(curr);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::PListItem hash_map<TKey, TData, FHash>::listDelete(PListItem BucketNode, PListItem Node)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+ if (!listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next))
+ return NodePointer(curr);
+
+ do
+ {
+ if (!listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next))
+ return NodePointer(curr);
+
+ } while (NodePointer(next) != CMPXCHG_Ptr(curr->Next, (PListItem)((uintptr_t)next | 1), NodePointer(next)));
+
+ if (!DisposeNode(prev, curr, next))
+ listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next); // cleanup
+
+ return NodePointer(curr);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ bool hash_map<TKey, TData, FHash>::listFind(const PListItem BucketNode, const uint32_t Hash, const TKey & Key, const PListItem Node, volatile PListItem * & Prev, PListItem & Curr, PListItem & Next)
+ {
+tryagain:
+ Prev = &(BucketNode->Next);
+ Curr = *Prev;
+ do
+ {
+ if (NodePointer(Curr) == NULL)
+ return false;
+
+ Next = NodePointer(Curr)->Next;
+ uint32_t h = NodePointer(Curr)->Hash;
+
+ if (*Prev != NodePointer(Curr))
+ goto tryagain; // don't judge me for that
+ //return listFind(BucketNode, Hash, Key, Node, Prev, Curr, Next); // it's the same but stack overflow can happen
+
+ if (!NodeMark(Next))
+ {
+ if (Node)
+ {
+ if ((h > Hash) || (Node == NodePointer(Curr)))
+ return NodePointer(Curr) == Node;
+ }
+ else if ((h > Hash) || ((h == Hash) && !(NodePointer(Curr)->Value.first < Key)))
+ {
+ return (h == Hash) && (NodePointer(Curr)->Value.first == Key);
+ }
+
+ Prev = &(NodePointer(Curr)->Next);
+ } else {
+ if (!DisposeNode(Prev, Curr, Next))
+ goto tryagain; // don't judge me for that
+ //return listFind(BucketNode, Hash, Key, Node, Prev, Curr, Next); // it's the same but stack overflow can happen
+ }
+ Curr = Next;
+ } while (true);
+
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::PListItem hash_map<TKey, TData, FHash>::initializeBucket(uint32_t Bucket, uint32_t Mask)
+ {
+ uint32_t parent = Bucket & (Mask << 1);
+ PListItem parentnode = getBucket(parent);
+ if (parentnode == NULL)
+ parentnode = initializeBucket(parent, Mask << 1);
+
+ PListItem dummy = makeDummyNode(Bucket);
+ PListItem bucketnode = listInsert(parentnode, dummy);
+ if (bucketnode != dummy)
+ {
+ delete dummy;
+ dummy = bucketnode;
+ }
+ setBucket(Bucket, dummy);
+
+ return dummy;
+ }
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::PListItem hash_map<TKey, TData, FHash>::getBucket(uint32_t Bucket)
+ {
+ void * table;
+ uint32_t mask;
+
+ table = (void*)m_HashTableData;
+ mask = getMask(HashTableSize(table));
+
+ uint32_t levelshift = (32 - HashTableSize(table)) & ~7;
+
+ while (levelshift < 24)
+ {
+ table = HashTablePtr(table)->Table[((Bucket & mask) >> levelshift) & 0xff];
+ levelshift = levelshift + 8;
+ if (!HashTablePtr(table))
+ return NULL;
+ }
+ return HashTablePtr(table)->Table[(Bucket & mask) >> 24];
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ void hash_map<TKey, TData, FHash>::setBucket(uint32_t Bucket, PListItem Dummy)
+ {
+ void * table;
+ void *volatile * last;
+ uint32_t mask;
+
+ table = m_HashTableData;
+ mask = getMask(HashTableSize(table));
+
+ uint32_t levelshift = (32 - HashTableSize(table)) & ~7;
+
+ while (levelshift < 24)
+ {
+ last = (void*volatile*)&HashTablePtr(table)->Table[((Bucket & mask) >> levelshift) & 0xff];
+ table = *last;
+ levelshift = levelshift + 8;
+ if (!table)
+ {
+ PHashTable newtable = makeNewTable();
+ table = CMPXCHG_Ptr<void>(*last, newtable, NULL);
+ if (table)
+ {
+ destroyTable(newtable);
+ } else {
+ table = newtable;
+ }
+ }
+ }
+ HashTablePtr(table)->Table[(Bucket & mask) >> 24] = Dummy;
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ hash_map<TKey, TData, FHash>::hash_map()
+ {
+ m_Count = 0;
+
+ m_GarbageCollector.Sentinel = GCMakeSentinel(0,0,0);
+ m_GarbageCollector.Purge0 = NULL;
+ m_GarbageCollector.Purge1 = NULL;
+
+ m_HashTableData = HashTable(makeNewTable(), 1);
+ setBucket(0x00000000, makeDummyNode(0x00000000));
+ setBucket(0x80000000, makeDummyNode(0x80000000));
+ HashTablePtr(m_HashTableData)->Table[0]->Next = getBucket(0x80000000);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ hash_map<TKey, TData, FHash>::~hash_map()
+ {
+ PListItem h = getBucket(0);
+ DeleteTable(HashTablePtr(m_HashTableData), HashTableSize(m_HashTableData));
+
+ while (h)
+ {
+ PListItem tmp = h;
+ h = NodePointer(h->Next);
+ delete tmp;
+ };
+
+ h = m_GarbageCollector.Purge0;
+ while (h)
+ {
+ PListItem tmp = h;
+ h = h->NextPurge;
+ delete tmp;
+ };
+
+ h = m_GarbageCollector.Purge1;
+ while (h)
+ {
+ PListItem tmp = h;
+ h = h->NextPurge;
+ delete tmp;
+ };
+
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename std::pair<typename hash_map<TKey, TData, FHash>::iterator, bool> hash_map<TKey, TData, FHash>::insert(const value_type & Val)
+ {
+ int gc = addRef();
+ PListItem node = new TListItem;
+ node->Value = Val;
+ node->Hash = FHash(&node->Value.first, sizeof(TKey)) | 1;
+ node->NextPurge = NULL;
+ node->Next = NULL;
+
+ void * tmp;
+ void * newdata;
+ tmp = (void*)m_HashTableData;
+
+ uint32_t mask = getMask(HashTableSize(tmp));
+
+ uint32_t bucket = node->Hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+ PListItem retnode = listInsert(bucketnode, node);
+ if (retnode != node)
+ {
+ delete node;
+ return std::make_pair(iterator(this, retnode, gc), false);
+ }
+
+ if ((INC_32(m_Count) > ((uint32_t)1 << (HashTableSize(tmp) + 3))) && (HashTableSize(tmp) < 31) && (HashTableSize(tmp) == HashTableSize(m_HashTableData)))
+ {
+ newdata = HashTable(HashTablePtr(tmp), HashTableSize(tmp) + 1);
+
+ if ((HashTableSize(tmp) & 0x7) == 0)
+ {
+ newdata = HashTable(makeNewTable(), HashTableSize(tmp) + 1);
+ HashTablePtr(newdata)->Table[0] = (TListItem*)HashTablePtr(tmp);
+
+ if (tmp != CMPXCHG_Ptr(m_HashTableData, newdata, tmp))
+ destroyTable(HashTablePtr(newdata)); // someone else expanded the table.
+ } else {
+ CMPXCHG_Ptr(m_HashTableData, newdata, tmp);
+ }
+
+ }
+
+ return std::make_pair(iterator(this, node, gc), true);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::iterator hash_map<TKey, TData, FHash>::find(const TKey & Key)
+ {
+ int gc = addRef();
+ uint32_t hash = FHash(&Key, sizeof(TKey)) | 1;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem volatile * prev;
+ PListItem curr, next;
+ if (listFind(bucketnode, hash, Key, NULL, prev, curr, next))
+ return iterator(this, NodePointer(curr), gc);
+
+ return iterator(this, NULL, gc);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_map<TKey, TData, FHash>::iterator hash_map<TKey, TData, FHash>::erase(const iterator & Where)
+ {
+ int gc = addRef();
+ uint32_t hash = Where.m_Item->Hash;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem res = listDelete(bucketnode, Where.m_Item);
+ if (Where.m_Item == res)
+ {
+ DEC_32(m_Count);
+ return iterator(this, NodePointer(res->Next), gc);
+ }
+ return iterator(this, res, gc);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ size_t hash_map<TKey, TData, FHash>::erase(const TKey & Key)
+ {
+ int gc = addRef();
+ uint32_t hash = FHash(&Key, sizeof(TKey)) | 1;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem result = listDelete(bucketnode, hash, Key);
+ if (result && (result->Value.first == Key))
+ {
+ DEC_32(m_Count);
+ delRef(gc);
+ return 1;
+ }
+
+ delRef(gc);
+ return 0;
+ };
+}
+
+#undef NodePointer
+#undef NodeMark
+
+#undef HashTablePtr
+#undef HashTableSize
+#undef HashTable
+
+#undef GCSelection
+#undef GCRefCount0
+#undef GCRefCount1
+#undef GCMakeSentinel
+
diff --git a/plugins/Dbx_tree/src/lockfree_hashmultimap.h b/plugins/Dbx_tree/src/lockfree_hashmultimap.h
new file mode 100644
index 0000000000..79981e5447
--- /dev/null
+++ b/plugins/Dbx_tree/src/lockfree_hashmultimap.h
@@ -0,0 +1,750 @@
+#pragma once
+
+/*
+
+lockfree hash-multi_map based on Ori Shalev and Nir Shavit
+
+implementation
+Copyright 2009-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.
+
+*/
+
+#pragma once
+
+#include <utility>
+#include "Hash.h"
+#include "intrinsics.h"
+
+#define NodePointer(listitem) ((PListItem)(((uintptr_t)(listitem)) & ~1))
+#define NodeMark(listitem) ((bool) (((uintptr_t)(listitem)) & 1))
+
+#define HashTablePtr(hashtable) ((PHashTable)(((uintptr_t)(hashtable)) & ~31))
+#define HashTableSize(hashtable) ((uint32_t)(((uintptr_t)(hashtable)) & 31))
+#define HashTable(tableptr, tablesize) ((void*)(((uintptr_t)(tableptr)) | ((tablesize) & 31)))
+
+#define GCSelection(Sentinel) ((Sentinel) >> 63)
+#define GCRefCount0(Sentinel) ((Sentinel) & 0x7fffffff)
+#define GCRefCount1(Sentinel) (((Sentinel) >> 32) & 0x7fffffff)
+#define GCMakeSentinel(Sel, RefCount0, RefCount1) ((((uint64_t)(Sel) & 1) << 63) | (((uint64_t)(RefCount1)) << 32) | ((uint64_t)(RefCount0)))
+
+#define GCRef0 (1)
+#define GCRef1 (0x0000000100000000)
+
+namespace lockfree
+{
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t) = Hash>
+ class hash_multimap
+ {
+ public:
+ typedef std::pair<TKey, TData> value_type;
+
+ private:
+ typedef struct TListItem
+ {
+ TListItem * volatile Next;
+ TListItem * volatile NextPurge;
+ volatile uint32_t Hash;
+ value_type Value;
+ } TListItem, *PListItem;
+
+ typedef struct THashTable
+ {
+ volatile PListItem Table[256];
+ } THashTable, *PHashTable;
+
+ typedef struct {
+ volatile uint64_t Sentinel;
+ volatile PListItem Purge0;
+ volatile PListItem Purge1;
+ } THashTableReferences;
+
+ THashTableReferences m_GarbageCollector;
+
+ volatile uint32_t m_Count;
+ void * volatile m_HashTableData;
+
+ PListItem listInsert(PListItem BucketNode, PListItem Node);
+ PListItem listDelete(PListItem BucketNode, uint32_t Hash, const TKey & Key);
+
+ PListItem listDelete(PListItem BucketNode, PListItem Node);
+
+ bool listFind(const PListItem BucketNode, const uint32_t Hash, const TKey & Key, const PListItem Node, volatile PListItem * & Prev, PListItem & Curr, PListItem & Next);
+
+ uint32_t getMask(uint32_t Size)
+ {
+ const uint32_t mask[32] = {
+ 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
+ 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
+ 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
+ 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
+ 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
+ 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
+ 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
+ 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
+ };
+ return mask[Size - 1];
+ };
+
+ PHashTable makeNewTable()
+ {
+ void * block = malloc(sizeof(THashTable) + 32 + sizeof(void*));
+ PHashTable result = reinterpret_cast<PHashTable>((reinterpret_cast<uintptr_t>(block) + 31 + sizeof(void*)) & (~(uintptr_t)31));
+ *(reinterpret_cast<void**>(result)-1) = block;
+ memset(reinterpret_cast<void*>(result), 0, sizeof(THashTable));
+ return reinterpret_cast<PHashTable>(result);
+ };
+
+ void destroyTable(PHashTable Table)
+ {
+ free(*(reinterpret_cast<void**>(Table) - 1));
+ };
+
+ PListItem makeDummyNode(uint32_t Hash)
+ {
+ PListItem result = new TListItem;
+ result->Hash = Hash;
+ result->Next = NULL;
+ result->NextPurge = NULL;
+ return result;
+ };
+
+ bool DisposeNode(volatile PListItem * Prev, PListItem Curr, PListItem Next);
+
+ PListItem initializeBucket(uint32_t Bucket, uint32_t Mask);
+
+ PListItem getBucket(uint32_t Bucket);
+
+ void setBucket(uint32_t Bucket, PListItem Dummy);
+
+ void DeleteTable(void * Table, uint32_t Size)
+ {
+ if (Size > 8)
+ {
+ for (uint32_t i = 0; i < 256; ++i)
+ {
+ if (HashTablePtr(Table)->Table[i])
+ DeleteTable(HashTablePtr(Table)->Table[i], Size - 8);
+ }
+ }
+
+ destroyTable(HashTablePtr(Table));
+ };
+
+
+ int addRef(int GC = -1);
+ void delRef(int GC);
+
+ public:
+
+
+ class iterator
+ {
+ protected:
+ friend class hash_multimap<TKey, TData, FHash>;
+ PListItem m_Item;
+ typename hash_multimap<TKey, TData, FHash> * m_Owner;
+ int m_GC;
+
+ iterator(hash_multimap<TKey, TData, FHash> * Owner, PListItem Item, int GC)
+ : m_Owner(Owner)
+ {
+ m_GC = GC;
+ m_Item = Item;
+
+ while (m_Item && (!(m_Item->Hash & 1) || NodeMark(m_Item->Next)))
+ m_Item = NodePointer(m_Item->Next);
+
+ if (!m_Item && (m_GC != -1))
+ {
+ m_Owner->delRef(m_GC);
+ m_GC = -1;
+ }
+
+ };
+ public:
+ iterator(const iterator & Other)
+ : m_Owner(Other.m_Owner),
+ m_Item(Other.m_Item)
+ {
+ m_GC = -1;
+ if (Other.m_GC != -1)
+ m_GC = m_Owner->addRef(Other.m_GC);
+ };
+ ~iterator()
+ {
+ if (m_GC != -1)
+ m_Owner->delRef(m_GC);
+ };
+
+ operator bool() const
+ {
+ return m_Item != NULL;
+ };
+ bool operator !() const
+ {
+ return m_Item == NULL;
+ };
+
+ value_type * operator ->()
+ {
+ return &m_Item->Value;
+ };
+ value_type & operator *()
+ {
+ return m_Item->Value;
+ };
+
+ bool operator ==(iterator& Other)
+ {
+ return m_Item->Value.first == Other.m_Item->Value.first;
+ };
+ bool operator < (iterator & Other)
+ {
+ return m_Item->Value.first < Other.m_Item->Value.first;
+ };
+ bool operator > (iterator & Other)
+ {
+ return m_Item->Value.first > Other.m_Item->Value.first;
+ };
+
+ iterator& operator =(const iterator& Other)
+ {
+ m_Owner = Other.m_Owner;
+ m_Item = Other.m_Item;
+
+ if (Other.m_GC != m_GC)
+ {
+ if (m_GC != -1)
+ m_Owner->delRef(m_GC);
+
+ m_GC = Other.m_GC;
+
+ if (Other.m_GC != -1)
+ m_GC = m_Owner->addRef(Other.m_GC);
+
+ }
+
+ return *this;
+ };
+
+ iterator& operator ++() //pre ++i
+ {
+ if (!m_Item)
+ return *this;
+
+ int gc = m_GC;
+ m_GC = m_Owner->addRef();
+ do
+ {
+ m_Item = NodePointer(m_Item->Next);
+ } while (m_Item && (!(m_Item->Hash & 1) || NodeMark(m_Item->Next)));
+
+ m_Owner->delRef(gc);
+ if (!m_Item)
+ {
+ m_Owner->delRef(m_GC);
+ m_GC = -1;
+ }
+ return *this;
+ };
+ iterator operator ++(int) //post i++
+ {
+ iterator bak(*this);
+ ++(*this);
+ return bak;
+ };
+ };
+
+ iterator begin()
+ {
+ return iterator(this, getBucket(0), addRef());
+ };
+
+ iterator end()
+ {
+ return iterator(this, NULL, -1);
+ };
+
+ hash_multimap();
+ ~hash_multimap();
+
+ std::pair<iterator, bool> insert(const value_type & Val);
+
+ iterator find(const TKey & Key);
+
+ iterator erase(const iterator & Where);
+
+ size_t erase(const TKey & Key);
+
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ int hash_multimap<TKey, TData, FHash>::addRef(int GC = -1)
+ {
+ uint64_t old;
+ uint64_t newvalue;
+ int res;
+ do {
+ old = m_GarbageCollector.Sentinel;
+ if (GC == 0) // this is safe because refcount will never fall to zero because of the original reference
+ {
+ newvalue = old + GCRef0;
+ res = 0;
+ } else if (GC == 1)
+ {
+ newvalue = old + GCRef1;
+ res = 1;
+ } else {
+ if (GCSelection(old))
+ {
+ newvalue = old + GCRef1;
+ res = 1;
+ } else {
+ newvalue = old + GCRef0;
+ res = 0;
+ }
+ }
+ }
+ while (CMPXCHG_64(m_GarbageCollector.Sentinel, newvalue, old) != old);
+
+ return res;
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ void hash_multimap<TKey, TData, FHash>::delRef(int GC)
+ {
+ uint64_t old;
+ uint64_t newvalue;
+ PListItem purge = NULL;
+ do {
+ old = m_GarbageCollector.Sentinel;
+ if (GC)
+ {
+ newvalue = old - GCRef1;
+
+ if (!GCSelection(old) && (GCRefCount1(old) == 1)) // the other gc is activated and we are the last one
+ {
+ if (!purge) // check if we had to loop...
+ purge = m_GarbageCollector.Purge1;
+
+ m_GarbageCollector.Purge1 = NULL;
+ }
+
+ } else {
+ newvalue = old - GCRef0;
+
+ if (GCSelection(old) && (GCRefCount0(old) == 1)) // the other gc is activated and we are the last one
+ {
+ if (!purge) // check if we had to loop...
+ purge = m_GarbageCollector.Purge0;
+
+ m_GarbageCollector.Purge0 = NULL;
+ }
+
+ }
+ } while (CMPXCHG_64(m_GarbageCollector.Sentinel, newvalue, old) != old);
+
+ purge = NodePointer(purge);
+ while (purge)
+ {
+ PListItem tmp = purge;
+ purge = purge->NextPurge;
+ delete tmp;
+ };
+ };
+
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ bool hash_multimap<TKey, TData, FHash>::DisposeNode(volatile PListItem * Prev, PListItem Curr, PListItem Next)
+ {
+ if (NodePointer(Curr) == CMPXCHG_Ptr(*Prev, NodePointer(Next), NodePointer(Curr)))
+ {
+ uint64_t old = m_GarbageCollector.Sentinel;
+ PListItem del = NodePointer(Curr);
+
+ if (GCSelection(old))
+ {
+ del->NextPurge = (PListItem)XCHG_Ptr(m_GarbageCollector.Purge1, del);
+
+ if (!GCRefCount0(old))
+ BTR_64(m_GarbageCollector.Sentinel, 63); // switch
+
+ } else {
+
+ del->NextPurge = (PListItem)XCHG_Ptr(m_GarbageCollector.Purge0, del);
+
+ if (!GCRefCount1(old))
+ BTS_64(m_GarbageCollector.Sentinel, 63); // switch
+
+ }
+ return true;
+ }
+
+ return false;
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::PListItem hash_multimap<TKey, TData, FHash>::listInsert(PListItem BucketNode, PListItem Node)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+ do
+ {
+ listFind(BucketNode, Node->Hash, Node->Value.first, NULL, prev, curr, next);
+
+ Node->Next = NodePointer(curr);
+
+ } while (NodePointer(curr) != CMPXCHG_Ptr(*prev, Node, NodePointer(curr)));
+ return Node;
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::PListItem hash_multimap<TKey, TData, FHash>::listDelete(PListItem BucketNode, uint32_t Hash, const TKey & Key)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+
+ if (!listFind(BucketNode, Hash, Key, NULL, prev, curr, next))
+ return NodePointer(curr);
+
+ do
+ {
+ if (!listFind(BucketNode, Hash, Key, NULL, prev, curr, next))
+ return NodePointer(curr);
+
+ } while (NodePointer(next) != CMPXCHG_Ptr(curr->Next, (PListItem)((uintptr_t)next | 1), NodePointer(next)));
+
+ if (!DisposeNode(prev, curr, next))
+ listFind(BucketNode, Hash, Key, NULL, prev, curr, next); // cleanup
+
+ return NodePointer(curr);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::PListItem hash_multimap<TKey, TData, FHash>::listDelete(PListItem BucketNode, PListItem Node)
+ {
+ PListItem volatile * prev;
+ PListItem curr, next;
+ if (!listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next))
+ return NodePointer(curr);
+
+ do
+ {
+ if (!listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next))
+ return NodePointer(curr);
+
+ } while (NodePointer(next) != CMPXCHG_Ptr(curr->Next, (PListItem)((uintptr_t)next | 1), NodePointer(next)));
+
+ if (!DisposeNode(prev, curr, next))
+ listFind(BucketNode, Node->Hash, Node->Value.first, Node, prev, curr, next); // cleanup
+
+ return NodePointer(curr);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ bool hash_multimap<TKey, TData, FHash>::listFind(const PListItem BucketNode, const uint32_t Hash, const TKey & Key, const PListItem Node, volatile PListItem * & Prev, PListItem & Curr, PListItem & Next)
+ {
+tryagain:
+ Prev = &(BucketNode->Next);
+ Curr = *Prev;
+ do
+ {
+ if (NodePointer(Curr) == NULL)
+ return false;
+
+ Next = NodePointer(Curr)->Next;
+ uint32_t h = NodePointer(Curr)->Hash;
+
+ if (*Prev != NodePointer(Curr))
+ goto tryagain; // don't judge me for that
+ //return listFind(BucketNode, Hash, Key, Node, Prev, Curr, Next); // it's the same but stack overflow can happen
+
+ if (!NodeMark(Next))
+ {
+ if (Node)
+ {
+ if ((h > Hash) || (Node == NodePointer(Curr)))
+ return NodePointer(Curr) == Node;
+ }
+ else if ((h > Hash) || ((h == Hash) && !(NodePointer(Curr)->Value.first < Key)))
+ {
+ return (h == Hash) && (NodePointer(Curr)->Value.first == Key);
+ }
+
+ Prev = &(NodePointer(Curr)->Next);
+ } else {
+ if (!DisposeNode(Prev, Curr, Next))
+ goto tryagain; // don't judge me for that
+ //return listFind(BucketNode, Hash, Key, Node, Prev, Curr, Next); // it's the same but stack overflow can happen
+ }
+ Curr = Next;
+ } while (true);
+
+ };
+
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::PListItem hash_multimap<TKey, TData, FHash>::initializeBucket(uint32_t Bucket, uint32_t Mask)
+ {
+ uint32_t parent = Bucket & (Mask << 1);
+ PListItem parentnode = getBucket(parent);
+ if (parentnode == NULL)
+ parentnode = initializeBucket(parent, Mask << 1);
+
+ PListItem dummy = makeDummyNode(Bucket);
+ PListItem bucketnode = listInsert(parentnode, dummy);
+ if (bucketnode != dummy)
+ {
+ delete dummy;
+ dummy = bucketnode;
+ }
+ setBucket(Bucket, dummy);
+
+ return dummy;
+ }
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::PListItem hash_multimap<TKey, TData, FHash>::getBucket(uint32_t Bucket)
+ {
+ void * table;
+ uint32_t mask;
+
+ table = (void*)m_HashTableData;
+ mask = getMask(HashTableSize(table));
+
+ uint32_t levelshift = (32 - HashTableSize(table)) & ~7;
+
+ while (levelshift < 24)
+ {
+ table = HashTablePtr(table)->Table[((Bucket & mask) >> levelshift) & 0xff];
+ levelshift = levelshift + 8;
+ if (!HashTablePtr(table))
+ return NULL;
+ }
+ return HashTablePtr(table)->Table[(Bucket & mask) >> 24];
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ void hash_multimap<TKey, TData, FHash>::setBucket(uint32_t Bucket, PListItem Dummy)
+ {
+ void * table;
+ void *volatile * last;
+ uint32_t mask;
+
+ table = m_HashTableData;
+ mask = getMask(HashTableSize(table));
+
+ uint32_t levelshift = (32 - HashTableSize(table)) & ~7;
+
+ while (levelshift < 24)
+ {
+ last = (void*volatile*)&HashTablePtr(table)->Table[((Bucket & mask) >> levelshift) & 0xff];
+ table = *last;
+ levelshift = levelshift + 8;
+ if (!table)
+ {
+ PHashTable newtable = makeNewTable();
+ table = CMPXCHG_Ptr<void>(*last, newtable, NULL);
+ if (table)
+ {
+ destroyTable(newtable);
+ } else {
+ table = newtable;
+ }
+ }
+ }
+ HashTablePtr(table)->Table[(Bucket & mask) >> 24] = Dummy;
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ hash_multimap<TKey, TData, FHash>::hash_multimap()
+ {
+ m_Count = 0;
+
+ m_GarbageCollector.Sentinel = GCMakeSentinel(0,0,0);
+ m_GarbageCollector.Purge0 = NULL;
+ m_GarbageCollector.Purge1 = NULL;
+
+ m_HashTableData = HashTable(makeNewTable(), 1);
+ setBucket(0x00000000, makeDummyNode(0x00000000));
+ setBucket(0x80000000, makeDummyNode(0x80000000));
+ HashTablePtr(m_HashTableData)->Table[0]->Next = getBucket(0x80000000);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ hash_multimap<TKey, TData, FHash>::~hash_multimap()
+ {
+ PListItem h = getBucket(0);
+ DeleteTable(HashTablePtr(m_HashTableData), HashTableSize(m_HashTableData));
+
+ while (h)
+ {
+ PListItem tmp = h;
+ h = NodePointer(h->Next);
+ delete tmp;
+ };
+
+ h = m_GarbageCollector.Purge0;
+ while (h)
+ {
+ PListItem tmp = h;
+ h = h->NextPurge;
+ delete tmp;
+ };
+
+ h = m_GarbageCollector.Purge1;
+ while (h)
+ {
+ PListItem tmp = h;
+ h = h->NextPurge;
+ delete tmp;
+ };
+
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename std::pair<typename hash_multimap<TKey, TData, FHash>::iterator, bool> hash_multimap<TKey, TData, FHash>::insert(const value_type & Val)
+ {
+ int gc = addRef();
+ PListItem node = new TListItem;
+ node->Value = Val;
+ node->Hash = FHash(&node->Value.first, sizeof(TKey)) | 1;
+ node->NextPurge = NULL;
+ node->Next = NULL;
+
+ void * tmp;
+ void * newdata;
+ tmp = (void*)m_HashTableData;
+
+ uint32_t mask = getMask(HashTableSize(tmp));
+
+ uint32_t bucket = node->Hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+ PListItem retnode = listInsert(bucketnode, node);
+ if (retnode != node)
+ {
+ delete node;
+ return std::make_pair(iterator(this, retnode, gc), false);
+ }
+
+ if ((INC_32(m_Count) > ((uint32_t)1 << (HashTableSize(tmp) + 3))) && (HashTableSize(tmp) < 31) && (HashTableSize(tmp) == HashTableSize(m_HashTableData)))
+ {
+ newdata = HashTable(HashTablePtr(tmp), HashTableSize(tmp) + 1);
+
+ if ((HashTableSize(tmp) & 0x7) == 0)
+ {
+ newdata = HashTable(makeNewTable(), HashTableSize(tmp) + 1);
+ HashTablePtr(newdata)->Table[0] = (TListItem*)HashTablePtr(tmp);
+
+ if (tmp != CMPXCHG_Ptr(m_HashTableData, newdata, tmp))
+ destroyTable(HashTablePtr(newdata)); // someone else expanded the table.
+ } else {
+ CMPXCHG_Ptr(m_HashTableData, newdata, tmp);
+ }
+
+ }
+
+ return std::make_pair(iterator(this, node, gc), true);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::iterator hash_multimap<TKey, TData, FHash>::find(const TKey & Key)
+ {
+ int gc = addRef();
+ uint32_t hash = FHash(&Key, sizeof(TKey)) | 1;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem volatile * prev;
+ PListItem curr, next;
+ if (listFind(bucketnode, hash, Key, NULL, prev, curr, next))
+ return iterator(this, NodePointer(curr), gc);
+
+ return iterator(this, NULL, gc);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ typename hash_multimap<TKey, TData, FHash>::iterator hash_multimap<TKey, TData, FHash>::erase(const iterator & Where)
+ {
+ int gc = addRef();
+ uint32_t hash = Where.m_Item->Hash;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem res = listDelete(bucketnode, Where.m_Item);
+ if (Where.m_Item == res)
+ {
+ DEC_32(m_Count);
+ return iterator(this, NodePointer(res->Next), gc);
+ }
+ return iterator(this, res, gc);
+ };
+
+ template <typename TKey, typename TData, uint32_t (*FHash)(const void *, uint32_t)>
+ size_t hash_multimap<TKey, TData, FHash>::erase(const TKey & Key)
+ {
+ int gc = addRef();
+ int count = 0;
+ uint32_t hash = FHash(&Key, sizeof(TKey)) | 1;
+ uint32_t mask = getMask(HashTableSize(m_HashTableData));
+ uint32_t bucket = hash & mask;
+ PListItem bucketnode = getBucket(bucket);
+
+ if (bucketnode == NULL)
+ bucketnode = initializeBucket(bucket, mask);
+
+ PListItem volatile * prev;
+ PListItem curr, next;
+ while (listFind(bucketnode, hash, Key, NULL, prev, curr, next))
+ {
+ if (curr == listDelete(bucketnode, curr))
+ count++;
+ }
+
+ XADD_32(m_Count, -count);
+ delRef(gc);
+ return count;
+ };
+}
+
+#undef NodePointer
+#undef NodeMark
+
+#undef HashTablePtr
+#undef HashTableSize
+#undef HashTable
+
+#undef GCSelection
+#undef GCRefCount0
+#undef GCRefCount1
+#undef GCMakeSentinel
+
diff --git a/plugins/Dbx_tree/src/savestrings_gcc.h b/plugins/Dbx_tree/src/savestrings_gcc.h
new file mode 100644
index 0000000000..9da680874d
--- /dev/null
+++ b/plugins/Dbx_tree/src/savestrings_gcc.h
@@ -0,0 +1,127 @@
+/*
+
+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.
+
+*/
+
+#pragma once
+
+inline int strcpy_s(
+ char *strDestination,
+ size_t numberOfElements,
+ const char *strSource
+)
+{
+ if (!strDestination) return EINVAL;
+ if (!strSource) {strDestination[0] = 0; return EINVAL;}
+ size_t l = strlen(strSource);
+ if (numberOfElements < l + 1) {strDestination[0] = 0; return ERANGE;}
+ memcpy(strDestination, strSource, l + 1);
+ return 0;
+}
+
+template <size_t size>
+inline int strcpy_s(
+ char (&strDestination)[size],
+ const char *strSource
+)
+{
+ if (!strDestination) return EINVAL;
+ if (!strSource) {strDestination[0] = 0; return EINVAL;}
+ size_t l = strlen(strSource);
+ if (size < l + 1) {strDestination[0] = 0; return ERANGE;}
+
+ memcpy(strDestination, strSource, l + 1);
+ return 0;
+}
+
+
+inline int strcat_s(
+ char *strDestination,
+ size_t numberOfElements,
+ const char *strSource
+)
+{
+ if (!strDestination) return EINVAL;
+ if (!strSource) {strDestination[0] = 0; return EINVAL;}
+ size_t l = strlen(strSource);
+ size_t m = strlen(strDestination);
+ if (numberOfElements < l + m + 1) {strDestination[0] = 0; return ERANGE;}
+
+ memcpy(&strDestination[m], strSource, l + 1);
+ return 0;
+}
+
+template <size_t size>
+inline int strcat_s(
+ char (&strDestination)[size],
+ const char *strSource
+)
+{
+ if (!strDestination) return EINVAL;
+ if (!strSource) {strDestination[0] = 0; return EINVAL;}
+ size_t l = strlen(strSource);
+ size_t m = strlen(strDestination);
+ if (size < l + m + 1) {strDestination[0] = 0; return ERANGE;}
+
+ memcpy(&strDestination[m], strSource, l + 1);
+ return 0;
+}
+
+inline int strncpy_s(
+ char *strDest,
+ size_t numberOfElements,
+ const char *strSource,
+ size_t count
+)
+{
+ if (count > numberOfElements)
+ return strcpy_s(strDest, numberOfElements, strSource);
+ else
+ return strcpy_s(strDest, count + 1, strSource);
+}
+
+
+template <size_t size>
+inline int sprintf_s(
+ char (&buffer)[size],
+ const char *format,
+ ...
+)
+{
+ va_list va;
+ va_start(va, format);
+ vsnprintf(buffer, size, format, va);
+ va_end(va);
+}
+
+template <size_t size>
+inline int swprintf_s(
+ wchar_t (&buffer)[size],
+ const wchar_t *format,
+ ...
+)
+{
+ va_list va;
+ va_start(va, format);
+ vsnwprintf(buffer, size, format, va);
+ va_end(va);
+}
+
+#define vsprintf_s vsnprintf
diff --git a/plugins/Dbx_tree/src/sigslot.h b/plugins/Dbx_tree/src/sigslot.h
new file mode 100644
index 0000000000..1e67a152bf
--- /dev/null
+++ b/plugins/Dbx_tree/src/sigslot.h
@@ -0,0 +1,2639 @@
+// sigslot.h: Signal/Slot classes
+//
+// Written by Sarah Thompson (sarah@telergy.com) 2002.
+//
+// License: Public domain. You are free to use this code however you like, with the proviso that
+// the author takes on no responsibility or liability for any use.
+//
+// QUICK DOCUMENTATION
+//
+// (see also the full documentation at http://sigslot.sourceforge.net/)
+//
+// #define switches
+// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables
+// all of the thread safety support on platforms where it is
+// available.
+//
+// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than
+// gcc on a platform that supports Posix threads. (When using gcc,
+// this is the default - use SIGSLOT_PURE_ISO to disable this if
+// necessary)
+//
+// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global.
+// Otherwise, the default is single_threaded. #define this yourself to
+// override the default. In pure ISO mode, anything other than
+// single_threaded will cause a compiler error.
+//
+// PLATFORM NOTES
+//
+// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream
+// compilers do this by default, but you may need to define it
+// yourself if your build environment is less standard. This causes
+// the Win32 thread support to be compiled in and used automatically.
+//
+// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads
+// available, so they are used automatically. You can override this
+// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
+// something other than gcc but still want to use Posix threads, you
+// need to #define SIGSLOT_USE_POSIX_THREADS.
+//
+// ISO C++ - If none of the supported platforms are detected, or if
+// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
+// along with any code that might cause a pure ISO C++ environment to
+// complain. Before you ask, gcc -ansi -pedantic won't compile this
+// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
+// errors that aren't really there. If you feel like investigating this,
+// please contact the author.
+//
+//
+// THREADING MODES
+//
+// single_threaded - Your program is assumed to be single threaded from the point of view
+// of signal/slot usage (i.e. all objects using signals and slots are
+// created and destroyed from a single thread). Behaviour if objects are
+// destroyed concurrently is undefined (i.e. you'll get the occasional
+// segmentation fault/memory exception).
+//
+// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and
+// slots can be safely created and destroyed from any thread, even when
+// connections exist. In multi_threaded_global mode, this is achieved by a
+// single global mutex (actually a critical section on Windows because they
+// are faster). This option uses less OS resources, but results in more
+// opportunities for contention, possibly resulting in more context switches
+// than are strictly necessary.
+//
+// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global,
+// except that each signal, and each object that inherits has_slots, all
+// have their own mutex/critical section. In practice, this means that
+// mutex collisions (and hence context switches) only happen if they are
+// absolutely essential. However, on some platforms, creating a lot of
+// mutexes can slow down the whole OS, so use this option with care.
+//
+// USING THE LIBRARY
+//
+// See the full documentation at http://sigslot.sourceforge.net/
+//
+//
+
+#ifndef SIGSLOT_H__
+#define SIGSLOT_H__
+
+#include <set>
+#include <list>
+
+#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
+# define _SIGSLOT_SINGLE_THREADED
+#elif defined(WIN32)
+# define _SIGSLOT_HAS_WIN32_THREADS
+# include <windows.h>
+#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
+# define _SIGSLOT_HAS_POSIX_THREADS
+# include <pthread.h>
+#else
+# define _SIGSLOT_SINGLE_THREADED
+#endif
+
+#define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_global
+
+#ifndef SIGSLOT_DEFAULT_MT_POLICY
+# ifdef _SIGSLOT_SINGLE_THREADED
+# define SIGSLOT_DEFAULT_MT_POLICY single_threaded
+# else
+# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
+# endif
+#endif
+
+
+namespace sigslot {
+
+ class single_threaded
+ {
+ public:
+ single_threaded()
+ {
+ ;
+ }
+
+ ~single_threaded()
+ {
+ ;
+ }
+
+ void lock()
+ {
+ ;
+ }
+
+ void unlock()
+ {
+ ;
+ }
+ };
+
+#ifdef _SIGSLOT_HAS_WIN32_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ static bool isinitialised = false;
+
+ if (!isinitialised)
+ {
+ InitializeCriticalSection(get_critsec());
+ isinitialised = true;
+ }
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ ~multi_threaded_global()
+ {
+ ;
+ }
+
+ void lock()
+ {
+ EnterCriticalSection(get_critsec());
+ }
+
+ void unlock()
+ {
+ LeaveCriticalSection(get_critsec());
+ }
+
+ private:
+ CRITICAL_SECTION* get_critsec()
+ {
+ static CRITICAL_SECTION g_critsec;
+ return &g_critsec;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ InitializeCriticalSection(&m_critsec);
+ }
+
+ ~multi_threaded_local()
+ {
+ DeleteCriticalSection(&m_critsec);
+ }
+
+ void lock()
+ {
+ EnterCriticalSection(&m_critsec);
+ }
+
+ void unlock()
+ {
+ LeaveCriticalSection(&m_critsec);
+ }
+
+ private:
+ CRITICAL_SECTION m_critsec;
+ };
+#endif // _SIGSLOT_HAS_WIN32_THREADS
+
+#ifdef _SIGSLOT_HAS_POSIX_THREADS
+ // The multi threading policies only get compiled in if they are enabled.
+ class multi_threaded_global
+ {
+ public:
+ multi_threaded_global()
+ {
+ pthread_mutex_init(get_mutex(), NULL);
+ }
+
+ multi_threaded_global(const multi_threaded_global&)
+ {
+ ;
+ }
+
+ ~multi_threaded_global()
+ {
+ ;
+ }
+
+ void lock()
+ {
+ pthread_mutex_lock(get_mutex());
+ }
+
+ void unlock()
+ {
+ pthread_mutex_unlock(get_mutex());
+ }
+
+ private:
+ pthread_mutex_t* get_mutex()
+ {
+ static pthread_mutex_t g_mutex;
+ return &g_mutex;
+ }
+ };
+
+ class multi_threaded_local
+ {
+ public:
+ multi_threaded_local()
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ multi_threaded_local(const multi_threaded_local&)
+ {
+ pthread_mutex_init(&m_mutex, NULL);
+ }
+
+ ~multi_threaded_local()
+ {
+ pthread_mutex_destroy(&m_mutex);
+ }
+
+ void lock()
+ {
+ pthread_mutex_lock(&m_mutex);
+ }
+
+ void unlock()
+ {
+ pthread_mutex_unlock(&m_mutex);
+ }
+
+ private:
+ pthread_mutex_t m_mutex;
+ };
+#endif // _SIGSLOT_HAS_POSIX_THREADS
+
+ template<class mt_policy>
+ class lock_block
+ {
+ public:
+ mt_policy *m_mutex;
+
+ lock_block(mt_policy *mtx)
+ : m_mutex(mtx)
+ {
+ m_mutex->lock();
+ }
+
+ ~lock_block()
+ {
+ m_mutex->unlock();
+ }
+ };
+
+ template<class mt_policy>
+ class has_slots;
+
+ template<class mt_policy>
+ class _connection_base0
+ {
+ public:
+ virtual ~_connection_base0() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit() = 0;
+ virtual _connection_base0* clone() = 0;
+ virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _connection_base1
+ {
+ public:
+ virtual ~_connection_base1() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type) = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* clone() = 0;
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _connection_base2
+ {
+ public:
+ virtual ~_connection_base2() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type) = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection_base3
+ {
+ public:
+ virtual ~_connection_base3() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type) = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _connection_base4
+ {
+ public:
+ virtual ~_connection_base4() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _connection_base5
+ {
+ public:
+ virtual ~_connection_base5() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type) = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone() = 0;
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _connection_base6
+ {
+ public:
+ virtual ~_connection_base6() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type) = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone() = 0;
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection_base7
+ {
+ public:
+ virtual ~_connection_base7() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type) = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _connection_base8
+ {
+ public:
+ virtual ~_connection_base8() { ; }
+ virtual has_slots<mt_policy>* getdest() const = 0;
+ virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
+ arg6_type, arg7_type, arg8_type) = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
+ };
+
+ template<class mt_policy>
+ class _signal_base : public mt_policy
+ {
+ public:
+ virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
+ virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0;
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class has_slots : public mt_policy
+ {
+ private:
+ typedef typename std::set<_signal_base<mt_policy> *> sender_set;
+ typedef typename sender_set::const_iterator const_iterator;
+
+ public:
+ has_slots()
+ {
+ ;
+ }
+
+ has_slots(const has_slots& hs)
+ : mt_policy(hs)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = hs.m_senders.begin();
+ const_iterator itEnd = hs.m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_duplicate(&hs, this);
+ m_senders.insert(*it);
+ ++it;
+ }
+ }
+
+ void signal_connect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.insert(sender);
+ }
+
+ void signal_disconnect(_signal_base<mt_policy>* sender)
+ {
+ lock_block<mt_policy> lock(this);
+ m_senders.erase(sender);
+ }
+
+ virtual ~has_slots()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_senders.begin();
+ const_iterator itEnd = m_senders.end();
+
+ while(it != itEnd)
+ {
+ (*it)->slot_disconnect(this);
+ ++it;
+ }
+
+ m_senders.erase(m_senders.begin(), m_senders.end());
+ }
+
+ private:
+ sender_set m_senders;
+ };
+
+ template<class mt_policy>
+ class _signal_base0 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef typename std::list<_connection_base0<mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base0()
+ {
+ ;
+ }
+
+ _signal_base0(const _signal_base0& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ ~_signal_base0()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class mt_policy>
+ class _signal_base1 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef typename std::list<_connection_base1<arg1_type, mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base1()
+ {
+ ;
+ }
+
+ _signal_base1(const _signal_base1<arg1_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base1()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class mt_policy>
+ class _signal_base2 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef typename std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>
+ connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base2()
+ {
+ ;
+ }
+
+ _signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base2()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _signal_base3 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>
+ connections_list;
+
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+ _signal_base3()
+ {
+ ;
+ }
+
+ _signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base3()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
+ class _signal_base4 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base4()
+ {
+ ;
+ }
+
+ _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base4()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ this->m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy>
+ class _signal_base5 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base5()
+ {
+ ;
+ }
+
+ _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base5()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy>
+ class _signal_base6 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base6()
+ {
+ ;
+ }
+
+ _signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base6()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _signal_base7 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *> connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base7()
+ {
+ ;
+ }
+
+ _signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base7()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
+ class _signal_base8 : public _signal_base<mt_policy>
+ {
+ public:
+ typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>
+ connections_list;
+ typedef typename connections_list::const_iterator const_iterator;
+ typedef typename connections_list::iterator iterator;
+
+ _signal_base8()
+ {
+ ;
+ }
+
+ _signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base<mt_policy>(s)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = s.m_connected_slots.begin();
+ const_iterator itEnd = s.m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_connect(this);
+ m_connected_slots.push_back((*it)->clone());
+
+ ++it;
+ }
+ }
+
+ void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == oldtarget)
+ {
+ m_connected_slots.push_back((*it)->duplicate(newtarget));
+ }
+
+ ++it;
+ }
+ }
+
+ ~_signal_base8()
+ {
+ disconnect_all();
+ }
+
+ void disconnect_all()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator it = m_connected_slots.begin();
+ const_iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ (*it)->getdest()->signal_disconnect(this);
+ delete *it;
+
+ ++it;
+ }
+
+ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
+ }
+
+ void disconnect(has_slots<mt_policy>* pclass)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ if ((*it)->getdest() == pclass)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ pclass->signal_disconnect(this);
+ return;
+ }
+
+ ++it;
+ }
+ }
+
+ void slot_disconnect(has_slots<mt_policy>* pslot)
+ {
+ lock_block<mt_policy> lock(this);
+ iterator it = m_connected_slots.begin();
+ iterator itEnd = m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ iterator itNext = it;
+ ++itNext;
+
+ if ((*it)->getdest() == pslot)
+ {
+ delete *it;
+ m_connected_slots.erase(it);
+ // delete *it;
+ }
+
+ it = itNext;
+ }
+ }
+
+ protected:
+ connections_list m_connected_slots;
+ };
+
+
+ template<class dest_type, class mt_policy>
+ class _connection0 : public _connection_base0<mt_policy>
+ {
+ public:
+ _connection0()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection0(dest_type* pobject, void (dest_type::*pmemfun)())
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection0()
+ {
+ ;
+ }
+
+ virtual _connection_base0<mt_policy>* clone()
+ {
+ return new _connection0<dest_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit()
+ {
+ (m_pobject->*m_pmemfun)();
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)();
+ };
+
+ template<class dest_type, class arg1_type, class mt_policy>
+ class _connection1 : public _connection_base1<arg1_type, mt_policy>
+ {
+ public:
+ _connection1()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection1()
+ {
+ ;
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* clone()
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1)
+ {
+ (m_pobject->*m_pmemfun)(a1);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class mt_policy>
+ class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ _connection2()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection2()
+ {
+ ;
+ }
+
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>
+ class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ _connection3()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection3()
+ {
+ ;
+ }
+
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class mt_policy>
+ class _connection4 : public _connection_base4<arg1_type, arg2_type,
+ arg3_type, arg4_type, mt_policy>
+ {
+ public:
+ _connection4()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection4()
+ {
+ ;
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3,
+ arg4_type a4)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,
+ arg4_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class mt_policy>
+ class _connection5 : public _connection_base5<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ _connection5()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection5()
+ {
+ ;
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* clone()
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class mt_policy>
+ class _connection6 : public _connection_base6<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ _connection6()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection6()
+ {
+ ;
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* clone()
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>
+ class _connection7 : public _connection_base7<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ _connection7()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection7()
+ {
+ ;
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* clone()
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type);
+ };
+
+ template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
+ class arg4_type, class arg5_type, class arg6_type, class arg7_type,
+ class arg8_type, class mt_policy>
+ class _connection8 : public _connection_base8<arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ _connection8()
+ {
+ this->pobject = NULL;
+ this->pmemfun = NULL;
+ }
+
+ _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ m_pobject = pobject;
+ m_pmemfun = pmemfun;
+ }
+
+ virtual ~_connection8()
+ {
+ ;
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);
+ }
+
+ virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
+ {
+ return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
+ }
+
+ virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);
+ }
+
+ virtual has_slots<mt_policy>* getdest() const
+ {
+ return m_pobject;
+ }
+
+ private:
+ dest_type* m_pobject;
+ void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type);
+ };
+
+ template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal0 : public _signal_base0<mt_policy>
+ {
+ public:
+ typedef typename _signal_base0<mt_policy>::connections_list::const_iterator const_iterator;
+ signal0()
+ {
+ ;
+ }
+
+ signal0(const signal0<mt_policy>& s)
+ : _signal_base0<mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal0()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)())
+ {
+ lock_block<mt_policy> lock(this);
+ _connection0<desttype, mt_policy>* conn =
+ new _connection0<desttype, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+
+ void operator()()
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit();
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal1 : public _signal_base1<arg1_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base1<arg1_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal1()
+ {
+ ;
+ }
+
+ signal1(const signal1<arg1_type, mt_policy>& s)
+ : _signal_base1<arg1_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal1()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection1<desttype, arg1_type, mt_policy>* conn =
+ new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, typename arg2_type, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base2<arg1_type, arg2_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal2()
+ {
+ ;
+ }
+
+ signal2(const signal2<arg1_type, arg2_type, mt_policy>& s)
+ : _signal_base2<arg1_type, arg2_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal2()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new
+ _connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, typename arg2_type, typename arg3_type, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal3()
+ {
+ ;
+ }
+
+ signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
+ : _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal3()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn =
+ new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,
+ pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal4()
+ {
+ ;
+ }
+
+ signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
+ : _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal4()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*
+ conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal5()
+ {
+ ;
+ }
+
+ signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>& s)
+ : _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal5()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,
+ arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5);
+
+ it = itNext;
+ }
+ }
+ };
+
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base6<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal6()
+ {
+ ;
+ }
+
+ signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>& s)
+ : _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal6()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, mt_policy>* conn =
+ new _connection6<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base7<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal7()
+ {
+ ;
+ }
+
+ signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>& s)
+ : _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal7()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, mt_policy>* conn =
+ new _connection7<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7);
+
+ it = itNext;
+ }
+ }
+ };
+
+ template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
+ class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
+ class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
+ {
+ public:
+ typedef typename _signal_base8<arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>::connections_list::const_iterator const_iterator;
+ signal8()
+ {
+ ;
+ }
+
+ signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
+ : _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)
+ {
+ ;
+ }
+
+ virtual ~signal8()
+ {
+ ;
+ }
+
+ template<class desttype>
+ void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
+ arg2_type, arg3_type, arg4_type, arg5_type, arg6_type,
+ arg7_type, arg8_type))
+ {
+ lock_block<mt_policy> lock(this);
+ _connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn =
+ new _connection8<desttype, arg1_type, arg2_type, arg3_type,
+ arg4_type, arg5_type, arg6_type, arg7_type,
+ arg8_type, mt_policy>(pclass, pmemfun);
+ this->m_connected_slots.push_back(conn);
+ pclass->signal_connect(this);
+ }
+
+ void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+
+ void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
+ arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
+ {
+ lock_block<mt_policy> lock(this);
+ const_iterator itNext, it = this->m_connected_slots.begin();
+ const_iterator itEnd = this->m_connected_slots.end();
+
+ while(it != itEnd)
+ {
+ itNext = it;
+ ++itNext;
+
+ (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);
+
+ it = itNext;
+ }
+ }
+ };
+
+} // namespace sigslot
+
+#endif // SIGSLOT_H__
+
diff --git a/plugins/Dbx_tree/src/stdint.h b/plugins/Dbx_tree/src/stdint.h
new file mode 100644
index 0000000000..59d067302f
--- /dev/null
+++ b/plugins/Dbx_tree/src/stdint.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]