working on input xml

This commit is contained in:
Shane Grant
2013-07-03 12:08:47 -07:00
parent 002b1ceeb1
commit 5cecbdf08f
3 changed files with 211 additions and 175 deletions

View File

@@ -28,49 +28,35 @@
#define CEREAL_ARCHIVES_XML_HPP_ #define CEREAL_ARCHIVES_XML_HPP_
#include <cereal/cereal.hpp> #include <cereal/cereal.hpp>
#include <cereal/details/util.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 <cereal/external/base64.hpp>
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <vector>
#include <string> #include <string>
#include <iostream> #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>
{ {
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!
@param precision The precision for floating point output */ @param precision The precision for floating point output
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) : @param outputType Controls whether type information will be printed in attributes */
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this), XMLOutputArchive(std::ostream & stream, size_t precision = 10, bool outputType = false ) :
itsStream(stream) OutputArchive<XMLOutputArchive>(this),
itsStream(stream),
itsOutputType( outputType )
{ {
// 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 );
@@ -97,20 +83,6 @@ namespace cereal
itsXML.clear(); itsXML.clear();
} }
void createNode( std::string const & name )
{
createNode( name.c_str() );
}
void createNode( char const * name )
{
auto node = itsXML.allocate_node( rapidxml::node_element, name );
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 //! Saves some data, encoded as a string
/*! The data will be be named with the most recent name if one exists, /*! 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 otherwise it will be given some default delimited value that depends upon
@@ -120,13 +92,9 @@ namespace cereal
{ {
itsOS.clear(); itsOS.seekp(0); itsOS.clear(); itsOS.seekp(0);
itsOS << value << std::ends; itsOS << value << std::ends;
insertValueNode( itsOS.str().c_str() );
}
void insertValueNode( const char * data )
{
// allocate strings for all of the data in the XML object // allocate strings for all of the data in the XML object
auto dataPtr = itsXML.allocate_string( data ); auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
// insert into the XML // 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_data, nullptr, dataPtr ) );
@@ -151,6 +119,22 @@ namespace cereal
itsNodes.emplace( node ); itsNodes.emplace( node );
} }
//! Causes the type to be appended to the most recently made node if output type is set to true
template <class T> inline
void insertType()
{
if( !itsOutputType )
return;
// generate a name for this new node
const auto nameString = util::demangledName<T>();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
}
//! Designates the most recently added node as finished //! Designates the most recently added node as finished
void finishNode() void finishNode()
{ {
@@ -163,14 +147,22 @@ namespace cereal
itsNodes.top().name = name; itsNodes.top().name = name;
} }
//! Saves some binary data, encoded as a base64 string //! Saves some binary data, encoded as a base64 string, with an optional name
void saveBinaryValue( const void * data, size_t size ) /*! This will create a new node, optionally named, and insert a value that consists of
the data encoded as a base64 string */
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
{ {
itsNodes.top().name = name;
startNode();
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size ); auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
saveValue( base64string ); saveValue( base64string );
//auto decoded = base64::decode(base64string);
//int const * zz = (int const*)decoded.data(); if( itsOutputType )
//std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl; itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
finishNode();
}; };
//! A struct that contains metadata about a node //! A struct that contains metadata about a node
@@ -209,9 +201,41 @@ namespace cereal
rapidxml::xml_document<> itsXML; //!< The XML document rapidxml::xml_document<> itsXML; //!< The XML document
std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
std::ostringstream itsOS; //!< Used to format strings internally std::ostringstream itsOS; //!< Used to format strings internally
bool itsOutputType; //!< Controls whether type information is printed
}; // XMLOutputArchive }; // XMLOutputArchive
struct XMLInputArchive; // ######################################################################
//! An output archive designed to save data to XML
class XMLInputArchive : public InputArchive<XMLInputArchive>
{
public:
//! Construct, reading in from the provided stream
/*! Reads in an entire XML document from some stream and parses it as soon
as serialization starts
@param stream The stream to read from. Can be a stringstream or a file. */
XMLInputArchive( std::istream & stream ) :
InputArchive<XMLInputArchive>( this ),
itsStream( stream ),
itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
{
try
{
itsXML.parse<rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
}
catch( rapidxml::parse_error const & e )
{
throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
//std::cout << e.what() << std::endl;
//std::cout << e.where<char>() << std::endl;
}
}
//private:
std::istream & itsStream;
std::vector<uint8_t> itsData; //!< The raw data loaded
rapidxml::xml_document<> itsXML; //!< The XML document
};
// ###################################################################### // ######################################################################
// XMLArchive prologue and epilogue functions // XMLArchive prologue and epilogue functions
@@ -247,6 +271,7 @@ namespace cereal
void prologue( XMLOutputArchive & ar, T const & data ) void prologue( XMLOutputArchive & ar, T const & data )
{ {
ar.startNode(); ar.startNode();
ar.insertType<T>();
} }
//! Epilogue for all other types other for XML archives //! Epilogue for all other types other for XML archives

View File

@@ -1,122 +1,122 @@
#ifndef RAPIDXML_UTILS_HPP_INCLUDED #ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED #define RAPIDXML_UTILS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski // Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13 // Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $ // Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful //! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. //! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
#include "rapidxml.hpp" #include "rapidxml.hpp"
#include <vector> #include <vector>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <stdexcept> #include <stdexcept>
namespace rapidxml namespace rapidxml
{ {
//! Represents data loaded from a file //! Represents data loaded from a file
template<class Ch = char> template<class Ch = char>
class file class file
{ {
public: public:
//! Loads file into the memory. Data will be automatically destroyed by the destructor. //! Loads file into the memory. Data will be automatically destroyed by the destructor.
//! \param filename Filename to load. //! \param filename Filename to load.
file(const char *filename) file(const char *filename)
{ {
using namespace std; using namespace std;
// Open stream // Open stream
basic_ifstream<Ch> stream(filename, ios::binary); basic_ifstream<Ch> stream(filename, ios::binary);
if (!stream) if (!stream)
throw runtime_error(string("cannot open file ") + filename); throw runtime_error(string("cannot open file ") + filename);
stream.unsetf(ios::skipws); stream.unsetf(ios::skipws);
// Determine stream size // Determine stream size
stream.seekg(0, ios::end); stream.seekg(0, ios::end);
size_t size = stream.tellg(); size_t size = stream.tellg();
stream.seekg(0); stream.seekg(0);
// Load data and add terminating 0 // Load data and add terminating 0
m_data.resize(size + 1); m_data.resize(size + 1);
stream.read(&m_data.front(), static_cast<streamsize>(size)); stream.read(&m_data.front(), static_cast<streamsize>(size));
m_data[size] = 0; m_data[size] = 0;
} }
//! Loads file into the memory. Data will be automatically destroyed by the destructor //! Loads file into the memory. Data will be automatically destroyed by the destructor
//! \param stream Stream to load from //! \param stream Stream to load from
file(std::basic_istream<Ch> &stream) file(std::basic_istream<Ch> &stream)
{ {
using namespace std; using namespace std;
// Load data and add terminating 0 // Load data and add terminating 0
stream.unsetf(ios::skipws); stream.unsetf(ios::skipws);
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>()); m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
if (stream.fail() || stream.bad()) if (stream.fail() || stream.bad())
throw runtime_error("error reading stream"); throw runtime_error("error reading stream");
m_data.push_back(0); m_data.push_back(0);
} }
//! Gets file data. //! Gets file data.
//! \return Pointer to data of file. //! \return Pointer to data of file.
Ch *data() Ch *data()
{ {
return &m_data.front(); return &m_data.front();
} }
//! Gets file data. //! Gets file data.
//! \return Pointer to data of file. //! \return Pointer to data of file.
const Ch *data() const const Ch *data() const
{ {
return &m_data.front(); return &m_data.front();
} }
//! Gets file data size. //! Gets file data size.
//! \return Size of file data, in characters. //! \return Size of file data, in characters.
std::size_t size() const std::size_t size() const
{ {
return m_data.size(); return m_data.size();
} }
private: private:
std::vector<Ch> m_data; // File data std::vector<Ch> m_data; // File data
}; };
//! Counts children of node. Time complexity is O(n). //! Counts children of node. Time complexity is O(n).
//! \return Number of children of node //! \return Number of children of node
template<class Ch> template<class Ch>
inline std::size_t count_children(xml_node<Ch> *node) inline std::size_t count_children(xml_node<Ch> *node)
{ {
xml_node<Ch> *child = node->first_node(); xml_node<Ch> *child = node->first_node();
std::size_t count = 0; std::size_t count = 0;
while (child) while (child)
{ {
++count; ++count;
child = child->next_sibling(); child = child->next_sibling();
} }
return count; return count;
} }
//! Counts attributes of node. Time complexity is O(n). //! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node //! \return Number of attributes of node
template<class Ch> template<class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node) inline std::size_t count_attributes(xml_node<Ch> *node)
{ {
xml_attribute<Ch> *attr = node->first_attribute(); xml_attribute<Ch> *attr = node->first_attribute();
std::size_t count = 0; std::size_t count = 0;
while (attr) while (attr)
{ {
++count; ++count;
attr = attr->next_attribute(); attr = attr->next_attribute();
} }
return count; return count;
} }
} }
#endif #endif

View File

@@ -299,7 +299,8 @@ int main()
{ {
//std::stringstream os; //std::stringstream os;
cereal::XMLOutputArchive oar( std::cout ); std::ofstream os("out.xml");
cereal::XMLOutputArchive oar( os );
oar( cereal::make_nvp("hello", 5 ) ); oar( cereal::make_nvp("hello", 5 ) );
std::string bla("bla"); std::string bla("bla");
oar( bla ); oar( bla );
@@ -318,13 +319,23 @@ int main()
"there", "there",
"buddy"}; "buddy"};
std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
Everything e; Everything e;
oar( cereal::make_nvp("EVERYTHING?!", e) ); oar( cereal::make_nvp("EVERYTHING", e) );
oar( vec ); oar( vec );
//int xxx[] = {-1, 95, 3}; oar( vec2 );
//oar.saveBinaryValue( xxx, sizeof(int)*3);
int xxx[] = {-1, 95, 3};
oar.saveBinaryValue( xxx, sizeof(int)*3, "xxxbinary" );
oar.saveBinaryValue( xxx, sizeof(int)*3 );
} }
{
std::ifstream is("out.xml");
cereal::XMLInputArchive oar( is );
std::cout << oar.itsData.size() << std::endl;
}