Update of /cvsroot/libfunutil/libfunutil/lib/s11n In directory sc8-pr-cvs1:/tmp/cvs-serv27725/lib/s11n Modified Files: Makefile Added Files: ns.CompactSerializer.cpp ns.FileLoader.cpp ns.FileLoader.h ns.HexSerializer.cpp ns.include_from_main.h ns.node_builder.cpp ns.node_builder.h ns.node_loader.cpp ns.node_loader.h ns.ParenSerializer.cpp ns.S11n.cpp ns.s11n_globals.cpp ns.s11n_globals.h ns.S11n.h ns.s11n_io.cpp ns.s11n_io.h ns.s11n-macros.h ns.s11n_node.cpp ns.s11n_node.h ns.serializable_adapter.h ns.Serializable.cpp ns.Serializable.h ns.Serializer.cpp ns.Serializer.h ns.serializer_loader.cpp ns.serializer_loader.h Log Message: egg --- NEW FILE: ns.CompactSerializer.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 { CompactSerializer::CompactSerializer() { }; CompactSerializer::~CompactSerializer() { }; s11n_node * CompactSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::CompactTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool CompactSerializer::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.FileLoader.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <S11N_NAMESPACE/FileLoader.h> #include <S11N_NAMESPACE/flex_lexers.h> // FlexTreeBuilder #include <S11N_NAMESPACE/s11n-macros.h> // BROKEN() namespace S11N_NAMESPACE { s11n_node * FileLoader::loadNode( const std::string & key ) const { std::string path = this->path_finder::find( key ); if( path.empty() ) return NULL; FlexTreeBuilder * bob = FlexTreeBuilder::loadBuilder( path ); if( ! bob ) return NULL; s11n_node * node = 0; if( bob->builder() ) { node = bob->root_node(); bob->builder()->autoDelete( false ); // we take control of node. } delete( bob ); return node; } } // namespace S11N_NAMESPACE --- NEW FILE: ns.FileLoader.h --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #ifndef S11N_NAMESPACE_S11NFILELOADER_H_INCLUDED #define S11N_NAMESPACE_S11NFILELOADER_H_INCLUDED 1 #include <string> #include <S11N_NAMESPACE/path_finder.h> #include <S11N_NAMESPACE/s11n_node.h> namespace S11N_NAMESPACE { /** A classloader for loading Serializable classes from files, plus a convenience class for loading files from arbitrary data types, without having to know the type nor if it is compressed or not. */ class FileLoader : public S11N_NAMESPACE::path_finder { public: typedef FileLoader ThisType; // typedef dll_loader ParentClass; // typedef ParentClass::value_type value_type; // typedef ParentClass::key_type key_type; FileLoader(){}; virtual ~ FileLoader(){}; /** First tries to load key via the ancestor's method(s), and returns that pointer if it works. Secondly it tries to find file key in this->path() and return a new value_type * if it can deserialize an object of that type from that file. The caller owns the returned pointer, which may be NULL. Note that the input file may be in any format internally supported by the library. */ template <typename SerializableType> SerializableType * load( const std::string & filename ) const { typedef SerializableType ST; s11n_node * node = FileLoader::loadNode( key ); if( node ) { ST * ch = 0; /** Grief!!!! gcc 3.3 refuses to compile this: ch = node->deserialize<ST>(); error is: parse error before `;' token but it allows the exact same code in some other contexts!!! A workaround is to qualify s11n_node's class, but that breaks polymorphism!!! deserialize() is a template func, so it can't be virtual, but that's beside the point! */ ch = node->s11n_node::deserialize<ST>(); delete( node ); } return ch; } /** Tries to load the root s11n_node from the input file. The caller owns the pointer. This is similar to load(), but the returned object is not deserialized (indeed, it is not Serializable). This function supports all current Serializer data formats, uncompressed or compressed (assuming the suitable decompressor is enabled in your library). */ s11n_node * loadNode( const std::string & ) const; }; // class FileLoader }; // namespace S11N_NAMESPACE #endif // S11N_NAMESPACE_S11NFILELOADER_H_INCLUDED --- NEW FILE: ns.HexSerializer.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 { HexSerializer::HexSerializer() { }; HexSerializer::~HexSerializer() { }; s11n_node * HexSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::HexTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool HexSerializer::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.include_from_main.h --- #ifndef S11N_INCLUDE_FROM_MAIN_H #define S11N_INCLUDE_FROM_MAIN_H #include <S11N_NAMESPACE/serializable_adapter.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); // ======= 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. #endif // S11N_INCLUDE_FROM_MAIN_H --- NEW FILE: ns.node_builder.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <deque> #include <cassert> #include <S11N_NAMESPACE/s11n-macros.h> // CERR macro #include <S11N_NAMESPACE/pointer_list.h> #include <S11N_NAMESPACE/class_loader.h> #include <S11N_NAMESPACE/node_builder.h> #include <S11N_NAMESPACE/serializable_adapter.h> #include <S11N_NAMESPACE/s11n_node.h> #include <S11N_NAMESPACE/Serializable.h> #define LEXER_LOUD 0 #define LOUT if(LEXER_LOUD) COUT #define lout if(LEXER_LOUD) cout namespace S11N_NAMESPACE { node_builder::node_builder( ):m_autodel( true ), m_node_count( 0 ), m_node( 0 ), m_root( 0 ) { } node_builder::~node_builder( ) { m_toplist.auto_delete( this->m_autodel ); } void node_builder::auto_delete( bool b ) { this->m_autodel = b; } bool node_builder::auto_delete( ) { return this->m_autodel; } unsigned long node_builder::node_count( ) const { return m_node_count; } unsigned long node_builder::node_depth( ) const { return m_nodestack.size( ); } bool node_builder::add_property( const std::string & key, const std::string & val ) { if ( !m_node ) return false; // if ( LEXER_LOUD ) // { // LOUT << node_depth( ) << " "; // for ( unsigned int i = 1; i < node_depth( ); i++ ) // lout << " "; // lout << "add_property(" << key << "," << val << ") [" << m_node->name( ) << "]" << endl; // } m_node->set( key, val ); return true; } bool node_builder::open_node( const std::string & classname, const std::string & name ) { typedef class_loader < S11N_NAMESPACE::Serializable > SerLoader; static SerLoader classLoader; ++m_node_count; m_node = ( m_nodestack.empty( )? NULL : m_nodestack.back( ) ); s11n_node * newnode = new s11n_node( ); if ( m_node ) { m_node->children( ).push_back( newnode ); } m_node = newnode; m_nodestack.push_back( m_node ); m_node->name( name ); m_node->impl_class( classname ); // if ( LEXER_LOUD ) // { // LOUT << node_depth( ) << " "; // for ( unsigned int i = 1; i < node_depth( ); i++ ) // lout << " "; // lout << "open_node(): new node [" << m_node->name( ) << "] [" << classname << "]" << endl; // } if ( 1 == node_depth( ) ) { m_root = m_node; m_toplist.push_back( m_node ); } return true; } bool node_builder::close_node( ) { if ( !m_node || m_nodestack.empty( ) ) { CERR << "close_node() error: called with an empty node stack!" << std::endl; assert( 0 /* close_node() error: called with an empty node stack! */ ); return false; } // if ( LEXER_LOUD ) // { // LOUT << node_depth( ) << " "; // for ( unsigned int i = 1; i < node_depth( ); i++ ) // lout << " "; // lout << "close_node() [" << m_node->impl_class( ) << "," << m_node->name( ) << "]" << endl; // } m_nodestack.pop_back( ); //LOUT << "last m_node=["<<*m_node<<"]" << endl; if ( m_nodestack.empty( ) ) { m_node = NULL; } else { m_node = m_nodestack.back( ); } return true; } node_builder::node_list_type & node_builder::root_nodes( ) { return m_toplist; } s11n_node *node_builder::root_node( ) { return m_root; } s11n_node * node_builder::current_node( ) { return m_node; } void node_builder::node_count( unsigned long c ) { this->m_node_count = c; } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.node_builder.h --- #ifndef S11N_NAMESPACE_S11NNODEBUILDER_H_INCLUDED #define S11N_NAMESPACE_S11NNODEBUILDER_H_INCLUDED 1 // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <deque> #include <cassert> #include <S11N_NAMESPACE/pointer_list.h> namespace S11N_NAMESPACE { class s11n_node; // forward decl /** node_builder is a helper class for building trees from deserialized data, designed particularly for use with lex/callback-based tree builders. It is experimental. Note that it owns all objects which build up it's tree. If you want them you must manually remove them from the container. You normally do not want them, however - they're mostly throwaway s11n_nodes on their way to becoming fully deserialized objects. This class only provides methods for building a tree, not for traversing it. Once you have built a tree, traverse it starting at the root_node(). */ class node_builder { public: typedef S11N_NAMESPACE::pointer_list < s11n_node > node_list_type; // note: i only use pointer_list because of it's memory // management. node_builder(); virtual ~ node_builder(); /** If auto_delete() is on (the default) then this object will delete it's children when it is destroyed. */ void auto_delete( bool b ); /** This is the getter for auto_delete( bool ). */ bool auto_delete(); /** Opens a new node, making that the current node. classname will be used for the node's impl_class() (see docs in s11n_node). name will be the object's name, which is important for de/serializing the node. It returns false on error, else true. The default implementation has no error conditions, and therefor always returns true. Node that classnames and node names need not be unique (nor make up unique combinations). Any number of nodes may have the same name or classname. */ virtual bool open_node( const std::string & classname, const std::string & nodename ); /** Closes the most-recently-opened node, effectively popping the previous node off of the node stack (it is not destroyed). It is an error, possibly fatal, to call this more often than calling open_node(). It returns false on error (e.g., called with no opened node). */ virtual bool close_node(); /** Adds an arbitrary property to the opened node. Note that you may not have more than one property of the same name - the one added last is the only one which exists. */ virtual bool add_property( const std::string & key, const std::string & val ); /** Returns the total number of nodes opened via open_node(). */ unsigned long node_count() const; /** Returns the current depth of opened nodes. */ unsigned long node_depth() const; /** Returns the list of all top-level nodes added via open_node(). Typically this is called after you are done using open_node() and close_node(), to collect any nodes added. More typically, this is called by a client to collect nodes which a lex-based parser added to this object. */ node_builder::node_list_type & root_nodes(); /** Returns the most recent root node parsed out of the input object. */ s11n_node *root_node(); /** Returns the current node. */ s11n_node * current_node(); // /** // experimental way to generically support comment blocks in parsers. // */ // void comment_mode( bool b ) { this->m_comment_mode = b; }; // bool comment_mode() const { return this->m_comment_mode; }; protected: /** Subclasses may use this to set the node count. */ void node_count( unsigned long c ); private: bool m_autodel; unsigned long m_node_count; // bool m_comment_mode; s11n_node * m_node; s11n_node * m_root; node_builder::node_list_type m_toplist; typedef std::deque < s11n_node * >node_stack; node_stack m_nodestack; }; }; // namespace S11N_NAMESPACE #endif // S11NNODEBUILDER_H_INCLUDE --- NEW FILE: ns.node_loader.cpp --- #include <S11N_NAMESPACE/serializer_loader.h> #include "node_loader.h" #include <iostream> #include <memory> // auto_ptr #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() #include <S11N_NAMESPACE/file_util.h> //bytes_from_file() #include <S11N_NAMESPACE/serializer_loader.h> #include <S11N_NAMESPACE/s11n_node.h> #include <S11N_NAMESPACE/context_singleton.h> //#include <typeinfo> // debugging. namespace S11N_NAMESPACE { path_finder & node_loader::path() { return this->m_path; } const path_finder & node_loader::path() const { return this->m_path; } path_finder & node_loader::shared_path() { static path_finder bob; return bob; } s11n_node * node_loader::load_node( const std::string & key ) { return context_singleton<node_loader,node_loader>::instance().load( key ); } s11n_node * node_loader::load_node( std::istream & is ) { return context_singleton<node_loader,node_loader>::instance().load( is ); } s11n_node * node_loader::load( std::istream & is ) const { static serializer_loader bobTheLoader; char cookie[50]; is.getline( cookie, sizeof( cookie ) ); if( ! is.good() ) return NULL; 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; return NULL; } return ser->deserialize( is ); } s11n_node * node_loader::load( const std::string & key ) const { std::string path = this->path().find( key ); if( path.empty() ) path = shared_path().find( key ); if( path.empty() ) { CERR << "File '"<<key<<"' not found in path ["<<this->path()<<"]"<<std::endl; return NULL; } std::auto_ptr<std::istream> is = std::auto_ptr<std::istream>( S11N_NAMESPACE::get_istream( path ) ); if( !(is.get()) || (!is->good()) ) { CERR << "Error opening file ["<<path<<"]."<<std::endl; return NULL; } return load( *is ); } } // namespace --- NEW FILE: ns.node_loader.h --- #ifndef S11N_NAMESPACE_NODELOADER_H_INCLUDED #define S11N_NAMESPACE_NODELOADER_H_INCLUDED 1 // License: Public Domain // Author: st...@wa... #include <iostream> #include <S11N_NAMESPACE/class_loader.h> #include <S11N_NAMESPACE/path_finder.h> namespace S11N_NAMESPACE { class s11n_node; // forward decl /** node_loader is a convenience class for loading Serializables from files. It is similar to FlexTreeBuilder::loadBuilder(), but: - operates MUCH differently. - is extendable at runtime, so new parsers can be added/loaded dynamically. - it much simpler to use. sample usage: <pre> s11n_node * root = node_loader::load_node( infilename ); MySerializableType * foo = root->deserialize<MySerializableType>(); </pre> */ class node_loader { public: // typedef class_loader<s11n_node> ParentClass; node_loader(){}; ~node_loader(){}; /** Tries to load an s11n_node from the given filename, searching Both this->path() and node_loader::shared_path(). It auto-determines the file format. Returns null for a number of reasons, including: - file not found or inaccessible. - file found but no parser could be selected for it. - parser selected, but no root-level node was found. Ideally it will return a new s11n_node, which the caller takes ownership of. */ s11n_node * load( const std::string & key ) const; /** Looks at the first few bytes of the given stream 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 returns. See S11N_NAMESPACE::basic_serializer and S11N_NAMESPACE::serializer_loader. */ s11n_node * load( std::istream & ) const; /** Convenience form of load(). */ static s11n_node * load_node( std::istream & ); /** Convenience form of load(). Uses shared_path() for file lookups. */ static s11n_node * load_node( const std::string & key ); /** A search path used by load(). */ const path_finder & path() const; /** A search path used by load(). */ path_finder & path(); /** A shared path used by all node_loader instances. It has a lower search priority than path() does. */ static path_finder & shared_path(); private: path_finder m_path; }; } // namespace #endif // S11N_NAMESPACE_NODELOADER_H_INCLUDED --- NEW FILE: ns.ParenSerializer.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 { ParenSerializer::ParenSerializer() { }; ParenSerializer::~ParenSerializer() { }; const basic_serializer::translation_map & ParenSerializer::translations() const { static ParenSerializer::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 * ParenSerializer::deserialize( std::istream & is ) { S11N_NAMESPACE::ParenTreeBuilder parser; return basic_serializer::deserialize( parser, is ); } bool ParenSerializer::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.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include "S11n.h" int classloader_registration_bogosity = 0; namespace S11N_NAMESPACE { }; // namespace S11N_NAMESPACE --- NEW FILE: ns.s11n_globals.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <string> #if HAVE_CONFIG_H # include "config.h" // S11N_LIBRARY_VERSION #endif #ifndef S11N_LIBRARY_VERSION # error S11N_LIBRARY_VERSION must be set! #endif #include <S11N_NAMESPACE/s11n_globals.h> namespace S11N_NAMESPACE { std::string library_version() { return std::string(S11N_LIBRARY_VERSION); } } // namespace S11N_NAMESPACE --- NEW FILE: ns.s11n_globals.h --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #ifndef S11N_NAMESPACE_S11N_GLOBALS_H_INCLUDED #define S11N_NAMESPACE_S11N_GLOBALS_H_INCLUDED 1 #include <string> #include <iostream> #include <memory> // auto_ptr // #include <S11N_NAMESPACE/class_loader.h> #include <S11N_NAMESPACE/instantiator.h> #include <S11N_NAMESPACE/s11n_node.h> #include <S11N_NAMESPACE/serializer_loader.h> #include <S11N_NAMESPACE/node_loader.h> // utility functions for client code. namespace S11N_NAMESPACE { /** Returns a string containing this library's version number. */ std::string library_version(); /** UNTESTED. 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 ) { static node_loader bob; std::auto_ptr<s11n_node> node = std::auto_ptr<s11n_node>( bob.load( istr ) ); if( ! (node.get()) ) { return NULL; } return node->s11n_node::deserialize<SerializableT>(); } /** UNTESTED. 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 ) { std::auto_ptr<std::istream> istr = std::auto_ptr<std::istream>( get_istream( file ) ); if( ! (istr.get()) ) return NULL; return load_serializable<SerializableT>( *istr ); } } // namespace #endif // S11N_NAMESPACE_S11N_GLOBALS_H_INCLUDED --- 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.s11n_io.cpp --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #include <iostream> #include <string> //#include <S11N_NAMESPACE/s11n-macros.h> // COUT/CERR macros #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() #include <S11N_NAMESPACE/s11n_io.h> #include <S11N_NAMESPACE/s11n-macros.h> // COUT/CERR, for debugging only. // namespace S11N_NAMESPACE // { // };// namespace S11N_NAMESPACE --- NEW FILE: ns.s11n_io.h --- #ifndef S11N_NAMESPACE_S11NIO_H_INCLUDED #define S11N_NAMESPACE_S11NIO_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 <S11N_NAMESPACE/s11n_node.h> // #if HAVE_CONFIG_H // # include "config.h" // #endif #include <S11N_NAMESPACE/file_util.h> // get_ostream(), get_istream() #include <S11N_NAMESPACE/Serializer.h> namespace S11N_NAMESPACE { /** 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. */ typedef S11N_NAMESPACE::FunXMLSerializer DefaultS11nType; /** s11n_io is a convenience (ha ha) class for saving/loading s11n_nodes and Serializables. 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 feel that client code is more maintainable, via using typedefs and/or shared objects, than via having to create these objects each time they are needed. A prime consideration is the ease of switching an app's or framework's default serialization type: <pre> typedef SimpleXMLSerializer SerT; typedef s11n_io<SerT> SaveLoad; ... SaveLoad::save( ... ); </pre> Loading without knowing the input format beforehand is unfortunately significantly more painful. See S11N_NAMESPACE::node_loader for a utility class which can do that. It (indirectly) uses S11N_NAMESPACE::compression_policy() to determine whether to write non/compressed files, so set any preference via that function. */ template < typename SerializerT = DefaultS11nType > class s11n_io { /** Convenience typedef */ typedef s11n_io<SerializerT> ThisType; public: /** This type of Serializer this class uses. */ typedef SerializerT serializer_type; /** Saves node to the given output stream. Returns false on error, which almost invariably means that the output stream could not be written to. */ static bool save( const s11n_node & node, std::ostream & os ) { serializer_type bob; return bob.serialize( node, os ); } /** As save( node, ostream ), but saves to the given file. Returns false on error, which normally indicates a file/stream-level error. S11N_NAMESPACE::compression_policy() is honored. */ static bool save( const s11n_node & node, const std::string & filename ) { std::ostream * fs = 0; fs = S11N_NAMESPACE::get_ostream( filename ); bool b = save( node, *fs ); delete( fs ); return b; } /** Creates an s11n_node named nodename, serializes ser into it and saves that to the given filename. See save( s11n_node, string ) for info about gzip support. */ template <typename serializable_type> static bool save( const std::string & nodename, const serializable_type & ser, const std::string & filename ) { s11n_node node; node.name( nodename ); if( ! node.serialize( ser ) ) return false; return save( node, filename ); } /** Creates an s11n_node named nodename, serializes ser into it and saves that to the given ostream. */ template <typename serializable_type> static bool save( const std::string & nodename, const serializable_type & ser, std::ostream & os ) { s11n_node node; node.name( nodename ); if( ! node.serialize( ser ) ) return false; return save( node, os ); } /** Tries to load an s11n_node from the given input stream. It returns a pointer to the object, which may be null. The caller owns the returned pointer. */ static s11n_node *load( std::istream & is ) { serializer_type bob; s11n_node *node = NULL; node = bob.deserialize( is ); return node; } /** Tries to load an s11n_node from the given file. It returns a pointer to the object, which may be null (indicating either a file-level error, parse error, or just about anything else). The caller owns the returned pointer. */ static s11n_node *load( const std::string & filename ) { std::istream * fs = 0; fs = S11N_NAMESPACE::get_istream( filename ); if( ! fs->good() ) { delete( fs ); return NULL; } s11n_node * n = load( *fs ); delete( fs ); return n; } /** This is a genuine lossy shortcut: it grabs the first s11n_node from filename and abandons the rest. It ignores the node's name, which may or may not be significant for your code (it's not, generally speaking, since you apparently know the type of the file's data). If a SerT cannot be deserialized out of the given file then NULL is returned, otherwise a pointer is returned, which the caller takes ownership of. */ template < typename SerT > static SerT * load_deserialize( const std::string & filename ) { s11n_node *node = load( filename ); if ( !node ) return NULL; SerT * ch = node->s11n_node::deserialize<SerT>(); delete( node ); return ch; } }; } // namespace S11N_NAMESPACE #endif // S11N_NAMESPACE_S11NIO_H_INCLUDED --- NEW FILE: ns.s11n-macros.h --- // // Author: stephan beal <st...@s1...> // License: Public Domain // #ifndef S11N_MACROS_H #define S11N_MACROS_H #include <iostream> #ifndef CERR #define CERR std::cerr << __FILE__ << ":" << std::dec << __LINE__ << " : " #define CERRL(A) CERR << A << std::endl; #endif #ifndef COUT #define COUT std::cout << __FILE__ << ":" << std::dec << __LINE__ << " : " #define COUTL(A) COUT << A << std::endl; #endif #include <cassert> #define BROKEN(A) assert( 0 /* broken code: A */ ) #endif // S11N_MACROS_H --- NEW FILE: ns.s11n_node.cpp --- // #include <S11N_NAMESPACE/S11ndll_loader.h> // default classloader type #include "s11n_node.h" namespace S11N_NAMESPACE { #define NODE_IMPL_CLASS "S11N_NAMESPACE::s11n_node" s11n_node::s11n_node( const std::string & name ) : m_name(name),m_iname(NODE_IMPL_CLASS) { } s11n_node::s11n_node( const std::string & name, const std::string implclass ) : m_name( name ), m_iname( implclass ) { } s11n_node::s11n_node() : m_name("s11n_node"), m_iname(NODE_IMPL_CLASS) { } bool s11n_node::take_child( const s11n_node * ch ) { child_list_type::iterator it = this->children().begin(); child_list_type::iterator et = this->children().end(); bool got = false; for( ; it != et; ++it ) { if( (*it) != ch ) continue; this->children().erase( it ); got = true; break; } return got; } s11n_node::~s11n_node() { m_babysitter.delete_all(); // we use this in lieu of setting m_babysitter.auto_delete( true ) in the ctor } s11n_node::child_list_type & s11n_node::children() { return this->m_babysitter; } const s11n_node::child_list_type & s11n_node::children() const { return this->m_babysitter; } void s11n_node::reset() { this->m_babysitter.delete_all(); this->clear_properties(); } void s11n_node::impl_class( const std::string & n ) { this->m_iname = n; } std::string s11n_node::impl_class()const { return this->m_iname; } void s11n_node::name( const std::string & n ) { this->m_name = n; } std::string s11n_node::name() const { return this->m_name; } unsigned int s11n_node::serialize_properties( const property_store & props ) { return this->property_store::merge( props ); } unsigned int s11n_node::deserialize_properties( property_store & p ) const { return p.merge( *this ); } int m_s11n_node_debug_level = 0; void s11n_node::debug_level( int dlevel ) { m_s11n_node_debug_level = dlevel; } int s11n_node::debug_level() { return m_s11n_node_debug_level; } }; // namespace S11N_NAMESPACE --- NEW FILE: ns.s11n_node.h --- // s11n_node.h // License: Public Domain // Author: st...@wa... #ifndef S11N_NAMESPACE_NODE_H_INCLUDED #define S11N_NAMESPACE_NODE_H_INCLUDED #include <string> #include <S11N_NAMESPACE/property_store.h> #include <S11N_NAMESPACE/pointer_list.h> #include <S11N_NAMESPACE/dll_loader.h> #include <S11N_NAMESPACE/to_string.h> // to/from_string() #include <S11N_NAMESPACE/debuggering_macros.h> // COUT/CERR #include <S11N_NAMESPACE/serializable_adapter.h> namespace S11N_NAMESPACE { /** s11n_node makes up the core of the s11n framework. Please see the library manual for complete details. The inherited property_store interface makes up a large portion of this class' functionality, so please refer to that class after you have absorbed every last word of this one's documentation. */ class s11n_node : public S11N_NAMESPACE::property_store { public: /** A convenience typedef. */ typedef S11N_NAMESPACE::pointer_list<s11n_node> babysitter_type; /** The container type used to store this object's children. */ typedef babysitter_type child_list_type; /** Creates a new node with an empty name() and an impl_class() of "S11N_NAMESPACE::s11n_node". */ s11n_node(); /** Creates a new node with the given name() and an impl_class() of "S11N_NAMESPACE::s11n_node". */ explicit s11n_node( const std::string & name ); /** Creates a new node with the given name() and and impl_class(). */ s11n_node( const std::string & name, const std::string implclass ); /** This is primarily virtual because of the class' parentage, not because you should subclass this type. */ virtual ~s11n_node(); /** Returns a list of the s11n_node children of this object. The caller should not delete any pointers from this list unless he also removes the pointers from the list, or else they will get double-deleted later. In practice it is (almost) never necessary for client code to work with this list. */ child_list_type & children(); /** A const form of children(). */ const child_list_type & children() const; /** Completely Untested. Removes the given child from this object's list. The caller takes ownership of it. Returns true if this object contained the pointer, otherwise false. */ bool take_child( const s11n_node * ); /** Removes all properties and serialized children from this object. Any pointers to children of this object become invalided (they get deleted) by a call to this function. Since client code doesn't normally hold pointers to s11n_node<> pointers this should not be a practical problem. */ void reset(); /** Returns all children() with a name() matching the given string. The results go into the given container, which must support push_back( const s11n_node * ). The caller does NOT own the child pointers: they are still owned by this object. It returns the number of children added to the container. Complexity: basically linear, based on the number of children in this object and how many have the name nodename (more matches requires more insertions into the target container). */ template < typename ContainerType > unsigned long children( const std::string & nodename, ContainerType & ctr ) const { s11n_node *ch = 0; s11n_node::child_list_type::const_iterator cit = this->children().begin(); s11n_node::child_list_type::const_iterator cet = this->children().end(); unsigned long count = 0; for ( ; cit != cet; ++cit ) { ch = ( *cit ); if ( ch->name() == nodename ) { ++count; ctr.push_back( ch ); } } return count; } /** Returns the first child node with the given node name, or NULL. The caller does not own the pointer. */ const s11n_node * child( const std::string & nodename ) const { s11n_node *ch = 0; s11n_node::child_list_type::const_iterator cit = this->children().begin(); s11n_node::child_list_type::const_iterator cet = this->children().end(); for ( ; cit != cet; ++cit ) { if ( ( *cit )->name() == nodename ) { ch = ( *cit ); break; } } return ch; } /** Defines the class name which should be used as the implementation for the node when it is deserialize()d. You normally needn't set this directly: it is set internally during serialize() and fetched as needed by deserialize(). There are special cases where it must be set by client code. "You will know when the time comes." See the library manual for full details. */ void impl_class( const std::string & n ); /** Returns the implementation class name set via impl_class(). */ std::string impl_class() const; /** The name which should be used as the key for storing the node. This is normally translated to something like an XML element name (e.g., <name>), and should not contain spaces or other characters which may not be usable as key names. To be safe, stick to alphanumeric and underscores, starting with a letter or underscore. (This class does no enforce any naming conventions, but your data file parsers certainly will.) */ void name( const std::string & n ); /** Returns this node's name, as set via name(string). */ std::string name() const; /** Sets a debugging level. Currently only 1 and 0 are supported. */ static void debug_level( int dlevel ); /** Returns the current debugging level. */ static int debug_level(); #define NODEDEBUG if( debug_level() ) CERR /** Returns the current classloader for the given SerializableType. */ template <class SerializableType> static class_loader<SerializableType> & classloader() { return context_singleton< dll_loader<SerializableType>, s11n_node >::instance(); } /** 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 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 returned, which the caller takes ownership of. */ template <class SerializableType> SerializableType * deserialize() const { const std::string classname = this->impl_class(); SerializableType *tgt = 0; tgt = this->classloader<SerializableType>().load( classname ); NODEDEBUG << "deserialize() impl=["<<classname<<"] name=["<<this->name()<<"] classloaded=["<<std::hex<<tgt<<"]"<<std::endl; if ( !tgt ) { NODEDEBUG << "could not instantiate node '" << this->name() << "' from class '"<< classname << "'. It is probably not registered with the classloader." << std::endl; return tgt; } if ( ! serializable_adapter<SerializableType>::deserialize( *tgt, *this ) ) { NODEDEBUG << "tgt->deserialize() failed. Deleting tgt. impl_class="<< classname << ", nodename=" << this->name() << std::endl; delete( tgt ); tgt = NULL; } return tgt; } /** Serializes ser into a subnode of this node, named nodename and gives it to ser for serialization. If that fails, nothing happens and false is returned. If it succeeds, it adds the new child node to this object and returns true. */ template <class SerializableType> bool serialize( const std::string & nodename, const SerializableType & ser ) { s11n_node *node = new s11n_node(); node->name( nodename ); typedef serializable_adapter<SerializableType> Adapter; // std::string classname = Adapter::impl_class(); // node->impl_class( Adapter::impl_class() ); NODEDEBUG << "serialize(" << nodename << " , " <<std::hex << &ser << ") typeid=["<<typeid(ser).name()<<"] impl_class="<<node->impl_class() << std::endl; if ( !Adapter::serialize( ser, *node ) ) { NODEDEBUG << "serialize(" << nodename << " , " <<std::hex << &ser << ") failed!" << std::endl; delete( node ); return false; } this->children().push_back( node ); return true; } /** Effectively calls: <pre> ser.serialize( node ); </pre> But it uses the API mapping provided by serializable_adapter<SerializableType>::serialize(). */ template <class SerializableType> bool serialize( const SerializableType & ser ) { typedef serializable_adapter<SerializableType> Adapter; return Adapter::serialize( ser, *this ); } /** Convenience function. Copies prop's properties into this object. Returns the number of properties copied. */ unsigned int serialize_properties( const property_store & props ); /** Convenience function. Copies this object's properties to p. Returns the number of properties copied. */ unsigned int deserialize_properties( property_store & p ) const; /** Serializes the given STL map into a sub-node of this object. Returns the number of properties gleened from the map. No child node is created if this function returns zero (i.e., if map is empty). Assumptions: - map conforms to std::map conventions. - both the key and value types of the map support the istream>>/ostream<< operators. - neither key nor value types may be pointer types. - keys must be suitable for use as property keys in data files, otherwisethey may not be readable by all parsers. A prime example of a dubious choice is doubles, since 3.000 is not a valid key for some formats (e.g., XML). Note that the new sub-node is not actually deserialize()able - it is an s11n_node which simply contains properties. It can be retrieved with deserialize_map() or by manually iterating over it's properties. */ template <typename ContainerType> unsigned long serialize_map( const std::string & nodename, const ContainerType & map ) { if( 0 == map.size() ) return 0; unsigned long ret = 0; typedef typename ContainerType::const_iterator CIT; CIT it = map.begin(); CIT et = map.end(); if( it == et ) return ret; s11n_node * node = new s11n_node(); node->name(nodename); for( ; it != et; ++it ) { node->set( S11N_NAMESPACE::to_string( (*it).first ), (*it).second ); ++ret; } if( 0 == ret ) delete( node ); else this->children().push_back( node ); return ret; } /** Deserializes a map which has been serialized using serialize_map(). Returns the number of objects retrieved from the map. See serialize_map() for a description of the requirements for ContainerType. In addition: - map must have typedefs for value_type, key_type and mapped_type. Some STL docs refer to mapped_type as ... [truncated message content] |