2014-07-25 19:29:08 +03:00
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2014-03-04 00:07:58 +02:00
// All rights reserved.
//
2014-07-25 19:29:08 +03:00
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
2014-07-23 16:03:52 +03:00
//
2014-07-25 19:29:08 +03:00
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2014-07-23 16:03:52 +03:00
//
2014-07-25 19:29:08 +03:00
2014-03-04 00:07:58 +02:00
# pragma once
2019-11-04 03:06:01 +02:00
# include <type_traits>
2014-03-04 00:07:58 +02:00
# include "misc_language.h"
# include "portable_storage_base.h"
# include "portable_storage_from_bin.h"
# include "portable_storage_to_json.h"
# include "portable_storage_from_json.h"
# include "portable_storage_val_converters.h"
2018-12-06 20:04:33 +02:00
# include "span.h"
2018-11-18 12:18:35 +02:00
# include "int-util.h"
2014-03-04 00:07:58 +02:00
namespace epee
{
2020-10-13 18:15:07 +03:00
class byte_slice ;
2014-03-04 00:07:58 +02:00
namespace serialization
{
/************************************************************************/
/* */
/************************************************************************/
class portable_storage
{
public :
typedef epee : : serialization : : hsection hsection ;
typedef epee : : serialization : : harray harray ;
2014-04-07 18:02:15 +03:00
typedef storage_entry meta_entry ;
2014-03-04 00:07:58 +02:00
portable_storage ( ) { }
virtual ~ portable_storage ( ) { }
hsection open_section ( const std : : string & section_name , hsection hparent_section , bool create_if_notexist = false ) ;
template < class t_value >
bool get_value ( const std : : string & value_name , t_value & val , hsection hparent_section ) ;
2014-04-07 18:02:15 +03:00
bool get_value ( const std : : string & value_name , storage_entry & val , hsection hparent_section ) ;
2014-03-04 00:07:58 +02:00
template < class t_value >
2019-11-04 03:06:01 +02:00
bool set_value ( const std : : string & value_name , t_value & & target , hsection hparent_section ) ;
2014-03-04 00:07:58 +02:00
//serial access for arrays of values --------------------------------------
//values
template < class t_value >
harray get_first_value ( const std : : string & value_name , t_value & target , hsection hparent_section ) ;
template < class t_value >
bool get_next_value ( harray hval_array , t_value & target ) ;
template < class t_value >
2019-11-04 03:06:01 +02:00
harray insert_first_value ( const std : : string & value_name , t_value & & target , hsection hparent_section ) ;
2014-03-04 00:07:58 +02:00
template < class t_value >
2019-11-04 03:06:01 +02:00
bool insert_next_value ( harray hval_array , t_value & & target ) ;
2014-03-04 00:07:58 +02:00
//sections
harray get_first_section ( const std : : string & pSectionName , hsection & h_child_section , hsection hparent_section ) ;
bool get_next_section ( harray hSecArray , hsection & h_child_section ) ;
harray insert_first_section ( const std : : string & pSectionName , hsection & hinserted_childsection , hsection hparent_section ) ;
bool insert_next_section ( harray hSecArray , hsection & hinserted_childsection ) ;
//------------------------------------------------------------------------
//delete entry (section, value or array)
bool delete_entry ( const std : : string & pentry_name , hsection hparent_section = nullptr ) ;
//-------------------------------------------------------------------------------
2020-10-13 18:15:07 +03:00
bool store_to_binary ( byte_slice & target , std : : size_t initial_buffer_size = 8192 ) ;
2018-12-06 20:04:33 +02:00
bool load_from_binary ( const epee : : span < const uint8_t > target ) ;
bool load_from_binary ( const std : : string & target ) { return load_from_binary ( epee : : strspan < uint8_t > ( target ) ) ; }
2014-03-04 00:07:58 +02:00
template < class trace_policy >
bool dump_as_xml ( std : : string & targetObj , const std : : string & root_name = " " ) ;
2014-05-25 20:06:40 +03:00
bool dump_as_json ( std : : string & targetObj , size_t indent = 0 , bool insert_newlines = true ) ;
2014-03-04 00:07:58 +02:00
bool load_from_json ( const std : : string & source ) ;
private :
section m_root ;
hsection get_root_section ( ) { return & m_root ; }
storage_entry * find_storage_entry ( const std : : string & pentry_name , hsection psection ) ;
template < class entry_type >
2019-11-04 03:06:01 +02:00
storage_entry * insert_new_entry_get_storage_entry ( const std : : string & pentry_name , hsection psection , entry_type & & entry ) ;
2014-03-04 00:07:58 +02:00
hsection insert_new_section ( const std : : string & pentry_name , hsection psection ) ;
# pragma pack(push)
# pragma pack(1)
struct storage_block_header
{
uint32_t m_signature_a ;
uint32_t m_signature_b ;
uint8_t m_ver ;
} ;
# pragma pack(pop)
} ;
inline
2014-05-25 20:06:40 +03:00
bool portable_storage : : dump_as_json ( std : : string & buff , size_t indent , bool insert_newlines )
2014-03-04 00:07:58 +02:00
{
TRY_ENTRY ( ) ;
std : : stringstream ss ;
2014-05-25 20:06:40 +03:00
epee : : serialization : : dump_as_json ( ss , m_root , indent , insert_newlines ) ;
2014-03-04 00:07:58 +02:00
buff = ss . str ( ) ;
return true ;
CATCH_ENTRY ( " portable_storage::dump_as_json " , false )
}
inline
2014-05-25 20:06:40 +03:00
bool portable_storage : : load_from_json ( const std : : string & source )
2014-03-04 00:07:58 +02:00
{
TRY_ENTRY ( ) ;
return json : : load_from_json ( source , * this ) ;
CATCH_ENTRY ( " portable_storage::load_from_json " , false )
}
template < class trace_policy >
2014-05-25 20:06:40 +03:00
bool portable_storage : : dump_as_xml ( std : : string & targetObj , const std : : string & root_name )
2014-03-04 00:07:58 +02:00
{
return false ; //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
}
inline
2018-12-06 20:04:33 +02:00
bool portable_storage : : load_from_binary ( const epee : : span < const uint8_t > source )
2014-03-04 00:07:58 +02:00
{
m_root . m_entries . clear ( ) ;
if ( source . size ( ) < sizeof ( storage_block_header ) )
{
LOG_ERROR ( " portable_storage: wrong binary format, packet size = " < < source . size ( ) < < " less than expected sizeof(storage_block_header)= " < < sizeof ( storage_block_header ) ) ;
return false ;
}
storage_block_header * pbuff = ( storage_block_header * ) source . data ( ) ;
2018-11-18 12:18:35 +02:00
if ( pbuff - > m_signature_a ! = SWAP32LE ( PORTABLE_STORAGE_SIGNATUREA ) | |
pbuff - > m_signature_b ! = SWAP32LE ( PORTABLE_STORAGE_SIGNATUREB )
2014-03-04 00:07:58 +02:00
)
{
2017-07-05 10:53:16 +03:00
LOG_ERROR ( " portable_storage: wrong binary format - signature mismatch " ) ;
2014-03-04 00:07:58 +02:00
return false ;
}
if ( pbuff - > m_ver ! = PORTABLE_STORAGE_FORMAT_VER )
{
LOG_ERROR ( " portable_storage: wrong binary format - unknown format ver = " < < pbuff - > m_ver ) ;
return false ;
}
TRY_ENTRY ( ) ;
throwable_buffer_reader buf_reader ( source . data ( ) + sizeof ( storage_block_header ) , source . size ( ) - sizeof ( storage_block_header ) ) ;
buf_reader . read ( m_root ) ;
return true ; //TODO:
CATCH_ENTRY ( " portable_storage::load_from_binary " , false ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
2014-05-25 20:06:40 +03:00
hsection portable_storage : : open_section ( const std : : string & section_name , hsection hparent_section , bool create_if_notexist )
2014-03-04 00:07:58 +02:00
{
TRY_ENTRY ( ) ;
hparent_section = hparent_section ? hparent_section : & m_root ;
storage_entry * pentry = find_storage_entry ( section_name , hparent_section ) ;
if ( ! pentry )
{
if ( ! create_if_notexist )
return nullptr ;
return insert_new_section ( section_name , hparent_section ) ;
}
CHECK_AND_ASSERT ( pentry , nullptr ) ;
//check that section_entry we find is real "CSSection"
if ( pentry - > type ( ) ! = typeid ( section ) )
{
if ( create_if_notexist )
* pentry = storage_entry ( section ( ) ) ; //replace
else
return nullptr ;
}
return & boost : : get < section > ( * pentry ) ;
CATCH_ENTRY ( " portable_storage::open_section " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
template < class to_type >
struct get_value_visitor : boost : : static_visitor < void >
{
to_type & m_target ;
get_value_visitor ( to_type & target ) : m_target ( target ) { }
template < class from_type >
void operator ( ) ( const from_type & v ) { convert_t ( v , m_target ) ; }
} ;
template < class t_value >
bool portable_storage : : get_value ( const std : : string & value_name , t_value & val , hsection hparent_section )
{
2014-04-30 23:50:06 +03:00
BOOST_MPL_ASSERT ( ( boost : : mpl : : contains < storage_entry : : types , t_value > ) ) ;
2014-03-04 00:07:58 +02:00
//TRY_ENTRY();
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( value_name , hparent_section ) ;
if ( ! pentry )
return false ;
get_value_visitor < t_value > gvv ( val ) ;
boost : : apply_visitor ( gvv , * pentry ) ;
return true ;
//CATCH_ENTRY("portable_storage::template<>get_value", false);
}
//---------------------------------------------------------------------------------------------------------------
2014-04-07 18:02:15 +03:00
inline
bool portable_storage : : get_value ( const std : : string & value_name , storage_entry & val , hsection hparent_section )
{
//TRY_ENTRY();
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( value_name , hparent_section ) ;
if ( ! pentry )
return false ;
val = * pentry ;
return true ;
//CATCH_ENTRY("portable_storage::template<>get_value", false);
}
//---------------------------------------------------------------------------------------------------------------
2014-03-04 00:07:58 +02:00
template < class t_value >
2019-11-04 03:06:01 +02:00
bool portable_storage : : set_value ( const std : : string & value_name , t_value & & v , hsection hparent_section )
2014-03-04 00:07:58 +02:00
{
2019-11-04 03:06:01 +02:00
using t_real_value = typename std : : decay < t_value > : : type ;
BOOST_MPL_ASSERT ( ( boost : : mpl : : contains < boost : : mpl : : push_front < storage_entry : : types , storage_entry > : : type , t_real_value > ) ) ;
2014-03-04 00:07:58 +02:00
TRY_ENTRY ( ) ;
if ( ! hparent_section )
hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( value_name , hparent_section ) ;
if ( ! pentry )
{
2019-11-04 03:06:01 +02:00
pentry = insert_new_entry_get_storage_entry ( value_name , hparent_section , std : : forward < t_value > ( v ) ) ;
2014-03-04 00:07:58 +02:00
if ( ! pentry )
return false ;
return true ;
}
2019-11-04 03:06:01 +02:00
* pentry = std : : forward < t_value > ( v ) ;
2014-03-04 00:07:58 +02:00
return true ;
CATCH_ENTRY ( " portable_storage::template<>set_value " , false ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
storage_entry * portable_storage : : find_storage_entry ( const std : : string & pentry_name , hsection psection )
{
TRY_ENTRY ( ) ;
CHECK_AND_ASSERT ( psection , nullptr ) ;
auto it = psection - > m_entries . find ( pentry_name ) ;
if ( it = = psection - > m_entries . end ( ) )
return nullptr ;
return & it - > second ;
CATCH_ENTRY ( " portable_storage::find_storage_entry " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
template < class entry_type >
2019-11-04 03:06:01 +02:00
storage_entry * portable_storage : : insert_new_entry_get_storage_entry ( const std : : string & pentry_name , hsection psection , entry_type & & entry )
2014-03-04 00:07:58 +02:00
{
2019-11-04 03:06:01 +02:00
static_assert ( std : : is_rvalue_reference < entry_type & & > ( ) , " unexpected copy of value " ) ;
2014-03-04 00:07:58 +02:00
TRY_ENTRY ( ) ;
CHECK_AND_ASSERT ( psection , nullptr ) ;
2019-11-04 03:06:01 +02:00
auto ins_res = psection - > m_entries . emplace ( pentry_name , std : : forward < entry_type > ( entry ) ) ;
2014-03-04 00:07:58 +02:00
return & ins_res . first - > second ;
CATCH_ENTRY ( " portable_storage::insert_new_entry_get_storage_entry " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
hsection portable_storage : : insert_new_section ( const std : : string & pentry_name , hsection psection )
{
TRY_ENTRY ( ) ;
storage_entry * pse = insert_new_entry_get_storage_entry ( pentry_name , psection , section ( ) ) ;
if ( ! pse ) return nullptr ;
return & boost : : get < section > ( * pse ) ;
CATCH_ENTRY ( " portable_storage::insert_new_section " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
template < class to_type >
struct get_first_value_visitor : boost : : static_visitor < bool >
{
to_type & m_target ;
get_first_value_visitor ( to_type & target ) : m_target ( target ) { }
template < class from_type >
bool operator ( ) ( const array_entry_t < from_type > & a )
{
const from_type * pv = a . get_first_val ( ) ;
if ( ! pv )
return false ;
convert_t ( * pv , m_target ) ;
return true ;
}
} ;
//---------------------------------------------------------------------------------------------------------------
template < class t_value >
harray portable_storage : : get_first_value ( const std : : string & value_name , t_value & target , hsection hparent_section )
{
BOOST_MPL_ASSERT ( ( boost : : mpl : : contains < storage_entry : : types , t_value > ) ) ;
//TRY_ENTRY();
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( value_name , hparent_section ) ;
if ( ! pentry )
return nullptr ;
if ( pentry - > type ( ) ! = typeid ( array_entry ) )
return nullptr ;
array_entry & ar_entry = boost : : get < array_entry > ( * pentry ) ;
get_first_value_visitor < t_value > gfv ( target ) ;
if ( ! boost : : apply_visitor ( gfv , ar_entry ) )
return nullptr ;
return & ar_entry ;
//CATCH_ENTRY("portable_storage::get_first_value", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template < class to_type >
struct get_next_value_visitor : boost : : static_visitor < bool >
{
to_type & m_target ;
get_next_value_visitor ( to_type & target ) : m_target ( target ) { }
template < class from_type >
bool operator ( ) ( const array_entry_t < from_type > & a )
{
//TODO: optimize code here: work without get_next_val function
const from_type * pv = a . get_next_val ( ) ;
if ( ! pv )
return false ;
convert_t ( * pv , m_target ) ;
return true ;
}
} ;
template < class t_value >
2014-05-25 20:06:40 +03:00
bool portable_storage : : get_next_value ( harray hval_array , t_value & target )
2014-03-04 00:07:58 +02:00
{
BOOST_MPL_ASSERT ( ( boost : : mpl : : contains < storage_entry : : types , t_value > ) ) ;
//TRY_ENTRY();
CHECK_AND_ASSERT ( hval_array , false ) ;
array_entry & ar_entry = * hval_array ;
get_next_value_visitor < t_value > gnv ( target ) ;
if ( ! boost : : apply_visitor ( gnv , ar_entry ) )
return false ;
return true ;
//CATCH_ENTRY("portable_storage::get_next_value", false);
}
//---------------------------------------------------------------------------------------------------------------
template < class t_value >
2019-11-04 03:06:01 +02:00
harray portable_storage : : insert_first_value ( const std : : string & value_name , t_value & & target , hsection hparent_section )
2014-03-04 00:07:58 +02:00
{
2019-11-04 03:06:01 +02:00
using t_real_value = typename std : : decay < t_value > : : type ;
static_assert ( std : : is_rvalue_reference < t_value & & > ( ) , " unexpected copy of value " ) ;
2014-03-04 00:07:58 +02:00
TRY_ENTRY ( ) ;
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( value_name , hparent_section ) ;
if ( ! pentry )
{
2019-11-04 03:06:01 +02:00
pentry = insert_new_entry_get_storage_entry ( value_name , hparent_section , array_entry ( array_entry_t < t_real_value > ( ) ) ) ;
2014-03-04 00:07:58 +02:00
if ( ! pentry )
return nullptr ;
}
if ( pentry - > type ( ) ! = typeid ( array_entry ) )
2019-11-04 03:06:01 +02:00
* pentry = storage_entry ( array_entry ( array_entry_t < t_real_value > ( ) ) ) ;
2014-03-04 00:07:58 +02:00
array_entry & arr = boost : : get < array_entry > ( * pentry ) ;
2019-11-04 03:06:01 +02:00
if ( arr . type ( ) ! = typeid ( array_entry_t < t_real_value > ) )
arr = array_entry ( array_entry_t < t_real_value > ( ) ) ;
2014-03-04 00:07:58 +02:00
2019-11-04 03:06:01 +02:00
array_entry_t < t_real_value > & arr_typed = boost : : get < array_entry_t < t_real_value > > ( arr ) ;
arr_typed . insert_first_val ( std : : forward < t_value > ( target ) ) ;
2014-03-04 00:07:58 +02:00
return & arr ;
CATCH_ENTRY ( " portable_storage::insert_first_value " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
template < class t_value >
2019-11-04 03:06:01 +02:00
bool portable_storage : : insert_next_value ( harray hval_array , t_value & & target )
2014-03-04 00:07:58 +02:00
{
2019-11-04 03:06:01 +02:00
using t_real_value = typename std : : decay < t_value > : : type ;
static_assert ( std : : is_rvalue_reference < t_value & & > ( ) , " unexpected copy of value " ) ;
2014-03-04 00:07:58 +02:00
TRY_ENTRY ( ) ;
CHECK_AND_ASSERT ( hval_array , false ) ;
2019-11-04 03:06:01 +02:00
CHECK_AND_ASSERT_MES ( hval_array - > type ( ) = = typeid ( array_entry_t < t_real_value > ) ,
false , " unexpected type in insert_next_value: " < < typeid ( array_entry_t < t_real_value > ) . name ( ) ) ;
2014-03-04 00:07:58 +02:00
2019-11-04 03:06:01 +02:00
array_entry_t < t_real_value > & arr_typed = boost : : get < array_entry_t < t_real_value > > ( * hval_array ) ;
arr_typed . insert_next_value ( std : : forward < t_value > ( target ) ) ;
2014-03-04 00:07:58 +02:00
return true ;
CATCH_ENTRY ( " portable_storage::insert_next_value " , false ) ;
}
//---------------------------------------------------------------------------------------------------------------
//sections
inline
harray portable_storage : : get_first_section ( const std : : string & sec_name , hsection & h_child_section , hsection hparent_section )
{
TRY_ENTRY ( ) ;
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( sec_name , hparent_section ) ;
if ( ! pentry )
return nullptr ;
if ( pentry - > type ( ) ! = typeid ( array_entry ) )
return nullptr ;
array_entry & ar_entry = boost : : get < array_entry > ( * pentry ) ;
if ( ar_entry . type ( ) ! = typeid ( array_entry_t < section > ) )
return nullptr ;
array_entry_t < section > & sec_array = boost : : get < array_entry_t < section > > ( ar_entry ) ;
section * psec = sec_array . get_first_val ( ) ;
if ( ! psec )
return nullptr ;
h_child_section = psec ;
return & ar_entry ;
CATCH_ENTRY ( " portable_storage::get_first_section " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
bool portable_storage : : get_next_section ( harray hsec_array , hsection & h_child_section )
{
TRY_ENTRY ( ) ;
CHECK_AND_ASSERT ( hsec_array , false ) ;
if ( hsec_array - > type ( ) ! = typeid ( array_entry_t < section > ) )
2015-05-26 08:07:17 +03:00
return false ;
2014-03-04 00:07:58 +02:00
array_entry_t < section > & sec_array = boost : : get < array_entry_t < section > > ( * hsec_array ) ;
h_child_section = sec_array . get_next_val ( ) ;
if ( ! h_child_section )
return false ;
return true ;
CATCH_ENTRY ( " portable_storage::get_next_section " , false ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
harray portable_storage : : insert_first_section ( const std : : string & sec_name , hsection & hinserted_childsection , hsection hparent_section )
{
TRY_ENTRY ( ) ;
if ( ! hparent_section ) hparent_section = & m_root ;
storage_entry * pentry = find_storage_entry ( sec_name , hparent_section ) ;
if ( ! pentry )
{
pentry = insert_new_entry_get_storage_entry ( sec_name , hparent_section , array_entry ( array_entry_t < section > ( ) ) ) ;
if ( ! pentry )
return nullptr ;
}
if ( pentry - > type ( ) ! = typeid ( array_entry ) )
* pentry = storage_entry ( array_entry ( array_entry_t < section > ( ) ) ) ;
array_entry & ar_entry = boost : : get < array_entry > ( * pentry ) ;
if ( ar_entry . type ( ) ! = typeid ( array_entry_t < section > ) )
ar_entry = array_entry ( array_entry_t < section > ( ) ) ;
array_entry_t < section > & sec_array = boost : : get < array_entry_t < section > > ( ar_entry ) ;
hinserted_childsection = & sec_array . insert_first_val ( section ( ) ) ;
return & ar_entry ;
CATCH_ENTRY ( " portable_storage::insert_first_section " , nullptr ) ;
}
//---------------------------------------------------------------------------------------------------------------
inline
2014-05-25 20:06:40 +03:00
bool portable_storage : : insert_next_section ( harray hsec_array , hsection & hinserted_childsection )
2014-03-04 00:07:58 +02:00
{
TRY_ENTRY ( ) ;
CHECK_AND_ASSERT ( hsec_array , false ) ;
CHECK_AND_ASSERT_MES ( hsec_array - > type ( ) = = typeid ( array_entry_t < section > ) ,
false , " unexpected type(not 'section') in insert_next_section, type: " < < hsec_array - > type ( ) . name ( ) ) ;
array_entry_t < section > & sec_array = boost : : get < array_entry_t < section > > ( * hsec_array ) ;
hinserted_childsection = & sec_array . insert_next_value ( section ( ) ) ;
return true ;
CATCH_ENTRY ( " portable_storage::insert_next_section " , false ) ;
}
//---------------------------------------------------------------------------------------------------------------
}
2014-05-25 20:06:40 +03:00
}