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/external/rapidxml/rapidxml.hpp>
|
||||
#include <cereal/external/rapidxml/rapidxml_print.hpp>
|
||||
#include <cereal/external/base64.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision>
|
||||
@@ -44,11 +66,11 @@ namespace cereal
|
||||
public:
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout! */
|
||||
XMLOutputArchive(std::ostream & stream) :
|
||||
even cout!
|
||||
@param precision The precision for floating point output */
|
||||
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) :
|
||||
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this),
|
||||
itsStream(stream),
|
||||
itsUnnamedCounter( 0 )
|
||||
itsStream(stream)
|
||||
{
|
||||
// rapidxml will delete all allocations when xml_document is cleared
|
||||
auto node = itsXML.allocate_node( rapidxml::node_declaration );
|
||||
@@ -58,7 +80,12 @@ namespace cereal
|
||||
|
||||
auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" );
|
||||
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
|
||||
@@ -68,15 +95,6 @@ namespace cereal
|
||||
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 )
|
||||
{
|
||||
createNode( name.c_str() );
|
||||
@@ -85,16 +103,104 @@ namespace cereal
|
||||
void createNode( char const * name )
|
||||
{
|
||||
auto node = itsXML.allocate_node( rapidxml::node_element, name );
|
||||
itsNodes.top()->append_node( node );
|
||||
itsNodes.push( node );
|
||||
++itsUnnamedCounter;
|
||||
itsNodes.top().node->append_node( node );
|
||||
itsNodes.emplace( node );
|
||||
|
||||
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:
|
||||
std::ostream & itsStream;
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
std::stack<rapidxml::xml_node<>*> itsNodes; //!< Stack of nodes, bottom one will always be the root
|
||||
size_t itsUnnamedCounter; //!< Used to give names to un-named values
|
||||
std::stack<NodeInfo> itsNodes;
|
||||
std::ostringstream os;
|
||||
};
|
||||
|
||||
struct XMLInputArchive;
|
||||
@@ -108,10 +214,31 @@ namespace cereal
|
||||
//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
|
||||
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);
|
||||
|
||||
auto x = cereal::make_nvp( "a", cereal::make_nvp("b", 5) );
|
||||
|
||||
{
|
||||
//std::stringstream os;
|
||||
cereal::XMLOutputArchive oar( std::cout );
|
||||
oar( cereal::make_nvp("hello", 5 ) );
|
||||
std::string bla("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