Index: ext/libicpf/src/cfg.cpp
===================================================================
diff -u -r771dac1fbb7608aa92942c6cab7c5c8b0cccb791 -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/cfg.cpp	(.../cfg.cpp)	(revision 771dac1fbb7608aa92942c6cab7c5c8b0cccb791)
+++ ext/libicpf/src/cfg.cpp	(.../cfg.cpp)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -126,8 +126,8 @@
 #define m_pvProps ((std::vector<property>*)m_hProps)
 
 /** Constructs a config object.
- * \param[in] bGlobal - specifies if this class should be globally accessible by the get_config() friend
- *				function.
+ * \param[in] pCfgBase - pointer to a base handler of the configuration strings
+ *						 cound be pointer to xml handler, ini handler or any other
  */
 config::config(config_base* pCfgBase) :
 	m_lock(),
@@ -138,1272 +138,511 @@
 
 /** Destructs the config class.
  */
-/*config::~config()
+config::~config()
 {
-	try
-	{
-		delete m_pvProps;
-		delete m_pvUnreg;
-	}
-	catch(...)
-	{
-	}
+	delete m_pvProps;
 }
 
-/** Function opens the specified file, reads all the lines sequentially
- *  and stores discovered property values in the internal structures.
- * \param[in] pszFile - path to a .conf file (could have any extension)
- * \return -1 on error or 0 if operation finished succesfully
- * \note The properties does not have to be registered prior to use this function.
+/** Function opens the specified file using the underlying config base
+ *  and converts the values read to a list of properties registered
+ *  earlier.
+ *
+ * \param[in] pszPath - path to a file to be read
  */
-/*int_t config::read(const char_t* pszFile)
+void config::read(const char_t* pszPath)
 {
-	// NOTE: this function should reset the m_bModified flag
-	// open the file
-	FILE* pFile;
-	if ( (pFile=fopen(pszFile, "r")) == NULL)
-		return -1;
-
-	char_t szLine[MAX_LINE], *pszData;
-
-	// lock the instance - has to be done here to make sure all settings are
-	// consistent if reloaded on-the-fly
 	m_lock.lock();
-	while(fgets(szLine, MAX_LINE, pFile))
+	try
 	{
-		szLine[MAX_LINE-1]='\0';		// needed when the line is too int_t
-		pszData=szLine;
+		// read the data using underlying object
+		m_pCfgBase->read(pszPath);
 
-		// interpret the line
-		// skip the whitespaces at the beginning
-		while(is_whitespace(*pszData))
-			pszData++;
-
-		// skip the comments and empty lines
-		if (pszData[0] == '#' || pszData[0] == ';' || pszData[0] == 0)
-			continue;
-
-		// split the line to the part on the left of '=' and to the right
-		char_t* pVal=strchr(pszData, '=');
-		if (pVal != NULL)
-		{
-			pVal[0]='\0';
-			pVal++;
-
-			// so we have name in the pszData and value pVal
-			process_line(trim(pszData), trim(pVal));
-		}
+		// and transform it to eatable form using registered properties
+		load_registered();
 	}
-
-	m_bModified=false;
+	catch(...)
+	{
+		m_lock.unlock();
+		throw;
+	}
 	m_lock.unlock();
-
-	m_clbPropertyChanged.exec((ulong_t)-1, NULL);
-
-	fclose(pFile);
-	
-	return 0;
 }
 
-/** Writes all the registered properties into the given file. To avoid
- *  deleting any comments or unused properties from a file - the function
- *  read all the file into memory (!) and modifies only the lines that
- *  contains the requested property key (or adds a new entry at the end).
- *  After that the file is being overwritten.
- * \param[in] pszFile - path to a .conf file to which the properties shoud be written
- * \return -1 on error, 0 on success.
+/** Writes all the registered properties into the given file using
+ *  the underlying config base to do this.
+ *
+ * \param[in] pszPath - path to a file to write the properties to
  */
-/*int_t config::write(const char_t* pszFile)
+void config::write(const char_t* pszPath)
 {
-	// if the config was not modified - why bother writing
-	if (!m_bModified)
-		return 0;
-
-	// at first - read the current file (whole) - line by line
-	std::vector<string> vLines;
-	FILE* pFile=fopen(pszFile, "r");
-	if (pFile != NULL)
-	{
-		char_t szLine[MAX_LINE];
-		while(fgets(szLine, MAX_LINE, pFile))
-		{
-			vLines.push_back((string)trim(szLine));
-		}
-
-		fclose(pFile);
-	}
-
-	// apply the registered properties to the lines
-	// NOTE: properties in the unreg cannot have changed, so we don't need to bother with them
 	m_lock.lock();
 
-#ifdef USE_ENCRYPTION
-	// encrypt everything if needed
 	try
 	{
-		for (std::vector<_PROP>::iterator it = m_pvProps->begin();it != m_pvProps->end();it++)
-		{
-			encrypt_property(&(*it));
-		}
+		// store current properties to the underlying object
+		store_registered();
+
+		// and save
+		m_pCfgBase->save(pszPath);
 	}
 	catch(...)
 	{
 		m_lock.unlock();
 		throw;
 	}
-#endif
 
-	bool bFnd=false;
-	string str;
-	for (std::vector<_PROP>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
-	{
-		// process only if the property was modified
-		// NOTE: if the file has been modified manually then they won't be overwritten
-		if ((*it).bModified)
-		{
-			// check every line that has been read for property match
-			bFnd=false;
-			for (std::vector<string>::iterator sit=vLines.begin();sit != vLines.end();sit++)
-			{
-				// line matches ?
-				if ((*sit).cmpn((*it).pszName, strlen((*it).pszName)) == 0)
-				{
-					// replace the line with a new value
-					prepare_line(&(*it), &(*sit));
-					bFnd=true;
-					break;		// break the inner 'for'
-				}
-			}
-
-			// if the line was not found - add the line at the end
-			if (!bFnd)
-			{
-				prepare_line(&(*it), &str);
-				vLines.push_back(str);
-			}
-
-			// mark as written, although it is a lie ;)
-			(*it).bModified=false;
-		}
-	}
-	m_bModified=false;
 	m_lock.unlock();
-
-	// save the new copy of file
-	// NOTE: at this point the props are all marked as non-modified - if the write fails then all the data are lost
-	if ( (pFile=fopen(pszFile, "w")) == NULL)
-		return -1;
-	
-	for (std::vector<string>::iterator vit=vLines.begin();vit != vLines.end();vit++)
-	{
-		if (fprintf(pFile, STRFMT "\n", (const char_t*)(*vit)) < 0)
-			return -1;
-	}
-
-	fclose(pFile);
-
-	return 0;
 }
 
 /** Function returns a property type for a given property id.
- *  \note The function returns only the type, and not the rest of the property flags.
- * \param[in] ulProp - property id to get info about.
- * \return The property type.
+ *
+ * \param[in] uiProp - property id to get info about
+ * \return The property type along with its flags.
  */
-/*int_t config::get_proptype(ulong_t ulProp)
+uint_t config::get_type(uint_t uiProp)
 {
 	m_lock.lock();
+	uint_t uiRet=m_pvProps->at(uiProp).get_type();
+	m_lock.unlock();
 
-	int_t iRet=m_pvProps->at(ulProp).iType & PTM_TYPE;
+	return uiRet;
+}
 
+/** Retrieves the count of values in the specified property.
+ *
+ * \param[in] uiProp - property id to retrieve information about
+ * \return Count of values.
+ */
+size_t config::get_value_count(uint_t uiProp)
+{
+	m_lock.lock();
+	size_t stRet=m_pvProps->at(uiProp).get_count();
 	m_lock.unlock();
-	return iRet;
+
+	return stRet;
 }
 
-/** Function registers property with int_t value, specified range and flags. Also
- *  checks if the property has already been registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed).
- * \param[in] pszName - name of the property (key in key = value)
- * \param[in] iDef - default value for the property
- * \param[in] iLo - the lesser value of value's allowable range
- * \param[in] iHi - the higher value of value's allowable range
- * \param[in] iFlags - additional flags that should be associated with property
- * \return Property ID of the newly registered property.
+/** Removes an array value at a given index.
+ *
+ * \param[in] uiProp - property id to have the value removed
+ * \param[in] stIndex - index of the value to remove
  */
-/*ulong_t config::register_int(const char_t* pszName, int_t iDef, int_t iLo, int_t iHi, int_t iFlags)
+void config::remove_array_value(uint_t uiProp, size_t stIndex)
 {
-	// check if there is already registered value with the given name
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
-	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		// check if the property is in the unreg container
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
-		{
-			// property not found in the unreg - means that this is quite new stuff
-			property.bModified=true;
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-			property.val.i.iVal=iDef;		// will be overwritten when reading file
-		}
-		else
-		{
-			// get the entry
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
-
-			// set the value from a string
-			int_t iVal=atol(property.val.pszVal);
-			delete [] property.val.pszVal;
-			property.val.i.iVal=iVal;
-		}
-		
-		// common part
-		property.iType=PT_INT | iFlags;
-		property.val.i.iLo=iLo;
-		property.val.i.iHi=iHi;
-		
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
-		
-		return ulRes;
-	}
+	m_pvProps->at(uiProp).remove(stIndex);
+	m_lock.unlock();
 }
 
-/** Function registers property with uint_t value, specified range and flags. Also
- *  checks if the property is registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed.
- * \param[in] pszName - name of the property (key in key = value)
- * \param[in] uiDef - default value for the property
- * \param[in] uiLo - the lesser value of value's allowable range
- * \param[in] uiHi - the higher value of value's allowable range
- * \param[in] iFlags - additional flags that should be associated with property
- * \return Property ID of the newly registered property.
+/** Clears the list of values in the given property.
+ *
+ * \param[in] uiProp - property id to have the values cleared
  */
-/*ulong_t config::register_uint(const char_t* pszName, uint_t uiDef, uint_t uiLo, uint_t uiHi, int_t iFlags)
+void config::clear_array_values(uint_t uiProp)
 {
-	// check if there is already registered value with the given name
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
-	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
-		{
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-			property.val.ui.uiVal=uiDef;		// will be overwritten when reading file
-			property.bModified=true;
-		}
-		else
-		{
-			// get the entry
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
-			
-			uint_t uiVal=strtoul(property.val.pszVal, NULL, 10);
-			delete [] property.val.pszVal;
-			property.val.ui.uiVal=uiVal;
-		}
+	m_pvProps->at(uiProp).clear_array();
+	m_lock.unlock();
+}
 
-		// common part
-		property.iType=PT_UINT | iFlags;
-		property.val.ui.uiLo=uiLo;
-		property.val.ui.uiHi=uiHi;
-
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
-
-		return ulRes;
-	}
+/** Retrieves the count of registered properties contained in this config.
+ *
+ * \return Count of properties.
+ */
+size_t config::count()
+{
+	return m_pvProps->size();
 }
 
-/** Function registers property with longlong_t value, specified range and flags. Also
- *  checks if the property is registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed.
- * \param[in] pszName - name of the property (key in key = value)
+/** Function registers the signed number property. If the underlying base object
+ *  contains a string with a specified key - the value is being translated to 
+ *  the value of this property.
+ *
+ * \param[in] pszName - name of the property
  * \param[in] llDef - default value for the property
- * \param[in] llLo - the lesser value of value's allowable range
- * \param[in] llHi - the higher value of value's allowable range
- * \param[in] iFlags - additional flags that should be associated with property
+ * \param[in] llLo - the lower bound of the allowable value range
+ * \param[in] llHi - the higher bound of the allowable value range
+ * \param[in] uiFlags - additional flags that should be associated with property
  * \return Property ID of the newly registered property.
  */
-/*ulong_t config::register_longlong(const char_t* pszName, longlong_t llDef, longlong_t llLo, longlong_t llHi, int_t iFlags)
+uint_t config::register_signed_num(const tchar_t* pszName, ll_t llDef, ll_t llLo, ll_t llHi, uint_t uiFlags)
 {
-	// check if there is already registered value with the given name
+	// prepare the property to insert
+	property prop(pszName, property::type_signed_num | (uiFlags & property::mask_flags));
+	prop.set_signed_range(llLo, llHi);
+
+	// and operate inside the internals
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
+
+	// get the value for the property name
+	ptr_t hFind=NULL;
+	if ( (hFind=m_pCfgBase->find(pszName)) != NULL )
 	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
+		const tchar_t* psz=NULL;
+		while( (psz=m_pCfgBase->find_next(hFind)) != NULL)
 		{
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-			property.val.ll.llVal=llDef;		// will be overwritten when reading file
-			property.bModified=true;
+			prop.set_value(psz, property::action_add);
 		}
-		else
-		{
-			// get the entry
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
 
-			ll_t llVal;
-#ifdef _WIN32
-			llVal=_atoi64(property.val.pszVal);
-#else
-			llVal=atoll(property.val.pszVal);
-#endif
-			delete [] property.val.pszVal;
-			property.val.ll.llVal=llVal;
-		}
+		m_pCfgBase->find_close(hFind);
+	}
+	else if (!(uiFlags & property::flag_array))
+		prop.set_signed_num(llDef);
 
-		// common
-		property.iType=PT_LONGLONG | iFlags;
-		property.val.ll.llLo=llLo;
-		property.val.ll.llHi=llHi;
+	// add to the vector
+	m_pvProps->push_back(prop);
+	uint_t uiProp=(uint_t)(m_pvProps->size()-1);
 
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
-
-		return ulRes;
-	}
+	m_lock.unlock();
+		
+	return uiProp;
 }
 
-/** Function registers property with ulonglong_t value, specified range and flags. Also
- *  checks if the property is registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed.
- * \param[in] pszName - name of the property (key in key = value)
+/** Function registers the unsigned number property. If the underlying base object
+ *  contains a string with a specified key - the value is being translated to 
+ *  the value of this property.
+ *
+ * \param[in] pszName - name of the property
  * \param[in] ullDef - default value for the property
- * \param[in] ullLo - the lesser value of value's allowable range
- * \param[in] ullHi - the higher value of value's allowable range
- * \param[in] iFlags - additional flags that should be associated with property
+ * \param[in] ullLo - the lower bound of the allowable value range
+ * \param[in] ullHi - the higher bound of the allowable value range
+ * \param[in] uiFlags - additional flags that should be associated with property
  * \return Property ID of the newly registered property.
  */
-/*ulong_t config::register_ulonglong(const char_t* pszName, ulonglong_t ullDef, ulonglong_t ullLo, ulonglong_t ullHi, int_t iFlags)
+uint_t config::register_unsigned_num(const tchar_t* pszName, ull_t ullDef, ull_t ullLo, ull_t ullHi, uint_t uiFlags)
 {
-	// check if there is already registered value with the given name
+	// prepare the property to insert
+	property prop(pszName, property::type_unsigned_num | (uiFlags & property::mask_flags));
+	prop.set_unsigned_range(ullLo, ullHi);
+
+	// and operate inside the internals
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
+
+	// get the value for the property name
+	ptr_t hFind=NULL;
+	if ( (hFind=m_pCfgBase->find(pszName)) != NULL )
 	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
+		const tchar_t* psz=NULL;
+		while( (psz=m_pCfgBase->find_next(hFind)) != NULL)
 		{
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-			property.val.ull.ullVal=ullDef;		// will be overwritten when reading file
-			property.bModified=true;
+			prop.set_value(psz, property::action_add);
 		}
-		else
-		{
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
 
-			ull_t ullVal;
-#ifdef _WIN32
-			ullVal=(ulonglong_t)_atoi64(property.val.pszVal);
-#else
-			ullVal=(ulonglong_t)atoll(property.val.pszVal);
-#endif
-			delete [] property.val.pszVal;
-			property.val.ull.ullVal=ullVal;
-		}
+		m_pCfgBase->find_close(hFind);
+	}
+	else if (!(uiFlags & property::flag_array))
+		prop.set_unsigned_num(ullDef);
 
-		// common
-		property.iType=PT_ULONGLONG | iFlags;
-		property.val.ull.ullLo=ullLo;
-		property.val.ull.ullHi=ullHi;
+	// add to the vector
+	m_pvProps->push_back(prop);
+	uint_t uiProp=(uint_t)(m_pvProps->size()-1);
 
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
-
-		return ulRes;
-	}
+	m_lock.unlock();
+		
+	return uiProp;
 }
 
-/** Function registers property with bool value and flags. Also
- *  checks if the property is registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed.
- * \param[in] pszName - name of the property (key in key = value)
+/** Function registers the boolean property. If the underlying base object
+ *  contains a string with a specified key - the value is being translated to 
+ *  the value of this property.
+ *
+ * \param[in] pszName - name of the property
  * \param[in] bDef - default value for the property
- * \param[in] iFlags - additional flags that should be associated with property
+ * \param[in] uiFlags - additional flags that should be associated with property
  * \return Property ID of the newly registered property.
  */
-/*ulong_t config::register_bool(const char_t* pszName, bool bDef, int_t iFlags)
+uint_t config::register_bool(const tchar_t* pszName, bool bDef, uint_t uiFlags)
 {
-	// check if there is already registered value with the given name
+	// prepare the property to insert
+	property prop(pszName, property::type_bool | (uiFlags & property::mask_flags));
+
+	// and operate inside the internals
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
+
+	// get the value for the property name
+	ptr_t hFind=NULL;
+	if ( (hFind=m_pCfgBase->find(pszName)) != NULL )
 	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
+		const tchar_t* psz=NULL;
+		while( (psz=m_pCfgBase->find_next(hFind)) != NULL)
 		{
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-			property.val.bVal=bDef;		// current
-			property.bModified=true;
+			prop.set_value(psz, property::action_add);
 		}
-		else
-		{
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
-			
-			bool bVal;
-			if (strcmp(property.val.pszVal, "yes") == 0)
-				bVal=true;
-			else if (strcmp(property.val.pszVal, "no") == 0)
-				bVal=false;
-			else
-				bVal=atoi(property.val.pszVal) != 0;
 
-			delete [] property.val.pszVal;
-			property.val.bVal=bVal;
-		}
+		m_pCfgBase->find_close(hFind);
+	}
+	else if (!(uiFlags & property::flag_array))
+		prop.set_bool(bDef);
 
-		// common
-		property.iType=PT_BOOL | iFlags;
+	// add to the vector
+	m_pvProps->push_back(prop);
+	uint_t uiProp=(uint_t)(m_pvProps->size()-1);
 
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
-
-		return ulRes;
-	}
+	m_lock.unlock();
+		
+	return uiProp;
 }
 
-/** Function registers property with string value and flags. Also
- *  checks if the property is registered if PF_CHECK flag has been specified (if it
- *  is, then the existing identifier is returned and nothing is changed.
- *  If the property is marked as encrypted, then the default value is being treated as
- *  unencrypted (and the appropriate flag is being set).
- * \param[in] pszName - name of the property (key in key = value)
+/** Function registers the string property. If the underlying base object
+ *  contains a string with a specified key - the value is being translated to 
+ *  the value of this property.
+ *
+ * \param[in] pszName - name of the property
  * \param[in] pszDef - default value for the property
- * \param[in] iFlags - additional flags that should be associated with property
+ * \param[in] uiFlags - additional flags that should be associated with property
  * \return Property ID of the newly registered property.
  */
-/*ulong_t config::register_string(const char_t* pszName, const char_t* pszDef, int_t iFlags)
+uint_t config::register_string(const tchar_t* pszName, const tchar_t* pszDef, uint_t uiFlags)
 {
-	// check if there is already registered value with the given name
+	// prepare the property to insert
+	property prop(pszName, property::type_string | (uiFlags & property::mask_flags));
+
+	// and operate inside the internals
 	m_lock.lock();
-	ulong_t ulRes;
-	if (iFlags & PF_CHECK && (ulRes=is_registered(pszName)) != (ulong_t)-1)
+
+	// get the value for the property name
+	ptr_t hFind=NULL;
+	if ( (hFind=m_pCfgBase->find(pszName)) != NULL )
 	{
-		m_lock.unlock();
-		return ulRes;
-	}
-	else
-	{
-		_PROP property;
-		
-		if ( (ulRes = is_unreg(pszName)) == (ulong_t)-1 )
+		const tchar_t* psz=NULL;
+		while( (psz=m_pCfgBase->find_next(hFind)) != NULL)
 		{
-			property.iType=PT_STRING | iFlags;
-#ifdef USE_ENCRYPTION
-			if (iFlags & PF_ENCRYPTED)
-				property.iType |= PF_DECODED;
-#endif
-			property.pszName=new char_t[strlen(pszName)+1];
-			strcpy(property.pszName, pszName);
-	
-			property.val.pszVal=new char_t[strlen(pszDef)+1];
-			strcpy(property.val.pszVal, pszDef);
-			property.bModified=true;
+			prop.set_value(psz, property::action_add);
 		}
-		else
-		{
-			property=m_pvUnreg->at(ulRes);
-			m_pvUnreg->erase(m_pvUnreg->begin()+ulRes);
-			property.iType = PT_STRING | iFlags;
-		}
-		
-		// add to the list
-		m_pvProps->push_back(property);
-		m_bModified=true;
-		ulRes=(ulong_t)(m_pvProps->size()-1);
-		m_lock.unlock();
 
-		return ulRes;
+		m_pCfgBase->find_close(hFind);
 	}
-}
+	else if (!(uiFlags & property::flag_array))
+		prop.set_string(pszDef);
 
-/** Functions retrieves the int_t value associated with a given property ID. Can be called
- *  from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The property value.
- */
-/*int_t config::get_int(ulong_t ulProp)
-{
-	m_lock.lock();
+	// add to the vector
+	m_pvProps->push_back(prop);
+	uint_t uiProp=(uint_t)(m_pvProps->size()-1);
 
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_INT);
-
-	int_t iRet=m_pvProps->at(ulProp).val.i.iVal;
 	m_lock.unlock();
-	return iRet;
+		
+	return uiProp;
 }
 
-/** Functions retrieves the uint_t value associated with a given property ID. Can be called
- *  from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The property value.
+/** Function retrieves the value as string.
+ *
+ * \param[in] uiProp - property to retrieve the value of
+ * \param[out] pszBuffer - pointer to a buffer to receive the string (unused
+ *						   if retrieving a string value)
+ * \param[in] stMaxSize - size of the buffer
+ * \param[in] stIndex - index of the value to retrieve (meaningful only for
+ *						array-based properties)
+ * \return Pointer to the string.
+ *
+ * \note Always use the returned value instead of the buffer contents. Returned
+ *		 value may point to some other memory location instead of pszBuffer.
  */
-/*uint_t config::get_uint(ulong_t ulProp)
+const tchar_t* config::get_value(uint_t uiProp, tchar_t* pszBuffer, size_t stMaxSize, size_t stIndex)
 {
 	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_UINT);
-
-	uint_t ulRet=m_pvProps->at(ulProp).val.ui.uiVal;
+	const tchar_t* psz=m_pvProps->at(uiProp).get_value(pszBuffer, stMaxSize, stIndex);
 	m_lock.unlock();
-	return ulRet;
-}
 
-/** Functions retrieves the longlong_t value associated with a given property ID. Can be called
- *  from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The property value.
- */
-/*longlong_t config::get_longlong(ulong_t ulProp)
-{
-	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_LONGLONG);
-
-	longlong_t llRet=m_pvProps->at(ulProp).val.ll.llVal;
-	m_lock.unlock();
-	return llRet;
+	return psz;
 }
 
-/** Functions retrieves the ulonglong_t value associated with a given property ID. Can be called
- *  from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The property value.
+/** Function retrieves the signed number value.
+ *
+ * \param[in] uiProp - property to retrieve the value of
+ * \param[in] stIndex - index of the value to retrieve (meaningful only for
+ *						array-based properties)
+ * \return Property value.
  */
-/*ulonglong_t config::get_ulonglong(ulong_t ulProp)
+ll_t config::get_signed_num(uint_t uiProp, size_t stIndex)
 {
 	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_ULONGLONG);
-
-	ulonglong_t ullRet=m_pvProps->at(ulProp).val.ull.ullVal;
+	ll_t ll=m_pvProps->at(uiProp).get_signed_num(stIndex);
 	m_lock.unlock();
-	return ullRet;
+	return ll;
 }
 
-/** Functions retrieves the bool value associated with a given property ID. Can be called
- *  from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The property value.
+/** Function retrieves the unsigned number value.
+ *
+ * \param[in] uiProp - property to retrieve the value of
+ * \param[in] stIndex - index of the value to retrieve (meaningful only for
+ *						array-based properties)
+ * \return Property value.
  */
-/*bool config::get_bool(ulong_t ulProp)
+ull_t config::get_unsigned_num(uint_t uiProp, size_t stIndex)
 {
 	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_BOOL);
-
-	bool bRet=m_pvProps->at(ulProp).val.bVal;
+	ull_t ull=m_pvProps->at(uiProp).get_unsigned_num(stIndex);
 	m_lock.unlock();
-	return bRet;
+	return ull;
 }
 
-/** Functions retrieves the string value associated with a given property ID. Can be called
- *  from any thread. The string contained in the internal structure is copied to the buffer
- *  specified by user. Max count of chars that can be copied is specified by the buffer length.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[out] psz - buffer for the string
- * \param[in] tMaxLen - length of the buffer
+/** Function retrieves the bool value.
+ *
+ * \param[in] uiProp - property to retrieve the value of
+ * \param[in] stIndex - index of the value to retrieve (meaningful only for
+ *						array-based properties)
+ * \return Property value.
  */
-/*void config::get_string(ulong_t ulProp, char_t* psz, size_t tMaxLen)
+bool config::get_bool(uint_t uiProp, size_t stIndex)
 {
 	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_STRING);
-
-	_PROP& property=m_pvProps->at(ulProp);
-
-#ifdef USE_ENCRYPTION
-	// if the property is encrypted and not decoded yet - decode it
-	try
-	{
-		decrypt_property(&property);
-	}
-	catch(...)
-	{
-		m_lock.unlock();
-		throw;
-	}
-#endif
-
-	char_t* pszSrc=property.val.pszVal;
-	strncpy(psz, pszSrc, tMaxLen);
-	psz[tMaxLen-1]='\0';
-
+	bool b=m_pvProps->at(uiProp).get_bool(stIndex);
 	m_lock.unlock();
+	return b;
 }
 
-/** Functions retrieves the int_t value associated with a given property ID. Can be called
- *  from any thread. Function returns a pointer to a string contained in the internal structures
- *  so it is definitely faster than the other get_string function, but is much nore dangerous.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \return The pointer to a string contained in the internal structure.
+/** Function retrieves the string value.
+ *
+ * \param[in] uiProp - property to retrieve the value of
+ * \param[in] stIndex - index of the value to retrieve (meaningful only for
+ *						array-based properties)
+ * \return Property value.
  */
-/*char_t* config::get_string(ulong_t ulProp)
+const tchar_t* config::get_string(uint_t uiProp, size_t stIndex)
 {
 	m_lock.lock();
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_STRING);
-
-	_PROP& property=m_pvProps->at(ulProp);
-
-#ifdef USE_ENCRYPTION
-	// if the property is encrypted and not decoded yet - decode it
-	try
-	{
-		decrypt_property(&property);
-	}
-	catch(...)
-	{
-		m_lock.unlock();
-		throw;
-	}
-#endif
-
-	char_t* psz=property.val.pszVal;
-	char_t* pszNew=new char_t[strlen(psz)+1];
-	strcpy(pszNew, psz);
-
+	const tchar_t* psz=m_pvProps->at(uiProp).get_string(stIndex);
 	m_lock.unlock();
-	
-	return pszNew;
+	return psz;
 }
 
-/** Function sets the int_t value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] lVal - the new value of property to set
+/** Function sets the property value from string.
+ *
+ * \param[in] uiProp - property id to set the value for
+ * \param[in] pszVal - string with property value
+ * \param[in] a - action to take if the property is array based
+ * \param[in] tIndex - index of a value to set at (for action action_setat)
+ * \param[out] pTracker - property tracker that collects the property ID's
  */
-/*void config::set_int(ulong_t ulProp, int_t iVal, property_tracker* pGroup)
+void config::set_value(uint_t uiProp, const tchar_t* pszVal, property::actions a, size_t tIndex, property_tracker* pTracker)
 {
 	m_lock.lock();
-
-	// get the data
-	_PROP& property=m_pvProps->at(ulProp);
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_INT);
-
-	int_t iOldVal=property.val.i.iVal;
-
-	// check the range
-	if (iVal < property.val.i.iLo)
-		property.val.i.iVal=property.val.i.iLo;
-	else if (iVal > property.val.i.iHi)
-		property.val.i.iVal=property.val.i.iHi;
-	else
-		property.val.i.iVal=iVal;
-
-	bool bMod=(property.val.i.iVal != iOldVal);
-	if (bMod)
-	{
-		property.bModified=true;
-		m_bModified=true;
-	}
+	m_pvProps->at(uiProp).set_value(pszVal, a, tIndex);
+	if (pTracker)
+		pTracker->add(uiProp);
 	m_lock.unlock();
-
-	if (bMod)
-	{
-		if (pGroup)
-			pGroup->add(ulProp);
-		else
-		{
-			property_tracker* pg=begin_group((ulong_t)-1);
-			pg->add(ulProp);
-			end_group(pg);
-		}
-	}
 }
 
-/** Function sets the uint_t value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] uiVal - the new value of property to set
+/** Function sets the signed number property value.
+ *
+ * \param[in] uiProp - property id to set the value for
+ * \param[in] llVal - property value to set
+ * \param[in] a - action to take if the property is array based
+ * \param[in] tIndex - index of a value to set at (for action action_setat)
+ * \param[out] pTracker - property tracker that collects the property ID's
  */
-/*void config::set_uint(ulong_t ulProp, uint_t uiVal, property_tracker* pGroup)
+void config::set_signed_num(uint_t uiProp, ll_t llVal, property::actions a, size_t tIndex, property_tracker* pTracker)
 {
 	m_lock.lock();
-
-	// get the data
-	_PROP& property=m_pvProps->at(ulProp);
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_UINT);
-
-	uint_t uiOldVal=property.val.ui.uiVal;
-
-	// check the range
-	if (uiVal < property.val.ui.uiLo)
-		property.val.ui.uiVal=property.val.ui.uiLo;
-	else if (uiVal > property.val.ui.uiHi)
-		property.val.ui.uiVal=property.val.ui.uiHi;
-	else
-		property.val.ui.uiVal=uiVal;
-	
-	bool bMod=(property.val.ui.uiVal != uiOldVal);
-
-	if (bMod)
-	{
-		property.bModified=true;
-		m_bModified=true;
-	}
+	m_pvProps->at(uiProp).set_signed_num(llVal, a, tIndex);
+	if (pTracker)
+		pTracker->add(uiProp);
 	m_lock.unlock();
-
-	if (bMod)
-	{
-		if (pGroup)
-			pGroup->add(ulProp);
-		else
-		{
-			property_tracker* pg=begin_group((ulong_t)-1);
-			pg->add(ulProp);
-			end_group(pg);
-		}
-	}
 }
 
-/** Function sets the longlong_t value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] llVal - the new value of property to set
+/** Function sets the unsigned number property value.
+ *
+ * \param[in] uiProp - property id to set the value for
+ * \param[in] llVal - property value to set
+ * \param[in] a - action to take if the property is array based
+ * \param[in] tIndex - index of a value to set at (for action action_setat)
+ * \param[out] pTracker - property tracker that collects the property ID's
  */
-/*void config::set_longlong(ulong_t ulProp, longlong_t llVal, property_tracker* pGroup)
+void config::set_unsigned_num(uint_t uiProp, ull_t ullVal, property::actions a, size_t tIndex, property_tracker* pTracker)
 {
 	m_lock.lock();
-
-	// get the data
-	_PROP& property=m_pvProps->at(ulProp);
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_LONGLONG);
-
-	ll_t llOldVal=property.val.ll.llVal;
-
-	// check the range
-	if (llVal < property.val.ll.llLo)
-		property.val.ll.llVal=property.val.ll.llLo;
-	else if (llVal > property.val.ll.llHi)
-		property.val.ll.llVal=property.val.ll.llHi;
-	else
-		property.val.ll.llVal=llVal;
-	
-	bool bMod=(property.val.ll.llVal != llOldVal);
-
-	if (bMod)
-	{
-		property.bModified=true;
-		m_bModified=true;
-	}
+	m_pvProps->at(uiProp).set_unsigned_num(ullVal, a, tIndex);
+	if (pTracker)
+		pTracker->add(uiProp);
 	m_lock.unlock();
-
-	if (bMod)
-	{
-		if (pGroup)
-			pGroup->add(ulProp);
-		else
-		{
-			property_tracker* pg=begin_group((ulong_t)-1);
-			pg->add(ulProp);
-			end_group(pg);
-		}
-	}
 }
 
-/** Function sets the ulonglong_t value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] ullVal - the new value of property to set
+/** Function sets the bool property value.
+ *
+ * \param[in] uiProp - property id to set the value for
+ * \param[in] llVal - property value to set
+ * \param[in] a - action to take if the property is array based
+ * \param[in] tIndex - index of a value to set at (for action action_setat)
+ * \param[out] pTracker - property tracker that collects the property ID's
  */
-/*void config::set_ulonglong(ulong_t ulProp, ulonglong_t ullVal, property_tracker* pGroup)
+void config::set_bool(uint_t uiProp, bool bVal, property::actions a, size_t tIndex, property_tracker* pTracker)
 {
 	m_lock.lock();
-
-	// get the data
-	_PROP& property=m_pvProps->at(ulProp);
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_ULONGLONG);
-
-	ull_t ullOldVal=property.val.ull.ullVal;
-
-	// check the range
-	if (ullVal < property.val.ull.ullLo)
-		property.val.ull.ullVal=property.val.ull.ullLo;
-	else if (ullVal > property.val.ull.ullHi)
-		property.val.ull.ullVal=property.val.ull.ullHi;
-	else
-		property.val.ull.ullVal=ullVal;
-	
-	bool bMod=(property.val.ull.ullVal != ullOldVal);
-
-	if (bMod)
-	{
-		property.bModified=true;
-		m_bModified=true;
-	}
+	m_pvProps->at(uiProp).set_bool(bVal, a, tIndex);
+	if (pTracker)
+		pTracker->add(uiProp);
 	m_lock.unlock();
-
-	if (bMod)
-	{
-		if (pGroup)
-			pGroup->add(ulProp);
-		else
-		{
-			property_tracker* pg=begin_group((ulong_t)-1);
-			pg->add(ulProp);
-			end_group(pg);
-		}
-	}
 }
 
-/** Function sets the bool value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] bVal - the new value of property to set
+/** Function sets the string property value.
+ *
+ * \param[in] uiProp - property id to set the value for
+ * \param[in] llVal - property value to set
+ * \param[in] a - action to take if the property is array based
+ * \param[in] tIndex - index of a value to set at (for action action_setat)
+ * \param[out] pTracker - property tracker that collects the property ID's
  */
-/*void config::set_bool(ulong_t ulProp, bool bVal, property_tracker* pGroup)
+void config::set_string(uint_t uiProp, const tchar_t* pszVal, property::actions a, size_t tIndex, property_tracker* pTracker)
 {
 	m_lock.lock();
-
-	// get the data
-	_PROP& property=m_pvProps->at(ulProp);
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_BOOL);
-
-	bool bMod=(property.val.bVal != bVal);
-	if (bMod)
-	{
-		property.val.bVal=bVal;
-		
-		property.bModified=true;
-		m_bModified=true;
-	}
+	m_pvProps->at(uiProp).set_string(pszVal, a, tIndex);
+	if (pTracker)
+		pTracker->add(uiProp);
 	m_lock.unlock();
-
-	if (bMod)
-	{
-		if (pGroup)
-			pGroup->add(ulProp);
-		else
-		{
-			property_tracker* pg=begin_group((ulong_t)-1);
-			pg->add(ulProp);
-			end_group(pg);
-		}
-	}
 }
 
-/** Function sets the string value for a property with specified ID. Can be
- *  called from any thread.
- * \param[in] ulProp - property identifier returned by one of the register_* functions
- * \param[in] pszVal - the new value of property to set
+/** Function reads the values for the registered properties from the underlying
+ *  base config object.
  */
-/*void config::set_string(ulong_t ulProp, const char_t* pszVal, property_tracker* pGroup)
+void config::load_registered()
 {
 	m_lock.lock();
 
-	_PROP& property=m_pvProps->at(ulProp);
-
-	assert((m_pvProps->at(ulProp).iType & PTM_TYPE) == PT_STRING);
-
-	delete [] property.val.pszVal;
-	property.val.pszVal=new char_t[strlen(pszVal)+1];
-	strcpy(property.val.pszVal, pszVal);
-	
-	property.bModified=true;
-	m_bModified=true;
-
-#ifdef USE_ENCRYPTION
-	// make sure the property is marked decoded
-	if (property.iType & PF_ENCRYPTED)
-		property.iType |= PF_DECODED;
-#endif
-
-	m_lock.unlock();
-
-	if (pGroup)
-		pGroup->add(ulProp);
-	else
+	ptr_t hFind=NULL;
+	const tchar_t* psz=NULL;
+	for (std::vector<property>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
 	{
-		property_tracker* pg=begin_group((ulong_t)-1);
-		pg->add(ulProp);
-		end_group(pg);
-	}
-}
+		// is this an array property ?
+		if ((*it).is_array())
+			(*it).clear_array();
 
-#ifdef USE_ENCRYPTION
-
-/** The function starts a new property group. Used to group notifications about the property changes (usually
- *  sent by using set_* functions. The notification informations are being passed to the callback object only
- *  after the end_group() was called.
- * \param[in] ulID - group id
- * \return A pointer to a new property group. Must be released using end_group().
- */
-/*property_tracker* config::begin_group(ulong_t ulID) const
-{
-	return new property_tracker(ulID);
-}
-
-/** Ends a property group started with a begin_group(). Releases the allocated pointer and sends a group property
- *  change information to the callback.
- * \param[in] pGroup - pointer to the property group allocated with begin_group()
- */
-/*void config::end_group(property_tracker* pGroup)
-{
-	assert(pGroup);
-	if (pGroup->count() > 0)
-		m_clbPropertyChanged.exec(pGroup->get_groupid(), (ptr_t)pGroup);
-	delete pGroup;
-}
-
-/** This function sets a password to be used with the encrypted properties. If this is the first password to be used
- *  then it is being set only. But if there was another password set previously, then any property encoded with the
- *  previous password will be decrypted using an old password before setting a new one.
- * \param[in] pszPass - a new password to be set.
- */
-/*void config::set_password(const char_t* pszPass)
-{
-	m_lock.lock();
-
-	if (!m_strPassword.is_empty())
-	{
-		// decrypt everything (if not already) using old password (if exists)
-		try
+		// and fill with value(s)
+		if ( (hFind=m_pCfgBase->find((*it).get_name())) != NULL)
 		{
-			for (std::vector<_PROP>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
+			while( (psz=m_pCfgBase->find_next(hFind)) != NULL)
 			{
-				decrypt_property(&(*it));
+				(*it).set_value(psz, property::action_add);
 			}
 		}
-		catch(...)
-		{
-			m_lock.unlock();
-			throw;
-		}
+
+		m_pCfgBase->find_close(hFind);
 	}
 
-	// set a new pass
-	char_t szPass[64+1];
-	str2key256(pszPass, szPass);
-
-	m_strPassword=(const char_t*)szPass;
-
 	m_lock.unlock();
 }
 
-/** Internal function that encrypts a one specified property structure. Does make a check regarding
- *  the correctness of the property. If it does not met the criteria, then function does nothing.
- * \param[in/out] property - address of the structure describing the property.
+/** Function stores the values of a registered properties to the underlying
+ *  base config object.
  */
-/*void config::encrypt_property(_PROP* property) const
+void config::store_registered()
 {
-	printf("Encrypting...\n");
+	m_lock.lock();
 
-	if ((property->iType & (PT_STRING | PF_ENCRYPTED | PF_DECODED)) == (PT_STRING | PF_ENCRYPTED | PF_DECODED))
+	tchar_t szBuffer[128];
+	for (std::vector<property>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
 	{
-		printf("Real encrypt...\n");
-		ulong_t ulLen=(ulong_t)(((strlen(property->val.pszVal)+1)*sizeof(char_t)+16)*2);
-		char_t *pszOut=new char_t[ulLen];
-		try
-		{
-			strcrypt_aes256(property->val.pszVal, (const char_t*)m_strPassword, pszOut);
-		}
-		catch(...)
-		{
-			delete [] pszOut;
-			throw;
-		}
+		// clear the current attributes for the property
+		m_pCfgBase->clear((*it).get_name());
 
-		delete [] property->val.pszVal;
-		property->val.pszVal=pszOut;
-
-		property->iType &= ~PF_DECODED;
-	}
-}
-
-/** Internal function that decrypts a one specified property structure. Does make a check regarding
- *  the correctness of the property. If it does not met the criteria, then function does nothing.
- * \param[in/out] property - address of the structure describing the property.
- */
-/*void config::decrypt_property(_PROP* property) const
-{
-	if ((property->iType & (PT_STRING | PF_ENCRYPTED | PF_DECODED)) == (PT_STRING | PF_ENCRYPTED))
-	{
-		ulong_t ulLen=(ulong_t)(strlen(property->val.pszVal)/2);
-		char_t *pszOut=new char_t[ulLen];
-		try
+		// and fill with value(s)
+		size_t tCount=(*it).get_count();
+		for (size_t t=0;t != tCount;t++)
 		{
-			strdecrypt_aes256(property->val.pszVal, (const char_t*)m_strPassword, pszOut);
+			m_pCfgBase->set_value((*it).get_name(), (*it).get_value(szBuffer, 128, t));;
 		}
-		catch(...)
-		{
-			delete [] pszOut;
-			throw;
-		}
-
-		delete [] property->val.pszVal;
-		property->val.pszVal=pszOut;
-
-		property->iType |= PF_DECODED;
 	}
-}
 
-#endif
-
-/** Function trims whitespaces at the beginning and at the end of a string. 
- *  The data in the string is modified, so any whitespace char_t at the end of a string
- *  is replaced with '\\0', and the function returns a pointer to the first character
- *  in the string that is not a whitespace.
- * \param[in,out] pszString - string to process
- * \return Pointer to the first non-whitespace character in a string.
- */
-/*char_t* config::trim(char_t* pszString) const
-{
-	char_t *pszData=pszString;
-
-	// skip the whitespaces at the beginning
-	while(is_whitespace(*pszData))
-		pszData++;
-
-	// the end
-	size_t iLen=strlen(pszData);
-	if (iLen != 0)
-	{
-		iLen--;
-		while (iLen > 0 && is_whitespace(*(pszData+iLen)))
-			pszData[iLen--]='\0';
-	}
-	return pszData;
+	m_lock.unlock();
 }
 
-/** Processes the two strings given (a key = value) - checks if there is any
- *  registered property with a given name, and if there is - the given value
- *  is applied to the property in the format specified by that property.
- * \param[in] pszName - name of the property to find
- * \param[in] pszValue - value of the property; the string is processed using 
- *                       the property type found
- */
-/*void config::process_line(const char_t* pszName, const char_t* pszValue)
-{
-	// check if the property name is registered
-	for (std::vector<_PROP>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
-	{
-		if (strcmp((*it).pszName, pszName) == 0)
-		{
-			// this function is called from read() which reads the standard stuff from a .conf file
-			(*it).bModified=false;
-
-			// this is it - type of property
-			switch (it->iType & PTM_TYPE)
-			{
-			case PT_INT:
-				{
-					it->val.i.iVal=atol(pszValue);
-					break;
-				}
-			case PT_UINT:
-				{
-					it->val.ui.uiVal=strtoul(pszValue, NULL, 10);
-					break;
-				}
-			case PT_LONGLONG:
-				{
-#ifdef _WIN32
-					it->val.ll.llVal=_atoi64(pszValue);
-#else
-					it->val.ll.llVal=atoll(pszValue);
-#endif
-					break;
-				}
-			case PT_ULONGLONG:
-				{
-#ifdef _WIN32
-					it->val.ull.ullVal=(ulonglong_t)_atoi64(pszValue);
-#else
-					it->val.ull.ullVal=(ulonglong_t)atoll(pszValue);
-#endif
-					break;
-				}
-			case PT_BOOL:
-				{
-					if (strcmp(pszValue, "yes") == 0)
-						it->val.bVal=true;
-					else if (strcmp(pszValue, "no") == 0)
-						it->val.bVal=false;
-					else
-						it->val.bVal=atoi(pszValue) != 0;
-					break;
-				}
-			case PT_STRING:
-				{
-					// delete the old value and add the new one
-					delete [] it->val.pszVal;
-					it->val.pszVal=new char_t[strlen(pszValue)+1];
-					strcpy(it->val.pszVal, pszValue);
-
-					// update the encryption ststus
-#ifdef USE_ENCRYPTION
-					(*it).iType &= ~PF_DECODED;
-#endif
-
-					break;
-				}
-			default:
-				break;
-			}
-
-			// we need not more processing
-			return;
-		}
-	}
-	
-	// if the property wasn't found - add to the unreg as string property
-	_PROP property;
-	property.iType=PT_STRING;
-	property.pszName=new char_t[strlen(pszName)+1];
-	strcpy(property.pszName, pszName);
-	property.bModified=false;
-	property.val.pszVal=new char_t[strlen(pszValue)+1];
-	strcpy(property.val.pszVal, pszValue);
-	
-	m_pvUnreg->push_back(property);
-}
-
-/** Prepares the string with the property value to be written to a file.
- *  There is no sane limitation of the string length (but one should be careful
- *  because such a limitation is integrated with read-related functions.
- * \param[in] property - pointer to the internal structure with property description
- * \param[out] pres - pointer to a string object that will receive the line of text
- */
-/*void config::prepare_line(const _PROP* property, string* pres) const
-{
-	assert(property && pres);
-
-	char_t szLine[MAX_LINE];
-	switch(property->iType & PTM_TYPE)
-	{
-	case PT_INT:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " LFMT, property->pszName, property->val.i.iVal);
-			break;
-		}
-	case PT_UINT:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " ULFMT, property->pszName, property->val.ui.uiVal);
-			break;
-		}
-	case PT_LONGLONG:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " LLFMT, property->pszName, property->val.ll.llVal);
-			break;
-		}
-	case PT_ULONGLONG:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " ULLFMT, property->pszName, property->val.ull.ullVal);
-			break;
-		}
-	case PT_BOOL:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " ULFMT, property->pszName, (uint_t)property->val.bVal);
-			break;
-		}
-	case PT_STRING:
-		{
-			snprintf(szLine, MAX_LINE, STRFMT " = " STRFMT, property->pszName, property->val.pszVal);
-			break;
-		}
-	default:
-		break;
-	}
-
-	szLine[MAX_LINE-1]='\0';
-//	printf(szLine);
-	*pres=szLine;
-}
-
-/** Searches for a property with a given name and returns a property
- *  ID if found.
- * \param[in] pszName - property name to search for
- * \return The property ID if property has been found, or -1 if not.
- */
-/*ulong_t config::is_registered(const char_t* pszName)
-{
-	// enum through all of the existing nodes
-	for (std::vector<_PROP>::iterator it=m_pvProps->begin();it != m_pvProps->end();it++)
-	{
-		if (strcmp(pszName, (*it).pszName) == 0)
-			return (ulong_t)(it-m_pvProps->begin());
-	}
-
-	return (ulong_t)-1;		// no property found
-}
-
-/** Searches for an unregistered property contained in the unreg container. Returns an
- *  index in the container unreg (if the entry have been found) or -1 (if not).
- * \param[in] pszName - name of the property to search for
- * \return Property index if found, -1 if not.
- */
-/*ulong_t config::is_unreg(const char_t* pszName)
-{
-	// enum through all of the existing nodes
-	for (std::vector<_PROP>::iterator it=m_pvUnreg->begin();it != m_pvUnreg->end();it++)
-	{
-		if (strcmp(pszName, (*it).pszName) == 0)
-			return (ulong_t)(it-m_pvUnreg->begin());
-	}
-
-	return (ulong_t)-1;		// no property found
-}*/
-
 END_ICPF_NAMESPACE
Index: ext/libicpf/src/cfg.h
===================================================================
diff -u -r771dac1fbb7608aa92942c6cab7c5c8b0cccb791 -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/cfg.h	(.../cfg.h)	(revision 771dac1fbb7608aa92942c6cab7c5c8b0cccb791)
+++ ext/libicpf/src/cfg.h	(.../cfg.h)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -77,12 +77,12 @@
 /** \name Construction/destruction */
 /**@{*/
 	config(config_base* pCfgBase);	///< Standard constructor
-	~config();	///< Standard destructor
+	~config();						///< Standard destructor
 /**@}*/
 	
 /** \name Reading and writing to the external medium */
 /**@{*/
-	void read(const tchar_t *pszPath);		///< Reads the file with properties
+	void read(const tchar_t *pszPath);		///< Reads the properties from the source file
 	void write(const tchar_t* pszPath);		///< Saves the properties to the file
 /**@}*/
 
@@ -121,15 +121,15 @@
 /** \name Getting and setting values */
 /**@{*/
 	/// Gets the value of string-type property
-	const tchar_t* get_value(uint_t uiProp, tchar_t* pszBuffer, size_t stMaxSize, size_t stIndex=0) const;
+	const tchar_t* get_value(uint_t uiProp, tchar_t* pszBuffer, size_t stMaxSize, size_t stIndex=0);
 	/// Gets the value of longlong_t-type property
-	ll_t get_signed_num(uint_t uiProp, size_t stIndex=0) const;
+	ll_t get_signed_num(uint_t uiProp, size_t stIndex=0);
 	/// Gets the value of ulonglong_t-type property
-	ull_t get_unsigned_num(uint_t uiProp, size_t stIndex=0) const;
+	ull_t get_unsigned_num(uint_t uiProp, size_t stIndex=0);
 	/// Gets the value of bool-type property
-	bool get_bool(uint_t uiProp, size_t stIndex=0) const;
+	bool get_bool(uint_t uiProp, size_t stIndex=0);
 	/// Gets the value of string-type property
-	const tchar_t* get_string(uint_t uiProp, size_t stIndex=0) const;
+	const tchar_t* get_string(uint_t uiProp, size_t stIndex=0);
 
 	// setting property data
 	/// Sets the value from the string
@@ -145,6 +145,10 @@
 /**@}*/
 
 protected:
+	void load_registered();			///< Loads the registered property values from the underlying config base
+	void store_registered();		///< Stores the registered property values to the underlying config base
+
+protected:
 	mutex m_lock;					///< Lock for the multi-threaded access to the properties
 	ptr_t m_hProps;					///< Handle to the registered property storage
 	config_base* m_pCfgBase;			///< Underlying base for this class
Index: ext/libicpf/src/cfg_xml.cpp
===================================================================
diff -u -r3e7ccb6efc5089399a7801082d923aeb41f53d2e -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/cfg_xml.cpp	(.../cfg_xml.cpp)	(revision 3e7ccb6efc5089399a7801082d923aeb41f53d2e)
+++ ext/libicpf/src/cfg_xml.cpp	(.../cfg_xml.cpp)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -3,6 +3,7 @@
 #include "exception.h"
 #include <string>
 #include <map>
+#include <assert.h>
 
 BEGIN_ICPF_NAMESPACE
 
@@ -279,22 +280,22 @@
  *
  * \param[in] pszName - key name for which the string should be set at
  * \param[in] pszValue - value to set
- * \param[in] bAdd - true if the string should be added to the previous, false if replaced.
+ * \param[in] a - action to take while setting
  */
-void xml_cfg::set_value(const tchar_t* pszName, const tchar_t* pszValue, bool bAdd)
+void xml_cfg::set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a)
 {
 	// traverse the current tag tree
-	set_value(m_pStorage, pszName, pszValue, bAdd);
+	set_value(m_pStorage, pszName, pszValue, a);
 }
 
 /** Sets the specified value in the given key name - recursive helper function.
  *
  * \param[in] pNodePtr - pointer to the xml node to process
  * \param[in] pszName - key name for which the string should be set at
  * \param[in] pszValue - value to set
- * \param[in] bAdd - true if the string should be added to the previous, false if replaced.
+ * \param[in] a - action to take while setting
  */
-void xml_cfg::set_value(ptr_t pNodePtr, const tchar_t* pszName, const tchar_t* pszValue, bool bAdd)
+void xml_cfg::set_value(ptr_t pNodePtr, const tchar_t* pszName, const tchar_t* pszValue, actions a)
 {
 	xml_node* pNode=(xml_node*)pNodePtr;
 
@@ -303,33 +304,62 @@
 	{
 		xml_storage::iterator it=pNode->m_mNodes.find(tstring(pszName, pszSign-pszName));
 		if (it != pNode->m_mNodes.end())
-			set_value(&(*it).second, pszSign+1, pszValue, bAdd);
+			set_value(&(*it).second, pszSign+1, pszValue, a);
 		else
 		{
 			std::pair<xml_storage::iterator, bool> pr=pNode->m_mNodes.insert(xml_storage::value_type(tstring(pszName, pszSign-pszName), xml_node(pNode)));
-			set_value(&(*pr.first).second, pszSign+1, pszValue, bAdd);
+			set_value(&(*pr.first).second, pszSign+1, pszValue, a);
 		}
 	}
 	else
 	{
-		// now it's the key going
-		if (pszValue == NULL)
+		// clear if we're replacing
+		switch(a)
 		{
-			if (bAdd)
-				pNode->m_mAttr.erase(tstring(pszName));	// remove the key from map
-			else
-				pNode->m_mAttr.clear();					// clear the entire map
-		}
-		else
-		{
-			// clear if we're replacing
-			if (!bAdd)
-				pNode->m_mAttr.clear();
-
-			// and add
+		case config_base::action_replace:
+			pNode->m_mAttr.clear();
+		case config_base::action_add:
 			pNode->m_mAttr.insert(attr_storage::value_type(tstring(pszName), tstring(pszValue)));
+			break;
+		default:
+			assert(false);
 		}
 	}
 }
 
+/** Clear values for a given property name.
+ *
+ * \param[in] pszName - name of the property to clear the values for
+ */
+void xml_cfg::clear(const tchar_t* pszName)
+{
+	clear(m_pStorage, pszName);
+}
+
+/** Recursive clear function - searches recursively for a proper node
+ *  and finally clears the string map.
+ *
+ * \param[in] pNodePtr - pointer to a node to be processed
+ * \param[in] pszName - name of the property to search for in the given node
+ */
+void xml_cfg::clear(ptr_t pNodePtr, const tchar_t* pszName)
+{
+	xml_node* pNode=(xml_node*)pNodePtr;
+
+	// parse the name
+	tchar_t* pSign=_tcschr(pszName, _t('/'));
+	if (pSign)
+	{
+		// locate the xml_node associated with the name
+		xml_storage::iterator it=pNode->m_mNodes.find(tstring(pszName, pSign-pszName));
+		if (it != pNode->m_mNodes.end())
+			clear(&(*it).second, pSign+1);
+	}
+	else
+	{
+		std::pair<attr_storage::iterator, attr_storage::iterator> pr=pNode->m_mAttr.equal_range(tstring(pszName));
+		pNode->m_mAttr.erase(pr.first, pr.second);
+	}
+}
+
 END_ICPF_NAMESPACE
Index: ext/libicpf/src/cfg_xml.h
===================================================================
diff -u -r3e7ccb6efc5089399a7801082d923aeb41f53d2e -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/cfg_xml.h	(.../cfg_xml.h)	(revision 3e7ccb6efc5089399a7801082d923aeb41f53d2e)
+++ ext/libicpf/src/cfg_xml.h	(.../cfg_xml.h)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -38,15 +38,19 @@
 	/// Closes the search operation
 	virtual void find_close(ptr_t pFindHandle);
 
-	/// Sets a value for a given key (either adds to or replaces the previous value)
-	virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, bool bAdd);
+	/// Sets a value for a given key
+	virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a=actions::action_add);
+	/// Clear values for a given property name
+	virtual void clear(const tchar_t* pszName);
 /**@}*/
 
 private:
 	/// Find helper - recursively searches for a specific key node
 	ptr_t find(ptr_t pNodePtr, const tchar_t* pszName);
 	/// Set value helper - searches for a specific node and sets the value
-	void set_value(ptr_t pNodePtr, const tchar_t* pszName, const tchar_t* pszValue, bool bAdd);
+	void set_value(ptr_t pNodePtr, const tchar_t* pszName, const tchar_t* pszValue, actions a=actions::action_add);
+	/// Clear helper - clears the appropriate attribures
+	void clear(ptr_t pNodePtr, const tchar_t* pszName);
 
 protected:
 	ptr_t m_hStorage;		///< Handle to the internal xml storage
Index: ext/libicpf/src/config_base.h
===================================================================
diff -u -r771dac1fbb7608aa92942c6cab7c5c8b0cccb791 -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/config_base.h	(.../config_base.h)	(revision 771dac1fbb7608aa92942c6cab7c5c8b0cccb791)
+++ ext/libicpf/src/config_base.h	(.../config_base.h)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -13,6 +13,14 @@
 class config_base
 {
 public:
+	/// Actions used when setting value
+	enum actions
+	{
+		action_add,
+		action_replace
+	};
+
+public:
 /** \name File operations */
 /**@{*/
 	/// Reads the xml document from the specified file
@@ -30,8 +38,10 @@
 	/// Closes the search operation
 	virtual void find_close(ptr_t pFindHandle) = 0;
 
-	/// Sets a value for a given key (either adds to or replaces the previous value)
-	virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, bool bAdd) = 0;
+	/// Sets a value for a given key
+	virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a=actions::action_add) = 0;
+	/// Clear values for a given property name
+	virtual void clear(const tchar_t* pszName) = 0;
 /**@}*/
 };
 
Index: ext/libicpf/src/config_property.h
===================================================================
diff -u -r771dac1fbb7608aa92942c6cab7c5c8b0cccb791 -r0d9a4d94a98872815d5840d1bcc4d394d455307c
--- ext/libicpf/src/config_property.h	(.../config_property.h)	(revision 771dac1fbb7608aa92942c6cab7c5c8b0cccb791)
+++ ext/libicpf/src/config_property.h	(.../config_property.h)	(revision 0d9a4d94a98872815d5840d1bcc4d394d455307c)
@@ -66,6 +66,8 @@
 	void init(const tchar_t* pszName, uint_t uiType, bool bClear=true);
 	/// Retrieves a property type (with flags)
 	uint_t get_type() const { return m_uiPropType; };
+	/// Checks if the property is array-based
+	bool is_array() const { return (m_uiPropType & prop_flags::flag_array) != false; };
 
 	/// Sets a property name
 	void set_name(const tchar_t* pszName) { m_pszName=copy_string(pszName); };