/*
 * Copyright(C) 2003 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile: testsup.h,v $
 * \version $Revision: 1.41 $
 * \date $Date: 2005/02/03 12:50:45 $
 * \author $Author: cav $
 *
 * \brief Test support function definitions
 * \todo Два типа на section и param
 */

#ifndef _TESTSUP_H
#define _TESTSUP_H

#include "common.h"

#include <functional>
#include <string>
#include <iterator>
#include "ASN1Blob.h"
#include "ASN1Util.h"
#include "CA_CMP_Types.h"

struct TSupportRegistrySearchContext_;
struct TSupportRegistrySearchValue_;

class config_exception : public std::runtime_error
{
public:
    explicit config_exception( const std::string &str )
	: std::runtime_error( str ) 
    {}
    static const std::string def;
private:
};

class entry_not_found_exception : public config_exception
{
public:
    explicit entry_not_found_exception( const std::string &str ) 
	: config_exception( str )
    {}
    static const std::string def;
};

class entry_bad_exception : public config_exception
{
public:
    explicit entry_bad_exception( const std::string &str ) 
	: config_exception( str )
    {}
    static const std::string def;
};

class entry_bad_type_exception : public entry_bad_exception
{
public:
    explicit entry_bad_type_exception( const std::string &str ) 
	: entry_bad_exception( str )
    {}
    static const std::string def;
};

class rights_exception : public config_exception
{
public:
    explicit rights_exception( const std::string &str ) 
	: config_exception( str )
    {}
    static const std::string def;
};

class ini_throw
{
public:
    static void throw_bad_type( const std::string &str =
	entry_bad_type_exception::def )
    { throw entry_bad_type_exception( str ); }
    static void throw_bad( const std::string &str =
	entry_bad_exception::def )
    { throw entry_bad_exception( str ); }
    static void throw_entry_not_found( const std::string &str =
	entry_not_found_exception::def )
    { throw entry_not_found_exception( str ); }
    static void throw_out_of_range( const std::string &str = out_of_range_def )
    { throw std::out_of_range( str ); }
    static void throw_memory()
    { throw std::bad_alloc(); }
    static void throw_runtime( const std::string &str = config_exception::def )
    { throw config_exception( str ); }
    static void throw_rights( const std::string &str  = rights_exception::def )
    { throw rights_exception( str ); }

    static const std::string out_of_range_def;
};

class Ini;

template<class Char>
class char_rtraits : public std::char_traits<Char>
{
public:
};

template<class Char, class Traits = char_rtraits<Char> >
class basic_multi_sz
{
public:
    typedef ptrdiff_t difference_type;
    typedef Char *value_type;
    typedef value_type *pointer;
    typedef const value_type *const_pointer;
    typedef value_type &reference;
    typedef const Char *const_reference;

    explicit basic_multi_sz() :size_( 0 )
    { 
	ptr_.resize(2);
	back_ = &ptr_[0] + 1; 
	ptr_[0] = Char(); 
	*back_ = Char(); 
    }
    explicit basic_multi_sz( const Char *src );
    basic_multi_sz( const basic_multi_sz &src ) : size_( src.size_ )
    {
	ptr_.resize(src.back_ - &(src.ptr_[0]) + 1);
	difference_type d = src.back_ - &(src.ptr_[0]);
	back_ = &ptr_[0] + d;
	Traits::copy( &ptr_[0], &(src.ptr_[0]), d + 1 );
    }

    basic_multi_sz& operator=( const basic_multi_sz &right )
    { basic_multi_sz tmp( right ); swap( tmp ); return *this; }

    void swap( basic_multi_sz &right ) throw()
    { 
	std::swap( ptr_, right.ptr_ ); 
	std::swap( size_, right.size_ );
	std::swap( back_, right.back_ );
    }

    class const_iterator : public std::iterator<std::bidirectional_iterator_tag,
	value_type, difference_type, const_pointer, const_reference>
    {
    public:
	// Конструкторы, деструкторы, операторы присваивания
	explicit const_iterator() : ptr_( 0 ) {}
	const_iterator( const const_iterator& src ) : ptr_( src.ptr_ ) {}
	    // Реализующий конструктор
	explicit const_iterator( const Char *ptr ) : ptr_( ptr ) {}
	const_iterator& operator=( const const_iterator &src )
	{ const_iterator tmp( src ); swap( tmp ); return *this; }

	void swap( const_iterator &src ) throw()
	{ std::swap<const Char*>( ptr_, src.ptr_ ); }

	// Разыменование
	const_reference operator*() const
	{ return ptr_; }

	// Перемещение
	const_iterator& operator++()
	{ ptr_ += Traits::length( ptr_ ) + 1; return *this; }
	const_iterator operator++( int )
	{ const_iterator tmp( *this ); ++(*this); return tmp; }
	const_iterator operator--( int )
	{ const_iterator tmp( *this ); --(*this); return tmp; }

	// Сравнение
	bool operator==(const const_iterator& right) const
	{ return ptr_ == right.ptr_; }
	bool operator!=(const const_iterator& right) const
	{ return !( *this == right ); }
    protected:
	const_reference ptr_;
    };
#if __SUNPRO_CC >= 0x560
    typedef std::reverse_iterator<const_iterator, std::bidirectional_iterator_tag, value_type, difference_type, const_pointer, const_reference>
	const_reverse_iterator;
#else
    typedef std::reverse_iterator<const_iterator>
	const_reverse_iterator;
#endif

    size_t size() const { return size_; }

    const_iterator begin() const
    { return const_iterator( &ptr_[0] + 1 ); }
    const_iterator end() const
    { return const_iterator( back_ ); }

    const_reverse_iterator rbegin() const
    { return const_reverse_iterator( end() ); }
    const_reverse_iterator rend() const
    { return const_reverse_iterator( begin() ); }

    bool empty() const 
    { return size() == 0; }

    basic_multi_sz& operator +=( const Char * );

protected:
    std::vector<Char> ptr_;
    size_t size_;
    Char *back_;
};

typedef basic_multi_sz<char> multi_sz;
typedef basic_multi_sz<wchar_t> wmulti_sz;

// Значение ini файла
class IniValue
{
public:
    typedef char path_char;
    typedef std::basic_string<path_char> path_string;

    enum ParamType
    {
	String = 1, Long = 2, Bool = 3, Binary = 4, LongLong = 5
    };

    explicit IniValue() : value_( 0 ) {}
    IniValue( const IniValue &src );
    ~IniValue();
    // Реализующий конструктор
    explicit IniValue( TSupportRegistrySearchValue_ *value ) throw();
    IniValue& operator=( const IniValue &src )
    { IniValue tmp( src ); swap( tmp ); return *this; }

    void swap( IniValue &src ) throw()
    { std::swap( value_, src.value_ ); }

    // Получение параметра
    path_string param() const;

    // Получение значения
    std::string get_string() const;
    std::wstring get_wstring() const;

    // Функция с проверкой длины. Длина передается в символах
    // не включая заключительный 0. Возвращает указатель на str
    char *get_string( char *str, size_t length ) const;
    // Функция с проверкой длины. Длина передается в символах
    // не включая заключительный 0. Возвращает указатель на str
    wchar_t *get_wstring( wchar_t *str, size_t length ) const;
    long get_long() const;
    long long get_long_long() const;
    bool get_bool() const;
    CACMPT_BLOB get_binary() const;
    int get_int() const;
    unsigned get_unsigned() const;
    CACMPT_Date get_date() const;
    CACMPT_Period get_period() const;
    int get_enum( const char **str_vals, int count ) const;
    int get_enum( const wchar_t **str_vals, int count ) const;
    Ini get_ref( const Ini &cur ) const;
    multi_sz get_multi_sz() const;

    wmulti_sz get_wmulti_sz() const;
    ParamType get_type() const;

    // Статические преобразования из базовых типов.
    static bool toint( long src, int &dest );
    static bool tounsigned( long src, unsigned &dest );
    static bool toenum( const char *str, const char **str_vals, 
	int count, int &dest );
    static bool toenum( const wchar_t *str, const wchar_t **str_vals, 
	int count, int &dest );

    // Проверка типов
    bool isint() const
    {
	int dummy;
	return ( get_type() & Long ) && toint( get_long(), dummy ); 
    }
    bool isunsigned() const
    {
	int dummy;
	return ( get_type() & Long ) && toint( get_long(), dummy ); 
    }
    bool isdate() const;
    bool isenum( const char **str_vals, size_t str_count ) const
    { 
	int dummy;
	return ( get_type() & String )
	    && toenum( get_string().c_str(), str_vals, str_count, dummy );
    }
    bool isenum( const wchar_t **str_vals, size_t str_count ) const
    { 
	int dummy;
	return ( get_type() & String )
	    && toenum( get_wstring().c_str(), str_vals, str_count, dummy );
    }

    void throw_bad_type( const char *stype ) const;
    void throw_bad() const;
protected:
    void get_string( std::string &res ) const
    { res = get_string(); }
    void get_string( std::wstring &res ) const
    { res = get_wstring(); }

    int toint( long src ) const
    { 
	int i = 0;
	if( !toint( src, i ) )
	    throw_bad_type( "int" );
	return i;
    }
    unsigned tounsigned( long src ) const
    { 
	unsigned u = 0;
	if( !tounsigned( src, u ) )
	    throw_bad_type( "unsigned" );
	return u;
    }
    CACMPT_Date todate( const char *str ) const
    { 
	return CACMPT_Date(str);
    }
    CACMPT_Date todate( const wchar_t *str ) const
    { 
	return CACMPT_Date( tostring(str) );
    }
    CACMPT_Period toperiod( const char *str ) const
    { 
	return CACMPT_Period(str);
    }
    CACMPT_Period toperiod( const wchar_t *str ) const
    { 
	return CACMPT_Period( tostring(str).c_str() );
    }
    int toenum( const char *str, const char **str_vals,
	int count ) const
    { 
	int e = 0;
	if( !toenum( str, str_vals, count, e ) )
	    throw_bad_type( "enum" );
	return e;
    }
    int toenum( const wchar_t *str, const wchar_t **str_vals, 
	int count ) const
    { 
	int e = 0;
	if( !toenum( str, str_vals, count, e ) )
	    throw_bad_type( "enum" );
	return e;
    }

private:
    TSupportRegistrySearchValue_ *value_;
};

class Ini
{
public:
    typedef char path_char;
    typedef std::basic_string<path_char> path_string;

    typedef ptrdiff_t difference_type;
    typedef IniValue *pointer;
    typedef const IniValue *const_pointer;
    typedef IniValue &reference;
    typedef const IniValue &const_reference;
    typedef IniValue value_type;

    // Конструкторы, деструкторы, присваивания
    explicit Ini();
    explicit Ini( const path_char *src );
    Ini( const Ini &src );
    Ini( const Ini &src, const path_char *subkey );
    Ini &operator=( const Ini &src )
    { Ini tmp( src ); swap( tmp ); return *this; }
    Ini &operator+=( const path_char *subkey )
    { Ini tmp( *this, subkey ); swap( tmp ); return *this; }

    bool operator==( const Ini &right ) const
    { return std::string( get_path() ) == right.get_path(); }
    bool operator!=( const Ini &right ) const
    { return !( *this == right ); }

    void swap( Ini &src ) throw();

    class const_iterator : public std::iterator<std::forward_iterator_tag,
	value_type, difference_type, const_pointer, const_reference>
    {
    public:
	typedef std::iterator<std::forward_iterator_tag,
	    value_type, difference_type, const_pointer, const_reference> 
	    base_iterator;

	// Конструкторы, деструкторы, операторы присваивания
	explicit const_iterator() : value_( 0 ), ptr_( 0 ) {}
	    // Реализующий конструктор
	explicit const_iterator( const path_char *path, bool section, bool end );
	const_iterator& operator=( const const_iterator &src )
	{ const_iterator tmp( src ); swap( tmp ); return *this; }
	~const_iterator();

	void swap( const_iterator &src ) throw()
	{ std::swap( ptr_, src.ptr_ ); std::swap( value_, src.value_ ); }

	// Разыменование
	reference operator*() const
	{ return value_; }
	pointer operator->() const
	{ return &**this; }

	// Перемещение
	const_iterator& operator++();
	const_iterator operator++( int )
	{ const_iterator tmp( *this ); ++(*this); return tmp; }

	// Сравнение
	bool operator==(const const_iterator& right) const;
	bool operator!=(const const_iterator& right) const
	{ return !( *this == right ); }

    protected:
	IniValue value_;
	void setend();
	bool isend() const throw();
    private:
	TSupportRegistrySearchContext_ *ptr_;
    };

    const path_char *get_path() const
    { return path.c_str(); }

    // Базовые функции поиска
    bool find( const path_char *param, reference value ) const;

    // Поиск с известным типом
    bool find( const path_char *param, std::string &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_string();
	return true;
    }
    bool find( const path_char *param, std::wstring &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_wstring();
	return true;
    }
    bool find( const path_char *param, char *str, size_t length ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	value.get_string( str, length );
	return true;
    }
    bool find( const path_char *param, wchar_t *str, size_t length ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	value.get_wstring( str, length );
	return true;
    }
    bool find( const path_char *param, long &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_long();
	return true;
    }
    bool find( const path_char *param, long long &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_long_long();
	return true;
    }
    bool find( const path_char *param, bool &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_bool();
	return true;
    }
    bool find( const path_char *param, CACMPT_BLOB &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_binary();
	return true;
    }
    bool find( const path_char *param, int &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_int();
	return true;
    }
    bool find( const path_char *param, unsigned &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_unsigned();
	return true;
    }
    bool find( const path_char *param, CACMPT_Date &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_date();
	return true;
    }
    bool find( const path_char *param, CACMPT_Period &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_period();
	return true;
    }
    bool find( const path_char *param, const char **str_vals, int count,
	int &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_enum( str_vals, count );
	return true;
    }
    bool find( const path_char *param, const wchar_t **str_vals, int count,
	int &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_enum( str_vals, count );
	return true;
    }
    bool find( const path_char *param, Ini &res, const Ini &cur ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_ref( cur );
	return true;
    }
    bool find( const path_char *param, Ini &res ) const
    { 
	return find( param, res, *this ); 
    }
    bool find( const path_char *param, multi_sz &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_multi_sz();
	return true;
    }
    bool find( const path_char *param, wmulti_sz &res ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	res = value.get_wmulti_sz();
	return true;
    }

    bool find_strings(const char * param, std::vector<std::string> & res)
    {
	std::string str;
	if (!find(param, str))
	    return false;
	res.resize(0);    
	int num=0;
	char numbuf[12];
	do
	{
	    res.push_back(str);
	    _snprintf(numbuf,sizeof(numbuf)-1,"%d",++num);
	}
	while (find((std::string(param)+numbuf).c_str(),str));
	return true;
    }

    bool find( const path_char *param, CACMPT_PARSED_RDN &rdn ) const;
    bool get_type( const path_char *param, value_type::ParamType &type ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return false;
	type = value.get_type();
	return true;
    }
    bool is( const path_char *param ) const
    {	
	value_type dummy;
	return find( param, dummy );
    }

    // Функции поиска с умолчаниями
    std::string find_def( const path_char *param, const char *def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_string();
    }
    std::wstring find_def( const path_char *param, const wchar_t *def ) 
	const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_wstring();
    }
	// Функция НЕ проверяют, что def значение удовлетворяет длине
	// всегда возвращают указатель на str
    char *find_def( const path_char *param, char *str, size_t length, 
	const char *def ) const
    {
	value_type value;
	if( !find( param, value ) )
	{
	    strcpy( str, def );
	    return str;
	}
	value.get_string( str, length );
	return str;
    }
	// Функция НЕ проверяют, что def значение удовлетворяет длине
	// всегда возвращают указатель на str
    wchar_t *find_def( const path_char *param, wchar_t *str, size_t length, 
	const wchar_t *def ) const
    {
	value_type value;
	if( !find( param, value ) )
	{
	    wcscpy( str, def );
	    return str;
	}
	value.get_wstring( str, length );
	return str;
    }
    long find_def( const path_char *param, long def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_long();
    }
    long long find_def( const path_char *param, long long def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_long_long();
    }
    bool find_def( const path_char *param, bool def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_bool();
    }
    CACMPT_BLOB find_def( const path_char *param, const CACMPT_BLOB &def ) 
	const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_binary();
    }
    int find_def( const path_char *param, int def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_int();
    }
    unsigned find_def( const path_char *param, unsigned def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_unsigned();
    }
    CACMPT_Date find_def( const path_char *param, const CACMPT_Date &def ) 
	const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_date();
    }
    CACMPT_Period find_def( const path_char *param, const CACMPT_Period &def ) 
	const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_period();
    }
    int find_def( const path_char *param, const char **str_vals, int count, 
	int def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_enum( str_vals, count );
    }
    int find_def( const path_char *param, const wchar_t **str_vals, int count, 
	int def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_enum( str_vals, count );
    }
    Ini find_def( const path_char *param, const Ini &def, const Ini &cur ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return Ini( def );
	return value.get_ref( cur );
    }
    Ini find_def( const path_char *param, const Ini &def ) const
    { 
	return find_def( param, def, *this ); 
    }
    multi_sz find_def( const path_char *param, const multi_sz &def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_multi_sz();
    }
    wmulti_sz find_def( const path_char *param, const wmulti_sz &def ) const
    {
	value_type value;
	if( !find( param, value ) )
	    return def;
	return value.get_wmulti_sz();
    }
    CACMPT_PARSED_RDN find_def( const path_char *param, 
	const CACMPT_PARSED_RDN &def ) const
    {
	CACMPT_PARSED_RDN r;
	if( !find( param, r ) )
	    return def;
	return r;
    }

    // Функции возбуждающие исключение при отсутствии параметра
    value_type at( const path_char *param ) const
    {
	value_type v;
	if( !find( param, v ) ) throw_not_found( param );
	return v;
    }
    value_type operator[]( const path_char *param ) const
    {
	return at( param );
    }
    std::string find_string( const path_char *param ) const
    { 
	return at( param ).get_string();
    }
    std::wstring find_wstring( const path_char *param ) const
    { 
	return at( param ).get_wstring();
    }
    char *find_string( const path_char *param, char *str, size_t length ) const
    { 
	return at( param ).get_string( str, length );
    }
    wchar_t *find_wstring( const path_char *param, wchar_t *str, size_t length ) 
	const
    { 
	return at( param ).get_wstring( str, length );
    }
    long find_long( const path_char *param ) const
    {
	return at( param ).get_long();
    }
    long long find_long_long( const path_char *param ) const
    {
	return at( param ).get_long_long();
    }
    bool find_bool( const path_char *param ) const
    {
	return at( param ).get_bool();
    }
    CACMPT_BLOB find_binary( const path_char *param ) const
    {
	return at( param ).get_binary();
    }
    int find_int( const path_char *param ) const
    {
	return at( param ).get_int();
    }
    unsigned find_unsigned( const path_char *param ) const
    {
	return at( param ).get_unsigned();
    }
    CACMPT_Date find_date( const path_char *param ) const
    {
	return at( param ).get_date();
    }
    CACMPT_Period find_period( const path_char *param ) const
    {
	return at( param ).get_period();
    }
    int find_enum( const path_char *param, const char **str_vals, int count )
	const
    {
	return at( param ).get_enum( str_vals, count );
    }
    int find_enum( const path_char *param, const wchar_t **str_vals, int count )
	const
    {
	return at( param ).get_enum( str_vals, count );
    }
    Ini find_ref( const path_char *param, const Ini &cur ) const
    {
	return at( param ).get_ref( cur );
    }
    Ini find_ref( const path_char *param ) const
    {
	return find_ref( param, *this );
    }
    multi_sz find_multu_sz( const path_char *param ) const
    {
	return at( param ).get_multi_sz();
    }
    wmulti_sz find_wmultu_sz( const path_char *param ) const
    {
	return at( param ).get_wmulti_sz();
    }
    CACMPT_PARSED_RDN find_rdn( const path_char *param ) const
    {
	CACMPT_PARSED_RDN rdn;
	if( !find( param, rdn ) ) throw_not_found( param );
	return rdn;
    }
    value_type::ParamType find_type( const path_char *param ) const
    {
	return at( param ).get_type();
    }

    // Функции установки параметра
    void insert( const path_char *param, const char *src ) const;
    void insert( const path_char *param, const wchar_t *src ) const;
    void insert( const path_char *param, long src ) const;
    void insert( const path_char *param, long long src ) const;
    void insert( const path_char *param, bool src ) const;
    void insert( const path_char *param, const CACMPT_BLOB &src ) const;
    void insert( const path_char *param, int src ) const;
    void insert( const path_char *param, unsigned src ) const;
    void insert( const path_char *param, const CACMPT_Date &src ) const;
    void insert( const path_char *param, const CACMPT_Period &src ) const;
    void insert( const path_char *param, const char **str_vals, int count,
	int &src ) const;
    void insert( const path_char *param, const wchar_t **str_vals, int count,
	int &src ) const;
    void insert( const path_char *param, const Ini &src ) const;
    void insert( const path_char *param, const multi_sz &src ) const;
    void insert( const path_char *param, const wmulti_sz &src ) const;
    void insert_strings(const path_char * param, const std::vector<std::string> & strings) 
    {
	if (strings.empty())
	    return;
	insert(param,strings[0].c_str());    
	for (unsigned i=1;i<strings.size();i++)
	{
	    char numbuf[8];
	    _snprintf(numbuf,sizeof(numbuf)-1,"%u",i);
	    insert((std::string(param)+numbuf).c_str(),strings[i].c_str());
	}
    }

    void erase( const path_char *param ) const;

    const_iterator param_begin() const
    { return const_iterator( path.c_str(), false, false ); }
    const_iterator param_end() const
    { return const_iterator( path.c_str(), false, true ); }

    const_iterator section_begin() const
    { return const_iterator( path.c_str(), true, false ); }
    const_iterator section_end() const
    { return const_iterator( path.c_str(), true, true ); }

    void throw_not_found( const path_char *param ) const;

protected:
    void build_param_path( const path_char *param, path_string &res ) const
    { res = path_string( get_path() ) + path_char( '\\' ) + param; }

    bool merge_path( const path_char *ref, path_string &res ) const;

    path_string path;

private:
    static void rback( path_string &src );
};

template<class path_string>
class rdn_prefix {
public:
    static const path_string email;
    static const path_string country;
    static const path_string state;
    static const path_string locality;
//    static const path_string street_address;
//    static const path_string unstructured_address;
    static const path_string organization;
    static const path_string org_unit;
    static const path_string title;
//    static const path_string domain_component;
//    static const path_string unstructured_name;
    static const path_string given_name;
    static const path_string initials;
    static const path_string sur_name;
    static const path_string pseudonym;
    static const path_string common_name;
};

template<class Pr> inline
Ini::const_iterator find_if( Ini::const_iterator First, Ini::const_iterator Last, Pr Pred )
{
    return find_if<Ini::const_iterator, Pr>( First, Last, Pred );
}

#endif // _TESTSUP_H
