Index: src/ch/ch.cpp
===================================================================
diff -u -rcbe8851b4ff9b0f235e2c700174370b8884cb844 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/ch/ch.cpp	(.../ch.cpp)	(revision cbe8851b4ff9b0f235e2c700174370b8884cb844)
+++ src/ch/ch.cpp	(.../ch.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -26,6 +26,7 @@
 #include "CrashDlg.h"
 #include "../common/version.h"
 #include "TCommandLineParser.h"
+#include "../libchcore/TStringSet.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
Index: src/libchcore/ConfigNode.cpp
===================================================================
diff -u
--- src/libchcore/ConfigNode.cpp	(revision 0)
+++ src/libchcore/ConfigNode.cpp	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -0,0 +1,47 @@
+// ============================================================================
+//  Copyright (C) 2001-2014 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  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 Library 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 "stdafx.h"
+#include "ConfigNode.h"
+
+BEGIN_CHCORE_NAMESPACE
+
+namespace details
+{
+
+	ConfigNode::ConfigNode(size_t stObjectID, const TString& strNodeName, int iOrder, const TString& strValue) :
+		m_stObjectID(stObjectID),
+		m_iOrder(m_setModifications, iOrder),
+		m_strNodeName(m_setModifications, strNodeName),
+		m_strValue(m_setModifications, strValue)
+	{
+		m_setModifications[eMod_Added] = true;
+	}
+
+	TString ConfigNode::GetNodeName() const
+	{
+		return m_strNodeName;
+	}
+
+	int ConfigNode::GetOrder() const
+	{
+		return m_iOrder;
+	}
+}
+
+END_CHCORE_NAMESPACE
Index: src/libchcore/ConfigNode.h
===================================================================
diff -u
--- src/libchcore/ConfigNode.h	(revision 0)
+++ src/libchcore/ConfigNode.h	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -0,0 +1,63 @@
+// ============================================================================
+//  Copyright (C) 2001-2014 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  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 Library 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 __TCONFIGNODE_H__
+#define __TCONFIGNODE_H__
+
+#include "TString.h"
+#include <boost/variant.hpp>
+#include <bitset>
+#include "TSharedModificationTracker.h"
+
+BEGIN_CHCORE_NAMESPACE
+
+namespace details
+{
+	class ConfigNode
+	{
+	public:
+		ConfigNode(size_t stObjectID, const TString& strNodeName, int iOrder, const TString& strValue);
+
+		TString GetNodeName() const;
+		int GetOrder() const;
+
+	public:
+		enum EModifications
+		{
+			eMod_None = 0,
+			eMod_Added = 1,
+			eMod_NodeName,
+			eMod_Value,
+			eMod_Order,
+
+			eMod_Last
+		};
+
+		typedef std::bitset<eMod_Last> Bitset;
+		mutable Bitset m_setModifications;
+
+		size_t m_stObjectID;
+		TSharedModificationTracker<int, Bitset, eMod_Order> m_iOrder;
+		TSharedModificationTracker<TString, Bitset, eMod_NodeName> m_strNodeName;
+		TSharedModificationTracker<TString, Bitset, eMod_Value> m_strValue;
+	};
+}
+
+END_CHCORE_NAMESPACE
+
+#endif
Index: src/libchcore/ConfigNodeContainer.cpp
===================================================================
diff -u
--- src/libchcore/ConfigNodeContainer.cpp	(revision 0)
+++ src/libchcore/ConfigNodeContainer.cpp	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -0,0 +1,564 @@
+// ============================================================================
+//  Copyright (C) 2001-2014 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  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 Library 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 "stdafx.h"
+#include "ConfigNodeContainer.h"
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/lexical_cast.hpp>
+#include "TCoreException.h"
+#include "ErrorCodes.h"
+#include <boost/property_tree/ptree.hpp>
+
+BEGIN_CHCORE_NAMESPACE
+
+namespace details
+{
+	///////////////////////////////////////////////////////////////////////
+	ChangeValue::ChangeValue(const TString& strNewValue) : m_strNewValue(strNewValue)
+	{
+	}
+
+	void ChangeValue::operator()(ConfigNode& rNode)
+	{
+		m_bWasModified = false;
+		if(rNode.m_strValue.Get() != m_strNewValue)
+		{
+			rNode.m_strValue.Modify() = m_strNewValue;
+			m_bWasModified = true;
+		}
+	}
+
+	bool ChangeValue::WasModified() const
+	{
+		return m_bWasModified;
+	}
+
+	///////////////////////////////////////////////////////////////////////
+	ChangeOrderAndValue::ChangeOrderAndValue(const TString& tNewValue, int iOrder) :
+	m_strNewValue(tNewValue),
+		m_iOrder(iOrder)
+	{
+	}
+
+	void ChangeOrderAndValue::operator()(ConfigNode& rNode)
+	{
+		m_bWasModified = false;
+		if(rNode.m_strValue.Get() != m_strNewValue || rNode.m_iOrder != m_iOrder)
+		{
+			rNode.m_strValue = m_strNewValue;
+			rNode.m_iOrder = m_iOrder;
+
+			m_bWasModified = true;
+		}
+	}
+
+	bool ChangeOrderAndValue::WasModified() const
+	{
+		return m_bWasModified;
+	}
+
+	///////////////////////////////////////////////////////////////////////
+	ConfigNodeContainer::ConfigNodeContainer() :
+		m_bDelayedEnabled(false),
+		m_stLastObjectID(0)
+	{
+	}
+
+	ConfigNodeContainer::ConfigNodeContainer(const ConfigNodeContainer& rSrc)
+	{
+		boost::shared_lock<boost::shared_mutex> lock(rSrc.m_lock);
+		m_mic = rSrc.m_mic;
+		m_strFilePath = rSrc.m_strFilePath;
+		m_setDelayedNotifications.Clear();
+		m_bDelayedEnabled = false;
+		m_stLastObjectID = rSrc.m_stLastObjectID;
+	}
+
+	ConfigNodeContainer& ConfigNodeContainer::operator=(const ConfigNodeContainer& rSrc)
+	{
+		if(this != &rSrc)
+		{
+			boost::unique_lock<boost::shared_mutex> lock2(m_lock);
+			boost::shared_lock<boost::shared_mutex> lock(rSrc.m_lock);
+
+			m_mic = rSrc.m_mic;
+			m_strFilePath = rSrc.m_strFilePath;
+			m_bDelayedEnabled = false;
+			m_stLastObjectID = rSrc.m_stLastObjectID;
+
+			m_setDelayedNotifications.Clear();
+		}
+
+		return *this;
+	}
+
+	TStringArray ConfigNodeContainer::GetArrayValue(PCTSTR pszPropName, const TStringArray& rDefaultValue) const
+	{
+		TStringArray tArray;
+
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+
+		std::pair<ConfigNodeContainer::NodeContainer::const_iterator, ConfigNodeContainer::NodeContainer::const_iterator> pairFnd
+			= m_mic.equal_range(boost::make_tuple(pszPropName));
+
+		if(pairFnd.first == m_mic.end())
+			return rDefaultValue;
+
+		while(pairFnd.first != m_mic.end() && pairFnd.first != pairFnd.second)
+		{
+			tArray.Add((*pairFnd.first).m_strValue);
+			++pairFnd.first;
+		}
+
+		return tArray;
+	}
+
+	bool ConfigNodeContainer::GetArrayValueNoDefault(PCTSTR pszPropName, TStringArray& rValue) const
+	{
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+
+		rValue.Clear();
+
+		std::pair<ConfigNodeContainer::NodeContainer::const_iterator, ConfigNodeContainer::NodeContainer::const_iterator> pairFnd
+			= m_mic.equal_range(boost::make_tuple(pszPropName));
+
+		if(pairFnd.first == m_mic.end())
+			return false;
+
+		while(pairFnd.first != m_mic.end() && pairFnd.first != pairFnd.second)
+		{
+			rValue.Add((*pairFnd.first).m_strValue);
+			++pairFnd.first;
+		}
+
+		return true;
+	}
+
+	bool ConfigNodeContainer::SetArrayValue(PCTSTR pszPropName, const TStringArray& rValue)
+	{
+		bool bResult = false;
+
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		std::pair<ConfigNodeContainer::NodeContainer::const_iterator, ConfigNodeContainer::NodeContainer::const_iterator> pairFnd
+			= m_mic.equal_range(boost::make_tuple(pszPropName));
+
+		if(pairFnd.first == m_mic.end())
+		{
+			// insert new items
+			for(size_t stIndex = 0; stIndex < rValue.GetCount(); ++stIndex)
+			{
+				m_mic.insert(ConfigNode(++m_stLastObjectID, pszPropName, boost::numeric_cast<int>(stIndex), rValue.GetAt(stIndex)));
+			}
+
+			return false;
+		}
+		else
+		{
+			// insert/modify/delete items (diff mode)
+			size_t stIndex = 0;
+			while(pairFnd.first != m_mic.end() && pairFnd.first != pairFnd.second)
+			{
+				if(stIndex < rValue.GetCount())
+				{
+					// update existing item
+					ChangeOrderAndValue tChange(rValue.GetAt(stIndex), boost::numeric_cast<int>(stIndex));
+					m_mic.modify(pairFnd.first, tChange);
+					bResult |= tChange.WasModified();
+
+					++pairFnd.first;
+				}
+				else
+				{
+					// delete this item
+					m_setRemovedObjects.Add(pairFnd.first->m_stObjectID);
+					pairFnd.first = m_mic.erase(pairFnd.first);
+				}
+
+				++stIndex;
+			}
+
+			while(stIndex < rValue.GetCount())
+			{
+				// add items not added before (with new oids)
+				m_mic.insert(ConfigNode(++m_stLastObjectID, pszPropName, boost::numeric_cast<int>(stIndex), rValue.GetAt(stIndex)));
+				++stIndex;
+			}
+
+			return true;
+		}
+	}
+
+	void ConfigNodeContainer::DeleteNode(PCTSTR pszPropName)
+	{
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		std::pair<ConfigNodeContainer::NodeContainer::const_iterator, ConfigNodeContainer::NodeContainer::const_iterator> pairFnd
+			= m_mic.equal_range(boost::make_tuple(pszPropName));
+
+		if(pairFnd.first == m_mic.end())
+			return;
+
+		ConfigNodeContainer::NodeContainer::const_iterator iter = pairFnd.first;
+		while(iter != m_mic.end() && iter != pairFnd.second)
+		{
+			m_setRemovedObjects.Add(iter->m_stObjectID);
+		}
+
+		m_mic.erase(pairFnd.first, pairFnd.second);
+	}
+
+	bool ConfigNodeContainer::ExtractNodes(PCTSTR pszNode, ConfigNodeContainer& tNewContainer) const
+	{
+		bool bFound = false;
+		TString strReplace(pszNode);
+		strReplace += _T(".");
+
+		boost::unique_lock<boost::shared_mutex> dst_lock(tNewContainer.m_lock);
+		tNewContainer.m_mic.clear();
+
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			if(iter->m_strNodeName.Get().StartsWith(strReplace))
+			{
+				bFound = true;
+
+				TString strName = iter->m_strNodeName.Get();
+				strName.MidSelf(strReplace.GetLength());
+
+				tNewContainer.m_mic.insert(ConfigNode(++tNewContainer.m_stLastObjectID, strName, iter->GetOrder(), iter->m_strValue));
+			}
+		}
+
+		return bFound;
+	}
+
+	bool ConfigNodeContainer::ExtractMultipleNodes(PCTSTR pszNode, std::vector<ConfigNodeContainer>& tNewContainers) const
+	{
+		bool bFound = false;
+		TString strReplace(pszNode);
+		strReplace += _T("[");
+
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+
+		size_t stLastIndex = std::numeric_limits<size_t>::max();
+		ConfigNodeContainer* pCurrentContainer = NULL;
+		
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			if(iter->m_strNodeName.Get().StartsWith(strReplace))
+			{
+				bFound = true;
+
+				TString strName = iter->m_strNodeName.Get();
+				strName.MidSelf(strReplace.GetLength());
+				size_t stPos = strName.Find(_T("]"));
+				if(stPos == std::numeric_limits<size_t>::max())
+					THROW_CORE_EXCEPTION(eErr_InvalidData);
+
+				size_t stNodeIndex = boost::lexical_cast<size_t>(strName.Left(stPos));
+				if(stNodeIndex != stLastIndex)
+				{
+					tNewContainers.push_back(ConfigNodeContainer());
+					pCurrentContainer = &tNewContainers.back();
+
+					stLastIndex = stNodeIndex;
+				}
+
+				pCurrentContainer->m_mic.insert(ConfigNode(++pCurrentContainer->m_stLastObjectID, strName.Mid(stPos + 1), iter->GetOrder(), iter->m_strValue));
+			}
+		}
+
+		return bFound;
+	}
+
+	void ConfigNodeContainer::ImportNodes(PCTSTR pszNode, const ConfigNodeContainer& tContainer)
+	{
+		boost::shared_lock<boost::shared_mutex> src_lock(tContainer.m_lock);
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		// search for nodes in this container that starts with pszNode
+		TString strSearch(pszNode);
+		strSearch += _T(".");
+
+		typedef std::pair<TString, int> PairInfo;
+		std::set<PairInfo> setExistingNames;
+		
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			if(iter->m_strNodeName.Get().StartsWith(strSearch))
+			{
+				setExistingNames.insert(std::make_pair(iter->m_strNodeName.Get(), iter->m_iOrder));
+			}
+		}
+
+		NodeContainer::const_iterator iter = tContainer.m_mic.begin();
+		for(; iter != tContainer.m_mic.end(); ++iter)
+		{
+			TString strNodeName = pszNode;
+			strNodeName += _T(".") + iter->m_strNodeName;
+
+			std::set<PairInfo>::iterator iterExisting = setExistingNames.find(std::make_pair(strNodeName, iter->m_iOrder));
+			if(iterExisting != setExistingNames.end())
+			{
+				// node already exists - modify instead of delete+add
+				m_mic.modify(iter, ChangeValue(iter->m_strValue));
+
+				setExistingNames.erase(iterExisting);
+			}
+			else
+			{
+				// node does not exist - need to add new one
+				m_mic.insert(ConfigNode(++m_stLastObjectID, strNodeName, iter->GetOrder(), iter->m_strValue));
+			}
+
+			// remove all nodes with names from setExisting
+			BOOST_FOREACH(const PairInfo& pairNode, setExistingNames)
+			{
+				NodeContainer::iterator iterToRemove = m_mic.find(boost::make_tuple(pairNode.first, pairNode.second));
+				if(iterToRemove != m_mic.end())
+					m_setRemovedObjects.Add(iterToRemove->m_stObjectID);
+
+				m_mic.erase(iterToRemove);
+			}
+		}
+	}
+
+	void ConfigNodeContainer::AddNodes(PCTSTR pszNode, const ConfigNodeContainer& tContainer)
+	{
+		boost::shared_lock<boost::shared_mutex> src_lock(tContainer.m_lock);
+		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+		// determine the current (max) number associated with the node name
+		TString strSearch(pszNode);
+		strSearch += _T("[");
+
+		size_t stMaxNodeNumber = 0;
+
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			TString strCurrentNode = iter->m_strNodeName.Get();
+			if(strCurrentNode.StartsWith(strSearch))
+			{
+				strCurrentNode.MidSelf(strSearch.GetLength());
+				size_t stPos = strCurrentNode.Find(_T("]"));
+				if(stPos == std::numeric_limits<size_t>::max())
+					THROW_CORE_EXCEPTION(eErr_InvalidData);
+
+				size_t stNumber = boost::lexical_cast<size_t>(strCurrentNode.Left(stPos));
+				stMaxNodeNumber = std::max(stMaxNodeNumber, stNumber + 1);
+			}
+		}
+
+		TString strNodePrefix = pszNode;
+		strNodePrefix += TString(_T("[")) + boost::lexical_cast<std::wstring>(stMaxNodeNumber).c_str() + _T("].");
+
+		NodeContainer::const_iterator iter = tContainer.m_mic.begin();
+		for(; iter != tContainer.m_mic.end(); ++iter)
+		{
+			TString strNodeName = strNodePrefix + iter->m_strNodeName;
+
+			m_mic.insert(ConfigNode(++m_stLastObjectID, strNodeName, iter->GetOrder(), iter->m_strValue));
+		}
+	}
+
+	void ConfigNodeContainer::ImportNode(TString strCurrentPath, const boost::property_tree::wiptree& rTree)
+	{
+		if(rTree.empty())
+			return;
+
+		// append separator for non-empty nodes
+		if(!strCurrentPath.IsEmpty())
+			strCurrentPath += _T(".");
+
+		TString strNewPath;
+
+		// analyze subnodes (has only leaf-node(s), multiple non-leaf subnodes with same name, multiple subnodes with different names)
+		std::set<TString> setNodeNames;
+		bool bAllLeafNodes = true;
+		size_t stChildCount = 0;
+		BOOST_FOREACH(const boost::property_tree::wiptree::value_type& rNode, rTree)
+		{
+			setNodeNames.insert(rNode.first.c_str());
+
+			if(!rNode.second.empty())
+				bAllLeafNodes = false;
+
+			++stChildCount;
+		}
+
+		// sanity check (either unique names or empty or an array with single name
+		size_t stNodeNamesCount = setNodeNames.size();
+		if(stChildCount != stNodeNamesCount && stNodeNamesCount != 1)
+			THROW_CORE_EXCEPTION(eErr_InvalidData);
+
+		enum EMode { eMode_LeafStringArrayEntries, eMode_LeafOrContainer, eMode_ContainerSplit, eMode_ContainerPassThrough };
+		EMode eMode = eMode_LeafStringArrayEntries;
+
+		if(stNodeNamesCount == 1 && stChildCount > 1)
+		{
+			if(bAllLeafNodes)
+				eMode = eMode_LeafStringArrayEntries;
+			else
+				eMode = eMode_ContainerSplit;
+		}
+		else
+			eMode = eMode_LeafOrContainer;
+
+		int iIndex = 0;
+		BOOST_FOREACH(const boost::property_tree::wiptree::value_type& rNode, rTree)
+		{
+			switch(eMode)
+			{
+			case eMode_LeafStringArrayEntries:
+				{
+					strNewPath = strCurrentPath + rNode.first.c_str();
+					m_mic.insert(ConfigNode(++m_stLastObjectID, strNewPath, iIndex++, rNode.second.get_value<std::wstring>().c_str()));
+					break;
+				}
+			case eMode_LeafOrContainer:
+				{
+					strNewPath = strCurrentPath + rNode.first.c_str();
+					if(rNode.second.empty())
+					{
+						// get leaf info
+						m_mic.insert(ConfigNode(++m_stLastObjectID, strNewPath, 0, rNode.second.get_value<std::wstring>().c_str()));
+					}
+					else
+					{
+						// traverse through the container
+						ImportNode(strNewPath, rNode.second);
+					}
+
+					break;
+				}
+			case eMode_ContainerSplit:
+				{
+					strNewPath = strCurrentPath + rNode.first.c_str() + _T("[") + boost::lexical_cast<std::wstring>(iIndex++).c_str() + _T("]");
+					ImportNode(strNewPath, rNode.second);
+					break;
+				}
+			case eMode_ContainerPassThrough:
+				{
+					break;
+				}
+			}
+		}
+	}
+
+	void ConfigNodeContainer::ImportFromPropertyTree(const boost::property_tree::wiptree& rTree, boost::unique_lock<boost::shared_mutex>&)
+	{
+//		boost::unique_lock<boost::shared_mutex> lock(m_lock);	// do not lock - locking is done outside
+		m_mic.clear();
+
+		// iterate through property tree
+		ImportNode(_T(""), rTree);
+
+		Dump();
+	}
+
+	void ConfigNodeContainer::ExportToPropertyTree(boost::property_tree::wiptree& rTree) const
+	{
+		rTree.clear();
+
+		size_t stLastBracketID = std::numeric_limits<size_t>::max();
+		TString strGroupNode;
+
+		TCHAR szData[1024];
+szData;
+		boost::property_tree::wiptree treeSubnodes;
+
+		int iNode = 0;
+iNode;
+		boost::shared_lock<boost::shared_mutex> lock(m_lock);
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			const TString& rNodeName = iter->m_strNodeName.Get();
+
+			// tmp
+			//_sntprintf_s(szData, 1024, _TRUNCATE, _T("ExportToPropertyTree (%ld): %s\n"), iNode++, (PCTSTR)rNodeName);
+//			OutputDebugString(szData);
+			// /tmp
+
+			TString strNodeName = rNodeName;
+
+			size_t stBracketPos = strNodeName.Find(_T("["));
+			if(stBracketPos != TString::npos)
+			{
+				// there is a bracket in the node name - this element is a part of a hierarchy of similar nodes
+				size_t stSecondBracketPos = strNodeName.Find(_T("["), stBracketPos + 1);
+				if(stSecondBracketPos == TString::npos)
+					THROW_CORE_EXCEPTION(eErr_InvalidData);
+
+				strGroupNode = strNodeName.Left(stBracketPos);
+				TString strSubnodeName = strNodeName.Mid(stSecondBracketPos + 1);
+
+				size_t stBracketID = boost::lexical_cast<size_t>(strNodeName.Mid(stBracketPos, stSecondBracketPos - stBracketPos - 1));
+				if(stBracketID != stLastBracketID)
+				{
+					// new ID - add new property tree node
+					if(!treeSubnodes.empty())
+					{
+						rTree.add_child((PCTSTR)strGroupNode, treeSubnodes);
+						treeSubnodes.clear();
+					}
+				}
+
+				// same ID - add new element to existing property tree node
+				treeSubnodes.put((PCTSTR)strSubnodeName, iter->m_strValue);
+			}
+			else
+			{
+				// add the subnodes from previous bracket-based entries
+				if(!treeSubnodes.empty())
+				{
+					rTree.add_child((PCTSTR)strGroupNode, treeSubnodes);
+					treeSubnodes.clear();
+				}
+
+				// no bracket in the node name - this is just a standard entry
+				rTree.add((PCTSTR)strNodeName, iter->m_strValue);
+			}
+		}
+
+		// add the last subnode if not empty
+		if(!treeSubnodes.empty())
+			rTree.add_child((PCTSTR)strGroupNode, treeSubnodes);
+	}
+
+	void ConfigNodeContainer::Dump()
+	{
+		const size_t stBufferSize = 1024;
+		TCHAR szBuffer[stBufferSize];
+
+		for(NodeContainer::const_iterator iter = m_mic.begin(); iter != m_mic.end(); ++iter)
+		{
+			_sntprintf_s(szBuffer, stBufferSize, _TRUNCATE, _T("Node (oid %I64u): %s.%ld = %s\n"), iter->m_stObjectID, (PCTSTR)iter->m_strNodeName.Get(), iter->m_iOrder.Get(), (PCTSTR)iter->m_strValue.Get());
+			OutputDebugString(szBuffer);
+		}
+	}
+
+	void ConfigNodeContainer::AddEntry(PCTSTR pszPropName, int iIndex, const TString& strValue)
+	{
+		m_mic.insert(ConfigNode(++m_stLastObjectID, pszPropName, iIndex, strValue));
+	}
+}
+
+END_CHCORE_NAMESPACE
Index: src/libchcore/ConfigNodeContainer.h
===================================================================
diff -u
--- src/libchcore/ConfigNodeContainer.h	(revision 0)
+++ src/libchcore/ConfigNodeContainer.h	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -0,0 +1,268 @@
+// ============================================================================
+//  Copyright (C) 2001-2014 by Jozef Starosczyk
+//  ixen@copyhandler.com
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU Library General Public License
+//  (version 2) as published by the Free Software Foundation;
+//
+//  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 Library 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 __CONFIGNODECONTAINER_H__
+#define __CONFIGNODECONTAINER_H__
+
+#include "TSharedModificationTracker.h"
+#include "ConfigNode.h"
+#include <bitset>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+
+#pragma warning(push)
+#pragma warning(disable: 4100 4702 4512)
+	#include <boost/signals2.hpp>
+#pragma warning(pop)
+#include "TStringSet.h"
+#include "TStringArray.h"
+#include "TRemovedObjects.h"
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <boost/lexical_cast.hpp>
+
+BEGIN_CHCORE_NAMESPACE
+
+namespace details
+{
+	struct ChangeValue
+	{
+		ChangeValue(const TString& strNewValue);
+
+		void operator()(ConfigNode& rNode);
+
+		bool WasModified() const;
+
+	private:
+		TString m_strNewValue;
+		bool m_bWasModified;
+	};
+
+	struct ChangeOrderAndValue
+	{
+		ChangeOrderAndValue(const TString& tNewValue, int iOrder);
+
+		void operator()(ConfigNode& rNode);
+
+		bool WasModified() const;
+
+	private:
+		TString m_strNewValue;
+		int m_iOrder;
+		bool m_bWasModified;
+	};
+
+	struct ConfigNodeContainer
+	{
+	public:
+		ConfigNodeContainer();
+		ConfigNodeContainer(const ConfigNodeContainer& rSrc);
+
+		ConfigNodeContainer& operator=(const ConfigNodeContainer& rSrc);
+
+		void AddEntry(PCTSTR pszPropName, int iIndex, const TString& strValue);
+
+		// get/set single values
+		template<class T>
+		T GetValue(PCTSTR pszPropName, const T& rDefaultValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			T tResult = rDefaultValue;
+
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+				tResult = boost::lexical_cast<T>((PCTSTR)(*iterFnd).m_strValue.Get());
+
+			return tResult;
+		}
+
+		template<>
+		TString GetValue<TString>(PCTSTR pszPropName, const TString& rDefaultValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			TString tResult = rDefaultValue;
+
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+				tResult = (*iterFnd).m_strValue;
+
+			return tResult;
+		}
+
+		template<>
+		bool GetValue<bool>(PCTSTR pszPropName, const bool& bDefaultValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			bool bResult = bDefaultValue;
+
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				if((*iterFnd).m_strValue.Get().CompareNoCase(_T("false")) == 0)
+					bResult = false;
+				else if((*iterFnd).m_strValue.Get().CompareNoCase(_T("true")) == 0)
+					bResult = true;
+				else
+					bResult = boost::lexical_cast<bool>((PCTSTR)(*iterFnd).m_strValue.Get());
+			}
+
+			return bResult;
+		}
+
+		template<class T>
+		bool GetValueNoDefault(PCTSTR pszPropName, T& rValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				rValue = boost::lexical_cast<T>((PCTSTR)(*iterFnd).m_strValue.Get());
+				return true;
+			}
+
+			return false;
+		}
+
+		template<>
+		bool GetValueNoDefault<TString>(PCTSTR pszPropName, TString& rValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				rValue = (*iterFnd).m_strValue;
+				return true;
+			}
+
+			return false;
+		}
+
+		template<>
+		bool GetValueNoDefault<bool>(PCTSTR pszPropName, bool& rValue) const
+		{
+			boost::shared_lock<boost::shared_mutex> lock(m_lock);
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				const TString& strValue = (*iterFnd).m_strValue.Get();
+				if(strValue.CompareNoCase(_T("false")) == 0)
+					rValue = false;
+				else if(strValue.CompareNoCase(_T("true")) == 0)
+					rValue = true;
+				else
+					rValue = boost::lexical_cast<bool>((PCTSTR)strValue);
+				return true;
+			}
+
+			return false;
+		}
+
+		template<class T>
+		bool SetValue(PCTSTR pszPropName, const T& rValue)
+		{
+			boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				ChangeValue tChange(boost::lexical_cast<std::wstring>(rValue).c_str());
+				m_mic.modify(iterFnd, tChange);
+				return tChange.WasModified();
+			}
+			else
+			{
+				m_mic.insert(ConfigNode(++m_stLastObjectID, pszPropName, 0, boost::lexical_cast<std::wstring>(rValue).c_str()));
+				return true;
+			}
+		}
+
+		template<>
+		bool SetValue<bool>(PCTSTR pszPropName, const bool& bValue)
+		{
+			boost::unique_lock<boost::shared_mutex> lock(m_lock);
+
+			ConfigNodeContainer::NodeContainer::const_iterator iterFnd = m_mic.find(boost::make_tuple(pszPropName, 0));
+			if(iterFnd != m_mic.end())
+			{
+				ChangeValue tChange(boost::lexical_cast<std::wstring>(bValue ? _T("true") : _T("false")).c_str());
+				m_mic.modify(iterFnd, tChange);
+				return tChange.WasModified();
+			}
+			else
+			{
+				m_mic.insert(ConfigNode(++m_stLastObjectID, pszPropName, 0, boost::lexical_cast<std::wstring>(bValue).c_str()));
+				return true;
+			}
+		}
+
+		// vector-based values
+		TStringArray GetArrayValue(PCTSTR pszPropName, const TStringArray& rDefaultValue) const;
+		bool GetArrayValueNoDefault(PCTSTR pszPropName, TStringArray& rValue) const;
+		bool SetArrayValue(PCTSTR pszPropName, const TStringArray& rValue);
+
+		// deletion
+		void DeleteNode(PCTSTR pszPropName);
+
+		// extracting nodes
+		bool ExtractNodes(PCTSTR pszNode, ConfigNodeContainer& tNewContainer) const;
+		bool ExtractMultipleNodes(PCTSTR pszNode, std::vector<ConfigNodeContainer>& tNewContainers) const;
+
+		void ImportNodes(PCTSTR pszNode, const ConfigNodeContainer& tContainer);		// replaces specified node with data from tContainer
+		void AddNodes(PCTSTR pszNode, const ConfigNodeContainer& tContainer);		// adds specified config as a newly numbered node in this container
+
+		void ImportFromPropertyTree(const boost::property_tree::wiptree& rTree, boost::unique_lock<boost::shared_mutex>&);
+		void ExportToPropertyTree(boost::property_tree::wiptree& rTree) const;
+
+		// debugging
+		void Dump();
+
+	private:
+		void ImportNode(TString strCurrentPath, const boost::property_tree::wiptree& rTree);
+
+	public:
+		typedef boost::multi_index_container<ConfigNode,
+			boost::multi_index::indexed_by<
+				boost::multi_index::ordered_unique<
+					boost::multi_index::composite_key<ConfigNode, 
+						boost::multi_index::const_mem_fun<ConfigNode, TString, &ConfigNode::GetNodeName>,
+						boost::multi_index::const_mem_fun<ConfigNode, int, &ConfigNode::GetOrder>
+					>
+				>
+			>
+		> NodeContainer;
+		
+		NodeContainer m_mic;
+
+		TString m_strFilePath;
+
+		boost::signals2::signal<void (const TStringSet&)> m_notifier;
+		TStringSet m_setDelayedNotifications;
+		bool m_bDelayedEnabled;
+		size_t m_stLastObjectID;
+
+		TRemovedObjects m_setRemovedObjects;
+
+		mutable boost::shared_mutex m_lock;
+	};
+}
+
+END_CHCORE_NAMESPACE
+
+#endif
Index: src/libchcore/TConfig.cpp
===================================================================
diff -u -r960167a493c3ae7ecbdc7e8c2b91619106d7a685 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TConfig.cpp	(.../TConfig.cpp)	(revision 960167a493c3ae7ecbdc7e8c2b91619106d7a685)
+++ src/libchcore/TConfig.cpp	(.../TConfig.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -26,93 +26,50 @@
 #include <iostream>
 #include <ios>
 #include "../libicpf/exception.h"
-#include "TBinarySerializer.h"
-#include "SerializationHelpers.h"
 #include "TConfigArray.h"
 
 #pragma warning(push)
 #pragma warning(disable: 4702 4512)
-#include <boost/property_tree/xml_parser.hpp>
+	#include <boost/property_tree/xml_parser.hpp>
 #pragma warning(pop)
+
 #include <boost/algorithm/string/find.hpp>
 #include <deque>
 #include "TConfigNotifier.h"
+#include "ConfigNodeContainer.h"
+#include "ErrorCodes.h"
+#include "TCoreException.h"
+#include "TRowData.h"
+#include "ISerializerRowData.h"
 
 BEGIN_CHCORE_NAMESPACE
 
 /////////////////////////////////////////////////////////////////////////////////////////////
-// common set/get templates
-template<class T>
-bool InternalGetValue(const boost::property_tree::wiptree& rTree, PCTSTR pszPropName, T& tOutValue, boost::shared_mutex& rLock)
-{
-	boost::shared_lock<boost::shared_mutex> lock(rLock);
-
-	boost::optional<T> tValue = rTree.get_optional<T>(pszPropName);
-	if(tValue.is_initialized())
-	{
-		tOutValue = tValue.get();
-		return true;
-	}
-	else
-		return false;
-}
-
-template<class T>
-bool InternalSetValue(boost::property_tree::wiptree& rTree, bool& bModified, boost::shared_mutex& rLock, PCTSTR pszPropName, const T& tNewValue)
-{
-	// separate scope for mutex (to avoid calling notifier inside critical section)
-	boost::upgrade_lock<boost::shared_mutex> lock(rLock);
-
-	boost::optional<T> tValue = rTree.get_optional<T>(pszPropName);
-	if(!tValue.is_initialized() || tValue.get() != tNewValue)
-	{
-		boost::upgrade_to_unique_lock<boost::shared_mutex> upgraded_lock(lock);
-		rTree.put<T>(pszPropName, tNewValue);
-		bModified = true;
-		return true;
-	}
-
-	return false;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////
 // class TConfig
 
+using namespace details;
+
 TConfig::TConfig() :
-	m_bDelayedEnabled(false),
-	m_bModified(false)
+	m_pImpl(new details::ConfigNodeContainer)
 {
 }
 
 TConfig::TConfig(const TConfig& rSrc) :
-	m_bDelayedEnabled(false),
-	m_bModified(rSrc.m_bModified)
+	m_pImpl(new details::ConfigNodeContainer(*rSrc.m_pImpl))
 {
-	boost::shared_lock<boost::shared_mutex> lock(rSrc.m_lock);
-
-	m_propTree = rSrc.m_propTree;
-	m_strFilePath = rSrc.m_strFilePath;
 }
 
 TConfig& TConfig::operator=(const TConfig& rSrc)
 {
 	if(this != &rSrc)
-	{
-		boost::shared_lock<boost::shared_mutex> src_lock(rSrc.m_lock);
-		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+		*m_pImpl = *rSrc.m_pImpl;
 
-		m_propTree = rSrc.m_propTree;
-		m_bModified = rSrc.m_bModified;
-		m_strFilePath = rSrc.m_strFilePath;
-		m_bDelayedEnabled = false;
-		m_setDelayedNotifications.Clear();
-	}
-
 	return *this;
 }
 
 TConfig::~TConfig()
 {
+	delete m_pImpl;
 }
 
 // read/write
@@ -121,491 +78,340 @@
 	if(!pszFile)
 		THROW(_T("Invalid argument"), 0, 0, 0);
 
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
+	// convert our underlying data to a property tree (currently probably the easiest way to convert data to xml
+	boost::property_tree::wiptree tPropertyTree;
 
+	std::wifstream ifs(pszFile, std::ios_base::in);
+	boost::property_tree::xml_parser::read_xml(ifs, tPropertyTree);
+
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+
 	// Note: we need to store filename for later use BEFORE trying to open a file
 	//       since it might be nonexistent, but we still would like to store config to this file later
-	ClearNL();		// also clears m_bModified
-	m_strFilePath = pszFile;
+	ClearNL();
+	GetImpl()->m_strFilePath = pszFile;
 
-	std::wifstream ifs(m_strFilePath, std::ios_base::in);
-	try
-	{
-		boost::property_tree::xml_parser::read_xml(ifs, m_propTree);
-	}
-	catch(...)
-	{
-		m_propTree.clear();
-		throw;
-	}
+	GetImpl()->ImportFromPropertyTree(tPropertyTree, lock);
 }
 
-void TConfig::Write(bool bOnlyIfModified)
+void TConfig::Write()
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	if(!bOnlyIfModified || m_bModified)
-	{
-		std::wofstream ofs(m_strFilePath, std::ios_base::out);
+	// NOTE: locking is done inside ExportToPropertyTree()
+	boost::property_tree::wiptree tPropertyTree;
+	GetImpl()->ExportToPropertyTree(tPropertyTree);
 
-		boost::property_tree::xml_parser::write_xml(ofs, m_propTree);
-		m_bModified = false;
-	}
+	std::wofstream ofs(GetImpl()->m_strFilePath, std::ios_base::out);
+	boost::property_tree::xml_parser::write_xml(ofs, tPropertyTree);
 }
 
-void TConfig::SerializeLoad(TReadBinarySerializer& rSerializer)
+void TConfig::ReadFromString(const TString& strInput)
 {
-	using namespace Serializers;
+	if(strInput.IsEmpty())
+		THROW(_T("Invalid argument"), 0, 0, 0);
 
-	boost::property_tree::wiptree propTree;
+	boost::property_tree::wiptree tPropertyTree;
 
-	SerializeLoadNode(rSerializer, propTree);
+	std::wistringstream ifs((const wchar_t*)strInput, std::ios_base::in);
+	boost::property_tree::xml_parser::read_xml(ifs, tPropertyTree);
 
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_propTree = propTree;
-}
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
 
-void TConfig::SerializeLoadNode(TReadBinarySerializer& rSerializer, boost::property_tree::wiptree& treeNode)
-{
-	using namespace Serializers;
+	ClearNL();
 
-	size_t stCount = 0;
-	Serialize(rSerializer, stCount);
-
-	while(stCount--)
-	{
-		// name of the node
-		TString strNodeName;
-		Serialize(rSerializer, strNodeName);
-
-		bool bValue = false;
-		Serialize(rSerializer, bValue);
-
-		if(bValue)
-		{
-			// value
-			TString strNodeValue;
-			Serialize(rSerializer, strNodeValue);
-
-			treeNode.add((PCTSTR)strNodeName, (PCTSTR)strNodeValue);
-		}
-		else
-		{
-			boost::property_tree::wiptree& rSubnodeTree = treeNode.add_child((PCTSTR)strNodeName, boost::property_tree::wiptree());
-			SerializeLoadNode(rSerializer, rSubnodeTree);
-		}
-	}
+	GetImpl()->ImportFromPropertyTree(tPropertyTree, lock);
 }
 
-void TConfig::SerializeStore(TWriteBinarySerializer& rSerializer)
+void TConfig::WriteToString(TString& strOutput)
 {
-	using namespace Serializers;
+	// NOTE: locking is done inside ExportToPropertyTree()
 
-	boost::property_tree::wiptree propTree;
+	boost::property_tree::wiptree tPropertyTree;
+	GetImpl()->ExportToPropertyTree(tPropertyTree);
 
-	// make a copy of internal tree (with locking) to avoid locking within serialization operation
-	{
-		boost::shared_lock<boost::shared_mutex> lock(m_lock);
-		propTree = m_propTree;
-	}
+	std::wostringstream ofs(std::ios_base::out);
+	boost::property_tree::xml_parser::write_xml(ofs, tPropertyTree);
 
-	// serialize the copy
-	SerializeStoreNode(rSerializer, propTree);
+	strOutput = ofs.str().c_str();
 }
 
-void TConfig::SerializeStoreNode(TWriteBinarySerializer& rSerializer, boost::property_tree::wiptree& treeNode)
+
+void TConfig::Store(const ISerializerContainerPtr& spContainer) const
 {
-	using namespace Serializers;
-	Serialize(rSerializer, treeNode.size());
+	if(!spContainer)
+		THROW_CORE_EXCEPTION(eErr_InvalidPointer);
 
-	for(boost::property_tree::wiptree::iterator iterNode = treeNode.begin(); iterNode != treeNode.end(); ++iterNode)
-	{
-		// is this node the leaf one?
-		boost::property_tree::wiptree& rSubNode = (*iterNode).second;
+	boost::shared_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
 
-		// name of the node
-		Serialize(rSerializer, (*iterNode).first.c_str());
+	spContainer->DeleteRows(m_pImpl->m_setRemovedObjects);
 
-		bool bValue = rSubNode.empty();
-		Serialize(rSerializer, bValue);
+	BOOST_FOREACH(const ConfigNode& rNode, m_pImpl->m_mic)
+	{
+		ISerializerRowDataPtr spRow;
 
-		if(bValue)
-		{
-			// value
-			Serialize(rSerializer, rSubNode.data().c_str());
-		}
+		bool bAdded = rNode.m_setModifications[ConfigNode::eMod_Added];
+		if(bAdded)
+			spRow = spContainer->AddRow(rNode.m_stObjectID);
+		else if(rNode.m_setModifications.any())
+			spRow = spContainer->GetRow(rNode.m_stObjectID);
 		else
-		{
-			// store children
-			SerializeStoreNode(rSerializer, rSubNode);
-		}
-	}
-}
+			continue;
 
-void TConfig::ReadFromString(const TString& strInput)
-{
-	if(strInput.IsEmpty())
-		THROW(_T("Invalid argument"), 0, 0, 0);
+		if(bAdded || rNode.m_setModifications[ConfigNode::eMod_NodeName])
+			*spRow % TRowData(_T("name"), rNode.GetNodeName());
+		if(bAdded || rNode.m_setModifications[ConfigNode::eMod_Order])
+			*spRow % TRowData(_T("node_order"), rNode.GetOrder());
+		if(bAdded || rNode.m_setModifications[ConfigNode::eMod_Value])
+			*spRow % TRowData(_T("value"), rNode.m_strValue.Get());
 
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-
-	ClearNL();		// also clears m_bModified
-
-	std::wistringstream ifs((const wchar_t*)strInput, std::ios_base::in);
-	try
-	{
-		boost::property_tree::xml_parser::read_xml(ifs, m_propTree);
+		rNode.m_setModifications.reset();
 	}
-	catch(...)
-	{
-		m_propTree.clear();
-		throw;
-	}
 }
 
-void TConfig::WriteToString(TString& strOutput)
+void TConfig::Load(const ISerializerContainerPtr& spContainer) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	if(!spContainer)
+		THROW_CORE_EXCEPTION(eErr_InvalidPointer);
 
-	std::wostringstream ofs(std::ios_base::out);
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+	m_pImpl->m_setRemovedObjects.Clear();
+	m_pImpl->m_mic.clear();
 
-	boost::property_tree::xml_parser::write_xml(ofs, m_propTree);
+	ISerializerRowReaderPtr spRowReader = spContainer->GetRowReader();
+	IColumnsDefinitionPtr spColumns = spRowReader->GetColumnsDefinitions();
+	if(spColumns->IsEmpty())
+		*spColumns % _T("name") % _T("node_order") % _T("value");
 
-	strOutput = ofs.str().c_str();
-}
-
-void TConfig::SetFilePath(PCTSTR pszPath)
-{
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	if(m_strFilePath != pszPath)
+	while(spRowReader->Next())
 	{
-		m_strFilePath = pszPath;
-		m_bModified = true;			// since the path is modified, we can only assume that stuff needs to be written into it regardless of the current modification state
-	}
-}
+		TString strName;
+		int iOrder = 0;
+		TString strValue;
 
-bool TConfig::IsModified() const
-{
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_bModified;
-}
+		spRowReader->GetValue(_T("name"), strName);
+		spRowReader->GetValue(_T("node_order"), iOrder);
+		spRowReader->GetValue(_T("value"), strValue);
 
-void TConfig::MarkAsModified()
-{
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_bModified = true;
+		m_pImpl->AddEntry(strName, iOrder, strValue);
+	}
 }
 
-void TConfig::MarkAsNotModified()
+void TConfig::SetFilePath(PCTSTR pszPath)
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_bModified = false;
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+	GetImpl()->m_strFilePath = pszPath;
 }
 
 void TConfig::Clear()
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
 
 	ClearNL();
 }
 
 void TConfig::ClearNL()
 {
-	m_propTree.clear();
-	m_bModified = false;
-	m_setDelayedNotifications.Clear();
-	m_bDelayedEnabled = false;
-	m_strFilePath.Clear();
+	GetImpl()->m_mic.clear();
+	GetImpl()->m_setDelayedNotifications.Clear();
+	GetImpl()->m_bDelayedEnabled = false;
+	GetImpl()->m_strFilePath.Clear();
 }
 
 // value setting/retrieval
 bool TConfig::GetBool(PCTSTR pszPropName, bool bDefault) const
 {
-	bool bResult = bDefault;
-	if(!InternalGetValue<bool>(m_propTree, pszPropName, bResult, m_lock))
-		bResult = bDefault;
-	return bResult;
+	return GetImpl()->GetValue(pszPropName, bDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, bool& bValue) const
 {
-	return InternalGetValue<bool>(m_propTree, pszPropName, bValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, bValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, bool bValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, bValue))
+	if(GetImpl()->SetValue(pszPropName, bValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 int TConfig::GetInt(PCTSTR pszPropName, int iDefault) const
 {
-	int iResult = 0;
-	if(!InternalGetValue<int>(m_propTree, pszPropName, iResult, m_lock))
-		iResult = iDefault;
-	return iResult;
+	return GetImpl()->GetValue(pszPropName, iDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, int& iValue) const
 {
-	return InternalGetValue<int>(m_propTree, pszPropName, iValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, iValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, int iValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, iValue))
+	if(GetImpl()->SetValue(pszPropName, iValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 unsigned int TConfig::GetUInt(PCTSTR pszPropName, unsigned int uiDefault) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_propTree.get<unsigned int>(pszPropName, uiDefault);
+	return GetImpl()->GetValue(pszPropName, uiDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, unsigned int& uiValue) const
 {
-	return InternalGetValue<unsigned int>(m_propTree, pszPropName, uiValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, uiValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, unsigned int uiValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, uiValue))
+	if(GetImpl()->SetValue(pszPropName, uiValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 long long TConfig::GetLongLong(PCTSTR pszPropName, long long llDefault) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_propTree.get<long long>(pszPropName, llDefault);
+	return GetImpl()->GetValue(pszPropName, llDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, long long& llValue) const
 {
-	return InternalGetValue<long long>(m_propTree, pszPropName, llValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, llValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, long long llValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, llValue))
+	if(GetImpl()->SetValue(pszPropName, llValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 unsigned long long TConfig::GetULongLong(PCTSTR pszPropName, unsigned long long ullDefault) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_propTree.get<unsigned long long>(pszPropName, ullDefault);
+	return GetImpl()->GetValue(pszPropName, ullDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, unsigned long long& ullValue) const
 {
-	return InternalGetValue<unsigned long long>(m_propTree, pszPropName, ullValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, ullValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, unsigned long long ullValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, ullValue))
+	if(GetImpl()->SetValue(pszPropName, ullValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 double TConfig::GetDouble(PCTSTR pszPropName, double dDefault) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	return m_propTree.get<double>(pszPropName, dDefault);
+	return GetImpl()->GetValue(pszPropName, dDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, double& dValue) const
 {
-	return InternalGetValue<double>(m_propTree, pszPropName, dValue, m_lock);
+	return GetImpl()->GetValueNoDefault(pszPropName, dValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, double dValue)
 {
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, dValue))
+	if(GetImpl()->SetValue(pszPropName, dValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 TString TConfig::GetString(PCTSTR pszPropName, const TString& strDefault) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	std::wstring wstrData = m_propTree.get<std::wstring>(pszPropName, std::wstring(strDefault));
-	return wstrData.c_str();
+	return GetImpl()->GetValue(pszPropName, strDefault);
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, TString& rstrValue) const
 {
-	std::wstring wstrData;
-	bool bResult = InternalGetValue<std::wstring>(m_propTree, pszPropName, wstrData, m_lock);
-	rstrValue = wstrData.c_str();
-
-	return bResult;
+	return GetImpl()->GetValueNoDefault(pszPropName, rstrValue);
 }
 
 TConfig& TConfig::SetValue(PCTSTR pszPropName, const TString& strValue)
 {
-	std::wstring wstrData = strValue;
-	if(InternalSetValue(m_propTree, m_bModified, m_lock, pszPropName, wstrData))
+	if(GetImpl()->SetValue(pszPropName, strValue))
 		SendNotification(pszPropName);
 
 	return *this;
 }
 
 bool TConfig::GetValue(PCTSTR pszPropName, TStringArray& rvValues) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-	rvValues.Clear();
-
-	// get rid of the last part of the property to get to the parent holding the real entries
-	std::wstring wstrPropertyName = pszPropName;
-	boost::iterator_range<std::wstring::iterator> iterFnd = boost::find_last(wstrPropertyName, _T("."));
-	if(iterFnd.begin() == wstrPropertyName.end())
-		return false;
-
-	std::wstring wstrNewPropName;
-	wstrNewPropName.insert(wstrNewPropName.end(), wstrPropertyName.begin(), iterFnd.begin());
-
-	boost::optional<const boost::property_tree::wiptree&> children = m_propTree.get_child_optional(wstrNewPropName);
-	if(children.is_initialized())
-	{
-		BOOST_FOREACH(const boost::property_tree::wiptree::value_type& rEntry, children.get())
-		{
-			rvValues.Add(rEntry.second.data().c_str());
-		}
-
-		return true;
-	}
-	else
-		return false;
+	return GetImpl()->GetArrayValueNoDefault(pszPropName, rvValues);
 }
 
-void TConfig::SetValue(PCTSTR pszPropName, const TStringArray& rvValues)
+TConfig& TConfig::SetValue(PCTSTR pszPropName, const TStringArray& rvValues)
 {
-	// get rid of the last part of the property to get to the parent holding the real entries
-	std::wstring wstrNewPropName;
-	std::wstring wstrPropertyName = pszPropName;
-	boost::iterator_range<std::wstring::iterator> iterFnd = boost::find_last(wstrPropertyName, _T("."));
-	if(iterFnd.begin() != wstrPropertyName.end())
-		wstrNewPropName.insert(wstrNewPropName.end(), wstrPropertyName.begin(), iterFnd.begin());
-	else
-		wstrNewPropName = pszPropName;
+	if(GetImpl()->SetArrayValue(pszPropName, rvValues))
+		SendNotification(pszPropName);
 
-	// separate scope for mutex (to avoid calling notifier inside critical section)
-	{
-		boost::unique_lock<boost::shared_mutex> lock(m_lock);
+	return *this;
+}
 
-		boost::optional<boost::property_tree::wiptree&> children = m_propTree.get_child_optional(wstrNewPropName);
-		if(children.is_initialized())
-			children.get().clear();
-		for(size_t stIndex = 0; stIndex < rvValues.GetCount(); ++stIndex)
-		{
-			m_propTree.add(pszPropName, (const wchar_t*)rvValues.GetAt(stIndex));
-		}
-
-		m_bModified = true;
-	}
-
-	SendNotification(pszPropName);
+void TConfig::DeleteNode(PCTSTR pszNodeName)
+{
+	GetImpl()->DeleteNode(pszNodeName);
 }
 
 // extraction of subtrees
 bool TConfig::ExtractSubConfig(PCTSTR pszSubTreeName, TConfig& rSubConfig) const
 {
-	boost::unique_lock<boost::shared_mutex> dst_lock(rSubConfig.m_lock);
-	rSubConfig.ClearNL();
-
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
-
-	boost::optional<const boost::property_tree::wiptree&> optChildren = m_propTree.get_child_optional(pszSubTreeName);
-	if(optChildren.is_initialized())
-	{
-		rSubConfig.m_propTree = optChildren.get();
-		return true;
-	}
-	else
-		return false;
+	return GetImpl()->ExtractNodes(pszSubTreeName, *rSubConfig.m_pImpl);
 }
 
 bool TConfig::ExtractMultiSubConfigs(PCTSTR pszSubTreeName, TConfigArray& rSubConfigs) const
 {
-	boost::shared_lock<boost::shared_mutex> lock(m_lock);
+	rSubConfigs.Clear();
 
-	std::wstring wstrPropertyName = pszSubTreeName;
-	boost::iterator_range<std::wstring::iterator> iterFnd = boost::find_last(wstrPropertyName, _T("."));
-	if(iterFnd.begin() == wstrPropertyName.end())
+	std::vector<ConfigNodeContainer> vNodeContainers;
+	if(!GetImpl()->ExtractMultipleNodes(pszSubTreeName, vNodeContainers))
 		return false;
 
-	std::wstring wstrNewPropName;
-	wstrNewPropName.insert(wstrNewPropName.end(), wstrPropertyName.begin(), iterFnd.begin());
-
-	boost::optional<const boost::property_tree::wiptree&> optChildren = m_propTree.get_child_optional(wstrNewPropName);
-	if(optChildren.is_initialized())
+	BOOST_FOREACH(const ConfigNodeContainer& rNode, vNodeContainers)
 	{
-		BOOST_FOREACH(const boost::property_tree::wiptree::value_type& rEntry, optChildren.get())
-		{
-			std::wstring strData = rEntry.first.c_str();
+		TConfig cfg;
+		*cfg.m_pImpl = rNode;
 
-			TConfig cfg;
-			cfg.m_propTree = rEntry.second;
-			rSubConfigs.Add(cfg);
-		}
-
-		return true;
+		rSubConfigs.Add(cfg);
 	}
-	else
-		return false;
+
+	return true;
 }
 
 void TConfig::PutSubConfig(PCTSTR pszSubTreeName, const TConfig& rSubConfig)
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	boost::shared_lock<boost::shared_mutex> src_lock(rSubConfig.m_lock);
-
-	m_propTree.put_child(pszSubTreeName, rSubConfig.m_propTree);
-
-	m_bModified = true;
+	GetImpl()->ImportNodes(pszSubTreeName, *rSubConfig.m_pImpl);
 }
 
 void TConfig::AddSubConfig(PCTSTR pszSubTreeName, const TConfig& rSubConfig)
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	boost::shared_lock<boost::shared_mutex> src_lock(rSubConfig.m_lock);
-
-	m_propTree.add_child(pszSubTreeName, rSubConfig.m_propTree);
-
-	m_bModified = true;
+	GetImpl()->AddNodes(pszSubTreeName, *rSubConfig.m_pImpl);
 }
 
-void TConfig::DeleteNode(PCTSTR pszNodeName)
-{
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_propTree.erase(pszNodeName);
-}
-
 void TConfig::ConnectToNotifier(void (*pfnCallback)(const TStringSet&, void*), void* pParam)
 {
-	m_notifier.connect(TConfigNotifier(pfnCallback, pParam));
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+	GetImpl()->m_notifier.connect(TConfigNotifier(pfnCallback, pParam));
 }
 
 void TConfig::DisconnectFromNotifier(void (*pfnCallback)(const TStringSet&, void*))
 {
-	m_notifier.disconnect(TConfigNotifier(pfnCallback, NULL));
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+	GetImpl()->m_notifier.disconnect(TConfigNotifier(pfnCallback, NULL));
 }
 
 void TConfig::DelayNotifications()
 {
-	boost::unique_lock<boost::shared_mutex> lock(m_lock);
-	m_bDelayedEnabled = true;
+	boost::unique_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+	GetImpl()->m_bDelayedEnabled = true;
 }
 
 void TConfig::ResumeNotifications()
@@ -614,16 +420,16 @@
 
 	// separate scope for shared mutex (to avoid calling notifier inside critical section)
 	{
-		boost::upgrade_lock<boost::shared_mutex> lock(m_lock);
-		if(m_bDelayedEnabled)
+		boost::upgrade_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+		if(GetImpl()->m_bDelayedEnabled)
 		{
-			m_bDelayedEnabled = false;
-			if(!m_setDelayedNotifications.IsEmpty())
+			GetImpl()->m_bDelayedEnabled = false;
+			if(!GetImpl()->m_setDelayedNotifications.IsEmpty())
 			{
-				setNotifications = m_setDelayedNotifications;
+				setNotifications = GetImpl()->m_setDelayedNotifications;
 
 				boost::upgrade_to_unique_lock<boost::shared_mutex> upgraded_lock(lock);
-				m_setDelayedNotifications.Clear();
+				GetImpl()->m_setDelayedNotifications.Clear();
 			}
 		}
 	}
@@ -637,38 +443,66 @@
 {
 	// separate scope for shared mutex (to avoid calling notifier inside critical section)
 	{
-		boost::upgrade_lock<boost::shared_mutex> lock(m_lock);
-		if(m_bDelayedEnabled)
+		boost::upgrade_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+		if(GetImpl()->m_bDelayedEnabled)
 		{
 			boost::upgrade_to_unique_lock<boost::shared_mutex> upgraded_lock(lock);
 
-			m_setDelayedNotifications.Insert(rsetInfo);
+			GetImpl()->m_setDelayedNotifications.Insert(rsetInfo);
 			return;
 		}
 	}
 
 	// NOTE: we don't lock here
-	m_notifier(rsetInfo);
+	GetImpl()->m_notifier(rsetInfo);
 }
 
 void TConfig::SendNotification(PCTSTR pszInfo)
 {
 	// separate scope for shared mutex (to avoid calling notifier inside critical section)
 	{
-		boost::upgrade_lock<boost::shared_mutex> lock(m_lock);
-		if(m_bDelayedEnabled)
+		boost::upgrade_lock<boost::shared_mutex> lock(GetImpl()->m_lock);
+		if(GetImpl()->m_bDelayedEnabled)
 		{
 			boost::upgrade_to_unique_lock<boost::shared_mutex> upgraded_lock(lock);
 
-			m_setDelayedNotifications.Insert(pszInfo);
+			GetImpl()->m_setDelayedNotifications.Insert(pszInfo);
 			return;
 		}
 	}
 
 	// NOTE: we don't lock here
 	TStringSet setData;
 	setData.Insert(pszInfo);
-	m_notifier(setData);
+	GetImpl()->m_notifier(setData);
 }
 
+details::ConfigNodeContainer* TConfig::GetImpl()
+{
+	return m_pImpl;
+}
+
+const details::ConfigNodeContainer* TConfig::GetImpl() const
+{
+	return m_pImpl;
+}
+
+TSmartPath TConfig::GetPath(PCTSTR pszPropName, const TSmartPath& pathDefault) const
+{
+	return PathFromWString(GetString(pszPropName, pathDefault.ToWString()));
+}
+
+bool TConfig::GetValue(PCTSTR pszPropName, TSmartPath& rpathValue) const
+{
+	TString strPath;
+	bool bResult = GetValue(pszPropName, strPath);
+	rpathValue = PathFromWString(strPath);
+	return bResult;
+}
+
+TConfig& TConfig::SetValue(PCTSTR pszPropName, const TSmartPath& pathValue)
+{
+	return SetValue(pszPropName, pathValue.ToWString());
+}
+
 END_CHCORE_NAMESPACE
Index: src/libchcore/TConfig.h
===================================================================
diff -u -r960167a493c3ae7ecbdc7e8c2b91619106d7a685 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TConfig.h	(.../TConfig.h)	(revision 960167a493c3ae7ecbdc7e8c2b91619106d7a685)
+++ src/libchcore/TConfig.h	(.../TConfig.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -23,21 +23,19 @@
 #ifndef __TCONFIG_H__
 #define __TCONFIG_H__
 
-#pragma warning(push)
-#pragma warning(disable: 4100 4702 4512)
-	#include <boost/property_tree/ptree.hpp>
-	#include <boost/signals2.hpp>
-#pragma warning(pop)
-#include "TStringSet.h"
-#include "TStringArray.h"
+#include "libchcore.h"
+#include "ISerializerContainer.h"
 
 BEGIN_CHCORE_NAMESPACE
 
-class TReadBinarySerializer;
-class TWriteBinarySerializer;
-
 class TConfigArray;
+class TStringSet;
 
+namespace details
+{
+	struct ConfigNodeContainer;
+}
+
 // class for handling configuration settings
 class LIBCHCORE_API TConfig
 {
@@ -52,21 +50,16 @@
 
 	// read/write
 	void Read(PCTSTR pszFile);
-	void Write(bool bOnlyIfModified = false);
+	void Write();
 
-	void SerializeLoad(TReadBinarySerializer& rSerializer);
-	void SerializeStore(TWriteBinarySerializer& rSerializer);
+	void Store(const ISerializerContainerPtr& spContainer) const;
+	void Load(const ISerializerContainerPtr& spContainer) const;
 
 	void ReadFromString(const TString& strInput);
 	void WriteToString(TString& strOutput);
 
 	void SetFilePath(PCTSTR pszPath);
 
-	// Modifications management
-	bool IsModified() const;
-	void MarkAsModified();
-	void MarkAsNotModified();
-
 	// value setting/retrieval
 	bool GetBool(PCTSTR pszPropName, bool bDefault = false) const;
 	bool GetValue(PCTSTR pszPropName, bool& bValue) const;
@@ -96,8 +89,12 @@
 	bool GetValue(PCTSTR pszPropName, TString& rstrValue) const;
 	TConfig& SetValue(PCTSTR pszPropName, const TString& strValue);
 
+	TSmartPath GetPath(PCTSTR pszPropName, const TSmartPath& pathDefault) const;
+	bool GetValue(PCTSTR pszPropName, TSmartPath& rpathValue) const;
+	TConfig& SetValue(PCTSTR pszPropName, const TSmartPath& pathValue);
+
 	bool GetValue(PCTSTR pszPropName, TStringArray& rvValues) const;
-	void SetValue(PCTSTR pszPropName, const TStringArray& rvValues);
+	TConfig& SetValue(PCTSTR pszPropName, const TStringArray& rvValues);
 
 	void DeleteNode(PCTSTR pszNodeName);
 
@@ -120,22 +117,14 @@
 
 	void ClearNL();
 
-	void SerializeStoreNode(TWriteBinarySerializer& rSerializer, boost::property_tree::wiptree& treeNode);
-	void SerializeLoadNode(TReadBinarySerializer& rSerializer, boost::property_tree::wiptree& treeNode);
+private:
+	details::ConfigNodeContainer* GetImpl();
+	const details::ConfigNodeContainer* GetImpl() const;
 
 private:
 #pragma warning(push)
 #pragma warning(disable: 4251)
-	boost::property_tree::wiptree m_propTree;
-	TString m_strFilePath;
-
-	boost::signals2::signal<void (const TStringSet&)> m_notifier;
-	TStringSet m_setDelayedNotifications;
-	bool m_bDelayedEnabled;
-
-	bool m_bModified;		///< Modification state - cleared when saving
-
-	mutable boost::shared_mutex m_lock;
+	details::ConfigNodeContainer* m_pImpl;
 #pragma warning(pop)
 };
 
Index: src/libchcore/TConfigSerializers.h
===================================================================
diff -u -rbe30619d750d8663d54cf02e7d4bde2ed2dd8d05 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TConfigSerializers.h	(.../TConfigSerializers.h)	(revision be30619d750d8663d54cf02e7d4bde2ed2dd8d05)
+++ src/libchcore/TConfigSerializers.h	(.../TConfigSerializers.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -24,6 +24,7 @@
 #define __TCONFIGSERIALIZERS_H__
 
 #include "TConfig.h"
+#include "TStringArray.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TDateTime.cpp
===================================================================
diff -u -r548382442cbf7bed7f744b279ce3f66b54992724 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TDateTime.cpp	(.../TDateTime.cpp)	(revision 548382442cbf7bed7f744b279ce3f66b54992724)
+++ src/libchcore/TDateTime.cpp	(.../TDateTime.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -22,8 +22,8 @@
 // ============================================================================
 #include "stdafx.h"
 #include "TDateTime.h"
-#include "SerializationHelpers.h"
 #include "TBinarySerializer.h"
+#include "SerializationHelpers.h"
 #include "TCoreException.h"
 #include "ErrorCodes.h"
 
Index: src/libchcore/TFileFilter.h
===================================================================
diff -u -rba802caea92ee56a154d1da3fe89a4b2f7875f0e -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TFileFilter.h	(.../TFileFilter.h)	(revision ba802caea92ee56a154d1da3fe89a4b2f7875f0e)
+++ src/libchcore/TFileFilter.h	(.../TFileFilter.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -22,6 +22,7 @@
 #include "libchcore.h"
 #include <atltime.h>
 #include "TDateTime.h"
+#include "TStringArray.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TPath.cpp
===================================================================
diff -u -r293e52b38d46653068006262172018a0f0d0a31c -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TPath.cpp	(.../TPath.cpp)	(revision 293e52b38d46653068006262172018a0f0d0a31c)
+++ src/libchcore/TPath.cpp	(.../TPath.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -26,11 +26,10 @@
 #pragma warning(pop)
 #include "../libicpf/exception.h"
 #include <cctype>
-#include "TBinarySerializer.h"
-#include "SerializationHelpers.h"
 #include "TCoreException.h"
 #include "ErrorCodes.h"
 #include "TPathContainer.h"
+#include "TStringArray.h"
 
 BEGIN_CHCORE_NAMESPACE
 
@@ -1072,56 +1071,7 @@
 	return m_pPath->m_strPath.GetLength();
 }
 
-void TSmartPath::Serialize(TReadBinarySerializer& rSerializer)
-{
-	PrepareToWrite();
-	Serializers::Serialize(rSerializer, m_pPath->m_strPath);
-}
-
-void TSmartPath::Serialize(TWriteBinarySerializer& rSerializer) const
-{
-	if(m_pPath)
-		Serializers::Serialize(rSerializer, m_pPath->m_strPath);
-	else
-		Serializers::Serialize(rSerializer, TString());
-}
-
 // ============================================================================
-/// chcore::TSmartPath::StoreInConfig
-/// @date 2011/04/05
-///
-/// @brief     Stores the path in configuration file.
-/// @param[in] rConfig - configuration object to store information in.
-/// @param[in] pszPropName - property name under which to store the path.
-// ============================================================================
-void TSmartPath::StoreInConfig(TConfig& rConfig, PCTSTR pszPropName) const
-{
-	rConfig.SetValue(pszPropName, m_pPath ? m_pPath->m_strPath : TString());
-}
-
-// ============================================================================
-/// chcore::TSmartPath::ReadFromConfig
-/// @date 2011/04/05
-///
-/// @brief     Reads a path from configuration file.
-/// @param[in] rConfig - configuration object to read path from.
-/// @param[in] pszPropName - property name from under which to read the path.
-/// @return    True if path properly read, false otherwise.
-// ============================================================================
-bool TSmartPath::ReadFromConfig(const TConfig& rConfig, PCTSTR pszPropName)
-{
-	TString wstrPath;
-	if(rConfig.GetValue(pszPropName, wstrPath))
-	{
-		PrepareToWrite();
-		m_pPath->m_strPath = wstrPath;
-		return true;
-	}
-	else
-		return false;
-}
-
-// ============================================================================
 /// TSmartPath::AppendIfNotExists
 /// @date 2009/11/29
 ///
Index: src/libchcore/TPath.h
===================================================================
diff -u -r293e52b38d46653068006262172018a0f0d0a31c -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TPath.h	(.../TPath.h)	(revision 293e52b38d46653068006262172018a0f0d0a31c)
+++ src/libchcore/TPath.h	(.../TPath.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -20,7 +20,7 @@
 #define __TPATH_H__
 
 #include "libchcore.h"
-#include "TConfig.h"
+#include "TString.h"
 
 BEGIN_CHCORE_NAMESPACE
 
@@ -142,13 +142,6 @@
 	bool IsEmpty() const;
 	size_t GetLength() const;
 
-	// Serialization
-	void Serialize(TReadBinarySerializer& rSerializer);
-	void Serialize(TWriteBinarySerializer& rSerializer) const;
-
-	void StoreInConfig(TConfig& rConfig, PCTSTR pszPropName) const;
-	bool ReadFromConfig(const TConfig& rConfig, PCTSTR pszPropName);
-
 protected:
 	void PrepareToWrite();
 
@@ -163,6 +156,4 @@
 
 END_CHCORE_NAMESPACE
 
-CONFIG_MEMBER_SERIALIZATION(TSmartPath)
-
 #endif
Index: src/libchcore/TPathContainer.cpp
===================================================================
diff -u -r73583f2ca01fa1b2eae49bbc63bce46b9ecff5db -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TPathContainer.cpp	(.../TPathContainer.cpp)	(revision 73583f2ca01fa1b2eae49bbc63bce46b9ecff5db)
+++ src/libchcore/TPathContainer.cpp	(.../TPathContainer.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -20,6 +20,7 @@
 #include "TPathContainer.h"
 #include "TCoreException.h"
 #include "ErrorCodes.h"
+#include "TStringArray.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TPathContainer.h
===================================================================
diff -u -r73583f2ca01fa1b2eae49bbc63bce46b9ecff5db -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TPathContainer.h	(.../TPathContainer.h)	(revision 73583f2ca01fa1b2eae49bbc63bce46b9ecff5db)
+++ src/libchcore/TPathContainer.h	(.../TPathContainer.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -21,6 +21,7 @@
 
 #include "libchcore.h"
 #include "TPath.h"
+#include "TConfig.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TSQLiteTaskSchema.cpp
===================================================================
diff -u -ra5aa3c3cb78f3767641de2627d1a49a1dc35b429 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision a5aa3c3cb78f3767641de2627d1a49a1dc35b429)
+++ src/libchcore/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -52,6 +52,9 @@
 		tStatement.Prepare(_T("CREATE TABLE scanned_files(id BIGINT UNIQUE, rel_path varchar(32768) NOT NULL, base_path_id BIGINT NOT NULL, attr INT NOT NULL, size BIGINT NOT NULL, time_created BIGINT NOT NULL, time_last_write BIGINT NOT NULL, time_last_access BIGINT NOT NULL, flags INT NOT NULL)"));
 		tStatement.Step();
 
+		tStatement.Prepare(_T("CREATE TABLE task_config(id BIGINT UNIQUE, name varchar(256) NOT NULL, node_order INT NOT NULL, value varchar(32768) NOT NULL)"));
+		tStatement.Step();
+
 		// and finally set the database version to current one
 		tVersion.SetVersion(1);
 	}
Index: src/libchcore/TString.cpp
===================================================================
diff -u -r14d99757fbeaa3e55d43b45b043033d8ba81980b -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TString.cpp	(.../TString.cpp)	(revision 14d99757fbeaa3e55d43b45b043033d8ba81980b)
+++ src/libchcore/TString.cpp	(.../TString.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -79,7 +79,7 @@
 
 			wchar_t* pszNewBuffer = new wchar_t[stNewLen];
 			if(m_pszData)
-				memcpy(pszNewBuffer, m_pszData, m_stStringLength);
+				_tcsncpy_s(pszNewBuffer, stNewLen, m_pszData, m_stStringLength + 1);
 			else
 				pszNewBuffer[0] = _T('\0');
 
@@ -204,7 +204,8 @@
 {
 	if(this != &rSrc && m_pData != rSrc.m_pData)
 	{
-		Release();
+		if(InterlockedDecrement(&m_pData->m_lRefCount) < 1)
+			delete m_pData;
 
 		if(InterlockedCompareExchange(&rSrc.m_pData->m_lRefCount, 0, 0) > 0)
 		{
Index: src/libchcore/TSubTaskBase.h
===================================================================
diff -u -r2efd22688b8d12be34c87bf2b024d8db6e317d60 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TSubTaskBase.h	(.../TSubTaskBase.h)	(revision 2efd22688b8d12be34c87bf2b024d8db6e317d60)
+++ src/libchcore/TSubTaskBase.h	(.../TSubTaskBase.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -27,6 +27,7 @@
 #include "TPath.h"
 #include "ESubTaskTypes.h"
 #include "TSubTaskStatsInfo.h"
+#include "TBinarySerializer.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TTask.cpp
===================================================================
diff -u -ra5aa3c3cb78f3767641de2627d1a49a1dc35b429 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TTask.cpp	(.../TTask.cpp)	(revision a5aa3c3cb78f3767641de2627d1a49a1dc35b429)
+++ src/libchcore/TTask.cpp	(.../TTask.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -36,6 +36,7 @@
 #include "ErrorCodes.h"
 #include "TRowData.h"
 #include "ISerializerRowData.h"
+#include "TStringSet.h"
 
 BEGIN_CHCORE_NAMESPACE
 
@@ -139,6 +140,9 @@
 
 		spContainer = m_spSerializer->GetContainer(_T("scanned_files"));
 		m_files.Load(spContainer, m_spSrcPaths);
+
+		spContainer = m_spSerializer->GetContainer(_T("task_config"));
+		m_tConfiguration.Load(spContainer);
 	}
 }
 
@@ -158,6 +162,9 @@
 
 		spContainer = m_spSerializer->GetContainer(_T("scanned_files"));
 		m_files.Store(spContainer);
+
+		spContainer = m_spSerializer->GetContainer(_T("task_config"));
+		m_tConfiguration.Store(spContainer);
 	}
 
 	m_spSerializer->Flush();
Index: src/libchcore/TTaskConfigTracker.cpp
===================================================================
diff -u -r548382442cbf7bed7f744b279ce3f66b54992724 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TTaskConfigTracker.cpp	(.../TTaskConfigTracker.cpp)	(revision 548382442cbf7bed7f744b279ce3f66b54992724)
+++ src/libchcore/TTaskConfigTracker.cpp	(.../TTaskConfigTracker.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -24,6 +24,7 @@
 #include "TTaskConfigTracker.h"
 #include "TCoreException.h"
 #include "ErrorCodes.h"
+#include "TStringSet.h"
 
 BEGIN_CHCORE_NAMESPACE
 
Index: src/libchcore/TTaskDefinition.cpp
===================================================================
diff -u -rb1ecc12ba4c1f2a7b4acd6e82fc4193535e55ff0 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision b1ecc12ba4c1f2a7b4acd6e82fc4193535e55ff0)
+++ src/libchcore/TTaskDefinition.cpp	(.../TTaskDefinition.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -226,35 +226,6 @@
 	tTaskInfo.ExtractSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
 }
 
-void TTaskDefinition::Store(const TSmartPath& strPath, bool bOnlyIfModified)
-{
-	if(!bOnlyIfModified || m_bModified || m_tConfiguration.IsModified())
-	{
-		// read everything
-		TConfig tTaskInfo;
-		tTaskInfo.SetFilePath(strPath.ToString());
-
-		// get information from config file
-		// task unique id - use if provided, generate otherwise
-		SetConfigValue(tTaskInfo, _T("TaskDefinition.UniqueID"), m_strTaskName);
-
-		// basic information
-		SetConfigValue(tTaskInfo, _T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths);
-		SetConfigValue(tTaskInfo, _T("TaskDefinition.DestinationPath"), m_pathDestinationPath);
-
-		int iOperation = m_tOperationPlan.GetOperationType();
-		SetConfigValue(tTaskInfo, _T("TaskDefinition.OperationType"), iOperation);
-
-		SetConfigValue(tTaskInfo, _T("TaskDefinition.Version"), m_ullTaskVersion);
-
-		tTaskInfo.PutSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration);
-
-		tTaskInfo.Write();
-
-		m_bModified = false;
-	}
-}
-
 void TTaskDefinition::StoreInString(TString& strOutput)
 {
 	// read everything
Index: src/libchcore/TTaskDefinition.h
===================================================================
diff -u -r73583f2ca01fa1b2eae49bbc63bce46b9ecff5db -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision 73583f2ca01fa1b2eae49bbc63bce46b9ecff5db)
+++ src/libchcore/TTaskDefinition.h	(.../TTaskDefinition.h)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -73,7 +73,6 @@
 
 	// Serialization
 	void Load(const TSmartPath& strPath);
-	void Store(const TSmartPath& strPath, bool bOnlyIfModified = false);
 
 	void StoreInString(TString& strInput);
 	void LoadFromString(const TString& strInput);
Index: src/libchcore/Tests/TestsTString.cpp
===================================================================
diff -u -r14d99757fbeaa3e55d43b45b043033d8ba81980b -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/Tests/TestsTString.cpp	(.../TestsTString.cpp)	(revision 14d99757fbeaa3e55d43b45b043033d8ba81980b)
+++ src/libchcore/Tests/TestsTString.cpp	(.../TestsTString.cpp)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -267,6 +267,13 @@
 	EXPECT_EQ(strValue, _T("Some string... appended."));
 }
 
+TEST(TStringTests, AppendString_WithReallocate)
+{
+	TString strValue(_T("Some string with up to 64 characters - 123456789012345678901"));
+	strValue.Append(_T("... appended."));
+	EXPECT_EQ(strValue, _T("Some string with up to 64 characters - 123456789012345678901... appended."));
+}
+
 // left, right, mid
 TEST(TStringTests, Left)
 {
Index: src/libchcore/libchcore.vc90.vcproj
===================================================================
diff -u -r960167a493c3ae7ecbdc7e8c2b91619106d7a685 -rb1e03eb232a784d6e2d40f67cbbbb33be0972228
--- src/libchcore/libchcore.vc90.vcproj	(.../libchcore.vc90.vcproj)	(revision 960167a493c3ae7ecbdc7e8c2b91619106d7a685)
+++ src/libchcore/libchcore.vc90.vcproj	(.../libchcore.vc90.vcproj)	(revision b1e03eb232a784d6e2d40f67cbbbb33be0972228)
@@ -1302,6 +1302,26 @@
 						RelativePath=".\TConfigNotifier.h"
 						>
 					</File>
+					<Filter
+						Name="details"
+						>
+						<File
+							RelativePath=".\ConfigNode.cpp"
+							>
+						</File>
+						<File
+							RelativePath=".\ConfigNode.h"
+							>
+						</File>
+						<File
+							RelativePath=".\ConfigNodeContainer.cpp"
+							>
+						</File>
+						<File
+							RelativePath=".\ConfigNodeContainer.h"
+							>
+						</File>
+					</Filter>
 				</Filter>
 			</Filter>
 			<Filter