FC Updates from BitShares and myself #21
33 changed files with 1774 additions and 1036 deletions
5
.gitmodules
vendored
5
.gitmodules
vendored
|
|
@ -6,4 +6,7 @@
|
|||
url = https://github.com/bitshares/secp256k1-zkp.git
|
||||
[submodule "vendor/websocketpp"]
|
||||
path = vendor/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
url = https://github.com/bitshares/websocketpp.git
|
||||
[submodule "vendor/editline"]
|
||||
path = vendor/editline
|
||||
url = https://github.com/troglobit/editline.git
|
||||
|
|
|
|||
|
|
@ -104,6 +104,54 @@ else ( MSVC )
|
|||
endif ( MSVC )
|
||||
# End configure secp256k1-zkp
|
||||
|
||||
# Configure editline
|
||||
if ( MSVC )
|
||||
# autoconf won't work here, hard code the defines
|
||||
set( EDITLINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline" )
|
||||
|
||||
file( GLOB EDITLINE_SOURCES "${EDITLINE_DIR}/src/editline.c" )
|
||||
add_library( editline ${EDITLINE_SOURCES} )
|
||||
|
||||
target_include_directories( editline PRIVATE "${EDITLINE_DIR}" PUBLIC "${EDITLINE_DIR}/include" )
|
||||
|
||||
set_target_properties( editline PROPERTIES COMPILE_DEFINITIONS LINKER_LANGUAGE C )
|
||||
else ( MSVC )
|
||||
include(ExternalProject)
|
||||
if ( MINGW )
|
||||
ExternalProject_Add( project_editline
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/editline --host=x86_64-w64-mingw32
|
||||
BUILD_COMMAND make
|
||||
INSTALL_COMMAND true
|
||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/.libs/libeditline.a
|
||||
)
|
||||
else ( MINGW )
|
||||
ExternalProject_Add( project_editline
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/editline
|
||||
BUILD_COMMAND make
|
||||
INSTALL_COMMAND true
|
||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/.libs/libeditline.a
|
||||
)
|
||||
endif ( MINGW )
|
||||
ExternalProject_Add_Step(project_editline autogen
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/autogen.sh
|
||||
DEPENDERS configure
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(project_editline binary_dir)
|
||||
|
||||
add_library(editline STATIC IMPORTED)
|
||||
set_property(TARGET editline PROPERTY IMPORTED_LOCATION ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set_property(TARGET editline PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/include)
|
||||
add_dependencies(editline project_editline)
|
||||
install( FILES ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
||||
endif ( MSVC )
|
||||
# End configure editline
|
||||
|
||||
IF( WIN32 )
|
||||
MESSAGE(STATUS "Configuring fc to build on Win32")
|
||||
|
||||
|
|
@ -253,27 +301,16 @@ add_subdirectory( vendor/websocketpp EXCLUDE_FROM_ALL )
|
|||
setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC )
|
||||
install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include )
|
||||
|
||||
# begin readline stuff
|
||||
find_package(Curses)
|
||||
find_package(Readline)
|
||||
|
||||
file(GLOB HEADERS "include/bts/cli/*.hpp")
|
||||
|
||||
if (READLINE_FOUND)
|
||||
target_compile_definitions (fc PRIVATE HAVE_READLINE)
|
||||
set(readline_libraries ${Readline_LIBRARY})
|
||||
if (CURSES_FOUND)
|
||||
list(APPEND readline_libraries ${CURSES_LIBRARY})
|
||||
endif()
|
||||
set(readline_includes ${Readline_INCLUDE_DIR})
|
||||
endif()
|
||||
# begin editline stuff
|
||||
target_compile_definitions (fc PRIVATE HAVE_EDITLINE)
|
||||
set(editline_libraries editline)
|
||||
if(WIN32)
|
||||
target_compile_definitions( fc PRIVATE _CRT_NONSTDC_NO_DEPRECATE )
|
||||
endif(WIN32)
|
||||
# end readline stuff
|
||||
# end editline stuff
|
||||
|
||||
if( NOT CPP_STANDARD )
|
||||
set( CPP_STANDARD, "-std=c++11" )
|
||||
set( CPP_STANDARD "-std=c++11" )
|
||||
endif()
|
||||
|
||||
IF(WIN32)
|
||||
|
|
@ -364,7 +401,6 @@ target_include_directories(fc
|
|||
${OPENSSL_INCLUDE_DIR}
|
||||
"vendor/diff-match-patch-cpp-stl"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/websocketpp
|
||||
"${readline_includes}"
|
||||
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/boost_1.51/include
|
||||
|
|
@ -375,7 +411,7 @@ target_include_directories(fc
|
|||
IF(NOT WIN32)
|
||||
set(LINK_USR_LOCAL_LIB -L/usr/local/lib)
|
||||
ENDIF()
|
||||
target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${readline_libraries} ${ECC_LIB} )
|
||||
target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${editline_libraries} ${ECC_LIB} )
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties( src/network/http/websocket.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
# - Try to find readline include dirs and libraries
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(Readline)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# Readline_ROOT_DIR Set this variable to the root installation of
|
||||
# readline if the module has problems finding the
|
||||
# proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# READLINE_FOUND System has readline, include and lib dirs found
|
||||
# Readline_INCLUDE_DIR The readline include directories.
|
||||
# Readline_LIBRARY The readline library.
|
||||
|
||||
find_path(Readline_ROOT_DIR
|
||||
NAMES include/readline/readline.h
|
||||
)
|
||||
|
||||
find_path(Readline_INCLUDE_DIR
|
||||
NAMES readline/readline.h
|
||||
HINTS ${Readline_ROOT_DIR}/include
|
||||
)
|
||||
|
||||
find_library(Readline_LIBRARY
|
||||
NAMES readline
|
||||
HINTS ${Readline_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
set(READLINE_FOUND TRUE)
|
||||
else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
FIND_LIBRARY(Readline_LIBRARY NAMES readline)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
|
||||
MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY)
|
||||
endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
|
||||
mark_as_advanced(
|
||||
Readline_ROOT_DIR
|
||||
Readline_INCLUDE_DIR
|
||||
Readline_LIBRARY
|
||||
)
|
||||
|
||||
MESSAGE( STATUS "Found Readline: ${Readline_LIBRARY}" )
|
||||
4
include/fc/config.hpp
Normal file
4
include/fc/config.hpp
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef FC_PACK_MAX_DEPTH
|
||||
// The maximum level of object nesting is around 20% of this value
|
||||
#define FC_PACK_MAX_DEPTH 1000
|
||||
#endif
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <fc/config.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
void pack( Stream& s, const std::deque<T>& value );
|
||||
void pack( Stream& s, const std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T>
|
||||
void unpack( Stream& s, std::deque<T>& value );
|
||||
void unpack( Stream& s, std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
}
|
||||
} // namespace fc
|
||||
|
|
|
|||
|
|
@ -8,61 +8,71 @@
|
|||
namespace fc {
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
inline void pack( Stream& s, const flat_set<T>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
inline void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
fc::raw::pack( s, *itr, _max_depth );
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename T>
|
||||
inline void unpack( Stream& s, flat_set<T>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
inline void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int size; unpack( s, size, _max_depth );
|
||||
value.clear();
|
||||
FC_ASSERT( size.value*sizeof(T) < MAX_ARRAY_ALLOC_SIZE );
|
||||
value.reserve(size.value);
|
||||
for( uint32_t i = 0; i < size.value; ++i )
|
||||
{
|
||||
T tmp;
|
||||
fc::raw::unpack( s, tmp );
|
||||
fc::raw::unpack( s, tmp, _max_depth );
|
||||
value.insert( std::move(tmp) );
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename K, typename... V>
|
||||
inline void pack( Stream& s, const flat_map<K,V...>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
inline void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
fc::raw::pack( s, *itr, _max_depth );
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename K, typename V, typename... A>
|
||||
inline void unpack( Stream& s, flat_map<K,V,A...>& value )
|
||||
inline void unpack( Stream& s, flat_map<K,V,A...>& value, uint32_t _max_depth )
|
||||
{
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int size; unpack( s, size, _max_depth );
|
||||
value.clear();
|
||||
FC_ASSERT( size.value*(sizeof(K)+sizeof(V)) < MAX_ARRAY_ALLOC_SIZE );
|
||||
value.reserve(size.value);
|
||||
for( uint32_t i = 0; i < size.value; ++i )
|
||||
{
|
||||
std::pair<K,V> tmp;
|
||||
fc::raw::unpack( s, tmp );
|
||||
fc::raw::unpack( s, tmp, _max_depth );
|
||||
value.insert( std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const bip::vector<T,A>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
void pack( Stream& s, const bip::vector<T,A>& value, uint32_t _max_depth ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
fc::raw::pack( s, *itr, _max_depth );
|
||||
++itr;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -71,13 +81,15 @@ namespace fc {
|
|||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, bip::vector<T,A>& value ) {
|
||||
void unpack( Stream& s, bip::vector<T,A>& value, uint32_t _max_depth ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
unpack( s, size, _max_depth );
|
||||
value.resize( size );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( auto& item : value )
|
||||
unpack( s, item );
|
||||
unpack( s, item, _max_depth );
|
||||
} else {
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
#pragma once
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/interprocess/containers/vector.hpp>
|
||||
#include <fc/config.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
|
|
@ -11,19 +12,19 @@ namespace fc {
|
|||
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
void pack( Stream& s, const flat_set<T>& value );
|
||||
void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T>
|
||||
void unpack( Stream& s, flat_set<T>& value );
|
||||
void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename K, typename... V>
|
||||
void pack( Stream& s, const flat_map<K,V...>& value );
|
||||
void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename K, typename V, typename... A>
|
||||
void unpack(Stream& s, flat_map<K, V, A...>& value);
|
||||
void unpack(Stream& s, flat_map<K, V, A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const bip::vector<T,A>& value );
|
||||
void pack( Stream& s, const bip::vector<T,A>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, bip::vector<T,A>& value );
|
||||
void unpack( Stream& s, bip::vector<T,A>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
} // namespace raw
|
||||
|
||||
} // fc
|
||||
|
|
|
|||
|
|
@ -260,31 +260,35 @@ namespace fc {
|
|||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::ecc::public_key& pk)
|
||||
void unpack( Stream& s, fc::ecc::public_key& pk, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
ecc::public_key_data ser;
|
||||
fc::raw::unpack(s,ser);
|
||||
fc::raw::unpack( s, ser, _max_depth - 1 );
|
||||
pk = fc::ecc::public_key( ser );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::ecc::public_key& pk)
|
||||
void pack( Stream& s, const fc::ecc::public_key& pk, uint32_t _max_depth )
|
||||
{
|
||||
fc::raw::pack( s, pk.serialize() );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::ecc::private_key& pk)
|
||||
void unpack( Stream& s, fc::ecc::private_key& pk, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::sha256 sec;
|
||||
unpack( s, sec );
|
||||
unpack( s, sec, _max_depth - 1 );
|
||||
pk = ecc::private_key::regenerate(sec);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::ecc::private_key& pk)
|
||||
void pack( Stream& s, const fc::ecc::private_key& pk, uint32_t _max_depth )
|
||||
{
|
||||
fc::raw::pack( s, pk.get_secret() );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, pk.get_secret(), _max_depth - 1 );
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
|
|
|||
|
|
@ -76,31 +76,35 @@ namespace fc {
|
|||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::public_key& pk)
|
||||
void unpack( Stream& s, fc::public_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
bytes ser;
|
||||
fc::raw::unpack(s,ser);
|
||||
fc::raw::unpack( s, ser, _max_depth - 1 );
|
||||
pk = fc::public_key( ser );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::public_key& pk)
|
||||
void pack( Stream& s, const fc::public_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
fc::raw::pack( s, pk.serialize() );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::private_key& pk)
|
||||
void unpack( Stream& s, fc::private_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
bytes ser;
|
||||
fc::raw::unpack(s,ser);
|
||||
fc::raw::unpack( s, ser, _max_depth - 1 );
|
||||
pk = fc::private_key( ser );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::private_key& pk)
|
||||
void pack( Stream& s, const fc::private_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
fc::raw::pack( s, pk.serialize() );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
|
||||
}
|
||||
}
|
||||
class variant;
|
||||
|
|
|
|||
|
|
@ -98,16 +98,18 @@ namespace fc {
|
|||
namespace raw
|
||||
{
|
||||
template<typename Stream, typename Storage>
|
||||
inline void pack( Stream& s, const fc::fixed_string<Storage>& u ) {
|
||||
inline void pack( Stream& s, const fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
unsigned_int size = u.size();
|
||||
pack( s, size );
|
||||
pack( s, size, _max_depth - 1 );
|
||||
s.write( (const char*)&u.data, size );
|
||||
}
|
||||
|
||||
template<typename Stream, typename Storage>
|
||||
inline void unpack( Stream& s, fc::fixed_string<Storage>& u ) {
|
||||
inline void unpack( Stream& s, fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
unsigned_int size;
|
||||
fc::raw::unpack( s, size );
|
||||
fc::raw::unpack( s, size, _max_depth - 1 );
|
||||
if( size.value > 0 ) {
|
||||
if( size.value > sizeof(Storage) ) {
|
||||
s.read( (char*)&u.data, sizeof(Storage) );
|
||||
|
|
@ -135,12 +137,12 @@ namespace fc {
|
|||
|
||||
/*
|
||||
template<typename Stream, typename... Args>
|
||||
inline void pack( Stream& s, const boost::multiprecision::number<Args...>& d ) {
|
||||
inline void pack( Stream& s, const boost::multiprecision::number<Args...>& d, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
s.write( (const char*)&d, sizeof(d) );
|
||||
}
|
||||
|
||||
template<typename Stream, typename... Args>
|
||||
inline void unpack( Stream& s, boost::multiprecision::number<Args...>& u ) {
|
||||
inline void unpack( Stream& s, boost::multiprecision::number<Args...>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
s.read( (const char*)&u, sizeof(u) );
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -122,22 +122,26 @@ namespace fc {
|
|||
namespace bip = boost::interprocess;
|
||||
|
||||
template<typename Stream, typename T, typename... A>
|
||||
inline void pack( Stream& s, const bip::vector<T,A...>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
++itr;
|
||||
}
|
||||
inline void pack( Stream& s, const bip::vector<T,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr, _max_depth );
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename T, typename... A>
|
||||
inline void unpack( Stream& s, bip::vector<T,A...>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
value.clear(); value.resize(size);
|
||||
for( auto& item : value )
|
||||
fc::raw::unpack( s, item );
|
||||
inline void unpack( Stream& s, bip::vector<T,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int size;
|
||||
unpack( s, size, _max_depth );
|
||||
value.clear(); value.resize(size);
|
||||
for( auto& item : value )
|
||||
fc::raw::unpack( s, item, _max_depth );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ namespace fc
|
|||
public:
|
||||
enum_type( EnumType t )
|
||||
:value(t){}
|
||||
|
||||
|
||||
enum_type( IntType t )
|
||||
:value( (EnumType)t ){}
|
||||
|
||||
|
||||
enum_type(){}
|
||||
|
||||
|
||||
explicit operator IntType()const { return static_cast<IntType>(value); }
|
||||
operator EnumType()const { return value; }
|
||||
operator std::string()const { return fc::reflector<EnumType>::to_string(value); }
|
||||
|
||||
|
||||
enum_type& operator=( IntType i ) { value = (EnumType)i; return *this;}
|
||||
enum_type& operator=( EnumType i ) { value = i; return *this;}
|
||||
bool operator<( EnumType i ) const { return value < i; }
|
||||
|
|
@ -60,19 +60,21 @@ namespace fc
|
|||
|
||||
|
||||
/** serializes like an IntType */
|
||||
namespace raw
|
||||
{
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp )
|
||||
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth )
|
||||
{
|
||||
fc::raw::pack( s, static_cast<IntType>(tp) );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, static_cast<IntType>(tp), _max_depth - 1 );
|
||||
}
|
||||
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp )
|
||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
IntType t;
|
||||
fc::raw::unpack( s, t );
|
||||
fc::raw::unpack( s, t, _max_depth - 1 );
|
||||
tp = t;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include <fc/variant.hpp>
|
||||
#include <fc/filesystem.hpp>
|
||||
|
||||
#define DEFAULT_MAX_RECURSION_DEPTH 200
|
||||
|
||||
namespace fc
|
||||
{
|
||||
class ostream;
|
||||
|
|
@ -18,62 +20,69 @@ namespace fc
|
|||
enum parse_type
|
||||
{
|
||||
legacy_parser = 0,
|
||||
#ifdef WITH_EXOTIC_JSON_PARSERS
|
||||
strict_parser = 1,
|
||||
relaxed_parser = 2,
|
||||
legacy_parser_with_string_doubles = 3
|
||||
legacy_parser_with_string_doubles = 3,
|
||||
#endif
|
||||
broken_nul_parser = 4
|
||||
};
|
||||
enum output_formatting
|
||||
{
|
||||
stringify_large_ints_and_doubles = 0,
|
||||
#ifdef WITH_EXOTIC_JSON_PARSERS
|
||||
legacy_generator = 1
|
||||
#endif
|
||||
};
|
||||
|
||||
static ostream& to_stream( ostream& out, const fc::string&);
|
||||
static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static ostream& to_stream( ostream& out, const fc::string& );
|
||||
static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
|
||||
static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser );
|
||||
static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
|
||||
static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser );
|
||||
static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser );
|
||||
static string to_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static string to_pretty_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static string to_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static string to_pretty_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
|
||||
static bool is_valid( const std::string& json_str, parse_type ptype = legacy_parser );
|
||||
static bool is_valid( const std::string& json_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
|
||||
template<typename T>
|
||||
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
|
||||
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
|
||||
{
|
||||
save_to_file( variant(v), fi, pretty, format );
|
||||
save_to_file( variant(v), fi, pretty, format, max_depth );
|
||||
}
|
||||
|
||||
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static variant from_file( const fc::path& p, parse_type ptype = legacy_parser );
|
||||
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
static variant from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
|
||||
|
||||
template<typename T>
|
||||
static T from_file( const fc::path& p, parse_type ptype = legacy_parser )
|
||||
static T from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
|
||||
{
|
||||
return json::from_file(p, ptype).as<T>();
|
||||
return json::from_file(p, ptype, max_depth).as<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
|
||||
static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
|
||||
{
|
||||
return to_string( variant(v), format );
|
||||
return to_string( variant(v), format, max_depth );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
|
||||
static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
|
||||
{
|
||||
return to_pretty_string( variant(v), format );
|
||||
return to_pretty_string( variant(v), format, max_depth );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
|
||||
static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
|
||||
{
|
||||
save_to_file( variant(v), fc::path(p), pretty );
|
||||
save_to_file( variant(v), fc::path(p), pretty, format, max_depth );
|
||||
}
|
||||
};
|
||||
|
||||
} // fc
|
||||
|
||||
#undef DEFAULT_MAX_RECURSION_DEPTH
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
namespace fc { namespace json_relaxed
|
||||
{
|
||||
template<typename T, bool strict>
|
||||
variant variant_from_stream( T& in );
|
||||
variant variant_from_stream( T& in, uint32_t max_depth );
|
||||
|
||||
template<typename T>
|
||||
fc::string tokenFromStream( T& in )
|
||||
|
|
@ -104,8 +104,15 @@ namespace fc { namespace json_relaxed
|
|||
if( in.peek() == q )
|
||||
{
|
||||
in.get();
|
||||
if( in.peek() != q )
|
||||
return fc::string();
|
||||
try
|
||||
{
|
||||
if( in.peek() != q )
|
||||
return fc::string();
|
||||
}
|
||||
catch( const fc::eof_exception& e )
|
||||
{
|
||||
return fc::string();
|
||||
}
|
||||
|
||||
// triple quote processing
|
||||
if( strict )
|
||||
|
|
@ -564,86 +571,18 @@ namespace fc { namespace json_relaxed
|
|||
} FC_CAPTURE_AND_RETHROW( (token) ) }
|
||||
|
||||
template<typename T, bool strict>
|
||||
variant_object objectFromStream( T& in )
|
||||
variant_object objectFromStream( T& in, uint32_t max_depth )
|
||||
{
|
||||
mutable_variant_object obj;
|
||||
try
|
||||
{
|
||||
char c = in.peek();
|
||||
if( c != '{' )
|
||||
FC_THROW_EXCEPTION( parse_error_exception,
|
||||
"Expected '{', but read '${char}'",
|
||||
("char",string(&c, &c + 1)) );
|
||||
in.get();
|
||||
skip_white_space(in);
|
||||
while( in.peek() != '}' )
|
||||
{
|
||||
if( in.peek() == ',' )
|
||||
{
|
||||
in.get();
|
||||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
string key = json_relaxed::stringFromStream<T, strict>( in );
|
||||
skip_white_space(in);
|
||||
if( in.peek() != ':' )
|
||||
{
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"",
|
||||
("key", key) );
|
||||
}
|
||||
in.get();
|
||||
auto val = json_relaxed::variant_from_stream<T, strict>( in );
|
||||
|
||||
obj(std::move(key),std::move(val));
|
||||
skip_white_space(in);
|
||||
}
|
||||
if( in.peek() == '}' )
|
||||
{
|
||||
in.get();
|
||||
return obj;
|
||||
}
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) );
|
||||
}
|
||||
catch( const fc::eof_exception& e )
|
||||
{
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) );
|
||||
}
|
||||
catch( const std::ios_base::failure& e )
|
||||
{
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) );
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" );
|
||||
std::function<std::string(T&)> get_key = []( T& in ){ return json_relaxed::stringFromStream<T, strict>( in ); };
|
||||
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, max_depth ); };
|
||||
return objectFromStreamBase<T>( in, get_key, get_value );
|
||||
}
|
||||
|
||||
template<typename T, bool strict>
|
||||
variants arrayFromStream( T& in )
|
||||
variants arrayFromStream( T& in, uint32_t max_depth )
|
||||
{
|
||||
variants ar;
|
||||
try
|
||||
{
|
||||
if( in.peek() != '[' )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
|
||||
in.get();
|
||||
skip_white_space(in);
|
||||
|
||||
while( in.peek() != ']' )
|
||||
{
|
||||
if( in.peek() == ',' )
|
||||
{
|
||||
in.get();
|
||||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
ar.push_back( json_relaxed::variant_from_stream<T, strict>(in) );
|
||||
skip_white_space(in);
|
||||
}
|
||||
if( in.peek() != ']' )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
|
||||
("variant", ar) );
|
||||
|
||||
in.get();
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}",
|
||||
("array", ar ) );
|
||||
return ar;
|
||||
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, max_depth ); };
|
||||
return arrayFromStreamBase<T>( in, get_value );
|
||||
}
|
||||
|
||||
template<typename T, bool strict>
|
||||
|
|
@ -688,60 +627,53 @@ namespace fc { namespace json_relaxed
|
|||
}
|
||||
|
||||
template<typename T, bool strict>
|
||||
variant variant_from_stream( T& in )
|
||||
variant variant_from_stream( T& in, uint32_t max_depth )
|
||||
{
|
||||
if( max_depth == 0 )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
|
||||
skip_white_space(in);
|
||||
variant var;
|
||||
while( signed char c = in.peek() )
|
||||
signed char c = in.peek();
|
||||
switch( c )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
in.get();
|
||||
continue;
|
||||
case '"':
|
||||
return json_relaxed::stringFromStream<T, strict>( in );
|
||||
case '{':
|
||||
return json_relaxed::objectFromStream<T, strict>( in );
|
||||
case '[':
|
||||
return json_relaxed::arrayFromStream<T, strict>( in );
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return json_relaxed::numberFromStream<T, strict>( in );
|
||||
// null, true, false, or 'warning' / string
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
|
||||
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
|
||||
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
|
||||
case 'y': case 'z':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
|
||||
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
|
||||
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
|
||||
case 'Y': case 'Z':
|
||||
case '_': case '/':
|
||||
return json_relaxed::wordFromStream<T, strict>( in );
|
||||
case 0x04: // ^D end of transmission
|
||||
case EOF:
|
||||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
|
||||
default:
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
|
||||
("c", c)("s", stringFromToken(in)) );
|
||||
}
|
||||
case '"':
|
||||
return json_relaxed::stringFromStream<T, strict>( in );
|
||||
case '{':
|
||||
return json_relaxed::objectFromStream<T, strict>( in, max_depth - 1 );
|
||||
case '[':
|
||||
return json_relaxed::arrayFromStream<T, strict>( in, max_depth - 1 );
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return json_relaxed::numberFromStream<T, strict>( in );
|
||||
// null, true, false, or 'warning' / string
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
|
||||
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
|
||||
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
|
||||
case 'y': case 'z':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
|
||||
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
|
||||
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
|
||||
case 'Y': case 'Z':
|
||||
case '_': case '/':
|
||||
return json_relaxed::wordFromStream<T, strict>( in );
|
||||
case 0x04: // ^D end of transmission
|
||||
case EOF:
|
||||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
|
||||
case 0:
|
||||
default:
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
|
||||
("c", c)("s", stringFromToken(in)) );
|
||||
}
|
||||
return variant();
|
||||
}
|
||||
|
||||
} } // fc::json_relaxed
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include <fc/config.hpp>
|
||||
#include <fc/container/flat_fwd.hpp>
|
||||
#include <fc/container/deque_fwd.hpp>
|
||||
#include <fc/io/varint.hpp>
|
||||
|
|
@ -11,9 +12,9 @@
|
|||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#define MAX_ARRAY_ALLOC_SIZE (1024*1024*10)
|
||||
#define MAX_ARRAY_ALLOC_SIZE (1024*1024*10)
|
||||
|
||||
namespace fc {
|
||||
namespace fc {
|
||||
class time_point;
|
||||
class time_point_sec;
|
||||
class variant;
|
||||
|
|
@ -31,94 +32,94 @@ namespace fc {
|
|||
template<typename T>
|
||||
inline size_t pack_size( const T& v );
|
||||
|
||||
template<typename Stream, typename Storage> inline void pack( Stream& s, const fc::fixed_string<Storage>& u );
|
||||
template<typename Stream, typename Storage> inline void unpack( Stream& s, fc::fixed_string<Storage>& u );
|
||||
template<typename Stream, typename Storage> inline void pack( Stream& s, const fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename Storage> inline void unpack( Stream& s, fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp );
|
||||
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp );
|
||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::unordered_set<T>& value );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::unordered_set<T>& value );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::unordered_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::unordered_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename... T> void pack( Stream& s, const static_variant<T...>& sv );
|
||||
template<typename Stream, typename... T> void unpack( Stream& s, static_variant<T...>& sv );
|
||||
template<typename Stream, typename... T> void pack( Stream& s, const static_variant<T...>& sv, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename... T> void unpack( Stream& s, static_variant<T...>& sv, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const flat_set<T>& value );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, flat_set<T>& value );
|
||||
//template<typename Stream, typename T> inline void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
//template<typename Stream, typename T> inline void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::deque<T>& value );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::deque<T>& value );
|
||||
//template<typename Stream, typename T> inline void pack( Stream& s, const std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
//template<typename Stream, typename T> inline void unpack( Stream& s, std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::unordered_map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::unordered_map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::unordered_map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::unordered_map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename K, typename... V> inline void pack( Stream& s, const flat_map<K,V...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... A> inline void unpack( Stream& s, flat_map<K,V,A...>& value );
|
||||
//template<typename Stream, typename K, typename... V> inline void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
//template<typename Stream, typename K, typename V, typename... A> inline void unpack( Stream& s, flat_map<K,V,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::pair<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::pair<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::pair<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::pair<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const variant_object& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, variant_object& v );
|
||||
template<typename Stream> inline void pack( Stream& s, const variant& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, variant& v );
|
||||
template<typename Stream> inline void pack( Stream& s, const variant_object& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, variant_object& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void pack( Stream& s, const variant& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, variant& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const path& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, path& v );
|
||||
template<typename Stream> inline void pack( Stream& s, const ip::endpoint& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, ip::endpoint& v );
|
||||
template<typename Stream> inline void pack( Stream& s, const path& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, path& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void pack( Stream& s, const ip::endpoint& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, ip::endpoint& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
|
||||
template<typename Stream, typename T> void unpack( Stream& s, fc::optional<T>& v );
|
||||
template<typename Stream, typename T> void unpack( Stream& s, const T& v );
|
||||
template<typename Stream, typename T> void pack( Stream& s, const fc::optional<T>& v );
|
||||
template<typename Stream, typename T> void pack( Stream& s, const safe<T>& v );
|
||||
template<typename Stream, typename T> void unpack( Stream& s, fc::safe<T>& v );
|
||||
template<typename Stream, typename T> void unpack( Stream& s, fc::optional<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> void unpack( Stream& s, const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> void pack( Stream& s, const fc::optional<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> void pack( Stream& s, const safe<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> void unpack( Stream& s, fc::safe<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> void unpack( Stream& s, time_point& );
|
||||
template<typename Stream> void pack( Stream& s, const time_point& );
|
||||
template<typename Stream> void unpack( Stream& s, time_point_sec& );
|
||||
template<typename Stream> void pack( Stream& s, const time_point_sec& );
|
||||
template<typename Stream> void unpack( Stream& s, std::string& );
|
||||
template<typename Stream> void pack( Stream& s, const std::string& );
|
||||
template<typename Stream> void unpack( Stream& s, fc::ecc::public_key& );
|
||||
template<typename Stream> void pack( Stream& s, const fc::ecc::public_key& );
|
||||
template<typename Stream> void unpack( Stream& s, fc::ecc::private_key& );
|
||||
template<typename Stream> void pack( Stream& s, const fc::ecc::private_key& );
|
||||
template<typename Stream> void unpack( Stream& s, time_point&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void pack( Stream& s, const time_point&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void unpack( Stream& s, time_point_sec&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void pack( Stream& s, const time_point_sec&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void unpack( Stream& s, std::string&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void pack( Stream& s, const std::string&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void unpack( Stream& s, fc::ecc::public_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void pack( Stream& s, const fc::ecc::public_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void unpack( Stream& s, fc::ecc::private_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> void pack( Stream& s, const fc::ecc::private_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const T& v );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, T& v );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::vector<T>& v );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::vector<T>& v );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::vector<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::vector<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const signed_int& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, signed_int& vi );
|
||||
template<typename Stream> inline void pack( Stream& s, const signed_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, signed_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const unsigned_int& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, unsigned_int& vi );
|
||||
template<typename Stream> inline void pack( Stream& s, const unsigned_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, unsigned_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const char* v );
|
||||
template<typename Stream> inline void pack( Stream& s, const std::vector<char>& value );
|
||||
template<typename Stream> inline void unpack( Stream& s, std::vector<char>& value );
|
||||
template<typename Stream> inline void pack( Stream& s, const char* v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void pack( Stream& s, const std::vector<char>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, std::vector<char>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename Stream, typename T, size_t N> inline void pack( Stream& s, const fc::array<T,N>& v);
|
||||
template<typename Stream, typename T, size_t N> inline void unpack( Stream& s, fc::array<T,N>& v);
|
||||
template<typename Stream, typename T, size_t N> inline void pack( Stream& s, const fc::array<T,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream, typename T, size_t N> inline void unpack( Stream& s, fc::array<T,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
|
||||
|
||||
template<typename Stream> inline void pack( Stream& s, const bool& v );
|
||||
template<typename Stream> inline void unpack( Stream& s, bool& v );
|
||||
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename Stream> inline void unpack( Stream& s, bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
|
||||
template<typename T> inline std::vector<char> pack( const T& v );
|
||||
template<typename T> inline T unpack( const std::vector<char>& s );
|
||||
template<typename T> inline T unpack( const char* d, uint32_t s );
|
||||
template<typename T> inline void unpack( const char* d, uint32_t s, T& v );
|
||||
template<typename T> inline std::vector<char> pack( const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename T> inline T unpack( const std::vector<char>& s, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename T> inline T unpack( const char* d, uint32_t s, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
template<typename T> inline void unpack( const char* d, uint32_t s, T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -10,53 +10,61 @@ namespace fc { namespace raw {
|
|||
class variant_packer : public variant::visitor
|
||||
{
|
||||
public:
|
||||
variant_packer( Stream& _s ):s(_s){}
|
||||
variant_packer( Stream& _s, uint32_t _max_depth ):s(_s),max_depth(_max_depth - 1)
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
}
|
||||
virtual void handle()const { }
|
||||
virtual void handle( const int64_t& v )const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const uint64_t& v )const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const double& v )const
|
||||
virtual void handle( const double& v )const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const bool& v )const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const string& v )const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const variant_object& v)const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
virtual void handle( const variants& v)const
|
||||
{
|
||||
fc::raw::pack( s, v );
|
||||
fc::raw::pack( s, v, max_depth );
|
||||
}
|
||||
|
||||
|
||||
Stream& s;
|
||||
|
||||
const uint32_t max_depth;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const variant& v )
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const variant& v, uint32_t _max_depth )
|
||||
{
|
||||
pack( s, uint8_t(v.get_type()) );
|
||||
v.visit( variant_packer<Stream>(s) );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
pack( s, uint8_t(v.get_type()), _max_depth );
|
||||
v.visit( variant_packer<Stream>( s, _max_depth ) );
|
||||
}
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, variant& v )
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, variant& v, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
uint8_t t;
|
||||
unpack( s, t );
|
||||
unpack( s, t, _max_depth );
|
||||
switch( t )
|
||||
{
|
||||
case variant::null_type:
|
||||
|
|
@ -64,49 +72,49 @@ namespace fc { namespace raw {
|
|||
case variant::int64_type:
|
||||
{
|
||||
int64_t val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = val;
|
||||
return;
|
||||
}
|
||||
case variant::uint64_type:
|
||||
{
|
||||
uint64_t val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = val;
|
||||
return;
|
||||
}
|
||||
case variant::double_type:
|
||||
{
|
||||
double val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = val;
|
||||
return;
|
||||
}
|
||||
case variant::bool_type:
|
||||
{
|
||||
bool val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = val;
|
||||
return;
|
||||
}
|
||||
case variant::string_type:
|
||||
{
|
||||
fc::string val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = fc::move(val);
|
||||
return;
|
||||
}
|
||||
case variant::array_type:
|
||||
{
|
||||
variants val;
|
||||
raw::unpack(s,val);
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = fc::move(val);
|
||||
return;
|
||||
}
|
||||
case variant::object_type:
|
||||
{
|
||||
variant_object val;
|
||||
raw::unpack(s,val);
|
||||
variant_object val;
|
||||
raw::unpack( s, val, _max_depth );
|
||||
v = fc::move(val);
|
||||
return;
|
||||
}
|
||||
|
|
@ -115,22 +123,26 @@ namespace fc { namespace raw {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const variant_object& v )
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const variant_object& v, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int vs = (uint32_t)v.size();
|
||||
pack( s, vs );
|
||||
pack( s, vs, _max_depth );
|
||||
for( auto itr = v.begin(); itr != v.end(); ++itr )
|
||||
{
|
||||
pack( s, itr->key() );
|
||||
pack( s, itr->value() );
|
||||
pack( s, itr->key(), _max_depth );
|
||||
pack( s, itr->value(), _max_depth );
|
||||
}
|
||||
}
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, variant_object& v )
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, variant_object& v, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
unsigned_int vs;
|
||||
unpack( s, vs );
|
||||
unpack( s, vs, _max_depth );
|
||||
|
||||
mutable_variant_object mvo;
|
||||
mvo.reserve(vs.value);
|
||||
|
|
@ -138,8 +150,8 @@ namespace fc { namespace raw {
|
|||
{
|
||||
fc::string key;
|
||||
fc::variant value;
|
||||
fc::raw::unpack(s,key);
|
||||
fc::raw::unpack(s,value);
|
||||
fc::raw::unpack( s, key, _max_depth );
|
||||
fc::raw::unpack( s, value, _max_depth );
|
||||
mvo.set( fc::move(key), fc::move(value) );
|
||||
}
|
||||
v = fc::move(mvo);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace fc {
|
|||
private:
|
||||
uint32_t _ip;
|
||||
};
|
||||
|
||||
|
||||
class endpoint {
|
||||
public:
|
||||
endpoint();
|
||||
|
|
@ -58,16 +58,16 @@ namespace fc {
|
|||
friend bool operator==( const endpoint& a, const endpoint& b );
|
||||
friend bool operator!=( const endpoint& a, const endpoint& b );
|
||||
friend bool operator< ( const endpoint& a, const endpoint& b );
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* The compiler pads endpoint to a full 8 bytes, so while
|
||||
* a port number is limited in range to 16 bits, we specify
|
||||
* a full 32 bits so that memcmp can be used with sizeof(),
|
||||
* otherwise 2 bytes will be 'random' and you do not know
|
||||
* a full 32 bits so that memcmp can be used with sizeof(),
|
||||
* otherwise 2 bytes will be 'random' and you do not know
|
||||
* where they are stored.
|
||||
*/
|
||||
uint32_t _port;
|
||||
uint32_t _port;
|
||||
address _ip;
|
||||
};
|
||||
|
||||
|
|
@ -80,41 +80,47 @@ namespace fc {
|
|||
void from_variant( const variant& var, ip::address& vo );
|
||||
|
||||
|
||||
namespace raw
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const ip::address& v )
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const ip::address& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
fc::raw::pack( s, uint32_t(v) );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
fc::raw::pack( s, uint32_t(v), _max_depth - 1 );
|
||||
}
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, ip::address& v )
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, ip::address& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
uint32_t _ip;
|
||||
fc::raw::unpack( s, _ip );
|
||||
fc::raw::unpack( s, _ip, _max_depth - 1 );
|
||||
v = ip::address(_ip);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const ip::endpoint& v )
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const ip::endpoint& v, uint32_t _max_depth )
|
||||
{
|
||||
fc::raw::pack( s, v.get_address() );
|
||||
fc::raw::pack( s, v.port() );
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
fc::raw::pack( s, v.get_address(), _max_depth );
|
||||
fc::raw::pack( s, v.port(), _max_depth );
|
||||
}
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, ip::endpoint& v )
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, ip::endpoint& v, uint32_t _max_depth )
|
||||
{
|
||||
FC_ASSERT( _max_depth > 0 );
|
||||
--_max_depth;
|
||||
ip::address a;
|
||||
uint16_t p;
|
||||
fc::raw::unpack( s, a );
|
||||
fc::raw::unpack( s, p );
|
||||
fc::raw::unpack( s, a, _max_depth );
|
||||
fc::raw::unpack( s, p, _max_depth );
|
||||
v = ip::endpoint(a,p);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace fc
|
||||
FC_REFLECT_TYPENAME( fc::ip::address )
|
||||
FC_REFLECT_TYPENAME( fc::ip::endpoint )
|
||||
FC_REFLECT_TYPENAME( fc::ip::address )
|
||||
FC_REFLECT_TYPENAME( fc::ip::endpoint )
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <fc/uint128.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
#define FC_REAL128_PRECISION (uint64_t(1000000) * uint64_t(1000000) * uint64_t(1000000))
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ namespace fc {
|
|||
real128& operator -= ( const real128& o );
|
||||
real128& operator /= ( const real128& o );
|
||||
real128& operator *= ( const real128& o );
|
||||
|
||||
|
||||
static real128 from_fixed( const uint128& fixed );
|
||||
|
||||
uint64_t to_uint64()const;
|
||||
|
|
@ -39,12 +39,15 @@ namespace fc {
|
|||
void to_variant( const real128& var, variant& vo );
|
||||
void from_variant( const variant& var, real128& vo );
|
||||
|
||||
namespace raw
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const real128& value_to_pack ) { s.write( (char*)&value_to_pack, sizeof(value_to_pack) ); }
|
||||
inline void pack( Stream& s, const real128& value_to_pack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{ s.write( (char*)&value_to_pack, sizeof(value_to_pack) ); }
|
||||
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, real128& value_to_unpack ) { s.read( (char*)&value_to_unpack, sizeof(value_to_unpack) ); }
|
||||
inline void unpack( Stream& s, real128& value_to_unpack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
||||
{ s.read( (char*)&value_to_unpack, sizeof(value_to_unpack) ); }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace fc {
|
|||
template<typename T>
|
||||
T& smart_ref<T>::operator = ( smart_ref<T>&& u ) {
|
||||
if( &u == this ) return *impl;
|
||||
if( impl ) delete impl;
|
||||
delete impl;
|
||||
impl = u.impl;
|
||||
u.impl = nullptr;
|
||||
return *impl;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include <fc/config.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/crypto/city.hpp>
|
||||
|
||||
|
|
@ -126,9 +127,9 @@ namespace fc
|
|||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const uint128& u ) { s.write( (char*)&u, sizeof(u) ); }
|
||||
inline void pack( Stream& s, const uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.write( (char*)&u, sizeof(u) ); }
|
||||
template<typename Stream>
|
||||
inline void unpack( Stream& s, uint128& u ) { s.read( (char*)&u, sizeof(u) ); }
|
||||
inline void unpack( Stream& s, uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.read( (char*)&u, sizeof(u) ); }
|
||||
}
|
||||
|
||||
size_t city_hash_size_t(const char *buf, size_t len);
|
||||
|
|
|
|||
|
|
@ -162,7 +162,14 @@ namespace fc
|
|||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); )
|
||||
{
|
||||
ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n";
|
||||
ss << " " << json::to_string( itr->get_data() )<<"\n";
|
||||
try
|
||||
{
|
||||
ss << " " << json::to_string( itr->get_data() )<<"\n";
|
||||
}
|
||||
catch( const fc::assert_exception& e )
|
||||
{
|
||||
ss << "ERROR: Failed to convert log data to string!\n";
|
||||
}
|
||||
ss << " " << itr->get_context().to_string();
|
||||
++itr;
|
||||
if( itr != my->_elog.end() ) ss<<"\n";
|
||||
|
|
@ -256,10 +263,16 @@ namespace fc
|
|||
("source_lineno", lineno)
|
||||
("expr", expr)
|
||||
;
|
||||
std::cout
|
||||
<< "FC_ASSERT triggered: "
|
||||
<< fc::json::to_string( assert_trip_info ) << "\n";
|
||||
return;
|
||||
try
|
||||
{
|
||||
std::cout
|
||||
<< "FC_ASSERT triggered: "
|
||||
<< fc::json::to_string( assert_trip_info ) << "\n";
|
||||
}
|
||||
catch( const fc::assert_exception& e )
|
||||
{ // this should never happen. assert_trip_info is flat.
|
||||
std::cout << "ERROR: Failed to convert info to string?!\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool enable_record_assert_trip = false;
|
||||
|
|
|
|||
354
src/io/json.cpp
354
src/io/json.cpp
|
|
@ -5,7 +5,7 @@
|
|||
#include <fc/io/fstream.hpp>
|
||||
#include <fc/io/sstream.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
//#include <utfcpp/utf8.h>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
|
@ -15,22 +15,30 @@
|
|||
namespace fc
|
||||
{
|
||||
// forward declarations of provided functions
|
||||
template<typename T, json::parse_type parser_type> variant variant_from_stream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variant variant_from_stream( T& in, uint32_t max_depth );
|
||||
template<typename T> char parseEscape( T& in );
|
||||
template<typename T> fc::string stringFromStream( T& in );
|
||||
template<typename T> bool skip_white_space( T& in );
|
||||
template<typename T> fc::string stringFromToken( T& in );
|
||||
template<typename T, json::parse_type parser_type> variant_object objectFromStream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variants arrayFromStream( T& in );
|
||||
template<typename T> variant_object objectFromStreamBase( T& in, std::function<std::string(T&)>& get_key, std::function<variant(T&)>& get_value );
|
||||
template<typename T, json::parse_type parser_type> variant_object objectFromStream( T& in, uint32_t max_depth );
|
||||
template<typename T> variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value );
|
||||
template<typename T, json::parse_type parser_type> variants arrayFromStream( T& in, uint32_t max_depth );
|
||||
template<typename T, json::parse_type parser_type> variant number_from_stream( T& in );
|
||||
template<typename T> variant token_from_stream( T& in );
|
||||
void escape_string( const string& str, ostream& os );
|
||||
template<typename T> void to_stream( T& os, const variants& a, json::output_formatting format );
|
||||
template<typename T> void to_stream( T& os, const variant_object& o, json::output_formatting format );
|
||||
template<typename T> void to_stream( T& os, const variant& v, json::output_formatting format );
|
||||
template<typename T> void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth );
|
||||
template<typename T> void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth );
|
||||
template<typename T> void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth );
|
||||
fc::string pretty_print( const fc::string& v, uint8_t indent );
|
||||
}
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
#define FALLTHROUGH [[fallthrough]];
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#include <fc/io/json_relaxed.hpp>
|
||||
|
||||
namespace fc
|
||||
|
|
@ -167,8 +175,8 @@ namespace fc
|
|||
("token", token.str() ) );
|
||||
}
|
||||
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant_object objectFromStream( T& in )
|
||||
template<typename T>
|
||||
variant_object objectFromStreamBase( T& in, std::function<std::string(T&)>& get_key, std::function<variant(T&)>& get_value )
|
||||
{
|
||||
mutable_variant_object obj;
|
||||
try
|
||||
|
|
@ -179,7 +187,6 @@ namespace fc
|
|||
"Expected '{', but read '${char}'",
|
||||
("char",string(&c, &c + 1)) );
|
||||
in.get();
|
||||
skip_white_space(in);
|
||||
while( in.peek() != '}' )
|
||||
{
|
||||
if( in.peek() == ',' )
|
||||
|
|
@ -188,7 +195,7 @@ namespace fc
|
|||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
string key = stringFromStream( in );
|
||||
string key = get_key( in );
|
||||
skip_white_space(in);
|
||||
if( in.peek() != ':' )
|
||||
{
|
||||
|
|
@ -196,10 +203,9 @@ namespace fc
|
|||
("key", key) );
|
||||
}
|
||||
in.get();
|
||||
auto val = variant_from_stream<T, parser_type>( in );
|
||||
auto val = get_value( in );
|
||||
|
||||
obj(std::move(key),std::move(val));
|
||||
skip_white_space(in);
|
||||
}
|
||||
if( in.peek() == '}' )
|
||||
{
|
||||
|
|
@ -219,7 +225,15 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variants arrayFromStream( T& in )
|
||||
variant_object objectFromStream( T& in, uint32_t max_depth )
|
||||
{
|
||||
std::function<std::string(T&)> get_key = []( T& in ){ return stringFromStream( in ); };
|
||||
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return variant_from_stream<T, parser_type>( in, max_depth ); };
|
||||
return objectFromStreamBase<T>( in, get_key, get_value );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value )
|
||||
{
|
||||
variants ar;
|
||||
try
|
||||
|
|
@ -227,7 +241,6 @@ namespace fc
|
|||
if( in.peek() != '[' )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
|
||||
in.get();
|
||||
skip_white_space(in);
|
||||
|
||||
while( in.peek() != ']' )
|
||||
{
|
||||
|
|
@ -237,8 +250,7 @@ namespace fc
|
|||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
ar.push_back( variant_from_stream<T, parser_type>(in) );
|
||||
skip_white_space(in);
|
||||
ar.push_back( get_value(in) );
|
||||
}
|
||||
if( in.peek() != ']' )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
|
||||
|
|
@ -250,6 +262,13 @@ namespace fc
|
|||
return ar;
|
||||
}
|
||||
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variants arrayFromStream( T& in, uint32_t max_depth )
|
||||
{
|
||||
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return variant_from_stream<T, parser_type>( in, max_depth ); };
|
||||
return arrayFromStreamBase<T>( in, get_value );
|
||||
}
|
||||
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant number_from_stream( T& in )
|
||||
{
|
||||
|
|
@ -276,6 +295,7 @@ namespace fc
|
|||
if (dot)
|
||||
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse a number with two decimal places");
|
||||
dot = true;
|
||||
FALLTHROUGH
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
|
|
@ -299,16 +319,20 @@ namespace fc
|
|||
}
|
||||
}
|
||||
catch (fc::eof_exception&)
|
||||
{
|
||||
{ // EOF ends the loop
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
{ // read error ends the loop
|
||||
}
|
||||
fc::string str = ss.str();
|
||||
if (str == "-." || str == ".") // check the obviously wrong things we could have encountered
|
||||
if (str == "-." || str == "." || str == "-") // check the obviously wrong things we could have encountered
|
||||
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse token \"${token}\" as a JSON numeric constant", ("token", str));
|
||||
if( dot )
|
||||
return parser_type == json::legacy_parser_with_string_doubles ? variant(str) : variant(to_double(str));
|
||||
return
|
||||
#ifdef WITH_EXOTIC_JSON_PARSERS
|
||||
parser_type == json::legacy_parser_with_string_doubles ? variant(str) :
|
||||
#endif
|
||||
variant(to_double(str));
|
||||
if( neg )
|
||||
return to_int64(str);
|
||||
return to_uint64(str);
|
||||
|
|
@ -379,132 +403,77 @@ namespace fc
|
|||
// make out ("falfe")
|
||||
// A strict JSON parser would signal this as an error, but we
|
||||
// will just treat the malformed token as an un-quoted string.
|
||||
return str + stringFromToken(in);;
|
||||
return str + stringFromToken(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant variant_from_stream( T& in )
|
||||
variant variant_from_stream( T& in, uint32_t max_depth )
|
||||
{
|
||||
if( max_depth == 0 )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
|
||||
skip_white_space(in);
|
||||
variant var;
|
||||
while( signed char c = in.peek() )
|
||||
signed char c = in.peek();
|
||||
switch( c )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
in.get();
|
||||
continue;
|
||||
case '"':
|
||||
return stringFromStream( in );
|
||||
case '{':
|
||||
return objectFromStream<T, parser_type>( in );
|
||||
case '[':
|
||||
return arrayFromStream<T, parser_type>( in );
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return number_from_stream<T, parser_type>( in );
|
||||
// null, true, false, or 'warning' / string
|
||||
case 'n':
|
||||
case 't':
|
||||
case 'f':
|
||||
return token_from_stream( in );
|
||||
case 0x04: // ^D end of transmission
|
||||
case EOF:
|
||||
case 0:
|
||||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
|
||||
default:
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
|
||||
("c", c)("s", stringFromToken(in)) );
|
||||
}
|
||||
case '"':
|
||||
return stringFromStream( in );
|
||||
case '{':
|
||||
return objectFromStream<T, parser_type>( in, max_depth - 1 );
|
||||
case '[':
|
||||
return arrayFromStream<T, parser_type>( in, max_depth - 1 );
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return number_from_stream<T, parser_type>( in );
|
||||
// null, true, false, or 'warning' / string
|
||||
case 'n':
|
||||
case 't':
|
||||
case 'f':
|
||||
return token_from_stream( in );
|
||||
case 0x04: // ^D end of transmission
|
||||
case EOF:
|
||||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
|
||||
case 0:
|
||||
if( parser_type == fc::json::broken_nul_parser )
|
||||
return variant();
|
||||
FALLTHROUGH
|
||||
default:
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
|
||||
("c", c)("s", stringFromToken(in)) );
|
||||
}
|
||||
return variant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** the purpose of this check is to verify that we will not get a stack overflow in the recursive descent parser */
|
||||
void check_string_depth( const string& utf8_str )
|
||||
{
|
||||
int32_t open_object = 0;
|
||||
int32_t open_array = 0;
|
||||
for( auto c : utf8_str )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case '{': open_object++; break;
|
||||
case '}': open_object--; break;
|
||||
case '[': open_array++; break;
|
||||
case ']': open_array--; break;
|
||||
default: break;
|
||||
}
|
||||
FC_ASSERT( open_object < 100 && open_array < 100, "object graph too deep", ("object depth",open_object)("array depth", open_array) );
|
||||
}
|
||||
}
|
||||
|
||||
variant json::from_string( const std::string& utf8_str, parse_type ptype )
|
||||
variant json::from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
|
||||
{ try {
|
||||
check_string_depth( utf8_str );
|
||||
|
||||
fc::stringstream in( utf8_str );
|
||||
//in.exceptions( std::ifstream::eofbit );
|
||||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream<fc::stringstream, legacy_parser>( in );
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<fc::stringstream, true>( in );
|
||||
case relaxed_parser:
|
||||
return json_relaxed::variant_from_stream<fc::stringstream, false>( in );
|
||||
default:
|
||||
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
|
||||
}
|
||||
fc::istream_ptr in( new fc::stringstream( utf8_str ) );
|
||||
fc::buffered_istream bin( in );
|
||||
return from_stream( bin, ptype, max_depth );
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) }
|
||||
|
||||
variants json::variants_from_string( const std::string& utf8_str, parse_type ptype )
|
||||
{ try {
|
||||
check_string_depth( utf8_str );
|
||||
variants json::variants_from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
|
||||
{
|
||||
variants result;
|
||||
fc::stringstream in( utf8_str );
|
||||
//in.exceptions( std::ifstream::eofbit );
|
||||
try {
|
||||
fc::stringstream in( utf8_str );
|
||||
while( true )
|
||||
{
|
||||
// result.push_back( variant_from_stream( in ));
|
||||
result.push_back(json_relaxed::variant_from_stream<fc::stringstream, false>( in ));
|
||||
}
|
||||
} catch ( const fc::eof_exception& ){}
|
||||
return result;
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) }
|
||||
/*
|
||||
void toUTF8( const char str, ostream& os )
|
||||
{
|
||||
// validate str == valid utf8
|
||||
utf8::replace_invalid( &str, &str + 1, ostream_iterator<char>(os) );
|
||||
result.push_back(json_relaxed::variant_from_stream<fc::stringstream, false>( in, max_depth ));
|
||||
} catch ( const fc::eof_exception& ) {
|
||||
return result;
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) )
|
||||
}
|
||||
|
||||
void toUTF8( const wchar_t c, ostream& os )
|
||||
{
|
||||
utf8::utf16to8( &c, (&c)+1, ostream_iterator<char>(os) );
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert '\t', '\a', '\n', '\\' and '"' to "\t\a\n\\\""
|
||||
*
|
||||
|
|
@ -574,7 +543,6 @@ namespace fc
|
|||
|
||||
default:
|
||||
os << *itr;
|
||||
//toUTF8( *itr, os );
|
||||
}
|
||||
}
|
||||
os << '"';
|
||||
|
|
@ -586,14 +554,14 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variants& a, json::output_formatting format )
|
||||
void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
os << '[';
|
||||
auto itr = a.begin();
|
||||
|
||||
while( itr != a.end() )
|
||||
{
|
||||
to_stream( os, *itr, format );
|
||||
to_stream( os, *itr, format, max_depth );
|
||||
++itr;
|
||||
if( itr != a.end() )
|
||||
os << ',';
|
||||
|
|
@ -601,7 +569,7 @@ namespace fc
|
|||
os << ']';
|
||||
}
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variant_object& o, json::output_formatting format )
|
||||
void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
os << '{';
|
||||
auto itr = o.begin();
|
||||
|
|
@ -610,7 +578,7 @@ namespace fc
|
|||
{
|
||||
escape_string( itr->key(), os );
|
||||
os << ':';
|
||||
to_stream( os, itr->value(), format );
|
||||
to_stream( os, itr->value(), format, max_depth );
|
||||
++itr;
|
||||
if( itr != o.end() )
|
||||
os << ',';
|
||||
|
|
@ -619,35 +587,28 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variant& v, json::output_formatting format )
|
||||
void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
FC_ASSERT( max_depth > 0, "Too many nested objects!" );
|
||||
switch( v.get_type() )
|
||||
{
|
||||
case variant::null_type:
|
||||
os << "null";
|
||||
return;
|
||||
case variant::int64_type:
|
||||
{
|
||||
int64_t i = v.as_int64();
|
||||
if( format == json::stringify_large_ints_and_doubles &&
|
||||
i > 0xffffffff )
|
||||
( v.as_int64() > INT32_MAX || v.as_int64() < INT32_MIN ) )
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
else
|
||||
os << i;
|
||||
|
||||
os << v.as_int64();
|
||||
return;
|
||||
}
|
||||
case variant::uint64_type:
|
||||
{
|
||||
uint64_t i = v.as_uint64();
|
||||
if( format == json::stringify_large_ints_and_doubles &&
|
||||
i > 0xffffffff )
|
||||
v.as_uint64() > 0xffffffff )
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
else
|
||||
os << i;
|
||||
|
||||
os << v.as_uint64();
|
||||
return;
|
||||
}
|
||||
case variant::double_type:
|
||||
if (format == json::stringify_large_ints_and_doubles)
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
|
|
@ -664,24 +625,20 @@ namespace fc
|
|||
escape_string( v.as_string(), os );
|
||||
return;
|
||||
case variant::array_type:
|
||||
{
|
||||
const variants& a = v.get_array();
|
||||
to_stream( os, a, format );
|
||||
to_stream( os, v.get_array(), format, max_depth - 1 );
|
||||
return;
|
||||
}
|
||||
case variant::object_type:
|
||||
{
|
||||
const variant_object& o = v.get_object();
|
||||
to_stream(os, o, format );
|
||||
to_stream(os, v.get_object(), format, max_depth - 1 );
|
||||
return;
|
||||
}
|
||||
default:
|
||||
FC_THROW_EXCEPTION( fc::invalid_arg_exception, "Unsupported variant type: " + v.get_type() );
|
||||
}
|
||||
}
|
||||
|
||||
fc::string json::to_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
fc::string json::to_string( const variant& v, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
fc::stringstream ss;
|
||||
fc::to_stream( ss, v, format );
|
||||
fc::to_stream( ss, v, format, max_depth );
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +718,7 @@ namespace fc
|
|||
//If we're in quotes and see a \n, just print it literally but unset the escape flag.
|
||||
if( quote && escape )
|
||||
escape = false;
|
||||
//No break; fall through to default case
|
||||
FALLTHROUGH
|
||||
default:
|
||||
if( first ) {
|
||||
ss<<'\n';
|
||||
|
|
@ -776,100 +733,75 @@ namespace fc
|
|||
|
||||
|
||||
|
||||
fc::string json::to_pretty_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
fc::string json::to_pretty_string( const variant& v, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
return pretty_print(to_string(v, format), 2);
|
||||
return pretty_print(to_string(v, format, max_depth), 2);
|
||||
}
|
||||
|
||||
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
if( pretty )
|
||||
{
|
||||
auto str = json::to_pretty_string( v, format );
|
||||
auto str = json::to_pretty_string( v, format, max_depth );
|
||||
fc::ofstream o(fi);
|
||||
o.write( str.c_str(), str.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
fc::ofstream o(fi);
|
||||
fc::to_stream( o, v, format );
|
||||
fc::to_stream( o, v, format, max_depth );
|
||||
}
|
||||
}
|
||||
variant json::from_file( const fc::path& p, parse_type ptype )
|
||||
variant json::from_file( const fc::path& p, parse_type ptype, uint32_t max_depth )
|
||||
{
|
||||
//auto tmp = std::make_shared<fc::ifstream>( p, ifstream::binary );
|
||||
//auto tmp = std::make_shared<std::ifstream>( p.generic_string().c_str(), std::ios::binary );
|
||||
//buffered_istream bi( tmp );
|
||||
boost::filesystem::ifstream bi( p, std::ios::binary );
|
||||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream<boost::filesystem::ifstream, legacy_parser>( bi );
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<boost::filesystem::ifstream, legacy_parser_with_string_doubles>( bi );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<boost::filesystem::ifstream, true>( bi );
|
||||
case relaxed_parser:
|
||||
return json_relaxed::variant_from_stream<boost::filesystem::ifstream, false>( bi );
|
||||
default:
|
||||
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
|
||||
}
|
||||
fc::istream_ptr in( new fc::ifstream( p ) );
|
||||
fc::buffered_istream bin( in );
|
||||
return from_stream( bin, ptype, max_depth );
|
||||
}
|
||||
variant json::from_stream( buffered_istream& in, parse_type ptype )
|
||||
variant json::from_stream( buffered_istream& in, parse_type ptype, uint32_t max_depth )
|
||||
{
|
||||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser>( in );
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser>( in, max_depth );
|
||||
#ifdef WITH_EXOTIC_JSON_PARSERS
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser_with_string_doubles>( in );
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser_with_string_doubles>( in, max_depth );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<buffered_istream, true>( in );
|
||||
return json_relaxed::variant_from_stream<buffered_istream, true>( in, max_depth );
|
||||
case relaxed_parser:
|
||||
return json_relaxed::variant_from_stream<buffered_istream, false>( in );
|
||||
return json_relaxed::variant_from_stream<buffered_istream, false>( in, max_depth );
|
||||
#endif
|
||||
case broken_nul_parser:
|
||||
return variant_from_stream<fc::buffered_istream, broken_nul_parser>( in, max_depth );
|
||||
default:
|
||||
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
|
||||
}
|
||||
}
|
||||
|
||||
ostream& json::to_stream( ostream& out, const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
ostream& json::to_stream( ostream& out, const variant& v, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
fc::to_stream( out, v, format );
|
||||
fc::to_stream( out, v, format, max_depth );
|
||||
return out;
|
||||
}
|
||||
ostream& json::to_stream( ostream& out, const variants& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
ostream& json::to_stream( ostream& out, const variants& v, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
fc::to_stream( out, v, format );
|
||||
fc::to_stream( out, v, format, max_depth );
|
||||
return out;
|
||||
}
|
||||
ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format, uint32_t max_depth )
|
||||
{
|
||||
fc::to_stream( out, v, format );
|
||||
fc::to_stream( out, v, format, max_depth );
|
||||
return out;
|
||||
}
|
||||
|
||||
bool json::is_valid( const std::string& utf8_str, parse_type ptype )
|
||||
bool json::is_valid( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
|
||||
{
|
||||
if( utf8_str.size() == 0 ) return false;
|
||||
fc::stringstream in( utf8_str );
|
||||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
variant_from_stream<fc::stringstream, legacy_parser>( in );
|
||||
break;
|
||||
case legacy_parser_with_string_doubles:
|
||||
variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
|
||||
break;
|
||||
case strict_parser:
|
||||
json_relaxed::variant_from_stream<fc::stringstream, true>( in );
|
||||
break;
|
||||
case relaxed_parser:
|
||||
json_relaxed::variant_from_stream<fc::stringstream, false>( in );
|
||||
break;
|
||||
default:
|
||||
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
|
||||
}
|
||||
try { in.peek(); } catch ( const eof_exception& e ) { return true; }
|
||||
fc::istream_ptr in( new fc::stringstream( utf8_str ) );
|
||||
fc::buffered_istream bin( in );
|
||||
from_stream( bin, ptype, max_depth );
|
||||
try { bin.peek(); } catch ( const eof_exception& e ) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,8 +128,15 @@ namespace fc
|
|||
if (!context.get_task_name().empty())
|
||||
gelf_message["_task_name"] = context.get_task_name();
|
||||
|
||||
string gelf_message_as_string = json::to_string(gelf_message);
|
||||
//unsigned uncompressed_size = gelf_message_as_string.size();
|
||||
string gelf_message_as_string;
|
||||
try
|
||||
{
|
||||
gelf_message_as_string = json::to_string(gelf_message);
|
||||
}
|
||||
catch( const fc::assert_exception& e )
|
||||
{
|
||||
gelf_message_as_string = "{\"level\":3,\"short_message\":\"ERROR while generating log message\"}";
|
||||
}
|
||||
gelf_message_as_string = zlib_compress(gelf_message_as_string);
|
||||
|
||||
// graylog2 expects the zlib header to be 0x78 0x9c
|
||||
|
|
|
|||
138
src/rpc/cli.cpp
138
src/rpc/cli.cpp
|
|
@ -7,22 +7,8 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
// I don't know exactly what version of readline we need. I know the 4.2 version that ships on some macs is
|
||||
// missing some functions we require. We're developing against 6.3, but probably anything in the 6.x
|
||||
// series is fine
|
||||
# if RL_VERSION_MAJOR < 6
|
||||
# ifdef _MSC_VER
|
||||
# pragma message("You have an old version of readline installed that might not support some of the features we need")
|
||||
# pragma message("Readline support will not be compiled in")
|
||||
# else
|
||||
# warning "You have an old version of readline installed that might not support some of the features we need"
|
||||
# warning "Readline support will not be compiled in"
|
||||
# endif
|
||||
# undef HAVE_READLINE
|
||||
# endif
|
||||
#ifdef HAVE_EDITLINE
|
||||
# include "editline.h"
|
||||
# ifdef WIN32
|
||||
# include <io.h>
|
||||
# endif
|
||||
|
|
@ -125,62 +111,90 @@ void cli::run()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
char * dupstr (const char* s) {
|
||||
char *r;
|
||||
|
||||
r = (char*) malloc ((strlen (s) + 1));
|
||||
strcpy (r, s);
|
||||
return (r);
|
||||
}
|
||||
|
||||
char* my_generator(const char* text, int state)
|
||||
/****
|
||||
* @brief loop through list of commands, attempting to find a match
|
||||
* @param token what the user typed
|
||||
* @param match sets to 1 if only 1 match was found
|
||||
* @returns the remaining letters of the name of the command or NULL if 1 match not found
|
||||
*/
|
||||
static char *my_rl_complete(char *token, int *match)
|
||||
{
|
||||
static size_t list_index, len;
|
||||
const char *name;
|
||||
|
||||
if (!state) {
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
bool have_one = false;
|
||||
std::string method_name;
|
||||
|
||||
auto& cmd = cli_commands();
|
||||
const size_t partlen = strlen (token); /* Part of token */
|
||||
|
||||
while( list_index < cmd.size() )
|
||||
for (const std::string& it : cmd)
|
||||
{
|
||||
name = cmd[list_index].c_str();
|
||||
list_index++;
|
||||
|
||||
if (strncmp (name, text, len) == 0)
|
||||
return (dupstr(name));
|
||||
if (it.compare(0, partlen, token) == 0)
|
||||
{
|
||||
if (have_one) {
|
||||
// we can only have 1, but we found a second
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
method_name = it;
|
||||
have_one = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
if (have_one)
|
||||
{
|
||||
*match = 1;
|
||||
method_name += " ";
|
||||
return strdup (method_name.c_str() + partlen);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
static char** cli_completion( const char * text , int start, int end)
|
||||
/***
|
||||
* @brief return an array of matching commands
|
||||
* @param token the incoming text
|
||||
* @param array the resultant array of possible matches
|
||||
* @returns the number of matches
|
||||
*/
|
||||
static int cli_completion(char *token, char ***array)
|
||||
{
|
||||
char **matches;
|
||||
matches = (char **)NULL;
|
||||
auto& cmd = cli_commands();
|
||||
int num_commands = cmd.size();
|
||||
|
||||
if (start == 0)
|
||||
matches = rl_completion_matches ((char*)text, &my_generator);
|
||||
else
|
||||
rl_bind_key('\t',rl_abort);
|
||||
char **copy = (char **) malloc (num_commands * sizeof(char *));
|
||||
if (copy == NULL)
|
||||
{
|
||||
// possible out of memory
|
||||
return 0;
|
||||
}
|
||||
int total_matches = 0;
|
||||
|
||||
return (matches);
|
||||
const size_t partlen = strlen(token);
|
||||
|
||||
for (const std::string& it : cmd)
|
||||
{
|
||||
if ( it.compare(0, partlen, token) == 0)
|
||||
{
|
||||
copy[total_matches] = strdup ( it.c_str() );
|
||||
++total_matches;
|
||||
}
|
||||
}
|
||||
*array = copy;
|
||||
|
||||
return total_matches;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/***
|
||||
* @brief Read input from the user
|
||||
* @param prompt the prompt to display
|
||||
* @param line what the user typed
|
||||
*/
|
||||
void cli::getline( const fc::string& prompt, fc::string& line)
|
||||
{
|
||||
// getting file descriptor for C++ streams is near impossible
|
||||
// so we just assume it's the same as the C stream...
|
||||
#ifdef HAVE_READLINE
|
||||
#ifdef HAVE_EDITLINE
|
||||
#ifndef WIN32
|
||||
if( isatty( fileno( stdin ) ) )
|
||||
#else
|
||||
|
|
@ -192,7 +206,8 @@ void cli::getline( const fc::string& prompt, fc::string& line)
|
|||
if( _isatty( _fileno( stdin ) ) )
|
||||
#endif
|
||||
{
|
||||
rl_attempted_completion_function = cli_completion;
|
||||
rl_set_complete_func(my_rl_complete);
|
||||
rl_set_list_possib_func(cli_completion);
|
||||
|
||||
static fc::thread getline_thread("getline");
|
||||
getline_thread.async( [&](){
|
||||
|
|
@ -201,10 +216,17 @@ void cli::getline( const fc::string& prompt, fc::string& line)
|
|||
line_read = readline(prompt.c_str());
|
||||
if( line_read == nullptr )
|
||||
FC_THROW_EXCEPTION( fc::eof_exception, "" );
|
||||
rl_bind_key( '\t', rl_complete );
|
||||
if( *line_read )
|
||||
add_history(line_read);
|
||||
line = line_read;
|
||||
try
|
||||
{
|
||||
if (*line_read)
|
||||
add_history(line_read);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free(line_read);
|
||||
throw;
|
||||
}
|
||||
free(line_read);
|
||||
}).wait();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include <fc/utility.hpp>
|
||||
#include <fc/fwd_impl.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
#include <fc/io/sstream.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
|
@ -256,6 +258,60 @@ namespace fc {
|
|||
}
|
||||
}
|
||||
|
||||
string format_string( const string& format, const variant_object& args )
|
||||
{
|
||||
stringstream ss;
|
||||
size_t prev = 0;
|
||||
auto next = format.find( '$' );
|
||||
while( prev < format.size() )
|
||||
{
|
||||
ss << format.substr( prev, next == string::npos ? string::npos : next - prev );
|
||||
|
||||
// if we got to the end, return it.
|
||||
if( next == size_t(string::npos) || next == format.size() )
|
||||
return ss.str();
|
||||
|
||||
// if we are not at the end, then update the start
|
||||
prev = next + 1;
|
||||
|
||||
if( format[prev] == '{' )
|
||||
{
|
||||
// if the next char is a open, then find close
|
||||
next = format.find( '}', prev );
|
||||
// if we found close...
|
||||
if( next != string::npos )
|
||||
{
|
||||
// the key is between prev and next
|
||||
string key = format.substr( prev+1, (next-prev-1) );
|
||||
|
||||
auto val = args.find( key );
|
||||
if( val != args.end() )
|
||||
{
|
||||
if( val->value().is_object() || val->value().is_array() )
|
||||
{
|
||||
try
|
||||
{
|
||||
ss << json::to_string( val->value() );
|
||||
}
|
||||
catch( const fc::assert_exception& e )
|
||||
{
|
||||
ss << "[\"ERROR_WHILE_CONVERTING_VALUE_TO_STRING\"]";
|
||||
}
|
||||
}
|
||||
else
|
||||
ss << val->value().as_string();
|
||||
}
|
||||
else
|
||||
ss << "${"<<key<<"}";
|
||||
prev = next + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
ss << format[next];
|
||||
next = format.find( '$', prev );
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
|
|
|||
|
|
@ -669,66 +669,6 @@ void from_variant( const variant& var, std::vector<char>& vo )
|
|||
// vo = std::vector<char>( b64.c_str(), b64.c_str() + b64.size() );
|
||||
}
|
||||
|
||||
string format_string( const string& format, const variant_object& args )
|
||||
{
|
||||
stringstream ss;
|
||||
size_t prev = 0;
|
||||
auto next = format.find( '$' );
|
||||
while( prev != size_t(string::npos) && prev < size_t(format.size()) )
|
||||
{
|
||||
ss << format.substr( prev, size_t(next-prev) );
|
||||
|
||||
// if we got to the end, return it.
|
||||
if( next == size_t(string::npos) )
|
||||
return ss.str();
|
||||
|
||||
// if we are not at the end, then update the start
|
||||
prev = next + 1;
|
||||
|
||||
if( format[prev] == '{' )
|
||||
{
|
||||
// if the next char is a open, then find close
|
||||
next = format.find( '}', prev );
|
||||
// if we found close...
|
||||
if( next != size_t(string::npos) )
|
||||
{
|
||||
// the key is between prev and next
|
||||
string key = format.substr( prev+1, (next-prev-1) );
|
||||
|
||||
auto val = args.find( key );
|
||||
if( val != args.end() )
|
||||
{
|
||||
if( val->value().is_object() || val->value().is_array() )
|
||||
{
|
||||
ss << json::to_string( val->value() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << val->value().as_string();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "${"<<key<<"}";
|
||||
}
|
||||
prev = next + 1;
|
||||
// find the next $
|
||||
next = format.find( '$', prev );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we didn't find it.. continue to while...
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << format[prev];
|
||||
++prev;
|
||||
next = format.find( '$', prev );
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
#elif !defined(_MSC_VER)
|
||||
void to_variant( long long int s, variant& v ) { v = variant( int64_t(s) ); }
|
||||
|
|
|
|||
|
|
@ -49,11 +49,14 @@ add_executable( all_tests all_tests.cpp
|
|||
crypto/dh_test.cpp
|
||||
crypto/rand_test.cpp
|
||||
crypto/sha_tests.cpp
|
||||
io/json_tests.cpp
|
||||
io/stream_tests.cpp
|
||||
network/http/websocket_test.cpp
|
||||
thread/task_cancel.cpp
|
||||
thread/thread_tests.cpp
|
||||
bloom_test.cpp
|
||||
real128_test.cpp
|
||||
serialization_test.cpp
|
||||
time_test.cpp
|
||||
utf8_test.cpp
|
||||
)
|
||||
|
|
|
|||
376
tests/io/json_tests.cpp
Normal file
376
tests/io/json_tests.cpp
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/variant_object.hpp>
|
||||
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/io/buffered_iostream.hpp>
|
||||
#include <fc/io/fstream.hpp>
|
||||
#include <fc/io/iostream.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
#include <fc/io/sstream.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(json_tests)
|
||||
|
||||
static void replace_some( std::string& str )
|
||||
{
|
||||
for( size_t i = 0; i < str.length(); i++ )
|
||||
if( str[i] == '\1' ) str[i] = '\0';
|
||||
else if( str[i] == '\'' ) str[i] = '"';
|
||||
}
|
||||
|
||||
static void test_fail_string( const std::string& str )
|
||||
{
|
||||
try {
|
||||
fc::json::from_string( str );
|
||||
BOOST_FAIL( "json::from_string('" + str + "') failed" );
|
||||
} catch( const fc::parse_error_exception& ) { // ignore, ok
|
||||
} catch( const fc::eof_exception& ) { // ignore, ok
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_string failed")(str) )
|
||||
}
|
||||
|
||||
static void test_fail_stream( const std::string& str )
|
||||
{
|
||||
fc::temp_file file( fc::temp_directory_path(), true );
|
||||
{
|
||||
std::fstream init( file.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( str.c_str(), str.length() );
|
||||
init.close();
|
||||
}
|
||||
try {
|
||||
fc::istream_ptr in( new fc::ifstream( file.path() ) );
|
||||
fc::buffered_istream bin( in );
|
||||
fc::json::from_stream( bin );
|
||||
BOOST_FAIL( "json::from_stream('" + str + "') failed using ifstream" );
|
||||
} catch( const fc::parse_error_exception& ) { // ignore, ok
|
||||
} catch( const fc::eof_exception& ) { // ignore, ok
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_stream failed using ifstream")(str) )
|
||||
try {
|
||||
fc::istream_ptr in( new fc::stringstream( str ) );
|
||||
fc::buffered_istream bin( in );
|
||||
fc::json::from_stream( bin );
|
||||
BOOST_FAIL( "json::from_stream('" + str + "') failed using stringstream" );
|
||||
} catch( const fc::parse_error_exception& ) { // ignore, ok
|
||||
} catch( const fc::eof_exception& ) { // ignore, ok
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_stream failed using stringstream")(str) )
|
||||
}
|
||||
|
||||
static void test_fail_file( const std::string& str )
|
||||
{
|
||||
fc::temp_file file( fc::temp_directory_path(), true );
|
||||
{
|
||||
std::fstream init( file.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( str.c_str(), str.length() );
|
||||
init.close();
|
||||
}
|
||||
try {
|
||||
fc::json::from_file( file.path() );
|
||||
BOOST_FAIL( "json::from_file('" + str + "') failed using" );
|
||||
} catch( const fc::parse_error_exception& ) { // ignore, ok
|
||||
} catch( const fc::eof_exception& ) { // ignore, ok
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_file failed")(str) )
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(imbalanced_test)
|
||||
{
|
||||
std::string open40("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[");
|
||||
std::string close40("]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
|
||||
std::string open80 = open40 + open40;
|
||||
std::string close80 = close40 + close40;
|
||||
std::vector<std::string> tests
|
||||
{ // for easier handling and better readability, in the following test
|
||||
// strings ' is used instead of " and \1 instead of \0
|
||||
"",
|
||||
"{",
|
||||
"{'",
|
||||
"{'}",
|
||||
"{'a'",
|
||||
"{'a':",
|
||||
"{'a':5",
|
||||
"[",
|
||||
"['",
|
||||
"[']",
|
||||
"[ 13",
|
||||
"' end",
|
||||
"{ 13: }",
|
||||
"\1",
|
||||
"{\1",
|
||||
"{\1}",
|
||||
"{'\1",
|
||||
"{'\1}",
|
||||
"{'a'\1",
|
||||
"{'a'\1}",
|
||||
"{'a': \1",
|
||||
"{'a': \1}",
|
||||
"[\1",
|
||||
"[\1]",
|
||||
"['\1",
|
||||
"['\1]",
|
||||
"[ 13\1",
|
||||
"[ 13\1]",
|
||||
"' end\1",
|
||||
open80 + "'" + close80 + close80 + "'," + open80 + open80
|
||||
+ close80 + close80 + close80
|
||||
};
|
||||
|
||||
for( std::string test : tests )
|
||||
{
|
||||
replace_some( test );
|
||||
test_fail_string( test );
|
||||
test_fail_stream( test );
|
||||
test_fail_file( test );
|
||||
}
|
||||
}
|
||||
|
||||
static bool equal( const fc::variant& a, const fc::variant& b )
|
||||
{
|
||||
auto a_type = a.get_type();
|
||||
auto b_type = b.get_type();
|
||||
if( a_type == fc::variant::type_id::int64_type && a.as<int64_t>() > 0 )
|
||||
a_type = fc::variant::type_id::uint64_type;
|
||||
if( b_type == fc::variant::type_id::int64_type && b.as<int64_t>() > 0 )
|
||||
b_type = fc::variant::type_id::uint64_type;
|
||||
if( a_type != b_type )
|
||||
{
|
||||
if( ( a_type == fc::variant::type_id::double_type
|
||||
&& b_type == fc::variant::type_id::string_type )
|
||||
|| ( a_type == fc::variant::type_id::string_type
|
||||
&& b_type == fc::variant::type_id::double_type ) )
|
||||
return a.as<double>() == b.as<double>();
|
||||
return false;
|
||||
}
|
||||
switch( a_type )
|
||||
{
|
||||
case fc::variant::type_id::null_type: return true;
|
||||
case fc::variant::type_id::int64_type: return a.as<int64_t>() == b.as<int64_t>();
|
||||
case fc::variant::type_id::uint64_type: return a.as<uint64_t>() == b.as<uint64_t>();
|
||||
case fc::variant::type_id::double_type: return a.as<double>() == b.as<double>();
|
||||
case fc::variant::type_id::bool_type: return a.as<bool>() == b.as<bool>();
|
||||
case fc::variant::type_id::string_type: return a.as<std::string>() == b.as<std::string>();
|
||||
case fc::variant::type_id::array_type:
|
||||
if( a.get_array().size() != b.get_array().size() ) return false;
|
||||
else
|
||||
{
|
||||
std::vector<fc::variant>::const_iterator b_it = b.get_array().begin();
|
||||
for( const auto& a_it : a.get_array() )
|
||||
{
|
||||
if( !equal( a_it, *b_it ) ) return false;
|
||||
b_it++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case fc::variant::type_id::object_type:
|
||||
if( a.get_object().size() != b.get_object().size() ) return false;
|
||||
for( const auto& a_it : a.get_object() )
|
||||
{
|
||||
const auto& b_obj = b.get_object().find( a_it.key() );
|
||||
if( b_obj == b.get_object().end() || !equal( a_it.value(), b_obj->value() ) ) return false;
|
||||
}
|
||||
return true;
|
||||
case fc::variant::type_id::blob_type:
|
||||
default:
|
||||
FC_THROW_EXCEPTION( fc::invalid_arg_exception, "Unsupported variant type: " + a.get_type() );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_recursive( const fc::variant& v )
|
||||
{ try {
|
||||
const std::string json = fc::json::to_string( v );
|
||||
BOOST_CHECK( fc::json::is_valid( json ) );
|
||||
BOOST_CHECK( !fc::json::is_valid( json + " " ) );
|
||||
|
||||
const std::string pretty = fc::json::to_pretty_string( v );
|
||||
BOOST_CHECK( fc::json::is_valid( pretty ) );
|
||||
BOOST_CHECK( !fc::json::is_valid( pretty + " " ) );
|
||||
|
||||
fc::temp_file file( fc::temp_directory_path(), true );
|
||||
fc::json::save_to_file( v, file.path(), false );
|
||||
|
||||
fc::variants list = fc::json::variants_from_string( json );
|
||||
BOOST_CHECK_EQUAL( 1, list.size() );
|
||||
BOOST_CHECK( equal( v, list[0] ) );
|
||||
|
||||
list = fc::json::variants_from_string( pretty );
|
||||
BOOST_CHECK_EQUAL( 1, list.size() );
|
||||
BOOST_CHECK( equal( v, list[0] ) );
|
||||
|
||||
BOOST_CHECK( equal( v, fc::json::from_string( json + " " ) ) );
|
||||
BOOST_CHECK( equal( v, fc::json::from_string( pretty + " " ) ) );
|
||||
BOOST_CHECK( equal( v, fc::json::from_file( file.path() ) ) );
|
||||
|
||||
if( v.get_type() == fc::variant::type_id::array_type )
|
||||
for( const auto& item : v.get_array() )
|
||||
test_recursive( item );
|
||||
else if( v.get_type() == fc::variant::type_id::object_type )
|
||||
for( const auto& item : v.get_object() )
|
||||
test_recursive( item.value() );
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( (v) ) }
|
||||
|
||||
BOOST_AUTO_TEST_CASE(structured_test)
|
||||
{
|
||||
fc::variant_object v_empty_obj;
|
||||
fc::variants v_empty_array;
|
||||
fc::variant v_null;
|
||||
fc::variant v_true( true );
|
||||
fc::variant v_false( false );
|
||||
fc::variant v_empty_str( "" );
|
||||
fc::variant v_str( "false" );
|
||||
fc::variant v_int8_1( (int8_t) 1 );
|
||||
fc::variant v_int8_2( (int8_t) -2 );
|
||||
fc::variant v_uint8_1( (int8_t) 1 );
|
||||
fc::variant v_int16_1( (int16_t) 1 );
|
||||
fc::variant v_int16_2( (int16_t) -2 );
|
||||
fc::variant v_uint16_1( (int16_t) 1 );
|
||||
fc::variant v_int32_1( (int32_t) 1 );
|
||||
fc::variant v_int32_2( (int32_t) -2 );
|
||||
fc::variant v_uint32_1( (int32_t) 1 );
|
||||
fc::variant v_int64_1( (int8_t) 1 );
|
||||
fc::variant v_int64_2( (int8_t) -2 );
|
||||
fc::variant v_uint64_1( (int8_t) 1 );
|
||||
fc::variant v_float_1( 0.0f );
|
||||
fc::variant v_float_2( -2.0f );
|
||||
fc::variant v_double_1( 0.0d );
|
||||
fc::variant v_double_2( -2.0d );
|
||||
fc::variants v_small_array
|
||||
{
|
||||
v_empty_obj,
|
||||
v_empty_array,
|
||||
v_null,
|
||||
v_true,
|
||||
v_false,
|
||||
v_empty_str
|
||||
};
|
||||
fc::mutable_variant_object v_small_obj;
|
||||
v_small_obj( "", v_empty_str )
|
||||
( "1", v_empty_array )
|
||||
( "2", v_null )
|
||||
( "a", v_true )
|
||||
( "b", v_false )
|
||||
( "x", v_small_array )
|
||||
( "y", v_empty_obj );
|
||||
fc::variants v_big_array
|
||||
{
|
||||
v_empty_obj,
|
||||
v_empty_array,
|
||||
v_null,
|
||||
v_true,
|
||||
v_false,
|
||||
v_empty_str,
|
||||
v_str,
|
||||
v_int8_1,
|
||||
v_int8_2,
|
||||
v_uint8_1,
|
||||
v_int16_1,
|
||||
v_int16_2,
|
||||
v_uint16_1,
|
||||
v_int32_1,
|
||||
v_int32_2,
|
||||
v_uint32_1,
|
||||
v_int64_1,
|
||||
v_int64_2,
|
||||
v_uint64_1,
|
||||
v_float_1,
|
||||
v_float_2,
|
||||
v_double_1,
|
||||
v_double_2,
|
||||
v_small_array,
|
||||
v_small_obj
|
||||
};
|
||||
fc::mutable_variant_object v_big_obj;
|
||||
v_big_obj( "v_empty_obj", v_empty_obj )
|
||||
( "v_empty_array", v_empty_array )
|
||||
( "v_null", v_null )
|
||||
( "v_true", v_true )
|
||||
( "v_false", v_false )
|
||||
( "v_empty_str", v_empty_str )
|
||||
( "v_str", v_str )
|
||||
( "v_int8_1", v_int8_1 )
|
||||
( "v_int8_2", v_int8_2 )
|
||||
( "v_uint8_1", v_uint8_1 )
|
||||
( "v_int16_1", v_int16_1 )
|
||||
( "v_int16_2", v_int16_2 )
|
||||
( "v_uint16_1", v_uint16_1 )
|
||||
( "v_int32_1", v_int32_1 )
|
||||
( "v_int32_2", v_int32_2 )
|
||||
( "v_uint32_1", v_uint32_1 )
|
||||
( "v_int64_1", v_int64_1 )
|
||||
( "v_int64_2", v_int64_2 )
|
||||
( "v_uint64_1", v_uint64_1 )
|
||||
( "v_float_1", v_float_1 )
|
||||
( "v_float_2", v_float_2 )
|
||||
( "v_double_1", v_double_1 )
|
||||
( "v_double_2", v_double_2 )
|
||||
( "v_small_array", v_small_array )
|
||||
( "v_small_obj", v_small_obj );
|
||||
v_big_array.push_back( v_big_obj );
|
||||
|
||||
test_recursive( v_big_array );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(precision_test)
|
||||
{
|
||||
BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( 0x100000000LL ) ) );
|
||||
BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( -0x100000000LL ) ) );
|
||||
std::string half = fc::json::to_string( fc::variant( 0.5 ) );
|
||||
BOOST_CHECK_EQUAL( '"', half.front() );
|
||||
BOOST_CHECK_EQUAL( '"', half.back() );
|
||||
half = half.substr( 1, half.length() - 2 );
|
||||
while( '0' == half.back() ) half.erase( half.length() - 1, 1 );
|
||||
BOOST_CHECK_EQUAL( "0.5", half );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recursion_test)
|
||||
{
|
||||
std::string ten_levels = "[[[[[[[[[[]]]]]]]]]]";
|
||||
fc::variant nested = fc::json::from_string( ten_levels );
|
||||
BOOST_CHECK_THROW( fc::json::from_string( ten_levels, fc::json::legacy_parser, 9 ), fc::parse_error_exception );
|
||||
|
||||
std::string back = fc::json::to_string( nested );
|
||||
BOOST_CHECK_EQUAL( ten_levels, back );
|
||||
BOOST_CHECK_THROW( fc::json::to_string( nested, fc::json::stringify_large_ints_and_doubles, 9 ), fc::assert_exception );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(rethrow_test)
|
||||
{
|
||||
fc::variants biggie;
|
||||
for( int i = 0; i < 250; i++ )
|
||||
{
|
||||
fc::variant tmp( std::move(biggie) );
|
||||
biggie.reserve(1);
|
||||
biggie.push_back( std::move(tmp) );
|
||||
}
|
||||
|
||||
auto test_r = [&biggie](){
|
||||
try {
|
||||
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "Argh! ${biggie}", ("biggie",biggie) ) };
|
||||
BOOST_CHECK_THROW( test_r(), fc::unknown_host_exception );
|
||||
|
||||
auto test_lr = [&biggie](){
|
||||
try {
|
||||
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
|
||||
} FC_LOG_AND_RETHROW() };
|
||||
BOOST_CHECK_THROW( test_lr(), fc::unknown_host_exception );
|
||||
|
||||
auto test_clr = [&biggie](){
|
||||
try {
|
||||
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
|
||||
} FC_CAPTURE_LOG_AND_RETHROW( (biggie) ) };
|
||||
BOOST_CHECK_THROW( test_clr(), fc::unknown_host_exception );
|
||||
|
||||
auto test_cl = [&biggie](){
|
||||
try {
|
||||
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
|
||||
} FC_CAPTURE_AND_LOG( (biggie) ) };
|
||||
test_cl();
|
||||
|
||||
auto test_cr = [&biggie](){
|
||||
try {
|
||||
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
|
||||
} FC_CAPTURE_AND_RETHROW( (biggie) ) };
|
||||
BOOST_CHECK_THROW( test_cr(), fc::unknown_host_exception );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
178
tests/io/stream_tests.cpp
Normal file
178
tests/io/stream_tests.cpp
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/io/buffered_iostream.hpp>
|
||||
#include <fc/io/fstream.hpp>
|
||||
#include <fc/io/sstream.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(stream_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stringstream_test)
|
||||
{
|
||||
const fc::string constant( "Hello", 6 ); // includes trailing \0
|
||||
fc::string writable( "World" );
|
||||
fc::stringstream in1( constant );
|
||||
fc::stringstream in2( writable );
|
||||
fc::stringstream out;
|
||||
|
||||
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
|
||||
*buf = 'w';
|
||||
in2.writesome( buf, 1, 0 );
|
||||
|
||||
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 3, out.writesome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 'l', in1.peek() );
|
||||
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 4, 0 ) );
|
||||
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
|
||||
BOOST_CHECK_EQUAL( 2, out.writesome( buf, 2, 0 ) );
|
||||
*buf = ' ';
|
||||
out.writesome( buf, 1, 0 );
|
||||
BOOST_CHECK_THROW( in1.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
BOOST_CHECK_EQUAL( 5, in2.readsome( buf, 6, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 5, out.writesome( buf, 5, 0 ) );
|
||||
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
|
||||
BOOST_CHECK_EQUAL( "Hello world", out.str() );
|
||||
BOOST_CHECK_THROW( in1.peek(), fc::eof_exception );
|
||||
BOOST_CHECK( in1.eof() );
|
||||
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
// BOOST_CHECK( in2.eof() ); // fails, apparently readsome doesn't set eof
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(buffered_stringstream_test)
|
||||
{
|
||||
const fc::string constant( "Hello", 6 ); // includes trailing \0
|
||||
fc::string writable( "World" );
|
||||
fc::istream_ptr in1( new fc::stringstream( constant ) );
|
||||
std::shared_ptr<fc::stringstream> in2( new fc::stringstream( writable ) );
|
||||
std::shared_ptr<fc::stringstream> out1( new fc::stringstream() );
|
||||
fc::buffered_istream bin1( in1 );
|
||||
fc::buffered_istream bin2( in2 );
|
||||
fc::buffered_ostream bout( out1 );
|
||||
|
||||
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
|
||||
*buf = 'w';
|
||||
in2->writesome( buf, 1, 0 );
|
||||
|
||||
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 3, bout.writesome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 'l', bin1.peek() );
|
||||
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 4, 0 ) );
|
||||
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
|
||||
BOOST_CHECK_EQUAL( 2, bout.writesome( buf, 2, 0 ) );
|
||||
*buf = ' ';
|
||||
bout.writesome( buf, 1, 0 );
|
||||
BOOST_CHECK_THROW( bin1.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
BOOST_CHECK_EQUAL( 5, bin2.readsome( buf, 6, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 5, bout.writesome( buf, 5, 0 ) );
|
||||
BOOST_CHECK_THROW( bin2.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
|
||||
bout.flush();
|
||||
|
||||
BOOST_CHECK_EQUAL( "Hello world", out1->str() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fstream_test)
|
||||
{
|
||||
fc::temp_file inf1( fc::temp_directory_path(), true );
|
||||
fc::temp_file inf2( fc::temp_directory_path(), true );
|
||||
fc::temp_file outf( fc::temp_directory_path(), true );
|
||||
|
||||
{
|
||||
std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( "Hello", 6 ); // includes trailing \0
|
||||
init.close();
|
||||
|
||||
init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( "world", 5 );
|
||||
init.close();
|
||||
|
||||
init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.close();
|
||||
}
|
||||
|
||||
fc::ifstream in1( inf1.path() );
|
||||
fc::ifstream in2( inf2.path() );
|
||||
fc::ofstream out( outf.path() );
|
||||
|
||||
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
|
||||
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 3, out.writesome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 4, 0 ) );
|
||||
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
|
||||
BOOST_CHECK_EQUAL( 2, out.writesome( buf, 2, 0 ) );
|
||||
*buf = ' ';
|
||||
out.writesome( buf, 1, 0 );
|
||||
BOOST_CHECK_THROW( in1.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
BOOST_CHECK_EQUAL( 5, in2.readsome( buf, 6, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 5, out.writesome( buf, 5, 0 ) );
|
||||
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
|
||||
{
|
||||
out.flush();
|
||||
std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in );
|
||||
BOOST_CHECK_EQUAL( 11, test.readsome( (&(*buf)), 11 ) );
|
||||
BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) );
|
||||
BOOST_CHECK_EQUAL( 0, test.readsome( (&(*buf)), 11 ) );
|
||||
test.close();
|
||||
}
|
||||
|
||||
BOOST_CHECK( in1.eof() );
|
||||
BOOST_CHECK( in2.eof() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(buffered_fstream_test)
|
||||
{
|
||||
fc::temp_file inf1( fc::temp_directory_path(), true );
|
||||
fc::temp_file inf2( fc::temp_directory_path(), true );
|
||||
fc::temp_file outf( fc::temp_directory_path(), true );
|
||||
|
||||
{
|
||||
std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( "Hello", 6 ); // includes trailing \0
|
||||
init.close();
|
||||
|
||||
init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.write( "world", 5 );
|
||||
init.close();
|
||||
|
||||
init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
|
||||
init.close();
|
||||
}
|
||||
|
||||
fc::istream_ptr in1( new fc::ifstream( inf1.path() ) );
|
||||
fc::istream_ptr in2( new fc::ifstream( inf2.path() ) );
|
||||
fc::ostream_ptr out( new fc::ofstream( outf.path() ) );
|
||||
fc::buffered_istream bin1( in1 );
|
||||
fc::buffered_istream bin2( in2 );
|
||||
fc::buffered_ostream bout( out );
|
||||
|
||||
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
|
||||
|
||||
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 3, bout.writesome( buf, 3, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 'l', bin1.peek() );
|
||||
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 4, 0 ) );
|
||||
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
|
||||
BOOST_CHECK_EQUAL( 2, bout.writesome( buf, 2, 0 ) );
|
||||
*buf = ' ';
|
||||
bout.writesome( buf, 1, 0 );
|
||||
BOOST_CHECK_THROW( bin1.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
BOOST_CHECK_EQUAL( 5, bin2.readsome( buf, 6, 0 ) );
|
||||
BOOST_CHECK_EQUAL( 5, bout.writesome( buf, 5, 0 ) );
|
||||
BOOST_CHECK_THROW( bin2.readsome( buf, 3, 0 ), fc::eof_exception );
|
||||
|
||||
{
|
||||
bout.flush();
|
||||
std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in );
|
||||
BOOST_CHECK_EQUAL( 11, test.readsome( (&(*buf)), 11 ) );
|
||||
BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) );
|
||||
BOOST_CHECK_EQUAL( 0, test.readsome( (&(*buf)), 11 ) );
|
||||
test.close();
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
108
tests/serialization_test.cpp
Normal file
108
tests/serialization_test.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
|
||||
#include <fc/container/flat.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
|
||||
namespace fc { namespace test {
|
||||
|
||||
struct item;
|
||||
inline bool operator < ( const item& a, const item& b );
|
||||
inline bool operator == ( const item& a, const item& b );
|
||||
|
||||
struct item_wrapper
|
||||
{
|
||||
item_wrapper() {}
|
||||
item_wrapper(item&& it) { v.reserve(1); v.insert( it ); }
|
||||
boost::container::flat_set<struct item> v;
|
||||
};
|
||||
inline bool operator < ( const item_wrapper& a, const item_wrapper& b );
|
||||
inline bool operator == ( const item_wrapper& a, const item_wrapper& b );
|
||||
|
||||
struct item
|
||||
{
|
||||
item(int32_t lvl = 0) : level(lvl) {}
|
||||
item(item_wrapper&& wp, int32_t lvl = 0) : level(lvl), w(wp) {}
|
||||
int32_t level;
|
||||
item_wrapper w;
|
||||
};
|
||||
|
||||
inline bool operator == ( const item& a, const item& b )
|
||||
{ return ( std::tie( a.level, a.w ) == std::tie( b.level, b.w ) ); }
|
||||
|
||||
inline bool operator < ( const item& a, const item& b )
|
||||
{ return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); }
|
||||
|
||||
inline bool operator == ( const item_wrapper& a, const item_wrapper& b )
|
||||
{ return ( std::tie( a.v ) == std::tie( b.v ) ); }
|
||||
|
||||
inline bool operator < ( const item_wrapper& a, const item_wrapper& b )
|
||||
{ return ( std::tie( a.v ) < std::tie( b.v ) ); }
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT( fc::test::item_wrapper, (v) );
|
||||
FC_REFLECT( fc::test::item, (level)(w) );
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(fc_serialization)
|
||||
|
||||
BOOST_AUTO_TEST_CASE( nested_objects_test )
|
||||
{ try {
|
||||
|
||||
auto create_nested_object = []( uint32_t level )
|
||||
{
|
||||
ilog( "Creating nested object with ${lv} level(s)", ("lv",level) );
|
||||
fc::test::item nested;
|
||||
for( uint32_t i = 1; i <= level; i++ )
|
||||
{
|
||||
if( i % 100 == 0 )
|
||||
ilog( "Creating level ${lv}", ("lv",i) );
|
||||
fc::test::item_wrapper wp( std::move(nested) );
|
||||
nested = fc::test::item( std::move(wp), i );
|
||||
}
|
||||
return nested;
|
||||
};
|
||||
|
||||
// 100 levels, should be allowed
|
||||
{
|
||||
auto nested = create_nested_object( 100 );
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
BOOST_TEST_MESSAGE( "About to pack." );
|
||||
fc::raw::pack( ss, nested );
|
||||
|
||||
BOOST_TEST_MESSAGE( "About to unpack." );
|
||||
fc::test::item unpacked;
|
||||
fc::raw::unpack( ss, unpacked );
|
||||
|
||||
BOOST_CHECK( unpacked == nested );
|
||||
}
|
||||
|
||||
// 150 levels, by default packing will fail
|
||||
{
|
||||
auto nested = create_nested_object( 150 );
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
BOOST_TEST_MESSAGE( "About to pack." );
|
||||
BOOST_CHECK_THROW( fc::raw::pack( ss, nested ), fc::assert_exception );
|
||||
}
|
||||
|
||||
// 150 levels and allow packing, unpacking will fail
|
||||
{
|
||||
auto nested = create_nested_object( 150 );
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
BOOST_TEST_MESSAGE( "About to pack." );
|
||||
fc::raw::pack( ss, nested, 1500 );
|
||||
|
||||
BOOST_TEST_MESSAGE( "About to unpack." );
|
||||
fc::test::item unpacked;
|
||||
BOOST_CHECK_THROW( fc::raw::unpack( ss, unpacked ), fc::assert_exception );
|
||||
}
|
||||
|
||||
} FC_CAPTURE_LOG_AND_RETHROW ( (0) ) }
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
1
vendor/editline
vendored
Submodule
1
vendor/editline
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5be965deec0527b48b393b7aca9cb2a76aec2a99
|
||||
2
vendor/websocketpp
vendored
2
vendor/websocketpp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 378437aecdcb1dfe62096ffd5d944bf1f640ccc3
|
||||
Subproject commit e6c4e3c54bf9cf1892c85a6ed6289486bba36fa1
|
||||
Loading…
Reference in a new issue