mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Working on prologue/epilogue for xml
This commit is contained in:
@@ -30,13 +30,35 @@
|
|||||||
#include <cereal/cereal.hpp>
|
#include <cereal/cereal.hpp>
|
||||||
#include <cereal/external/rapidxml/rapidxml.hpp>
|
#include <cereal/external/rapidxml/rapidxml.hpp>
|
||||||
#include <cereal/external/rapidxml/rapidxml_print.hpp>
|
#include <cereal/external/rapidxml/rapidxml_print.hpp>
|
||||||
|
#include <cereal/external/base64.hpp>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct XMLHelper
|
||||||
|
{
|
||||||
|
const char * popName()
|
||||||
|
{
|
||||||
|
if( names.empty() )
|
||||||
|
return nullptr;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto name = names.top();
|
||||||
|
names.pop();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stack<const char *> names;
|
||||||
|
};
|
||||||
|
}
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
//! An output archive designed to save data to XML
|
//! An output archive designed to save data to XML
|
||||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision>
|
class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision>
|
||||||
@@ -44,11 +66,11 @@ namespace cereal
|
|||||||
public:
|
public:
|
||||||
//! Construct, outputting to the provided stream
|
//! Construct, outputting to the provided stream
|
||||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||||
even cout! */
|
even cout!
|
||||||
XMLOutputArchive(std::ostream & stream) :
|
@param precision The precision for floating point output */
|
||||||
|
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) :
|
||||||
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this),
|
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this),
|
||||||
itsStream(stream),
|
itsStream(stream)
|
||||||
itsUnnamedCounter( 0 )
|
|
||||||
{
|
{
|
||||||
// rapidxml will delete all allocations when xml_document is cleared
|
// rapidxml will delete all allocations when xml_document is cleared
|
||||||
auto node = itsXML.allocate_node( rapidxml::node_declaration );
|
auto node = itsXML.allocate_node( rapidxml::node_declaration );
|
||||||
@@ -58,7 +80,12 @@ namespace cereal
|
|||||||
|
|
||||||
auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" );
|
auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" );
|
||||||
itsXML.append_node( root );
|
itsXML.append_node( root );
|
||||||
itsNodes.push( root );
|
itsNodes.emplace( root );
|
||||||
|
|
||||||
|
// testing
|
||||||
|
itsStream << std::boolalpha;
|
||||||
|
itsStream.precision( precision );
|
||||||
|
//itsStream.setf( std::ios::floatfield, std::ios::fixed );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor, flushes the XML
|
//! Destructor, flushes the XML
|
||||||
@@ -68,15 +95,6 @@ namespace cereal
|
|||||||
itsXML.clear();
|
itsXML.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Writes size bytes of data to the output stream
|
|
||||||
void saveBinary( const void * data, size_t size )
|
|
||||||
{
|
|
||||||
size_t const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
|
|
||||||
|
|
||||||
if(writtenSize != size)
|
|
||||||
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
void createNode( std::string const & name )
|
void createNode( std::string const & name )
|
||||||
{
|
{
|
||||||
createNode( name.c_str() );
|
createNode( name.c_str() );
|
||||||
@@ -85,16 +103,104 @@ namespace cereal
|
|||||||
void createNode( char const * name )
|
void createNode( char const * name )
|
||||||
{
|
{
|
||||||
auto node = itsXML.allocate_node( rapidxml::node_element, name );
|
auto node = itsXML.allocate_node( rapidxml::node_element, name );
|
||||||
itsNodes.top()->append_node( node );
|
itsNodes.top().node->append_node( node );
|
||||||
itsNodes.push( node );
|
itsNodes.emplace( node );
|
||||||
++itsUnnamedCounter;
|
|
||||||
|
node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, "5432" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Saves some data, encoded as a string
|
||||||
|
/*! The data will be be named with the most recent name if one exists,
|
||||||
|
otherwise it will be given some default delimited value that depends upon
|
||||||
|
the parent node */
|
||||||
|
template <class T> inline
|
||||||
|
void saveValue( T const & value )
|
||||||
|
{
|
||||||
|
os.clear(); os.seekp(0);
|
||||||
|
os << value << std::ends;
|
||||||
|
//std::cout << ".... " << os.str().c_str() << std::endl;
|
||||||
|
insertValueNode( os.str().c_str() );
|
||||||
|
itsStream << value << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Appends a named node to the current top node with some data
|
||||||
|
/*! The name is generated by calling the top node's getValueName(),
|
||||||
|
which will generate an incremental value name if one has not been set
|
||||||
|
prior to calling this */
|
||||||
|
void insertValueNode( const char * data )
|
||||||
|
{
|
||||||
|
//const auto nameString = itsNodes.top().getValueName();
|
||||||
|
|
||||||
|
// allocate strings for all of the data in the XML object
|
||||||
|
//auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||||
|
auto dataPtr = itsXML.allocate_string( data );
|
||||||
|
|
||||||
|
// insert into the XML
|
||||||
|
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
|
||||||
|
//itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_element, namePtr, dataPtr, nameString.size() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void startNode()
|
||||||
|
{
|
||||||
|
const auto nameString = itsNodes.top().getValueName();
|
||||||
|
|
||||||
|
// allocate strings for all of the data in the XML object
|
||||||
|
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||||
|
|
||||||
|
// insert into the XML
|
||||||
|
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
|
||||||
|
itsNodes.top().node->append_node( node );
|
||||||
|
itsNodes.emplace( node );
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishNode()
|
||||||
|
{
|
||||||
|
itsNodes.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Saves some binary data, encoded as a base64 string
|
||||||
|
void saveBinaryValue( const void * data, size_t size )
|
||||||
|
{
|
||||||
|
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||||
|
saveValue( base64string );
|
||||||
|
//auto decoded = base64::decode(base64string);
|
||||||
|
//int const * zz = (int const*)decoded.data();
|
||||||
|
//std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NodeInfo
|
||||||
|
{
|
||||||
|
NodeInfo( rapidxml::xml_node<> * n = nullptr,
|
||||||
|
const char * nm = nullptr ) :
|
||||||
|
node( n ),
|
||||||
|
counter( 0 ),
|
||||||
|
name( nm )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
rapidxml::xml_node<> * node;
|
||||||
|
size_t counter;
|
||||||
|
const char * name;
|
||||||
|
|
||||||
|
std::string getValueName()
|
||||||
|
{
|
||||||
|
if( name )
|
||||||
|
{
|
||||||
|
auto n = name;
|
||||||
|
name = nullptr;
|
||||||
|
return {n};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "value" + std::to_string( counter++ ) + "\0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::ostream & itsStream;
|
std::ostream & itsStream;
|
||||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||||
std::stack<rapidxml::xml_node<>*> itsNodes; //!< Stack of nodes, bottom one will always be the root
|
std::stack<NodeInfo> itsNodes;
|
||||||
size_t itsUnnamedCounter; //!< Used to give names to un-named values
|
std::ostringstream os;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XMLInputArchive;
|
struct XMLInputArchive;
|
||||||
@@ -108,10 +214,31 @@ namespace cereal
|
|||||||
//ar( t.value );
|
//ar( t.value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Saving for POD types to xml
|
||||||
|
template<class T> inline
|
||||||
|
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||||
|
save(XMLOutputArchive & ar, T const & t)
|
||||||
|
{
|
||||||
|
ar.saveValue( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! saving string to xml
|
||||||
template<class CharT, class Traits, class Alloc> inline
|
template<class CharT, class Traits, class Alloc> inline
|
||||||
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||||
{
|
{
|
||||||
ar.createNode( str );
|
ar.saveValue( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void prologue( XMLOutputArchive & ar, T const & data )
|
||||||
|
{
|
||||||
|
ar.startNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void epilogue( XMLOutputArchive & ar, T const & data )
|
||||||
|
{
|
||||||
|
ar.finishNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
|||||||
@@ -295,14 +295,18 @@ int main()
|
|||||||
|
|
||||||
assert(e_in == e_out);
|
assert(e_in == e_out);
|
||||||
|
|
||||||
auto x = cereal::make_nvp( "a", cereal::make_nvp("b", 5) );
|
|
||||||
|
|
||||||
{
|
{
|
||||||
//std::stringstream os;
|
//std::stringstream os;
|
||||||
cereal::XMLOutputArchive oar( std::cout );
|
cereal::XMLOutputArchive oar( std::cout );
|
||||||
oar( cereal::make_nvp("hello", 5 ) );
|
oar( cereal::make_nvp("hello", 5 ) );
|
||||||
std::string bla("bla");
|
std::string bla("bla");
|
||||||
oar( bla );
|
oar( bla );
|
||||||
|
oar( 5 );
|
||||||
|
oar( 3.3 );
|
||||||
|
oar( 3.2f );
|
||||||
|
oar( true );
|
||||||
|
//int xxx[] = {-1, 95, 3};
|
||||||
|
//oar.saveBinaryValue( xxx, sizeof(int)*3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user