From 5cecbdf08fa16fae84506c3ba78488811c9af6a1 Mon Sep 17 00:00:00 2001 From: Shane Grant Date: Wed, 3 Jul 2013 12:08:47 -0700 Subject: [PATCH] working on input xml --- include/cereal/archives/xml.hpp | 123 +++++---- .../external/rapidxml/rapidxml_utils.hpp | 244 +++++++++--------- sandbox.cpp | 19 +- 3 files changed, 211 insertions(+), 175 deletions(-) diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp index f68b8bed..862d8fd0 100644 --- a/include/cereal/archives/xml.hpp +++ b/include/cereal/archives/xml.hpp @@ -28,49 +28,35 @@ #define CEREAL_ARCHIVES_XML_HPP_ #include +#include + #include #include #include #include #include +#include #include #include 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 names; - }; - } // ###################################################################### //! An output archive designed to save data to XML - class XMLOutputArchive : public OutputArchive + class XMLOutputArchive : public OutputArchive { public: //! Construct, outputting to the provided stream /*! @param stream The stream to output to. Can be a stringstream, a file stream, or even cout! - @param precision The precision for floating point output */ - XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) : - OutputArchive(this), - itsStream(stream) + @param precision The precision for floating point output + @param outputType Controls whether type information will be printed in attributes */ + XMLOutputArchive(std::ostream & stream, size_t precision = 10, bool outputType = false ) : + OutputArchive(this), + itsStream(stream), + itsOutputType( outputType ) { // rapidxml will delete all allocations when xml_document is cleared auto node = itsXML.allocate_node( rapidxml::node_declaration ); @@ -97,20 +83,6 @@ namespace cereal 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 /*! 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 @@ -120,13 +92,9 @@ namespace cereal { itsOS.clear(); itsOS.seekp(0); 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 - auto dataPtr = itsXML.allocate_string( data ); + auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() ); // insert into the XML itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) ); @@ -151,6 +119,22 @@ namespace cereal itsNodes.emplace( node ); } + //! Causes the type to be appended to the most recently made node if output type is set to true + template inline + void insertType() + { + if( !itsOutputType ) + return; + + // generate a name for this new node + const auto nameString = util::demangledName(); + + // 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 void finishNode() { @@ -163,14 +147,22 @@ namespace cereal itsNodes.top().name = name; } - //! Saves some binary data, encoded as a base64 string - void saveBinaryValue( const void * data, size_t size ) + //! Saves some binary data, encoded as a base64 string, with an optional name + /*! 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( 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; + + if( itsOutputType ) + itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) ); + + finishNode(); }; //! A struct that contains metadata about a node @@ -209,9 +201,41 @@ namespace cereal rapidxml::xml_document<> itsXML; //!< The XML document std::stack itsNodes; //!< A stack of nodes added to the document std::ostringstream itsOS; //!< Used to format strings internally + bool itsOutputType; //!< Controls whether type information is printed }; // XMLOutputArchive - struct XMLInputArchive; + // ###################################################################### + //! An output archive designed to save data to XML + class XMLInputArchive : public InputArchive + { + 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( this ), + itsStream( stream ), + itsData( std::istreambuf_iterator( stream ), std::istreambuf_iterator() ) + { + try + { + itsXML.parse( reinterpret_cast( 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() << std::endl; + } + } + + //private: + std::istream & itsStream; + std::vector itsData; //!< The raw data loaded + rapidxml::xml_document<> itsXML; //!< The XML document + }; // ###################################################################### // XMLArchive prologue and epilogue functions @@ -247,6 +271,7 @@ namespace cereal void prologue( XMLOutputArchive & ar, T const & data ) { ar.startNode(); + ar.insertType(); } //! Epilogue for all other types other for XML archives diff --git a/include/cereal/external/rapidxml/rapidxml_utils.hpp b/include/cereal/external/rapidxml/rapidxml_utils.hpp index 5eafa35d..96f331b6 100644 --- a/include/cereal/external/rapidxml/rapidxml_utils.hpp +++ b/include/cereal/external/rapidxml/rapidxml_utils.hpp @@ -1,122 +1,122 @@ -#ifndef RAPIDXML_UTILS_HPP_INCLUDED -#define RAPIDXML_UTILS_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \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. - -#include "rapidxml.hpp" -#include -#include -#include -#include - -namespace rapidxml -{ - - //! Represents data loaded from a file - template - class file - { - - public: - - //! Loads file into the memory. Data will be automatically destroyed by the destructor. - //! \param filename Filename to load. - file(const char *filename) - { - using namespace std; - - // Open stream - basic_ifstream stream(filename, ios::binary); - if (!stream) - throw runtime_error(string("cannot open file ") + filename); - stream.unsetf(ios::skipws); - - // Determine stream size - stream.seekg(0, ios::end); - size_t size = stream.tellg(); - stream.seekg(0); - - // Load data and add terminating 0 - m_data.resize(size + 1); - stream.read(&m_data.front(), static_cast(size)); - m_data[size] = 0; - } - - //! Loads file into the memory. Data will be automatically destroyed by the destructor - //! \param stream Stream to load from - file(std::basic_istream &stream) - { - using namespace std; - - // Load data and add terminating 0 - stream.unsetf(ios::skipws); - m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); - if (stream.fail() || stream.bad()) - throw runtime_error("error reading stream"); - m_data.push_back(0); - } - - //! Gets file data. - //! \return Pointer to data of file. - Ch *data() - { - return &m_data.front(); - } - - //! Gets file data. - //! \return Pointer to data of file. - const Ch *data() const - { - return &m_data.front(); - } - - //! Gets file data size. - //! \return Size of file data, in characters. - std::size_t size() const - { - return m_data.size(); - } - - private: - - std::vector m_data; // File data - - }; - - //! Counts children of node. Time complexity is O(n). - //! \return Number of children of node - template - inline std::size_t count_children(xml_node *node) - { - xml_node *child = node->first_node(); - std::size_t count = 0; - while (child) - { - ++count; - child = child->next_sibling(); - } - return count; - } - - //! Counts attributes of node. Time complexity is O(n). - //! \return Number of attributes of node - template - inline std::size_t count_attributes(xml_node *node) - { - xml_attribute *attr = node->first_attribute(); - std::size_t count = 0; - while (attr) - { - ++count; - attr = attr->next_attribute(); - } - return count; - } - -} - -#endif +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \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. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/sandbox.cpp b/sandbox.cpp index 522756ce..6bcbbe70 100644 --- a/sandbox.cpp +++ b/sandbox.cpp @@ -299,7 +299,8 @@ int main() { //std::stringstream os; - cereal::XMLOutputArchive oar( std::cout ); + std::ofstream os("out.xml"); + cereal::XMLOutputArchive oar( os ); oar( cereal::make_nvp("hello", 5 ) ); std::string bla("bla"); oar( bla ); @@ -318,13 +319,23 @@ int main() "there", "buddy"}; + std::vector> vec2 = {vec, vec, vec}; + Everything e; - oar( cereal::make_nvp("EVERYTHING?!", e) ); + oar( cereal::make_nvp("EVERYTHING", e) ); oar( vec ); - //int xxx[] = {-1, 95, 3}; - //oar.saveBinaryValue( xxx, sizeof(int)*3); + oar( vec2 ); + + 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; + }