diff options
| author | Vadim Dashevskiy <watcherhd@gmail.com> | 2014-02-14 15:34:14 +0000 | 
|---|---|---|
| committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2014-02-14 15:34:14 +0000 | 
| commit | 7578f068b6dd10641ced7d08d5eebb4654c4911c (patch) | |
| tree | f215e043a5798381032e17fe124669f868e067ef /plugins/!Deprecated/Dbx_tree/src | |
| parent | 0168c0457bb31905368134ae8ec1020a08d20970 (diff) | |
Dbx_tree moved to deprecated
git-svn-id: http://svn.miranda-ng.org/main/trunk@8122 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/!Deprecated/Dbx_tree/src')
49 files changed, 17139 insertions, 0 deletions
diff --git a/plugins/!Deprecated/Dbx_tree/src/BTree.h b/plugins/!Deprecated/Dbx_tree/src/BTree.h new file mode 100644 index 0000000000..f1d44ccd27 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/BTree.h @@ -0,0 +1,1343 @@ +/*
 +
 +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"
 +#include <stdint.h>
 +
 +#include "Logger.h"
 +
 +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);
 +	}
 +
 +	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/!Deprecated/Dbx_tree/src/BlockManager.cpp b/plugins/!Deprecated/Dbx_tree/src/BlockManager.cpp new file mode 100644 index 0000000000..b6a7d22feb --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/BlockManager.cpp @@ -0,0 +1,963 @@ +/*
 +
 +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 "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;
 +
 +	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)
 +		{
 +			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;
 +		
 +	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/!Deprecated/Dbx_tree/src/BlockManager.h b/plugins/!Deprecated/Dbx_tree/src/BlockManager.h new file mode 100644 index 0000000000..dcccd4f0b9 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/Cipher.h b/plugins/!Deprecated/Dbx_tree/src/Cipher.h new file mode 100644 index 0000000000..26cd7424bb --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Cipher.h @@ -0,0 +1,180 @@ +/*
 +
 +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
 +
 +#ifdef _MSC_VER
 +#include "stdint.h"
 +#else
 +#include <stdint.h>
 +#endif
 +
 +#include <wchar.h>
 +
 +#pragma pack(push, 1)
 +
 +#ifdef __INTERFACE_ONLY__
 +#define __INTERFACE_VIRTUAL__
 +#else
 +#define __INTERFACE_VIRTUAL__ virtual
 +#endif
 +
 +class CCipher
 +{
 +public:
 +	typedef struct TCipherInterface
 +	{
 +		CCipher * self;
 +		uint32_t Size;
 +		void           (__cdecl CCipher::*Destroy)();
 +
 +		const wchar_t* (__cdecl CCipher::*Name)();
 +		const wchar_t* (__cdecl CCipher::*Description)();
 +		const uint32_t (__cdecl CCipher::*BlockSizeBytes)();
 +		const bool     (__cdecl CCipher::*IsStreamCipher)();
 +
 +		void           (__cdecl CCipher::*SetKey)(void* Key, uint32_t KeyLength);
 +		void           (__cdecl CCipher::*Encrypt)(void* Data, uint32_t Size, uint32_t Nonce, uint32_t StartByte);
 +		void           (__cdecl CCipher::*Decrypt)(void* Data, uint32_t Size, uint32_t Nonce, uint32_t StartByte);
 +
 +	} TCipherInterface;
 +	TCipherInterface * m_Interface;
 +
 +#ifndef __INTERFACE_ONLY__
 +	virtual void __cdecl Destroy()
 +	{
 +		delete this;
 +	}
 +
 +	CCipher()
 +	{
 +		m_Interface = new TCipherInterface;
 +		m_Interface->Size = sizeof(TCipherInterface);
 +		m_Interface->self = this;
 +		m_Interface->Destroy        = &CCipher::Destroy;
 +		m_Interface->Name           = &CCipher::Name;
 +		m_Interface->Description    = &CCipher::Description;
 +		m_Interface->BlockSizeBytes = &CCipher::BlockSizeBytes;
 +		m_Interface->IsStreamCipher = &CCipher::IsStreamCipher;
 +		m_Interface->SetKey         = &CCipher::SetKey;
 +		m_Interface->Encrypt        = &CCipher::Encrypt;
 +		m_Interface->Decrypt        = &CCipher::Decrypt;
 +	};
 +#endif
 +
 +#ifdef __INTERFACE_ONLY__
 +	CCipher(TCipherInterface * Interface)
 +	{
 +		m_Interface = Interface;
 +	};
 +#endif
 +
 +	__INTERFACE_VIRTUAL__ ~CCipher()
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		(m_Interface->self->*(m_Interface->Destroy))();
 +	}
 +#else
 +	{	}
 +#endif
 +	;
 +
 +	__INTERFACE_VIRTUAL__ const wchar_t* __cdecl Name()
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->Name))();
 +	}
 +#else
 +	= 0
 +#endif
 +		;
 +
 +	__INTERFACE_VIRTUAL__ const wchar_t* __cdecl Description()
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->Description))();
 +	}
 +#else
 +	= 0
 +#endif
 +		;
 +
 +	__INTERFACE_VIRTUAL__ const uint32_t __cdecl BlockSizeBytes()
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->BlockSizeBytes))();
 +	}
 +#else
 +		= 0
 +#endif
 +		;
 +
 +	__INTERFACE_VIRTUAL__ const bool __cdecl IsStreamCipher()
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->IsStreamCipher))();
 +	}
 +#else
 +		= 0
 +#endif
 +		;
 +
 +	__INTERFACE_VIRTUAL__ void __cdecl SetKey(void* Key, uint32_t KeyLength)
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->SetKey))(Key, KeyLength);
 +	}
 +#else
 +		= 0
 +#endif
 +		;
 +	__INTERFACE_VIRTUAL__ void __cdecl Encrypt(void* Data, uint32_t Size, uint32_t Nonce, uint32_t StartByte)
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->Encrypt))(Data, Size, Nonce, StartByte);
 +	}
 +#else
 +		= 0
 +#endif
 +		;
 +	__INTERFACE_VIRTUAL__ void __cdecl Decrypt(void* Data, uint32_t Size, uint32_t Nonce, uint32_t StartByte)
 +#ifdef __INTERFACE_ONLY__
 +	{
 +		return (m_Interface->self->*(m_Interface->Decrypt))(Data, Size, Nonce, StartByte);
 +	}
 +#else
 +		= 0
 +#endif
 +		;
 +
 +};
 +
 +typedef struct TCipherInfo
 +{
 +	uint32_t cbSize;
 +	const uint32_t ID;
 +	const wchar_t* Name;
 +	const wchar_t* Description;
 +	CCipher::TCipherInterface * (__cdecl *Create)();
 +} TCipherInfo;
 +
 +#pragma pack(pop)
 diff --git a/plugins/!Deprecated/Dbx_tree/src/Compatibility.cpp b/plugins/!Deprecated/Dbx_tree/src/Compatibility.cpp new file mode 100644 index 0000000000..bc42386664 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Compatibility.cpp @@ -0,0 +1,853 @@ +/*
 +
 +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 "Compatibility.h"
 +#include "Logger.h"
 +#define DB_NOHELPERFUNCTIONS
 +#include "m_database.h"
 +#include "m_db_int.h"
 +#undef DB_NOHELPERFUNCTIONS
 +
 +HANDLE gEvents[6] = {0,0,0,0,0,0};
 +
 +HANDLE hEventDeletedEvent,
 +       hEventAddedEvent,
 +		 hEventFilterAddedEvent,
 +		 hSettingChangeEvent,
 +		 hContactDeletedEvent,
 +		 hContactAddedEvent;
 +
 +int CDataBase::CheckProto(DBCachedContact *cc, const char *proto)
 +{
 +	if (cc->szProto == NULL) {
 +		char protobuf[MAX_PATH] = {0};
 +		DBVARIANT dbv;
 + 		dbv.type = DBVT_ASCIIZ;
 +		dbv.pszVal = protobuf;
 +		dbv.cchVal = sizeof(protobuf);
 +		if (GetContactSettingStatic(cc->contactID, "Protocol", "p", &dbv) != 0 || (dbv.type != DBVT_ASCIIZ))
 +			return 0;
 +
 +		cc->szProto = m_cache->GetCachedSetting(NULL, protobuf, 0, (int)strlen(protobuf));
 +	}
 +
 +	return !strcmp(cc->szProto, proto);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::AddContact(void)
 +{
 +	TDBTEntity entity = {0,0,0,0};
 +	entity.hParentEntity = DBEntityGetRoot(0, 0);
 +	entity.hAccountEntity = entity.hParentEntity;
 +
 +	TDBTEntityHandle res = getEntities().CreateEntity(entity);
 +	if (res == DBT_INVALIDPARAM)
 +		return (HANDLE)1;
 +
 +	m_cache->AddContactToCache(res);
 +
 +	NotifyEventHooks(hContactAddedEvent, res, 0);
 +	return (HANDLE)res;
 +}
 +
 +STDMETHODIMP_(LONG) CDataBase::DeleteContact(MCONTACT contactID)
 +{
 +	NotifyEventHooks(hContactDeletedEvent, contactID, 0);
 +
 +	int res = DBEntityDelete(contactID, 0);
 +	if (res == DBT_INVALIDPARAM)
 +		return 1;
 +
 +	if (res == 0)
 +		m_cache->FreeCachedContact(contactID);
 +
 +	return res;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::IsDbContact(MCONTACT contactID)
 +{
 +	int flags = DBEntityGetFlags(contactID, 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, 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;
 +}
 +
 +STDMETHODIMP_(MCONTACT) CDataBase::FindFirstContact(const char* szProto)
 +{
 +	DBCachedContact *cc = m_cache->GetFirstContact();
 +	if (cc == NULL)
 +		return NULL;
 +
 +	if (!szProto || CheckProto(cc, szProto))
 +		return cc->contactID;
 +
 +	return FindNextContact(cc->contactID, szProto);
 +}
 +
 +STDMETHODIMP_(MCONTACT) CDataBase::FindNextContact(MCONTACT contactID, const char* szProto)
 +{
 +	while (contactID) {
 +		DBCachedContact *cc = m_cache->GetNextContact(contactID);
 +		if (cc == NULL)
 +			break;
 +
 +		if (!szProto || CheckProto(cc, szProto))
 +			return cc->contactID;
 +
 +		contactID = cc->contactID;
 +		continue;
 +	}
 +
 +	return NULL;
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +static bool isEncrypted(LPCSTR szModule, LPCSTR szSetting)
 +{
 +	if (!_strnicmp(szSetting, "password", 8))      return true;
 +	if (!strcmp(szSetting, "NLProxyAuthPassword")) return true;
 +	if (!strcmp(szSetting, "LNPassword"))          return true;
 +	if (!strcmp(szSetting, "FileProxyPassword"))   return true;
 +	if (!strcmp(szSetting, "TokenSecret"))         return true;
 +
 +	if (!strcmp(szModule, "SecureIM")) {
 +		if (!strcmp(szSetting, "pgp"))              return true;
 +		if (!strcmp(szSetting, "pgpPrivKey"))       return true;
 +	}
 +	return false;
 +}
 +
 +//VERY VERY VERY BASIC ENCRYPTION FUNCTION
 +
 +static void Encrypt(char *msg, BOOL up)
 +{
 +	int jump = (up) ? 5 : -5;
 +	for (int i = 0; msg[i]; i++)
 +		msg[i] = msg[i] + jump;
 +}
 +
 +__forceinline void EncodeString(LPSTR buf)
 +{
 +	Encrypt(buf, TRUE);
 +}
 +
 +__forceinline void DecodeString(LPSTR buf)
 +{
 +	Encrypt(buf, FALSE);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +STDMETHODIMP_(BOOL) CDataBase::GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv)
 +{
 +	dbv->type = 0;
 +
 +	char namebuf[512];
 +	namebuf[0] = 0;
 +
 +	if (!(szModule || szSetting))
 +		return -1;
 +
 +	if (szModule)
 +		strcpy_s(namebuf, szModule);
 +	strcat_s(namebuf, "/");
 +	if (szSetting)
 +		strcat_s(namebuf, szSetting);
 +
 +	TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
 +	TDBTSetting set = {0,0,0,0};
 +	desc.cbSize = sizeof(desc);
 +	desc.Entity = contactID;
 +	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:
 +		dbv->type = DBVT_ASCIIZ;
 +		dbv->pszVal = set.Value.pAnsi;
 +		dbv->cchVal = set.Value.Length - 1;
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(dbv->pszVal);
 +		break;
 +	case DBT_ST_UTF8:
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(set.Value.pUTF8);
 +		dbv->type = DBVT_WCHAR;
 +		dbv->pwszVal = mir_utf8decodeW(set.Value.pUTF8);
 +		if (dbv->pwszVal)
 +			dbv->cchVal = static_cast<uint32_t>(wcslen(dbv->pwszVal));
 +		else
 +			dbv->cchVal = 0;
 +		mir_free(set.Value.pUTF8);
 +		break;
 +	case DBT_ST_WCHAR:
 +		dbv->type = DBVT_WCHAR;
 +		dbv->pwszVal = set.Value.pWide;
 +		dbv->cchVal = set.Value.Length - 1;
 +		break;
 +	case DBT_ST_BLOB:
 +		dbv->type = DBVT_BLOB;
 +		dbv->pbVal = set.Value.pBlob;
 +		dbv->cpbVal = set.Value.Length;
 +		break;
 +	case DBT_ST_BOOL:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = (uint8_t)set.Value.Bool;
 +		break;
 +	case DBT_ST_BYTE: case DBT_ST_CHAR:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = set.Value.Byte;
 +		break;
 +	case DBT_ST_SHORT: case DBT_ST_WORD:
 +		dbv->type = DBVT_WORD;
 +		dbv->wVal = set.Value.Word;
 +		break;
 +	case DBT_ST_INT: case DBT_ST_DWORD:
 +		dbv->type = DBVT_DWORD;
 +		dbv->dVal = set.Value.DWord;
 +		break;
 +	case DBT_ST_INT64: case DBT_ST_QWORD:
 +	case DBT_ST_DOUBLE: case DBT_ST_FLOAT:
 +		dbv->type = DBVT_BLOB;
 +		dbv->cpbVal = sizeof(set.Value);
 +		dbv->pbVal = reinterpret_cast<BYTE*>(mir_alloc(sizeof(set.Value)));
 +		memcpy(dbv->pbVal, &set.Value, sizeof(set.Value));
 +		break;
 +
 +	default:
 +		return -1;
 +	}
 +
 +	return 0;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv)
 +{
 +	if ((dbv->type & DBVTF_VARIABLELENGTH) == 0)
 +	{
 +		FreeVariant(dbv);
 +		dbv->type = 0;
 +	}
 +
 +	char namebuf[512];
 +	namebuf[0] = 0;
 +	if (szModule)
 +		strcpy_s(namebuf, szModule);
 +	strcat_s(namebuf, "/");
 +	if (szSetting)
 +		strcat_s(namebuf, szSetting);
 +
 +	TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
 +	TDBTSetting set = {0,0,0,0};
 +	desc.cbSize = sizeof(desc);
 +	desc.Entity = contactID;
 +	desc.pszSettingName = namebuf;
 +
 +	set.cbSize = sizeof(set);
 +	set.Descriptor = &desc;
 +
 +	switch (dbv->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:
 +		dbv->type = DBVT_ASCIIZ;
 +		dbv->pszVal = set.Value.pAnsi;
 +		dbv->cchVal = set.Value.Length - 1;
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(dbv->pszVal);
 +		break;
 +	case DBT_ST_UTF8:
 +		dbv->type = DBVT_UTF8;
 +		dbv->pszVal = set.Value.pUTF8;
 +		dbv->cchVal = set.Value.Length - 1;
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(dbv->pszVal);
 +		break;
 +	case DBT_ST_WCHAR:
 +		if (dbv->type == DBVT_WCHAR) {
 +			dbv->pwszVal = set.Value.pWide;
 +			dbv->cchVal = set.Value.Length - 1;
 +		}
 +		else {
 +			dbv->type = DBVT_UTF8;
 +			dbv->pszVal = mir_utf8encodeW(set.Value.pWide);
 +			dbv->cchVal = static_cast<uint32_t>(strlen(dbv->pszVal));
 +			if (isEncrypted(szModule, szSetting))
 +				DecodeString(dbv->pszVal);
 +			mir_free(set.Value.pWide);
 +		}
 +		break;
 +	case DBT_ST_BLOB:
 +		dbv->type = DBVT_BLOB;
 +		dbv->pbVal = set.Value.pBlob;
 +		dbv->cpbVal = set.Value.Length;
 +		break;
 +	case DBT_ST_BOOL:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = (uint8_t)set.Value.Bool;
 +		break;
 +	case DBT_ST_BYTE: case DBT_ST_CHAR:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = set.Value.Byte;
 +		break;
 +	case DBT_ST_SHORT: case DBT_ST_WORD:
 +		dbv->type = DBVT_WORD;
 +		dbv->wVal = set.Value.Word;
 +		break;
 +	case DBT_ST_INT: case DBT_ST_DWORD:
 +		dbv->type = DBVT_DWORD;
 +		dbv->dVal = set.Value.DWord;
 +		break;
 +	case DBT_ST_INT64: case DBT_ST_QWORD:
 +	case DBT_ST_DOUBLE: case DBT_ST_FLOAT:
 +		dbv->type = DBVT_BLOB;
 +		dbv->cpbVal = sizeof(set.Value);
 +		dbv->pbVal = reinterpret_cast<BYTE*>(mir_alloc(sizeof(set.Value)));
 +		memcpy(dbv->pbVal, &set.Value, sizeof(set.Value));
 +		break;
 +	default:
 +		return -1;
 +	}
 +
 +	return 0;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv)
 +{
 +	char namebuf[512];
 +	namebuf[0] = 0;
 +	if (szModule)
 +		strcpy_s(namebuf, szModule);
 +	strcat_s(namebuf, "/");
 +	if (szSetting)
 +		strcat_s(namebuf, szSetting);
 +
 +	TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
 +	TDBTSetting set = {0,0,0,0};
 +	desc.cbSize = sizeof(desc);
 +	desc.Entity = contactID;
 +	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) ^ (dbv->type & DBVTF_VARIABLELENGTH))
 +	{
 +		if (set.Type & DBT_STF_VariableLength)
 +			mir_free(set.Value.pBlob);
 +		return -1;
 +	}
 +
 +	switch (set.Type) {
 +	case DBT_ST_ANSI:
 +		if (dbv->cchVal < set.Value.Length) {
 +			memcpy(dbv->pszVal, set.Value.pAnsi, dbv->cchVal);
 +			dbv->pszVal[dbv->cchVal - 1] = 0;
 +		}
 +		else memcpy(dbv->pszVal, set.Value.pAnsi, set.Value.Length);
 +
 +		dbv->type = DBVT_ASCIIZ;
 +		dbv->cchVal = set.Value.Length - 1;
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(dbv->pszVal);
 +
 +		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 (dbv->cchVal < set.Value.Length) {
 +			memcpy(dbv->pszVal, set.Value.pUTF8, dbv->cchVal);
 +			dbv->pszVal[dbv->cchVal - 1] = 0;
 +		}
 +		else memcpy(dbv->pszVal, set.Value.pUTF8, set.Value.Length);
 +
 +		dbv->type = DBVT_ASCIIZ;
 +		dbv->cchVal = set.Value.Length - 1;
 +		if (isEncrypted(szModule, szSetting))
 +			DecodeString(dbv->pszVal);
 +
 +		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 (dbv->cchVal < l + 1) {
 +				memcpy(dbv->pszVal, tmp, dbv->cchVal);
 +				dbv->pszVal[l] = 0;
 +			}
 +			else memcpy(dbv->pszVal, tmp, l + 1);
 +
 +			dbv->type = DBVT_ASCIIZ;
 +			dbv->cchVal = l;
 +			if (isEncrypted(szModule, szSetting))
 +				DecodeString(dbv->pszVal);
 +
 +			mir_free(tmp);
 +		}
 +		break;
 +	case DBT_ST_BLOB:
 +		if (dbv->cchVal < set.Value.Length)
 +			memcpy(dbv->pbVal, set.Value.pBlob, dbv->cchVal);
 +		else
 +			memcpy(dbv->pbVal, set.Value.pBlob, set.Value.Length);
 +
 +		dbv->type = DBVT_BLOB;
 +		dbv->cchVal = set.Value.Length;
 +		mir_free(set.Value.pBlob);
 +		break;
 +	case DBT_ST_BOOL:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = set.Value.Bool ? TRUE : FALSE;
 +		break;
 +	case DBT_ST_BYTE: case DBT_ST_CHAR:
 +		dbv->type = DBVT_BYTE;
 +		dbv->bVal = set.Value.Byte;
 +		break;
 +	case DBT_ST_SHORT: case DBT_ST_WORD:
 +		dbv->type = DBVT_WORD;
 +		dbv->wVal = set.Value.Word;
 +		break;
 +	case DBT_ST_INT: case DBT_ST_DWORD:
 +		dbv->type = DBVT_DWORD;
 +		dbv->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(MCONTACT contactID, 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 = contactID;
 +	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;
 +		if (isEncrypted(dbcws->szModule, dbcws->szSetting))
 +			EncodeString(dbcws->value.pszVal);
 +		break;
 +	case DBVT_UTF8:
 +		if (isEncrypted(dbcws->szModule, dbcws->szSetting))
 +			EncodeString(dbcws->value.pszVal);
 +		{
 +			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, contactID, (LPARAM)dbcws);
 +		mir_free(dbcws->value.pszVal);
 +		dbcws->value.type = DBVT_WCHAR;
 +		dbcws->value.pwszVal = tmp;		
 +	}
 +	else NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)dbcws);
 +
 +	return 0;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting)
 +{
 +	char namebuf[512];
 +	namebuf[0] = 0;
 +	if (szModule)
 +		strcpy_s(namebuf, szModule);
 +	strcat_s(namebuf, "/");
 +	if (szSetting)
 +		strcat_s(namebuf, szSetting);
 +
 +	TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
 +	desc.cbSize = sizeof(desc);
 +	desc.Entity = contactID;
 +	desc.pszSettingName = namebuf;
 +
 +	if (DBSettingDelete(reinterpret_cast<WPARAM>(&desc), 0) == DBT_INVALIDPARAM)
 +		return -1;
 +
 +	{
 +		DBCONTACTWRITESETTING tmp = {0,0,0,0};
 +		tmp.szModule = szModule;
 +		tmp.szSetting = szSetting;
 +		tmp.value.type = 0;
 +		NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&tmp);
 +	}
 +
 +	return 0;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::EnumContactSettings(MCONTACT contactID, DBCONTACTENUMSETTINGS* pces)
 +{
 +	TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0};
 +	desc.cbSize = sizeof(desc);
 +	desc.Entity = contactID;
 +
 +	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)contactID;
 +	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(MCONTACT contactID)
 +{
 +	if (contactID == 0)
 +		contactID = getEntities().getRootEntity();
 +
 +	return DBEventGetCount(contactID, 0);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei)
 +{
 +	if (dbei->cbSize < sizeof(DBEVENTINFO))
 +		return (HANDLE)-1;
 +
 +	int tmp = NotifyEventHooks(hEventFilterAddedEvent, contactID, (LPARAM)dbei);
 +	if (tmp != 0)
 +		return (HANDLE)tmp;
 +
 +	if (contactID == 0)
 +		contactID = 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(contactID, reinterpret_cast<LPARAM>(&ev));
 +	if (res != DBT_INVALIDPARAM)
 +	{
 +		NotifyEventHooks(hEventAddedEvent, contactID, res);
 +		return (HANDLE)res;
 +	}
 +	return NULL;
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::DeleteEvent(MCONTACT contactID, HANDLE hDbEvent)
 +{
 +	int res = NotifyEventHooks(hEventDeletedEvent, contactID, (WPARAM)hDbEvent);
 +
 +	if (contactID == 0)
 +		contactID = 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(MCONTACT contactID, HANDLE hDbEvent)
 +{
 +	int res = DBEventMarkRead((WPARAM)hDbEvent, 0);
 +	if ((res != DBT_INVALIDPARAM) && (res & DBEF_SENT))
 +		res = res & ~DBEF_READ;
 +	return res;
 +}
 +
 +STDMETHODIMP_(MCONTACT) CDataBase::GetEventContact(HANDLE hDbEvent)
 +{
 +	TDBTEntityHandle res = DBEventGetEntity((WPARAM)hDbEvent, 0);
 +	if (res == getEntities().getRootEntity())
 +		res = 0;
 +
 +	return res;
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::FindFirstEvent(MCONTACT contactID)
 +{
 +	if (contactID == 0)
 +		contactID = getEntities().getRootEntity();
 +
 +	return (HANDLE)getEvents().compFirstEvent(contactID);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::FindFirstUnreadEvent(MCONTACT contactID)
 +{
 +	if (contactID == 0)
 +		contactID = getEntities().getRootEntity();
 +	return (HANDLE)getEvents().compFirstUnreadEvent(contactID);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::FindLastEvent(MCONTACT contactID)
 +{
 +	if (contactID == 0)
 +		contactID = getEntities().getRootEntity();
 +	return (HANDLE)getEvents().compLastEvent(contactID);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::FindNextEvent(HANDLE hDbEvent)
 +{
 +	return (HANDLE)getEvents().compNextEvent((WPARAM)hDbEvent);
 +}
 +
 +STDMETHODIMP_(HANDLE) CDataBase::FindPrevEvent(HANDLE hDbEvent)
 +{
 +	return (HANDLE)getEvents().compPrevEvent((WPARAM)hDbEvent);
 +}
 +
 +STDMETHODIMP_(BOOL) CDataBase::EnumModuleNames(DBMODULEENUMPROC pCallback, void *pParam)
 +{
 +	if (!pCallback)
 +		return -1;
 +	
 +	return 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) {}
 +
 +
 +STDMETHODIMP_(BOOL) CDataBase::IsSettingEncrypted(LPCSTR szModule, LPCSTR szSetting)
 +{
 +	return FALSE;
 +}
 +
 +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/!Deprecated/Dbx_tree/src/Compatibility.h b/plugins/!Deprecated/Dbx_tree/src/Compatibility.h new file mode 100644 index 0000000000..3b33980dad --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Compatibility.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.
 +
 +*/
 +
 +#pragma once
 +
 +#include "Interface.h"
 +#include "DataBase.h"
 +
 +bool CompatibilityRegister();
 +
 diff --git a/plugins/!Deprecated/Dbx_tree/src/DataBase.cpp b/plugins/!Deprecated/Dbx_tree/src/DataBase.cpp new file mode 100644 index 0000000000..465ceae643 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/DataBase.cpp @@ -0,0 +1,372 @@ +/*
 +
 +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 "DataBase.h"
 +#include "newpluginapi.h"
 +#include "Logger.h"
 +
 +CDataBase *gDataBase = NULL;
 +
 +CDataBase::CDataBase(const TCHAR *FileName)
 +{
 +	InitDbInstance(this);
 +	//RegisterServices();
 +
 +	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()
 +{
 +	delete m_Events;
 +	delete m_Settings;
 +	delete m_Entities;
 +
 +	m_Entities = NULL;
 +	m_Settings = NULL;
 +	m_Events   = NULL;
 +
 +	for (int i = DBFileMax - 1; i >= 0; --i)
 +	{
 +		delete m_BlockManager[i];
 +		delete m_FileAccess[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;
 +
 +	m_FileAccess[Index] = new CMappedMemory(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);
 +
 +	for (MCONTACT id = m_Entities->compFirstContact(); id != 0; id = m_Entities->compNextContact(id)) {
 +		DBCachedContact *cc = m_cache->AddContactToCache(id);
 +		CheckProto(cc, "");
 +	}
 +
 +	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/!Deprecated/Dbx_tree/src/DataBase.h b/plugins/!Deprecated/Dbx_tree/src/DataBase.h new file mode 100644 index 0000000000..6f3cc07b6e --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/DataBase.h @@ -0,0 +1,232 @@ +/*
 +
 +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 <stdint.h>
 +#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);
 +
 +public:     // services 
 +	INT_PTR __cdecl  DBEntityGetRoot(WPARAM wParam, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityChildCount(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityGetParent(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityMove(WPARAM hEntity, LPARAM hParent);
 +	INT_PTR __cdecl  DBEntityGetFlags(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityIterInit(WPARAM pFilter, LPARAM hParent);
 +	INT_PTR __cdecl  DBEntityIterNext(WPARAM hIteration, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityIterClose(WPARAM hIteration, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityDelete(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityCreate(WPARAM pEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEntityGetAccount(WPARAM hEntity, LPARAM lParam);
 +
 +	INT_PTR __cdecl  DBVirtualEntityCreate(WPARAM hEntity, LPARAM hParent);
 +	INT_PTR __cdecl  DBVirtualEntityGetParent(WPARAM hVirtualEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBVirtualEntityGetFirst(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBVirtualEntityGetNext(WPARAM hVirtualEntity, LPARAM lParam);
 +
 +	INT_PTR __cdecl  DBSettingFind(WPARAM pSettingDescriptor, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingDelete(WPARAM pSettingDescriptor, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingDeleteHandle(WPARAM hSetting, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingWrite(WPARAM pSetting, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingWriteHandle(WPARAM pSetting, LPARAM hSetting);
 +	INT_PTR __cdecl  DBSettingRead(WPARAM pSetting, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingReadHandle(WPARAM pSetting, LPARAM hSetting);
 +	INT_PTR __cdecl  DBSettingIterInit(WPARAM pFilter, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingIterNext(WPARAM hIteration, LPARAM lParam);
 +	INT_PTR __cdecl  DBSettingIterClose(WPARAM hIteration, LPARAM lParam);
 +
 +	INT_PTR __cdecl  DBEventGetBlobSize(WPARAM hEvent, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventGet(WPARAM hEvent, LPARAM pEvent);
 +	INT_PTR __cdecl  DBEventGetCount(WPARAM hEntity, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventDelete(WPARAM hEvent, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventAdd(WPARAM hEntity, LPARAM pEvent);
 +	INT_PTR __cdecl  DBEventMarkRead(WPARAM hEvent, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventWriteToDisk(WPARAM hEvent, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventGetEntity(WPARAM hEvent, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventIterInit(WPARAM pFilter, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventIterNext(WPARAM hIteration, LPARAM lParam);
 +	INT_PTR __cdecl  DBEventIterClose(WPARAM hIteration, LPARAM lParam);
 +
 +	bool RegisterServices();
 +
 +	typedef INT_PTR ( __cdecl CDataBase::*DbServiceFunc )( WPARAM, LPARAM );
 +	void CreateDbService(const char *szServiceName, DbServiceFunc pFunc);
 +
 +protected:  // to be compatible with the standard Miranda databases
 +	STDMETHODIMP_(void)     SetCacheSafetyMode(BOOL);
 +
 +	STDMETHODIMP_(LONG)     GetContactCount(void);
 +	STDMETHODIMP_(MCONTACT) FindFirstContact(const char* szProto = NULL);
 +	STDMETHODIMP_(MCONTACT) FindNextContact(MCONTACT contactID, const char* szProto = NULL);
 +	STDMETHODIMP_(LONG)     DeleteContact(MCONTACT contactID);
 +	STDMETHODIMP_(HANDLE)   AddContact(void);
 +	STDMETHODIMP_(BOOL)     IsDbContact(MCONTACT contactID);
 +
 +	STDMETHODIMP_(LONG)     GetEventCount(MCONTACT contactID);
 +	STDMETHODIMP_(HANDLE)   AddEvent(MCONTACT contactID, DBEVENTINFO *dbe);
 +	STDMETHODIMP_(BOOL)     DeleteEvent(MCONTACT contactID, HANDLE hDbEvent);
 +	STDMETHODIMP_(LONG)     GetBlobSize(HANDLE hDbEvent);
 +	STDMETHODIMP_(BOOL)     GetEvent(HANDLE hDbEvent, DBEVENTINFO *dbe);
 +	STDMETHODIMP_(BOOL)     MarkEventRead(MCONTACT contactID, HANDLE hDbEvent);
 +	STDMETHODIMP_(MCONTACT) GetEventContact(HANDLE hDbEvent);
 +	STDMETHODIMP_(HANDLE)   FindFirstEvent(MCONTACT contactID);
 +	STDMETHODIMP_(HANDLE)   FindFirstUnreadEvent(MCONTACT contactID);
 +	STDMETHODIMP_(HANDLE)   FindLastEvent(MCONTACT contactID);
 +	STDMETHODIMP_(HANDLE)   FindNextEvent(HANDLE hDbEvent);
 +	STDMETHODIMP_(HANDLE)   FindPrevEvent(HANDLE hDbEvent);
 +								   
 +	STDMETHODIMP_(BOOL)     EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam);
 +								   
 +	STDMETHODIMP_(BOOL)     GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv);
 +	STDMETHODIMP_(BOOL)     GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv);
 +	STDMETHODIMP_(BOOL)     GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv);
 +	STDMETHODIMP_(BOOL)     FreeVariant(DBVARIANT *dbv);
 +	STDMETHODIMP_(BOOL)     WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws);
 +	STDMETHODIMP_(BOOL)     DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting);
 +	STDMETHODIMP_(BOOL)     EnumContactSettings(MCONTACT contactID, DBCONTACTENUMSETTINGS* dbces);
 +	STDMETHODIMP_(BOOL)     SetSettingResident(BOOL bIsResident, const char *pszSettingName);
 +	STDMETHODIMP_(BOOL)     EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam);
 +	STDMETHODIMP_(BOOL)     IsSettingEncrypted(LPCSTR szModule, LPCSTR szSetting);
 +
 +	int CheckProto(DBCachedContact *cc, const char *proto);
 +};
 diff --git a/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.cpp b/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.cpp new file mode 100644 index 0000000000..e48ebfff08 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.cpp @@ -0,0 +1,91 @@ +/*
 +
 +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"
 +
 +/*
 +	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)
 +{
 +	CDataBase* pDb = new CDataBase(profile);
 +	pDb->OpenDB();
 +	return pDb;
 +}
 +
 +/*
 +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)
 +{
 +	delete (CDataBase*)db;
 +	return 0;
 +}
 +
 +DATABASELINK gDBLink = {
 +	sizeof(DATABASELINK),
 +	__INTERNAL_NAME,
 +	_T("dbx tree driver"),
 +	makeDatabase,
 +	grokHeader,
 +	LoadDatabase,
 +	UnloadDatabase,
 +	NULL  // does not support file checking
 +};
 diff --git a/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.h b/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.h new file mode 100644 index 0000000000..ebc61c5047 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/DatabaseLink.h @@ -0,0 +1,27 @@ +/*
 +
 +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 "Compatibility.h"
\ No newline at end of file diff --git a/plugins/!Deprecated/Dbx_tree/src/DirectAccess.cpp b/plugins/!Deprecated/Dbx_tree/src/DirectAccess.cpp new file mode 100644 index 0000000000..7095bdaa8a --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/DirectAccess.cpp @@ -0,0 +1,119 @@ +/*
 +
 +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 "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/!Deprecated/Dbx_tree/src/DirectAccess.h b/plugins/!Deprecated/Dbx_tree/src/DirectAccess.h new file mode 100644 index 0000000000..cc4241c235 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/EncryptionManager.cpp b/plugins/!Deprecated/Dbx_tree/src/EncryptionManager.cpp new file mode 100644 index 0000000000..ceaff9a015 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/EncryptionManager.cpp @@ -0,0 +1,240 @@ +/*
 +
 +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 "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()
 +{
 +	delete m_Ciphers[CURRENT].Cipher;
 +	m_Ciphers[CURRENT].Cipher = NULL;
 +	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/!Deprecated/Dbx_tree/src/EncryptionManager.h b/plugins/!Deprecated/Dbx_tree/src/EncryptionManager.h new file mode 100644 index 0000000000..5bd04360a2 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/EncryptionManager.h @@ -0,0 +1,103 @@ +/*
 +
 +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 <stdint.h>
 +#include "sigslot.h"
 +
 +#define __INTERFACE_ONLY__
 +#include "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/!Deprecated/Dbx_tree/src/Entities.cpp b/plugins/!Deprecated/Dbx_tree/src/Entities.cpp new file mode 100644 index 0000000000..590cf6f85b --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Entities.cpp @@ -0,0 +1,1028 @@ +/*
 +
 +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 "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>;
 +	iter->returned = new stdext::hash_set<TDBTEntityHandle>;
 +	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();
 +
 +		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/!Deprecated/Dbx_tree/src/Entities.h b/plugins/!Deprecated/Dbx_tree/src/Entities.h new file mode 100644 index 0000000000..9cb3a6fea3 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Entities.h @@ -0,0 +1,291 @@ +/*
 +
 +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>
 +#include <hash_set>
 +
 +#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;
 +		stdext::hash_set<TDBTEntityHandle> * returned;
 +	} 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/!Deprecated/Dbx_tree/src/Events.cpp b/plugins/!Deprecated/Dbx_tree/src/Events.cpp new file mode 100644 index 0000000000..11870f1d1f --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Events.cpp @@ -0,0 +1,983 @@ +/*
 +
 +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 "Events.h"
 +
 +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;
 +
 +		mir_snprintf(n, SIZEOF(n), "$EventTypes/%08x/ModuleID", GlobalID);
 +		TDBTSettingHandle h = m_Settings.ReadSetting(sid);
 +
 +		if ((h != DBT_INVALIDPARAM) && (h != 0))
 +		{
 +			mir_snprintf(n, SIZEOF(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;
 +
 +		mir_snprintf(n, SIZEOF(n), "$EventTypes/%08x/ModuleID", res);
 +		s.Type = DBT_ST_INT;
 +		s.Value.Int = EventType;
 +		m_Settings.WriteSetting(s);
 +
 +		mir_snprintf(n, SIZEOF(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/!Deprecated/Dbx_tree/src/Events.h b/plugins/!Deprecated/Dbx_tree/src/Events.h new file mode 100644 index 0000000000..170ff6fc3c --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Events.h @@ -0,0 +1,250 @@ +/*
 +
 +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"
 +
 +#include <hash_map>
 +#include <hash_set>
 +#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;
 +	typedef stdext::hash_map<uint32_t, PEventType> TTypeMap;
 +
 +	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;
 +	typedef stdext::hash_map<TDBTEntityHandle, TEntityEventsRecord*> TEntityEventsMap;
 +	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/!Deprecated/Dbx_tree/src/FileAccess.cpp b/plugins/!Deprecated/Dbx_tree/src/FileAccess.cpp new file mode 100644 index 0000000000..0042abab40 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/FileAccess.cpp @@ -0,0 +1,296 @@ +/*
 +
 +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 "FileAccess.h"
 +#include <vector>
 +#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,
 +		      TranslateT("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)?TranslateT(" was successfully"):TranslateT(" could not be"),
 +			    jrn?jrn+1:bckjrnname, (hjrnfilebackup!=INVALID_HANDLE_VALUE)?TranslateT(" was successfully"):TranslateT(" could not be"),
 +			    path);
 +			} else {
 +			LOG(logWARNING,
 +					TranslateT("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/!Deprecated/Dbx_tree/src/FileAccess.h b/plugins/!Deprecated/Dbx_tree/src/FileAccess.h new file mode 100644 index 0000000000..f49643e2a3 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/FileBTree.h b/plugins/!Deprecated/Dbx_tree/src/FileBTree.h new file mode 100644 index 0000000000..3a9e58a43e --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/Hash.cpp b/plugins/!Deprecated/Dbx_tree/src/Hash.cpp new file mode 100644 index 0000000000..ae02000c3e --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Hash.cpp @@ -0,0 +1,184 @@ +/*
 +
 +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 "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/!Deprecated/Dbx_tree/src/Hash.h b/plugins/!Deprecated/Dbx_tree/src/Hash.h new file mode 100644 index 0000000000..ae5a1d06be --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Hash.h @@ -0,0 +1,25 @@ +/*
 +
 +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 <stdint.h>
 +
 +uint32_t Hash(const void * Data, uint32_t Length);
 diff --git a/plugins/!Deprecated/Dbx_tree/src/Interface.h b/plugins/!Deprecated/Dbx_tree/src/Interface.h new file mode 100644 index 0000000000..b207c58391 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Interface.h @@ -0,0 +1,42 @@ +/*
 +
 +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 INTERFACE_VERSION_ONLY
 +
 +#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"
 +
 +#include "version.h"
 +
 +extern HINSTANCE   hInstance;
 +
 +extern DATABASELINK gDBLink;
 +#endif
 diff --git a/plugins/!Deprecated/Dbx_tree/src/IterationHeap.h b/plugins/!Deprecated/Dbx_tree/src/IterationHeap.h new file mode 100644 index 0000000000..db06f7e695 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/Logger.cpp b/plugins/!Deprecated/Dbx_tree/src/Logger.cpp new file mode 100644 index 0000000000..79b7bedd72 --- /dev/null +++ b/plugins/!Deprecated/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 "Interface.h"
 +#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 += mir_vsntprintf(msgbuf, SIZEOF(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 += mir_sntprintf(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 += mir_sntprintf(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(__PLUGIN_NAME);
 +		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(__PLUGIN_NAME), 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);
 +	delete [] p->lpszText;
 +	delete p;
 +}
\ No newline at end of file diff --git a/plugins/!Deprecated/Dbx_tree/src/Logger.h b/plugins/!Deprecated/Dbx_tree/src/Logger.h new file mode 100644 index 0000000000..a97b928555 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/MREWSync.cpp b/plugins/!Deprecated/Dbx_tree/src/MREWSync.cpp new file mode 100644 index 0000000000..d61867b15f --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/MREWSync.cpp @@ -0,0 +1,331 @@ +/*
 +
 +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 "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/!Deprecated/Dbx_tree/src/MREWSync.h b/plugins/!Deprecated/Dbx_tree/src/MREWSync.h new file mode 100644 index 0000000000..2ffcbc08d7 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/MappedMemory.cpp b/plugins/!Deprecated/Dbx_tree/src/MappedMemory.cpp new file mode 100644 index 0000000000..7ced28a886 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/MappedMemory.cpp @@ -0,0 +1,142 @@ +/*
 +
 +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 "MappedMemory.h"
 +#include "Logger.h"
 +
 +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)
 +	{
 +		FlushViewOfFile(m_Base, NULL);
 +		UnmapViewOfFile(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)
 +	{
 +		FlushViewOfFile(m_Base, 0);
 +		UnmapViewOfFile(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 = CreateFileMappingA(m_DirectFile, NULL, PAGE_READWRITE, 0, Size, NULL);
 +
 +	if (!m_FileMapping)
 +	{
 +		LOGSYS(logERROR, _T("CreateFileMapping failed"));
 +		return 0;
 +	}
 +
 +	m_Base = (uint8_t*)MapViewOfFile(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()
 +{
 +	FlushViewOfFile(m_Base, NULL);
 +	FlushFileBuffers(m_DirectFile);
 +}
 diff --git a/plugins/!Deprecated/Dbx_tree/src/MappedMemory.h b/plugins/!Deprecated/Dbx_tree/src/MappedMemory.h new file mode 100644 index 0000000000..8b13aa7bd1 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/MappedMemory.h @@ -0,0 +1,45 @@ +/*
 +
 +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();
 +};
 diff --git a/plugins/!Deprecated/Dbx_tree/src/SHA256.cpp b/plugins/!Deprecated/Dbx_tree/src/SHA256.cpp new file mode 100644 index 0000000000..f612eab22b --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/SHA256.cpp @@ -0,0 +1,298 @@ +/*
 +
 +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 "SHA256.h"
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#if !defined(_MSC_VER) || !defined(_M_IX86)
 +#define NO_ASM
 +#endif
 +#define SHA_LOOPUNROLL
 +
 +#define rotr(x,n) _lrotr(x,n)
 +
 +
 +// 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/!Deprecated/Dbx_tree/src/SHA256.h b/plugins/!Deprecated/Dbx_tree/src/SHA256.h new file mode 100644 index 0000000000..ef3f005ccb --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/SHA256.h @@ -0,0 +1,44 @@ +/*
 +
 +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 <stdint.h>
 +
 +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/!Deprecated/Dbx_tree/src/Services.cpp b/plugins/!Deprecated/Dbx_tree/src/Services.cpp new file mode 100644 index 0000000000..412b05d76b --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Services.cpp @@ -0,0 +1,412 @@ +/*
 +
 +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 "Database.h"
 +
 +INT_PTR CDataBase::DBEntityGetRoot(WPARAM wParam, LPARAM lParam)
 +{
 +	return getEntities().getRootEntity();
 +}
 +
 +INT_PTR CDataBase::DBEntityChildCount(WPARAM hEntity, LPARAM lParam)
 +{
 +	if (hEntity == 0)
 +		hEntity = getEntities().getRootEntity();
 +
 +	return getEntities().getChildCount(hEntity);
 +}
 +
 +INT_PTR CDataBase::DBEntityGetParent(WPARAM hEntity, LPARAM lParam)
 +{
 +	if (hEntity == 0)
 +		hEntity = getEntities().getRootEntity();
 +
 +	return getEntities().getParent(hEntity);
 +}
 +
 +INT_PTR CDataBase::DBEntityMove(WPARAM hEntity, LPARAM hParent)
 +{
 +	if ((hEntity == 0) || (hEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	if (hParent == 0)
 +		hParent = getEntities().getRootEntity();
 +
 +	return getEntities().setParent(hEntity, hParent);
 +}
 +
 +INT_PTR CDataBase::DBEntityGetFlags(WPARAM hEntity, LPARAM lParam)
 +{
 +	if (hEntity == 0)
 +		hEntity = getEntities().getRootEntity();
 +
 +	return getEntities().getFlags(hEntity);
 +}
 +
 +INT_PTR CDataBase::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 = getEntities().getRootEntity();
 +
 +	return getEntities().IterationInit(*reinterpret_cast<PDBTEntityIterFilter>(pFilter), hParent);
 +}
 +
 +INT_PTR CDataBase::DBEntityIterNext(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getEntities().IterationNext(hIteration);
 +}
 +
 +INT_PTR CDataBase::DBEntityIterClose(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getEntities().IterationClose(hIteration);
 +}
 +
 +INT_PTR CDataBase::DBEntityDelete(WPARAM hEntity, LPARAM lParam)
 +{
 +	if ((hEntity == 0) || (hEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	return getEntities().DeleteEntity(hEntity);
 +}
 +
 +INT_PTR CDataBase::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 = 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 getEntities().CreateEntity(*reinterpret_cast<PDBTEntity>(pEntity));
 +}
 +
 +INT_PTR CDataBase::DBEntityGetAccount(WPARAM hEntity, LPARAM lParam)
 +{
 +	return getEntities().getAccount(hEntity);
 +}
 +
 +INT_PTR CDataBase::DBVirtualEntityCreate(WPARAM hEntity, LPARAM hParent)
 +{
 +	if ((hEntity == 0) || (hEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	if (hParent == 0)
 +		hParent = getEntities().getRootEntity();
 +
 +	return getEntities().VirtualCreate(hEntity, hParent);
 +}
 +INT_PTR CDataBase::DBVirtualEntityGetParent(WPARAM hVirtualEntity, LPARAM lParam)
 +{
 +	if ((hVirtualEntity == 0) || (hVirtualEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	return getEntities().VirtualGetParent(hVirtualEntity);
 +}
 +INT_PTR CDataBase::DBVirtualEntityGetFirst(WPARAM hEntity, LPARAM lParam)
 +{
 +	if ((hEntity == 0) || (hEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	return getEntities().VirtualGetFirst(hEntity);
 +}
 +INT_PTR CDataBase::DBVirtualEntityGetNext(WPARAM hVirtualEntity, LPARAM lParam)
 +{
 +	if ((hVirtualEntity == 0) || (hVirtualEntity == getEntities().getRootEntity()))
 +		return DBT_INVALIDPARAM;
 +
 +	return getEntities().VirtualGetNext(hVirtualEntity);
 +}
 +
 +
 +INT_PTR CDataBase::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 getSettings().FindSetting(*reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor));
 +}
 +INT_PTR CDataBase::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 getSettings().DeleteSetting(*reinterpret_cast<PDBTSettingDescriptor>(pSettingDescriptor));
 +}
 +INT_PTR CDataBase::DBSettingDeleteHandle(WPARAM hSetting, LPARAM lParam)
 +{
 +	if (hSetting == 0)
 +		return DBT_INVALIDPARAM;
 +
 +	return getSettings().DeleteSetting(hSetting);
 +}
 +INT_PTR CDataBase::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 getSettings().WriteSetting(*reinterpret_cast<PDBTSetting>(pSetting));
 +}
 +INT_PTR CDataBase::DBSettingWriteHandle(WPARAM pSetting, LPARAM hSetting)
 +{
 +	if (pSetting == NULL)
 +		return DBT_INVALIDPARAM;
 +
 +	if (reinterpret_cast<PDBTSetting>(pSetting)->cbSize != sizeof(TDBTSetting))
 +		return DBT_INVALIDPARAM;
 +
 +	return getSettings().WriteSetting(*reinterpret_cast<PDBTSetting>(pSetting), hSetting);
 +}
 +INT_PTR CDataBase::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 getSettings().ReadSetting(*reinterpret_cast<PDBTSetting>(pSetting));
 +}
 +INT_PTR CDataBase::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 getSettings().ReadSetting(*((PDBTSetting)pSetting), hSetting);
 +}
 +INT_PTR CDataBase::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 getSettings().IterationInit(*reinterpret_cast<PDBTSettingIterFilter>(pFilter));
 +}
 +INT_PTR CDataBase::DBSettingIterNext(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getSettings().IterationNext(hIteration);
 +}
 +INT_PTR CDataBase::DBSettingIterClose(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getSettings().IterationClose(hIteration);
 +}
 +
 +INT_PTR CDataBase::DBEventGetBlobSize(WPARAM hEvent, LPARAM lParam)
 +{
 +	return getEvents().GetBlobSize(hEvent);
 +}
 +
 +INT_PTR CDataBase::DBEventGet(WPARAM hEvent, LPARAM pEvent)
 +{
 +	if ((pEvent == NULL) || (reinterpret_cast<PDBTEvent>(pEvent)->cbSize != sizeof(TDBTEvent)))
 +		return DBT_INVALIDPARAM;
 +
 +	return getEvents().Get(hEvent, *reinterpret_cast<PDBTEvent>(pEvent));
 +}
 +
 +INT_PTR CDataBase::DBEventGetCount(WPARAM hEntity, LPARAM lParam)
 +{
 +	return getEvents().GetCount(hEntity);
 +}
 +
 +INT_PTR CDataBase::DBEventDelete(WPARAM hEvent, LPARAM lParam)
 +{
 +	return getEvents().Delete(hEvent);
 +}
 +
 +INT_PTR CDataBase::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 getEvents().Add(hEntity, *((PDBTEvent)pEvent));
 +}
 +
 +INT_PTR CDataBase::DBEventMarkRead(WPARAM hEvent, LPARAM lParam)
 +{
 +	return getEvents().MarkRead(hEvent);
 +}
 +
 +INT_PTR CDataBase::DBEventWriteToDisk(WPARAM hEvent, LPARAM lParam)
 +{
 +	return getEvents().WriteToDisk(hEvent);
 +}
 +
 +INT_PTR CDataBase::DBEventGetEntity(WPARAM hEvent, LPARAM lParam)
 +{
 +	return getEvents().getEntity(hEvent);
 +}
 +
 +INT_PTR CDataBase::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 getEvents().IterationInit(*reinterpret_cast<PDBTEventIterFilter>(pFilter));
 +}
 +
 +INT_PTR CDataBase::DBEventIterNext(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getEvents().IterationNext(hIteration);
 +}
 +
 +INT_PTR CDataBase::DBEventIterClose(WPARAM hIteration, LPARAM lParam)
 +{
 +	if ((hIteration == 0) || (hIteration == DBT_INVALIDPARAM))
 +		return hIteration;
 +
 +	return getEvents().IterationClose(hIteration);
 +}
 +
 +void CDataBase::CreateDbService(const char* szService, DbServiceFunc serviceProc)
 +{
 +	::CreateServiceFunctionObj(szService, ( MIRANDASERVICEOBJ )*( void** )&serviceProc, this );
 +}
 +
 +bool CDataBase::RegisterServices()
 +{
 +	CreateDbService(MS_DBT_ENTITY_GETROOT, &CDataBase::DBEntityGetRoot);
 +	CreateDbService(MS_DBT_ENTITY_CHILDCOUNT,       &CDataBase::DBEntityChildCount);
 +	CreateDbService(MS_DBT_ENTITY_GETPARENT,        &CDataBase::DBEntityGetParent);
 +	CreateDbService(MS_DBT_ENTITY_MOVE,             &CDataBase::DBEntityMove);
 +	CreateDbService(MS_DBT_ENTITY_GETFLAGS,         &CDataBase::DBEntityGetFlags);
 +	CreateDbService(MS_DBT_ENTITY_ITER_INIT,        &CDataBase::DBEntityIterInit);
 +	CreateDbService(MS_DBT_ENTITY_ITER_NEXT,        &CDataBase::DBEntityIterNext);
 +	CreateDbService(MS_DBT_ENTITY_ITER_CLOSE,       &CDataBase::DBEntityIterClose);
 +	CreateDbService(MS_DBT_ENTITY_DELETE,           &CDataBase::DBEntityDelete);
 +	CreateDbService(MS_DBT_ENTITY_CREATE,           &CDataBase::DBEntityCreate);
 +	CreateDbService(MS_DBT_ENTITY_GETACCOUNT,       &CDataBase::DBEntityGetAccount);
 +
 +	CreateDbService(MS_DBT_VIRTUALENTITY_CREATE,    &CDataBase::DBVirtualEntityCreate);
 +	CreateDbService(MS_DBT_VIRTUALENTITY_GETPARENT, &CDataBase::DBVirtualEntityGetParent);
 +	CreateDbService(MS_DBT_VIRTUALENTITY_GETFIRST,  &CDataBase::DBVirtualEntityGetFirst);
 +	CreateDbService(MS_DBT_VIRTUALENTITY_GETNEXT,   &CDataBase::DBVirtualEntityGetNext);
 +
 +	CreateDbService(MS_DBT_SETTING_FIND,            &CDataBase::DBSettingFind);
 +	CreateDbService(MS_DBT_SETTING_DELETE,          &CDataBase::DBSettingDelete);
 +	CreateDbService(MS_DBT_SETTING_DELETEHANDLE,    &CDataBase::DBSettingDeleteHandle);
 +	CreateDbService(MS_DBT_SETTING_WRITE,           &CDataBase::DBSettingWrite);
 +	CreateDbService(MS_DBT_SETTING_WRITEHANDLE,     &CDataBase::DBSettingWriteHandle);
 +	CreateDbService(MS_DBT_SETTING_READ,            &CDataBase::DBSettingRead);
 +	CreateDbService(MS_DBT_SETTING_READHANDLE,      &CDataBase::DBSettingReadHandle);
 +	CreateDbService(MS_DBT_SETTING_ITER_INIT,       &CDataBase::DBSettingIterInit);
 +	CreateDbService(MS_DBT_SETTING_ITER_NEXT,       &CDataBase::DBSettingIterNext);
 +	CreateDbService(MS_DBT_SETTING_ITER_CLOSE,      &CDataBase::DBSettingIterClose);
 +
 +	CreateDbService(MS_DBT_EVENT_GETBLOBSIZE,       &CDataBase::DBEventGetBlobSize);
 +	CreateDbService(MS_DBT_EVENT_GET,               &CDataBase::DBEventGet);
 +	CreateDbService(MS_DBT_EVENT_GETCOUNT,          &CDataBase::DBEventGetCount);
 +	CreateDbService(MS_DBT_EVENT_DELETE,            &CDataBase::DBEventDelete);
 +	CreateDbService(MS_DBT_EVENT_ADD,               &CDataBase::DBEventAdd);
 +	CreateDbService(MS_DBT_EVENT_MARKREAD,          &CDataBase::DBEventMarkRead);
 +	CreateDbService(MS_DBT_EVENT_WRITETODISK,       &CDataBase::DBEventWriteToDisk);
 +	CreateDbService(MS_DBT_EVENT_GETENTITY,         &CDataBase::DBEventGetEntity);
 +	CreateDbService(MS_DBT_EVENT_ITER_INIT,         &CDataBase::DBEventIterInit);
 +	CreateDbService(MS_DBT_EVENT_ITER_NEXT,         &CDataBase::DBEventIterNext);
 +	CreateDbService(MS_DBT_EVENT_ITER_CLOSE,        &CDataBase::DBEventIterClose);
 +	return true;
 +}
 diff --git a/plugins/!Deprecated/Dbx_tree/src/Settings.cpp b/plugins/!Deprecated/Dbx_tree/src/Settings.cpp new file mode 100644 index 0000000000..17d8fe635f --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Settings.cpp @@ -0,0 +1,1473 @@ +/*
 +
 +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 "Settings.h"
 +#include <math.h> // floor function
 +#include "Hash.h"
 +
 +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;
 +		}
 +	}
 +
 +	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())
 +	{
 +		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 + mir_snprintf(buffer, SIZEOF(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 + mir_snwprintf(buffer, SIZEOF(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 + mir_snprintf(buffer, SIZEOF(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 + mir_snwprintf(buffer, SIZEOF(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 + mir_snprintf(buffer, SIZEOF(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 + mir_snwprintf(buffer, SIZEOF(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
 +	}
 +
 +	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())
 +	{
 +		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/!Deprecated/Dbx_tree/src/Settings.h b/plugins/!Deprecated/Dbx_tree/src/Settings.h new file mode 100644 index 0000000000..28be10603e --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/TLS.h b/plugins/!Deprecated/Dbx_tree/src/TLS.h new file mode 100644 index 0000000000..bc7e1ed2d0 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/TLS.h @@ -0,0 +1,160 @@ +/*
 +
 +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()
 +{
 +	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/!Deprecated/Dbx_tree/src/Thread.cpp b/plugins/!Deprecated/Dbx_tree/src/Thread.cpp new file mode 100644 index 0000000000..d4a5396e03 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Thread.cpp @@ -0,0 +1,115 @@ +/*
 +
 +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 "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/!Deprecated/Dbx_tree/src/Thread.h b/plugins/!Deprecated/Dbx_tree/src/Thread.h new file mode 100644 index 0000000000..09b0b6c016 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/Version.h b/plugins/!Deprecated/Dbx_tree/src/Version.h new file mode 100644 index 0000000000..029f6c649d --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/Version.h @@ -0,0 +1,15 @@ +#define __MAJOR_VERSION            0
 +#define __MINOR_VERSION            0
 +#define __RELEASE_NUM            0
 +#define __BUILD_NUM               18
 +
 +#include <stdver.h>
 +
 +#define __PLUGIN_NAME            "Miranda dbx_tree database driver"
 +#define __INTERNAL_NAME            "Dbx_tree"
 +#define __FILENAME               "Dbx_tree.dll"
 +#define __DESCRIPTION             "Provides extended Miranda database support."
 +#define __AUTHOR               "Michael 'Protogenes' Kunz"
 +#define __AUTHOREMAIL            "Michael.Kunz@s2005.TU-Chemnitz.de"
 +#define __AUTHORWEB               "http://miranda-ng.org/p/Dbx_tree/"
 +#define __COPYRIGHT               "© 2007 - 2010 Michael 'Protogenes' Kunz"
 diff --git a/plugins/!Deprecated/Dbx_tree/src/dbConfig_rc.h b/plugins/!Deprecated/Dbx_tree/src/dbConfig_rc.h new file mode 100644 index 0000000000..099067d3ec --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/dbVersion_rc.h b/plugins/!Deprecated/Dbx_tree/src/dbVersion_rc.h new file mode 100644 index 0000000000..24a3ae4cf4 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/init.cpp b/plugins/!Deprecated/Dbx_tree/src/init.cpp new file mode 100644 index 0000000000..2a18a988dd --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/init.cpp @@ -0,0 +1,68 @@ +/*
 +
 +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 PLUGININFOEX gPluginInfoEx = {
 +	sizeof(PLUGININFOEX),
 +	__PLUGIN_NAME,
 +	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
 +	__DESCRIPTION,
 +	__AUTHOR,
 +	__AUTHOREMAIL,
 +	__COPYRIGHT,
 +	__AUTHORWEB,
 +	UNICODE_AWARE | STATIC_PLUGIN,
 +	// {28F45248-8C9C-4BEE-9307-7BCF3E12BF99}
 +	{0x28f45248, 0x8c9c, 0x4bee, {0x93, 0x07, 0x7b, 0xcf, 0x3e, 0x12, 0xbf, 0x99}}
 +};
 +
 +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);
 +	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/!Deprecated/Dbx_tree/src/intrinsics.h b/plugins/!Deprecated/Dbx_tree/src/intrinsics.h new file mode 100644 index 0000000000..2627fc03fc --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/intrinsics.h @@ -0,0 +1,399 @@ +#pragma once
 +
 +#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
 diff --git a/plugins/!Deprecated/Dbx_tree/src/inttypes.h b/plugins/!Deprecated/Dbx_tree/src/inttypes.h new file mode 100644 index 0000000000..79a1315500 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/inttypes.h @@ -0,0 +1,299 @@ +// 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_INTTYPES_H_ // [
 +#define _MSC_INTTYPES_H_
 +
 +#pragma once
 +
 +#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/!Deprecated/Dbx_tree/src/lockfree_hashmap.h b/plugins/!Deprecated/Dbx_tree/src/lockfree_hashmap.h new file mode 100644 index 0000000000..7ec2df3ce4 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/lockfree_hashmultimap.h b/plugins/!Deprecated/Dbx_tree/src/lockfree_hashmultimap.h new file mode 100644 index 0000000000..79981e5447 --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/sigslot.h b/plugins/!Deprecated/Dbx_tree/src/sigslot.h new file mode 100644 index 0000000000..1e67a152bf --- /dev/null +++ b/plugins/!Deprecated/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/!Deprecated/Dbx_tree/src/stdafx.cpp b/plugins/!Deprecated/Dbx_tree/src/stdafx.cpp new file mode 100644 index 0000000000..ed529fed13 --- /dev/null +++ b/plugins/!Deprecated/Dbx_tree/src/stdafx.cpp @@ -0,0 +1,18 @@ +/*
 +Copyright (C) 2012-14 Miranda NG project (http://miranda-ng.org)
 +
 +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 version 2
 +of the License.
 +
 +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, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "Interface.h"
\ No newline at end of file  | 
