Update of /cvsroot/libfunutil/libfunutil/lib/s11n In directory sc8-pr-cvs1:/tmp/cvs-serv28813 Modified Files: Makefile ns.include_from_main.h ns.node_builder.cpp ns.node_loader.cpp ns.node_loader.h ns.s11n_globals.h ns.s11n_io.h ns.s11n_node.h ns.serializable_adapter.h ns.serializer_loader.cpp ns.serializer_loader.h Added Files: ns.compact_serializer.cpp ns.hex_serializer.cpp ns.paren_serializer.cpp ns.s11n.h ns.serializable.cpp ns.serializable.h ns.serializer.cpp ns.serializer.h Removed Files: ns.Serializer.h Log Message: mass file-name changes. All classes now have stl-style names, partly for consistency, partly because that's my fad at the moment, and partly to avoid stepping on the original fun::{Serializ{er,able}}.h. --- NEW FILE: ns.compact_serializer.cpp --- #include <iostream> #include <string> #include <S11N_NAMESPACE/flex_lexers.h> #include <S11N_NAMESPACE/string_util.h> #include <S11N_NAMESPACE/serializer.h> // maintenance note: this class is about 98% identical to FunTxt. i // need a way to combine these better. namespace S11N_NAMESPACE { compact_serializer::compact_serializer() { }; compact_serializer::~compact_serializer() { }; s11n_node * compact_serializer::deserialize( std::istream & is ) { S11N_NAMESPACE::CompactTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool compact_serializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !basic_serializer::serialize( node, os ) ) return false; static const int ctrlwidth = 2; static const int size2b = 2; static const int size8b = 8; static const int cookiewidth = 8; // static const int charwidth = 2; static unsigned int depth = 0; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); std::string::size_type sizE = 0; // WTF must all this stream manip be done on every fucking insert? #define OS_INT(C,W) os.width(W);os<<std::hex<<std::right<<(unsigned int)(C); #define INSERT(vaR,WIDTH) sizE = vaR.size(); OS_INT(sizE,WIDTH); \ for( std::string::size_type ins = 0; ins < sizE; ins++ ) {\ /*OS_INT(vaR[ins],charwidth);*/ \ os << (unsigned char) vaR[ins]; \ }; if ( 1 == depth ) { os.setf( std::ios_base::hex ); os.fill('0'); os.setf(std::ios_base::right, std::ios_base::adjustfield); OS_INT(Magic_Cookie,cookiewidth); os << '\n'; } OS_INT(Node_Open,ctrlwidth); INSERT(nname,size2b); INSERT(impl,size2b); S11N_NAMESPACE::property_store::const_iterator it = node.property_store::begin(); S11N_NAMESPACE::property_store::const_iterator et = node.property_store::end(); std::string propval; std::string propname; //bool gotprops = ( it != et ); for ( ; it != et; ++it ) { OS_INT(Prop_Open,ctrlwidth); propname = ( *it ).first; INSERT(propname,size2b); propval = ( *it ).second; INSERT(propval,size8b); //OS_INT(Prop_Close); } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); bool ret = true; for ( ; cit != cet; ++cit ) { if ( !this->serialize( *( *cit ), os ) ) { ret = false; } //os << (out_type) '\n'; } OS_INT(Node_Close,ctrlwidth); os << '\n'; if( 1 == depth ) { OS_INT(Data_End,cookiewidth); os << std::endl; // //os << (out_type) '\n'; // os.flush(); // maintenance: os must be flush()ed or the client may be forced to do it. } --depth; return ret; } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.hex_serializer.cpp --- #include <iostream> #include <string> #include <S11N_NAMESPACE/flex_lexers.h> #include <S11N_NAMESPACE/string_util.h> #include <S11N_NAMESPACE/serializer.h> // maintenance note: this class is about 98% identical to FunTxt. i // need a way to combine these better. namespace S11N_NAMESPACE { hex_serializer::hex_serializer() { }; hex_serializer::~hex_serializer() { }; s11n_node * hex_serializer::deserialize( std::istream & is ) { S11N_NAMESPACE::HexTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool hex_serializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !basic_serializer::serialize( node, os ) ) return false; typedef unsigned int out_type; static unsigned int depth = 0; // recursion depth. // token sizes: static const int width2b = 2; static const int cookie_width = 8; static const int width8b = 8; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); std::string::size_type sizE = 0; // WTF must all this stream manip be done on every insert? #define OS_INT(C,W) os.width(W);os<<std::hex<<std::right<<(out_type)(C); #define INSERT(vaR,WIDTH) sizE = vaR.size(); OS_INT(sizE,WIDTH); \ for( std::string::size_type ins = 0; ins < sizE; ins++ ) {\ OS_INT(vaR[ins],width2b); \ } if ( 1 == depth ) { os.setf( std::ios_base::hex ); os.fill('0'); os.setf(std::ios_base::right, std::ios_base::adjustfield); OS_INT(Magic_Cookie,cookie_width); os << '\n'; } OS_INT(Node_Open,width2b); INSERT(nname,width2b); INSERT(impl,width2b); S11N_NAMESPACE::property_store::const_iterator it = node.property_store::begin(); S11N_NAMESPACE::property_store::const_iterator et = node.property_store::end(); std::string propval; std::string propname; //bool gotprops = ( it != et ); for ( ; it != et; ++it ) { OS_INT(Prop_Open,width2b); propname = ( *it ).first; INSERT(propname,width2b); propval = ( *it ).second; INSERT(propval,width8b); //OS_INT(Prop_Close); } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); bool ret = true; for ( ; cit != cet; ++cit ) { if ( !this->serialize( *( *cit ), os ) ) { ret = false; } //os << (out_type) '\n'; } OS_INT(Node_Close,width2b); os << '\n'; if( 1 == depth ) { OS_INT(Data_End,width8b); //os << (out_type) '\n'; os << std::endl; // maintenance: os must be flush()ed or the client may be forced to do it. } --depth; return ret; } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.paren_serializer.cpp --- #include <iostream> #include <string> #include <S11N_NAMESPACE/flex_lexers.h> #include <S11N_NAMESPACE/string_util.h> #include <S11N_NAMESPACE/serializer.h> // maintenance note: this class is about 98% identical to FunTxt. i // need a way to combine these better. namespace S11N_NAMESPACE { paren_serializer::paren_serializer() { }; paren_serializer::~paren_serializer() { }; const basic_serializer::translation_map & paren_serializer::translations() const { static paren_serializer::translation_map bob; static bool donethat = false; if( (!donethat) && (donethat=true) ) { // The order of these escapes is signifant. // We only do double-backslashes to accomodate // the case that the final chars in a property // is a backslash (yes, this has happened, and // it hosed the data when sending it via a // format which uses \\\n to support multi-line // values). bob["\\"] = "\\\\"; bob[")"] = "\\)"; bob["("] = "\\("; // It is not strictly necessary to escape \(, // but we do so because Parens is intended to // be easy for hand-editing, and not escaping // them confuses emacs when we have escaped // closing parens. :) } return bob; } s11n_node * paren_serializer::deserialize( std::istream & is ) { S11N_NAMESPACE::ParenTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool paren_serializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !basic_serializer::serialize( node, os ) ) return false; static const bool indention = true; static const std::string tab = (indention ? "\t" : ""); static unsigned int depth = 0; static const char Open = '('; static const char Close = ')'; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); std::string indent; for ( unsigned int i = 1; i < depth; i++ ) indent += tab; std::string indentChild = indent + tab; std::string indentProp = " "; // indent + tab; if ( 1 == depth ) { os << "(S11N_NAMESPACE::parens)\n"; } os << nname << "="<<Open<<impl; S11N_NAMESPACE::property_store::const_iterator it = node.property_store::begin(); S11N_NAMESPACE::property_store::const_iterator et = node.property_store::end(); std::string propval; //bool gotprops = ( it != et ); for ( ; it != et; ++it ) { propval = ( *it ).second; S11N_NAMESPACE::translate_entities( propval, this->translations(), false ); os << indentProp << Open <<( *it ).first << " " << propval << Close; } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); bool ret = true; bool gotkids = (cit != cet); if( gotkids ) os << ( indention ? "\n" : " " ); for ( ; cit != cet; ++cit ) { os << indentChild; if ( !this->serialize( *( *cit ), os ) ) { ret = false; } } if( gotkids ) os << indent; os << ")"; os << (indention ? "\n" : " "); if( 1 == depth ) { if( ! indention ) os << std::endl; else os.flush(); } --depth; // maintenance: os must be flush()ed or the client may be forced to do it (endl does the same). return ret; } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.s11n.h --- // Author: stephan beal <st...@s1...> // License: Public Domain #ifndef S11N_NAMESPACE_S11N_H_INCLUDED #define S11N_NAMESPACE_S11N_H_INCLUDED 1 // please don't use this header - it's being phased out. // #include <S11N_NAMESPACE/s11n_node.h> // #include <S11N_NAMESPACE/serializable.h> // #include <S11N_NAMESPACE/serializable_adapter.h> /** The s11n serialization (s11n) framework is an object serialization framework modelled heavily off work by Rusty Ballinger (bo...@us... http://libfunutil.sourceforge.net). As far as i know Rusty was the one to coin the phrase "s11n" (short for "serialization", in the same way that i18n is short for internationalization). In addition to the class documentation, please see the library manual, available in the source tree, in the docs subdir. The most important classes for clients are: - s11n_node (and it's parent, S11N_NAMESPACE::property_store) - basic_serializer - node_loader */ namespace S11N_NAMESPACE { }; #endif // S11N_NAMESPACE_S11N_H_INCLUDED --- NEW FILE: ns.serializable.cpp --- #include <S11N_NAMESPACE/s11n-macros.h> // CERR #include <S11N_NAMESPACE/s11n_node.h> // #include <S11N_NAMESPACE/serializable_adapter.h> #include "serializable.h" #include <S11N_NAMESPACE/s11n_node.h> // make the library aware of serializable as a serializable type: namespace S11N_NAMESPACE { // static serializable_adapter<serializable> for_template_linking_reasons = serializable_adapter<serializable>(); serializable::serializable() // const std::string & implclassname ) : m_implclass( implclassname ) { } serializable::~serializable() { } bool serializable::s7e( s11n_node & node ) const { if ( node.impl_class().empty() ) { CERR << "warning: impl_class() has not been set for this class. Cannot serialize it!" << std::endl; return false; } // node.impl_class( this->impl_class() ); return true; } bool serializable::d9e( const s11n_node & ) { return true; } // void serializable::impl_class( const std::string & cn ) // { // this->m_implclass = cn; // } // std::string serializable::impl_class()const // { // return this->m_implclass; // } }; //namespace S11N_NAMESPACE --- NEW FILE: ns.serializable.h --- // // License: Public Domain // Author: st...@wa... // #ifndef S11N_NAMESPACE_SERIALIZABLE_H_INCLUDED #define S11N_NAMESPACE_SERIALIZABLE_H_INCLUDED #include <string> namespace S11N_NAMESPACE { class s11n_node; // forward decl /** serializable plays several roles: - used to develop conventions used by the de/serialize()-related functions of the core s11n classes (mainly s11n_node). - following the conventions set by s11n_node, it acts as a default base class implementation for a serializable hierarchy. - defines a reference implementation for these oft-mentioned s11n_node conventions. Client classes can immediately start subclassing this class and get to work serializing their objects. An alternative, for those who want to be serializable but not serializable, is described elsewhere. (The the lib manual.) serializable is technically not part of the core library, except in the sense that it is used as a testing ground for framework-level conventions. See the extensive docs in the library manual for more detail than you could want to know about this interface. */ class serializable { public: serializable(); // const std::string & implclassname = "S11N_NAMESPACE::serializable" ); virtual ~ serializable(); /** Serializes this object into the given node. Returns true on success and false on error. The default implementation returns false only if this->impl_class() is not set. (It /should/ return false if node.name().empty(), but that breaks some otherwise-legitimate usage.) It is important that you either call the default implementation of this function or call node.impl_class( this->impl_class() ), so that the proper implementation class name can be set for deserialization. e.g.: <pre> if( ! this->serializable::serialize( node ) ) return false; </pre> To recursively serialize child objects use one of node's various serialize() functions. This function really should be called serialize(), but it is not because: - i am attempting to keep the core library clean of serializable, and the function rename is an easy way to help enforce that. - i needed a test-bed for serializable_adapter ;) */ virtual bool s7e( S11N_NAMESPACE::s11n_node & node ) const; /** Deserializes this object from the given node. Returns true on success and false on error, in which case this object is in an undefined state and is probably best destroyed. To recursively deserialize child objects use one of node's various deserialize() functions or the child's deserialize() - the exact approach depends largely on whether you are using pointers to the children or not. See s7e() for notes regarding this function's odd name. */ virtual bool d9e( const S11N_NAMESPACE::s11n_node & ); }; }; // namespace S11N_NAMESPACE #include <S11N_NAMESPACE/serializable_adapter.h> SERIALIZABLE_ADAPTER(S11N_NAMESPACE::serializable,s7e,d9e); // this is the // only sane place to put this, i think? #endif // S11N_NAMESPACE_SERIALIZABLE_H_INCLUDED --- NEW FILE: ns.serializer.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <iostream> #include <sstream> #include <string> #include <map> #include <S11N_NAMESPACE/class_loader.h> #include <S11N_NAMESPACE/instantiator.h> // object_factory #include <S11N_NAMESPACE/flex_lexers.h> #include <S11N_NAMESPACE/string_util.h> // escape_string(), translate_chars() #include <S11N_NAMESPACE/s11n_io.h> #include <S11N_NAMESPACE/s11n_globals.h> // xml_entity_map(). #include <S11N_NAMESPACE/debuggering_macros.h> // COUT/CERR, for debugging only. namespace S11N_NAMESPACE { basic_serializer::basic_serializer(){}; basic_serializer::~basic_serializer(){}; bool basic_serializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !os ) return false; // arguable: if ( node.name().empty() || node.impl_class().empty() ) return false; return true; } bool basic_serializer::serialize( const s11n_node & node, const std::string & filename ) const { std::auto_ptr<std::ostream> os = std::auto_ptr<std::ostream>( S11N_NAMESPACE::get_ostream( filename ) ); if ( !os.get() ) return false; return serialize( node, *os ); } s11n_node * basic_serializer::deserialize( std::istream & ) { return NULL; } s11n_node * basic_serializer::deserialize( const std::string &filename ) { std::auto_ptr<std::istream> is = std::auto_ptr<std::istream>( S11N_NAMESPACE::get_istream( filename ) ); if ( !is.get() ) return false; return deserialize( *is ); } s11n_node * basic_serializer::deserialize( FlexTreeBuilder & parser, std::istream & is ) { if ( ! is.good() ) return NULL; s11n_node * node = 0; parser.lexer()->switch_streams( &is ); parser.lexer_loop(); node = parser.root_node(); parser.builder()->auto_delete( false ); // tell it not to delete the node. return node; } const basic_serializer::translation_map & basic_serializer::translations() const { static translation_map bob; return bob; } FunTxtSerializer::FunTxtSerializer() { }; FunTxtSerializer::~FunTxtSerializer() { }; s11n_node * FunTxtSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::FunTxt parser; return basic_serializer::deserialize( parser, is ); } const basic_serializer::translation_map & FunTxtSerializer::translations() const { static basic_serializer::translation_map bob; static bool donethat = false; if( (!donethat) && (donethat=true) ) { // the order of these escapes is signifant. // We only do double-backslashes to accomodate // the case that the final char in a property // is a backslash (yes, this has happened, and // it hosed the input). bob["\\"] = "\\\\"; bob["\n"] = "\\\n"; bob["{"] = "\\{"; bob["}"] = "\\}"; } return bob; } bool FunTxtSerializer::serialize( const s11n_node & node, std::ostream & os ) const { //COUT << "serialize( s11n_node["<<node.name()<<"|"<<node.impl_class()<<"] )"<<endl; if ( !basic_serializer::serialize( node, os ) ) return false; static const std::string tab = "\t"; static unsigned int depth = 0; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); // if( nname.empty() || impl.empty() ) // { // } std::string indent; for ( unsigned int i = 1; i < depth; i++ ) indent += tab; std::string indent2 = indent + tab; if ( 1 == depth ) { os << "#SerialTree 1\n"; } if ( !nname.empty() ) os << indent << nname << " class=" << impl << "\n"; os << indent << "{\n"; S11N_NAMESPACE::property_store::const_iterator it = node.begin(); S11N_NAMESPACE::property_store::const_iterator et = node.end(); std::string propval; for ( ; it != et; ++it ) { propval = (*it).second; // arguable: S11N_NAMESPACE::trim_string( propval ); S11N_NAMESPACE::translate_entities( propval, this->translations() ); os << indent2 << ( *it ).first << " " << propval << "\n"; } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); bool ret = true; if ( cit != cet ) { for ( ; cit != cet; ++cit ) { if ( !this->serialize( *( *cit ), os ) ) ret = false; } } os << indent << "}" << std::endl; // if we don't use endl the client is possibly forced to flush() the stream :/ //os << indent << "# end " << nname << std::endl; --depth; return ret; } FunXMLSerializer::FunXMLSerializer() { }; FunXMLSerializer::~FunXMLSerializer() { }; // bool deserialize( s11n_node & target, const std::istream & ) { return false; } const basic_serializer::translation_map & FunXMLSerializer::translations() const { static basic_serializer::translation_map bob; if( 0 == bob.size() ) { bob["&"] = "&"; bob["\""] = """; bob["'"] = "'"; bob[">"] = ">"; bob["<"] = "<"; } return bob; } bool FunXMLSerializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !basic_serializer::serialize( node, os ) ) return false; static const std::string tab = "\t"; static unsigned int depth = 0; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); std::string indent; for ( unsigned int i = 1; i < depth; i++ ) indent += tab; std::string indent2 = indent + tab; if ( 1 == depth ) { os << "<!DOCTYPE SerialTree>\n"; } os << indent << "<" << nname << " class=\"" << impl << "\">\n"; S11N_NAMESPACE::property_store::const_iterator it = node.property_store::begin(); S11N_NAMESPACE::property_store::const_iterator et = node.property_store::end(); std::string propval; if ( it != et ) { for ( ; it != et; ++it ) { propval = ( *it ).second; S11N_NAMESPACE::translate_entities( propval, this->translations(), false ); os << indent2; os << "<" << ( *it ).first << ">" << propval << "</" << ( *it ).first << ">"; os << "\n"; } } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); if ( cit != cet ) { for ( ; cit != cet; ++cit ) { this->serialize( *( *cit ), os ); } } os << indent << "</" << nname << ">" << std::endl; // if we don't use endl the client is possibly forced to flush() the stream :/ --depth; return os; } s11n_node * FunXMLSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::FunXML parser; return basic_serializer::deserialize( parser, is ); } SimpleXMLSerializer::SimpleXMLSerializer() { }; SimpleXMLSerializer::~SimpleXMLSerializer() { }; const basic_serializer::translation_map & SimpleXMLSerializer::translations() const { static basic_serializer::translation_map bob; if( 0 == bob.size() ) { bob["&"] = "&"; bob["\n"] = "
"; bob["\""] = """; bob["'"] = "'"; bob[">"] = ">"; bob["<"] = "<"; } return bob; } bool SimpleXMLSerializer::serialize( const s11n_node & node, std::ostream & os ) const { if ( !basic_serializer::serialize( node, os ) ) return false; static const std::string tab = "\t"; static unsigned int depth = 0; ++depth; std::string nname = node.name(); std::string impl = node.impl_class(); std::string indent; for ( unsigned int i = 1; i < depth; i++ ) indent += tab; std::string indent2 = indent + tab; if ( 1 == depth ) { os << "<!DOCTYPE S11N_NAMESPACE::simplexml>\n"; } os << indent << "<" << nname; os << " s11n_class=\"" << impl << "\""; std::string pname, pval; S11N_NAMESPACE::property_store::const_iterator it = node.property_store::begin(); S11N_NAMESPACE::property_store::const_iterator et = node.property_store::end(); if ( it != et ) { for ( ; it != et; ++it ) { if ( "CDATA" == ( *it ).first ) continue; // special treatment later on pname = (*it).first; pval = (*it).second; // S11N_NAMESPACE::escape_string( pval, "\"" ); S11N_NAMESPACE::translate_entities( pval, this->translations(), false ); os << " " << pname << "=\"" << pval << "\""; } } //os << ">"; bool use_closer = false; // if false then an element can <close_itself /> if ( node.is_set( "CDATA" ) ) { os << ">"; use_closer = true; os << "<![CDATA[" << node.get_string( "CDATA" ) << "]]>"; //cdata << "<![CDATA[" << node.get_string( "CDATA" ) << "]]>"; } s11n_node::child_list_type::const_iterator cit = node.children().begin(); s11n_node::child_list_type::const_iterator cet = node.children().end(); bool tailindent = false; if ( cit != cet ) { if( ! use_closer ) os << ">"; use_closer = true; tailindent = true; for ( ; cit != cet; ++cit ) { os << "\n" << indent2; // asthetics :/ this->serialize( *( *cit ), os ); } os << "\n"; } os << ( tailindent ? indent : "" ); if( use_closer ) { os << "</" << nname << ">"; } else { os << " />"; } --depth; if( 0 == depth ) os << std::endl; // if we don't use endl the client is possibly forced to flush() the stream :/ return os; } s11n_node * SimpleXMLSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::SimpleXMLFlexer parser; return basic_serializer::deserialize( parser, is ); } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.serializer.h --- #ifndef S11N_NAMESPACE_SERIALIZER_H_INCLUDED #define S11N_NAMESPACE_SERIALIZER_H_INCLUDED 1 // // Author: stephan beal <st...@s1...> // License: Public Domain // This file defines interfaces for saving/loading s11n_node and // serializable objects. // #include <sstream> #include <memory> // auto_ptr #include <iostream> #include <map> #include <S11N_NAMESPACE/file_util.h> #include <S11N_NAMESPACE/s11n_node.h> #include <S11N_NAMESPACE/flex_lexers.h> // FlexTreeBuilder namespace S11N_NAMESPACE { /** serializer defines an interface for s11n_node importers and exporters (i.e., the classes which save and load s11n_nodes to various underlying data formats). The default implementation does nothing useful, but is not pure abstract for reasons which i have yet to figure out. :/ Note that the sometimes awkward usage of this class and it's relatives is largely a side-effect of the hassle i went through to get multiple FlexLexer subclasses into the same library. Subclasses should honor the following: - De/serialized objects can always be expected to use (or have consistent access to) an s11n_node's get<>(), set<>() and children() methods, plus any of the public de/serializeXXX() functions. Any additional functionality which a de/serializer provides must be accounted for in serializable subclasses if they are expected to use this. An example of such a case is the handling of CDATA when reading XML: the s11n_node interface has no "good" place to put this, so the SimpleXMLSerializer simply puts the data in the node's CDATA property, and clients which expect CDATA at that location can use it. Likewise, the SimpleXML saver writes anything from the CDATA property as XML CDATA. - feel free to add to this interface, but be warned that getting access to a specific FlexLexer subclass in this code (required for lex-based deserialization) is annoying enough that you might not want to do so. (God, if only FlexLexer didn't rely on macros to define subclasses...) - um... there must be something else i'm forgetting to tell you. Dev/design note: it is important to me that the core s11n code never develop a dependency on any of this interface. */ class basic_serializer { public: /** A convenience typedef, mainly for subclasses. */ typedef std::map<std::string,std::string> translation_map; basic_serializer(); virtual ~basic_serializer(); /** The default implementations of de/serialize() always return true and do nothing. This function is unfortunately mis-named: s11n_node is not a serializable type. They SHOULD return false if either node.name() or node.impl_class() is empty, and that is under consideration. (todo: make sure that gets considered at some point.) */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; /** Convenience form of deserialize() which takes a filename. */ bool serialize( const s11n_node & node, const std::string & filename ) const; /** Serializes ser to the given ostream, using the node name nodename. Use this to write a serializable as a root data node without having to create an intermediary s11n_node (that will be done in this function). */ template <typename serializableType> bool serialize( const std::string & nodename, const serializableType & ser, std::ostream & os ) const { if ( !os ) return false; s11n_node root( nodename ); // , ser.impl_class() ); if( ! root.serialize( ser ) ) return false; return this->serialize( root, os ); } /** Saves the given serializable to the given filename, using a root node name of nodename. Returns true on success, false on error. In practice, s11n_node::serialize() fails very rarely, so an error is most likely indicative of a file/stream-level problem (access rights, for example). To get the exact reason for a failure the code must do the Holy Ritual of Meyers-Stallman four times successively in proper style and comfortable clothing. */ template <typename serializableType> bool serialize( const std::string & nodename, const serializableType & ser, const std::string & filename ) const { std::auto_ptr<std::ostream> os = std::auto_ptr<std::ostream>( S11N_NAMESPACE::get_ostream( filename ) ); if ( !os.get() ) return false; return serialize( nodename, ser, *os ); } /** Returns the first node extraced from the given input stream. The default implementation always returns NULL. The caller takes ownership of the returned pointer. This function is unfortunately mis-named: s11n_node is not a serializable type. */ virtual s11n_node * deserialize( std::istream & ); /** Convenience form of deserialize(), taking a filename. It handles compressed files if that is enabled in your library. */ s11n_node * deserialize( const std::string & filename ); /** Returns a map intended for use with S11N_NAMESPACE::translate_entities(). Subclasses should re-implement this to escape/unescape property values. The default implementation returns an empty map. */ virtual const translation_map & translations() const; protected: /** To reduce code duplication in subclasses. It uses the given FlexTreeBuilder to parse the given input stream and returns the top-most node in the tree. The parser is relenquished of control of the returned node, and the caller takes responsibility for it. */ s11n_node * deserialize( FlexTreeBuilder & parser, std::istream & ); }; /** De/serializes nodes to/from a simple-grammared text format. See the FunTxt class (in flex_lexers.h) for details on the data format. The lexer code lives in funtxt.flex.at. Sample: <pre> #SerialTree 1 node_name class=NodeClass { property_name property value subnode_name class=SubnodeClass { prop val prop2 values can be arbitrarily long \ and may contain backslash-escaped newlines. } } </pre> */ class FunTxtSerializer : public basic_serializer { public: FunTxtSerializer(); virtual ~ FunTxtSerializer(); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Returns a map intended for use with S11N_NAMESPACE::translate_entities(). Clients may use this to escape/unescape property values. Output Translations: <pre> "\" = "\\" "\n" = "\\n" "{" = "\{" "}" = "\}" </pre> At input-time the reverse translations are applied. */ virtual const translation_map & translations() const; }; /** De/serializes nodes to/from a simple-grammared XML format. See the FunXML class (in flex_lexers.h) for details on the data format. The lexer code lives in funxml.flex.at. Sample: <pre> <!DOCTYPE SerialTree> <node_name class="NodeClass"> <property_name>property value</property_name> <subnode_name class="SubnodeClass"> <prop>val</prop> <prop2>val</prop2> </subnode_name> </node_name> </pre> */ class FunXMLSerializer : public basic_serializer { public: FunXMLSerializer(); virtual ~ FunXMLSerializer(); /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; /** Returns a map intended for use with S11N_NAMESPACE::translate_entities(). Clients may use this to escape/unescape property values. Output Translations: <pre> "&" = "&" "\"" = """ "'" = "'" ">" = ">" "<" = "<" </pre> (Note: in the HTML version of these docs the above almost certainly doesn't display properly!) At input-time the reverse translations are applied. */ virtual const translation_map & translations() const; }; /** De/serializes nodes to/from a basic XML format. All s11n_node properties are stored as XML attributes, thus this format is not suitable for some complex string data. As a special case this object handles XML CDATA as described below. - Serialization: if the s11n_node.has a CDATA property that is saved as CDATA and the property is NOT saved in the attributes list. - Deserialization: if an XML has CDATA then the s11n_node's CDATA property is set to that content. (Format-neutral as it is, s11n_node has no specific place to store CDATA, thus we kludge it.) No current client code uses the CDATA property, but this seems a reasonable approach for clients who can use it. i mean, the parser parses it, so it might was well get used, right? i think the "right" thing to do is ignore the CDATA altogether and assign everything in it's own property. See the simplexml.flex.at for the supported grammar. Sample: <pre> <!DOCTYPE S11N_NAMESPACE::simplexml> <node_name s11n_class="NodeClass" property_name="property value"> <subnode_name s11n_class="SubnodeClass" prop="val" prop2="val" /> </node_name> </pre> */ class SimpleXMLSerializer:public basic_serializer { public: SimpleXMLSerializer(); virtual ~ SimpleXMLSerializer(); /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; /** <pre> "&" = "&" "\"" = """ "'" = "'" ">" = ">" "<" = "<" "\n" = "
" </pre> (Note: in the HTML version of these docs the above almost certainly doesn't display properly!) */ virtual const translation_map & translations() const; }; /** paren_serializer supports an almost-like-lisp grammar. The lexer code lives in paren.flex.at. The impl for this class in in paren_serializer.cpp and the lexer is in paren.flex.at. Sample: <pre> (S11N_NAMESPACE::parens) root_node=(NodeClass (property_name property value) (* comment block *) # comment line ; comment line subnode_name=(SubnodeClass # comment to end of line (prop val) (prop2 val2) (prop_escaped \(parens in vals\) must be escaped) ) ) </pre> // Historical note: it is technical unnecessary to escape opening parens in property values, // but escaping them is "required" because this format is meant to be hand-editable and hand-editable // inherently means EMACS... the fact is, however, that if values have escaped closing parens, // yet opening parens are not escaped, emacs' auto-indention mode gets unhappy. :( */ class paren_serializer : public basic_serializer { public: paren_serializer(); virtual ~paren_serializer(); /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; /** Returns a map intended for use with S11N_NAMESPACE::translate_entities(). Clients may use this to escape/unescape property values. Output Translations: <pre> "\" = "\\" "(" = "\(" ")" = "\)" </pre> At input-time the reverse translations are applied. */ virtual const translation_map & translations() const; }; #define DISABLE_HEXSERIALIZER 1 #if ! DISABLE_HEXSERIALIZER /** Reads/writes serialized data from/to a very bloated, hex-code-based format. It is not human readable and output files are significantly larger than those of most serializers. The impl for this class in in hex_serializer.cpp and the lexer is in hex.flex.at. Sample: <pre> 51190001 11096e6f64655f6e616d65094... </pre> */ class hex_serializer : public basic_serializer { public: /** This enum defines the control tokens used to delimit records. If these are changed then the input parser needs to accomodate the changes (it lives in hex.flex.at). Maintenance note: control tokens should be exactly 4 bytes long and cookies should be 8. */ enum { Magic_Cookie = 0x51190001, // that's as close as i can get to S11N Node_Open = 0x11, Node_Close = 0x10, Prop_Open = 0x21, Data_End = 0x51190000 // not strictly necessary }; hex_serializer(); virtual ~ hex_serializer(); /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; }; #endif // DISABLE_HEXSERIALIZER /** Read/writes serialized data from/to an almost-binary format. The impl for this class is in compact_serializer.cpp and the lexer is in compact.flex.at Sample: <pre> 51191001 f109node_name09NodeClasse10dproperty_name0000000eproperty value... </pre> */ class compact_serializer : public basic_serializer { public: /** This enum defines the control tokens used to delimit records. If these are changed then the input parser needs to accomodate the changes (it lives in compact.flex.at). Maintenance note: control tokens should be exactly 2 bytes long and cookies should be 8. */ enum { Magic_Cookie = 0x51191001, Node_Open = 0xf1, Node_Close = 0xf0, Prop_Open = 0xe1, Data_End = 0x51191000 // not strictly necessary }; compact_serializer(); virtual ~ compact_serializer(); /** Tries to deserialize an s11n_node from the given istream. Returns the node extracted from the stream, or NULL on error. The caller owns the returned pointer. */ virtual s11n_node * deserialize( std::istream & ); /** Serializes node to the given ostream. */ virtual bool serialize( const s11n_node & node, std::ostream & os ) const; }; } // namespace S11N_NAMESPACE #endif // S11N_NAMESPACE_SERIALIZER_H_INCLUDED Index: Makefile =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/Makefile,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- Makefile 17 Nov 2003 20:28:20 -0000 1.5 +++ Makefile 19 Nov 2003 22:11:54 -0000 1.6 @@ -4,30 +4,30 @@ S11N_NAMESPACE ?= s11n NS_SOURCES = \ - ns.CompactSerializer.cpp \ - ns.ParenSerializer.cpp \ + ns.compact_serializer.cpp \ + ns.paren_serializer.cpp \ ns.s11n_io.cpp \ ns.s11n_node.cpp \ ns.node_builder.cpp \ ns.node_loader.cpp \ - ns.Serializable.cpp \ - ns.Serializer.cpp \ + ns.serializable.cpp \ + ns.serializer.cpp \ ns.serializer_loader.cpp \ ns.s11n_globals.cpp # buggy: -# HexSerializer.cpp +# hex_serializer.cpp NS_HEADERS = \ - ns.S11n.h \ + ns.s11n.h \ ns.s11n_io.h \ ns.s11n_node.h \ ns.node_builder.h \ ns.node_loader.h \ - ns.Serializable.h \ + ns.serializable.h \ ns.serializable_adapter.h \ - ns.Serializer.h \ + ns.serializer.h \ ns.serializer_loader.h \ ns.s11n-macros.h \ ns.s11n_globals.h @@ -44,7 +44,7 @@ NAMESPACE = $(S11N_NAMESPACE) NAMESPACE_TOKEN = S11N_NAMESPACE -NAMESPACE_PREFIX = ns. +NAMESPACE_PREFIkX = ns. NAMESPACE_FILTERED_FILES = $(SOURCES) $(HEADERS) namespace: $(NAMESPACE_FILTERED_FILES) include $(toc_makesdir)/NAMESPACE.make Index: ns.include_from_main.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.include_from_main.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.include_from_main.h 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.include_from_main.h 19 Nov 2003 22:11:54 -0000 1.2 @@ -2,13 +2,13 @@ #define S11N_INCLUDE_FROM_MAIN_H #include <S11N_NAMESPACE/serializable_adapter.h> -#include <S11N_NAMESPACE/Serializable.h> +#include <S11N_NAMESPACE/serializable.h> // contains code which must, for linking reasons, // be defined only once, in the client's main app. // ======= fuck: clients must include this line in their main app. -// SERIALIZABLE_ADAPTER(S11N_NAMESPACE::Serializable,s7e,d9e); +// SERIALIZABLE_ADAPTER(S11N_NAMESPACE::serializable,s7e,d9e); // ======= if they don't then they don't get this specialization // and the lib won't link, because this code won't get linked // into libs11n. Index: ns.node_builder.cpp =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.node_builder.cpp,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.node_builder.cpp 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.node_builder.cpp 19 Nov 2003 22:11:54 -0000 1.2 @@ -13,7 +13,7 @@ #include <S11N_NAMESPACE/serializable_adapter.h> #include <S11N_NAMESPACE/s11n_node.h> -#include <S11N_NAMESPACE/Serializable.h> +#include <S11N_NAMESPACE/serializable.h> #define LEXER_LOUD 0 @@ -67,7 +67,7 @@ bool node_builder::open_node( const std::string & classname, const std::string & name ) { - typedef class_loader < S11N_NAMESPACE::Serializable > SerLoader; + typedef class_loader < S11N_NAMESPACE::serializable > SerLoader; static SerLoader classLoader; ++m_node_count; Index: ns.node_loader.cpp =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.node_loader.cpp,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.node_loader.cpp 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.node_loader.cpp 19 Nov 2003 22:11:54 -0000 1.2 @@ -4,7 +4,7 @@ #include <iostream> #include <memory> // auto_ptr -#include <S11N_NAMESPACE/Serializer.h> +#include <S11N_NAMESPACE/serializer.h> // #include <S11N_NAMESPACE/s11n_io.h> #include <S11N_NAMESPACE/debuggering_macros.h> // COUT/CERR #include <S11N_NAMESPACE/string_util.h> //trim_string() @@ -52,7 +52,7 @@ std::auto_ptr<basic_serializer> ser = std::auto_ptr<basic_serializer>( bobTheLoader.load( cookie ) ); if( ! (ser.get()) ) { - CERR << "Did not find Serializer for cookie ["<<cookie<<"]."<<std::endl; + CERR << "Did not find serializer for cookie ["<<cookie<<"]."<<std::endl; return NULL; } return ser->deserialize( is ); Index: ns.node_loader.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.node_loader.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.node_loader.h 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.node_loader.h 19 Nov 2003 22:11:54 -0000 1.2 @@ -14,7 +14,7 @@ class s11n_node; // forward decl /** - node_loader is a convenience class for loading Serializables + node_loader is a convenience class for loading serializables from files. It is similar to FlexTreeBuilder::loadBuilder(), but: - operates MUCH differently. @@ -58,9 +58,9 @@ /** Looks at the first few bytes of the given stream - and tries to find a Serializer for it. If it finds + and tries to find a serializer for it. If it finds none it returns NULL. If it finds one it returns - whatever that Serializer's deserialize() method + whatever that serializer's deserialize() method returns. See S11N_NAMESPACE::basic_serializer and S11N_NAMESPACE::serializer_loader. Index: ns.s11n_globals.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.s11n_globals.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.s11n_globals.h 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.s11n_globals.h 19 Nov 2003 22:11:54 -0000 1.2 @@ -28,14 +28,14 @@ /** UNTESTED. - Tries to deserialize a SerializableT from the input + Tries to deserialize a serializableT from the input stream. Returns a new object on success and NULL on error. The caller owns the returned pointer. */ - template <typename SerializableT> - static SerializableT * load_serializable( std::istream & istr ) + template <typename serializableT> + static serializableT * load_serializable( std::istream & istr ) { static node_loader bob; std::auto_ptr<s11n_node> node = std::auto_ptr<s11n_node>( bob.load( istr ) ); @@ -43,24 +43,24 @@ { return NULL; } - return node->s11n_node::deserialize<SerializableT>(); + return node->s11n_node::deserialize<serializableT>(); } /** UNTESTED. - Tries to deserialize a SerializableT from the input + Tries to deserialize a serializableT from the input stream. Returns a new object on success and NULL on error. The caller owns the returned pointer. */ - template <typename SerializableT> - static SerializableT * load_serializable( const std::string & file ) + template <typename serializableT> + static serializableT * load_serializable( const std::string & file ) { std::auto_ptr<std::istream> istr = std::auto_ptr<std::istream>( get_istream( file ) ); if( ! (istr.get()) ) return NULL; - return load_serializable<SerializableT>( *istr ); + return load_serializable<serializableT>( *istr ); } Index: ns.s11n_io.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.s11n_io.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.s11n_io.h 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.s11n_io.h 19 Nov 2003 22:11:54 -0000 1.2 @@ -5,7 +5,7 @@ // Author: stephan beal <st...@s1...> // License: Public Domain // This file defines interfaces for saving/loading s11n_node and -// Serializable objects. +// serializable objects. // #include <sstream> @@ -17,7 +17,7 @@ // #endif #include <S11N_NAMESPACE/file_util.h> // get_ostream(), get_istream() -#include <S11N_NAMESPACE/Serializer.h> +#include <S11N_NAMESPACE/serializer.h> namespace S11N_NAMESPACE { @@ -26,17 +26,17 @@ DefaultS11nType is a typedef for default saver/loader type used by s11n_io for de/serializing from/to iostreams. - It must be an S11N_NAMESPACE::Serializer type. + It must be an S11N_NAMESPACE::serializer type. */ typedef S11N_NAMESPACE::FunXMLSerializer DefaultS11nType; /** s11n_io is a convenience (ha ha) class for saving/loading - s11n_nodes and Serializables. + s11n_nodes and serializables. - The templatized parameter, SerializerT, must be a subtype - of S11N_NAMESPACE::Serializer. + The templatized parameter, serializerT, must be a subtype + of S11N_NAMESPACE::serializer. A note about the static functions: whether they should be static or not is mainly a maintenance-related question. i @@ -61,18 +61,18 @@ determine whether to write non/compressed files, so set any preference via that function. */ - template < typename SerializerT = DefaultS11nType > + template < typename serializerT = DefaultS11nType > class s11n_io { /** Convenience typedef */ - typedef s11n_io<SerializerT> ThisType; + typedef s11n_io<serializerT> ThisType; public: /** - This type of Serializer this class uses. + This type of serializer this class uses. */ - typedef SerializerT serializer_type; + typedef serializerT serializer_type; /** Saves node to the given output stream. Returns Index: ns.s11n_node.h =================================================================== RCS file: /cvsroot/libfunutil/libfunutil/lib/s11n/ns.s11n_node.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- ns.s11n_node.h 17 Nov 2003 20:28:22 -0000 1.1 +++ ns.s11n_node.h 19 Nov 2003 22:11:54 -0000 1.2 @@ -207,13 +207,13 @@ /** Returns the current classloader for the given - SerializableType. + serializableType. */ - template <class SerializableType> - static class_loader<SerializableType> & classloader() + template <class serializableType> + static class_loader<serializableType> & classloader() { return context_singleton< - dll_loader<SerializableType>, + dll_loader<serializableType>, s11n_node >::instance(); } @@ -221,22 +221,22 @@ /** Tries to create a new object of the type named in this->impl_class(). If that class cannot be loaded - by class_loader<SerializableType> then NULL is + by class_loader<serializableType> then NULL is returned. It next tries to deserialize() the new object, passing it (*this). If that fails, the new child is deleted and NULL is returned. - If all else goes peachy, a (SerializableType *) is + If all else goes peachy, a (serializableType *) is returned, which the caller takes ownership of. */ - template <class SerializableType> - SerializableType * deserialize() const + template <class serializableType> + serializableType * deserialize() const { const std::string classname = this->impl_class(); - SerializableType *tgt = 0; - tgt = this->classloader<SerializableType>().load( classname ); + serializableType *tgt = 0; + tgt = this->classloader<serializableType>().load( classname ); ... [truncated message content] |