From: stephan b. <sg...@us...> - 2004-12-26 04:04:43
|
Update of /cvsroot/pclasses/pclasses2/src/s11n/io/expat In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30469/src/s11n/io/expat Added Files: expat_serializer.cpp expat_serializer.h in.expat Makefile.toc Log Message: egg: initial port of s11n::io layer, the parts which don't need FlexLexer and friends. It compiles and links, but is untested after factory-related changes. --- NEW FILE: expat_serializer.cpp --- #include <pclasses/Phoenix.h> #include <pclasses/s11n/data_node.h> #include <pclasses/s11n/s11n_node.h> #include <pclasses/s11n/io/serializers.h> #include "expat_serializer.h" namespace P { namespace s11n { namespace io { /** Internal-use initializer for setting up the expat Serializer translation map. */ struct expat_serializer_translations_initializer { template <typename MapType> void operator()( MapType & map ) { map["&"] = "&"; map["\""] = """; map["'"] = "'"; map[">"] = ">"; map["<"] = "<"; } }; entity_translation_map & expat_serializer_translations() { typedef ::P::Phoenix< entity_translation_map, sharing::expat_sharing_context, expat_serializer_translations_initializer > TheMap; return TheMap::instance(); } } }} // namespace P::s11n::io namespace { void expat_serializer_registration_init() { #define SERINST(NodeT) \ ::P::s11n::io::register_serializer< ::P::s11n::io::expat_serializer< NodeT > >( "P::s11n::io::expat_serializer", "expat" ); SERINST(::P::s11n::data_node); SERINST(::P::s11n::s11n_node); #undef SERINST } int expat_reg_placeholder = ( expat_serializer_registration_init(), 1 ); } // anonymous namespace --- NEW FILE: Makefile.toc --- #!/usr/bin/make -f include toc.make HEADERS = expat_serializer.h SOURCES = expat_serializer.cpp DIST_FILES += $(SOURCES) $(HEADERS) ######################################################################## ifneq (1,$(PCLASSES_HAVE_LIBEXPAT)) $(warning expat_serializer build disabled because PCLASSES_HAVE_LIBEXPAT is not set to 1.) all: ######################################################################## else ######################################################################## INSTALL_PACKAGE_HEADERS += $(HEADERS) INSTALL_PACKAGE_HEADERS_DEST = $(INSTALL_PACKAGE_HEADERS_BASE)/s11n/io SYMLINK_HEADERS = $(INSTALL_PACKAGE_HEADERS) SYMLINK_HEADERS_DEST = $(top_srcdir)/include/pclasses/s11n/io include $(TOC_MAKESDIR)/SYMLINK_HEADERS.make OBJECTS = expat_serializer.o CLEAN_FILES += $(OBJECTS) all: $(OBJECTS) ######################################################################## endif # ^^^^ end PCLASSES_HAVE_LIBEXPAT block ######################################################################## --- NEW FILE: in.expat --- <!DOCTYPE s11n::io::expat_serializer> <somenode class="NoClass"> <a>()\b</a> <foo>bar</foo> <empty /> <long>this is a long property</long> <dino class="DinoClass" /> <fred class="FredClass"> <key>value</key> </fred> <wilma class="WilmaClass"> <the>lovely wife</the> </wilma> <betty class="BettyClass"> <value>the apple of Barney's eye</value> </betty> <deep class="Foo"> <deeper class="Foo"> <how_deep>really deep!</how_deep> <and_deeper class="Ouch"> </and_deeper> </deeper> </deep> </somenode> --- NEW FILE: expat_serializer.h --- #ifndef s11n_EXPAT_SERIALIZER_HPP_INCLUDED #define s11n_EXPAT_SERIALIZER_HPP_INCLUDED 1 #include <pclasses/s11n/str.h> // translate() #include <pclasses/s11n/s11n_debuggering_macros.h> // COUT/CERR #include <pclasses/s11n/io/data_node_format.h> #include <pclasses/s11n/traits.h> // node_traits #include <expat.h> #define MAGIC_COOKIE_EXPAT_XML "<!DOCTYPE P::s11n::io::expat_serializer>" #include <stdexcept> #include <sstream> #define EXPATDEBUG if(0) CERR #define EXPAT_CLASS_ATTRIBUTE "class" namespace P { namespace s11n { namespace io { namespace sharing { /** Sharing context used by expat_serializer. */ struct expat_sharing_context {}; } /** convenience typedef */ typedef std::map<std::string,std::string> entity_translation_map; /** The entity translations map used by expat_serializer. */ entity_translation_map & expat_serializer_translations(); /** expat_serializer is an XML-based Serializer, using libexpat to read it's data. */ template <typename NodeType> class expat_serializer : public data_node_serializer<NodeType> { public: typedef NodeType node_type; typedef expat_serializer<node_type> this_type; // convenience typedef expat_serializer() : m_depth(0) { this->magic_cookie( MAGIC_COOKIE_EXPAT_XML ); } virtual ~expat_serializer() {} /** Writes src out to dest. */ virtual bool serialize( const node_type & src, std::ostream & dest ) { typedef ::P::s11n::node_traits<node_type> NT; // INDENT() is a helper macro for some serializers. #define INDENT(LEVEL,ECHO) indent = ""; for( size_t i = 0; i < depth + LEVEL; i++ ) { indent += '\t'; if(ECHO) buff << '\t'; } std::ostringstream buff; // we buffer so we can handle self-closing nodes size_t depth = this->m_depth++; if ( 0 == depth ) { buff << this->magic_cookie() << '\n'; } std::string nname = NT::name(src); std::string impl = NT::class_name(src); str::translate( impl, expat_serializer_translations(), false ); std::string indent; buff << "<" << nname << " "<<EXPAT_CLASS_ATTRIBUTE<<"=\""<< impl <<"\""; bool closed = false; typename NT::const_iterator cit = NT::begin(src), cet = NT::end(src); std::string propval; std::string key; if( cet != cit ) { // got properties? closed = true; buff << ">\n"; INDENT(1,0); for ( ; cet != cit; ++cit ) { key = ( *cit ).first; propval = ( *cit ).second; buff << indent << "<" << key; if( propval.empty() ) { buff << "/>"; } else { buff << ">"; propval = str::translate( propval, expat_serializer_translations(), false ); buff << propval; buff << "</" << key << ">"; } buff << "\n"; } } typename NT::child_const_iterator chit = NT::children(src).begin(), chet = NT::children(src).end(); if( chet != chit ) { // got kids? if( !closed ) { // close node opener buff << ">\n"; closed = true; } INDENT(1,0); std::for_each( chit, chet, node_child_simple_formatter<this_type>( *this, buff, indent, "" ) ); } if( closed ) { INDENT(0,1); buff << "</" << nname << ">"; } else // self-close node { buff << "/>"; } dest << buff.str() << "\n"; if( 0 == depth ) { dest.flush(); // if we don't do this then the client is possibly forced to flush() the stream :/ } --this->m_depth; return true; #undef INDENT } static void XMLCALL start_node( void *, const char * name, const char ** attr ) { m_cbuf = ""; if( attr[0] ) { // object node std::string clname = "WTF?"; const std::string classnameattr = std::string(EXPAT_CLASS_ATTRIBUTE); for( int i = 0; attr[i]; i += 2 ) { if( attr[i] == classnameattr ) { clname = attr[i+1]; break; } } EXPATDEBUG << "Opening object node["<<clname<<","<<name<<"]\n"; m_builder.open_node( clname, name ); } else // property node { m_name = name; EXPATDEBUG << "Opening property node["<<m_name<<"]\n"; } } /** expat end-node callback. */ static void XMLCALL end_node( void *, const char * ) { if( ! m_name.empty() ) // property node { EXPATDEBUG << "Closing property node["<<m_name<<"="<<m_cbuf<<"]\n"; m_builder.add_property( m_name, m_cbuf ); } else { // object_node EXPATDEBUG << "Closing object node.\n"; m_builder.close_node(); } m_name = ""; m_cbuf = ""; } /** expat char-data callback. */ static void XMLCALL char_handler( void *, const char * txt, int len ) { if( m_name.empty() ) return; // we're not in a property. const char *c; for( int i = 0; i < len; i++ ) { c = txt++; m_cbuf += *c; } EXPATDEBUG << "char_handler(...,"<<len<<"): m_cbuf=[" << m_cbuf << "]\n"; } /** Uses expat to try to parse a tree of nodes from the given stream. */ node_type * expat_parse_stream( std::istream & is ) { XML_Parser p = XML_ParserCreate(NULL); if (! p) { EXPATDEBUG << "Couldn't allocate memory for parser\n"; return 0; } XML_SetElementHandler(p, start_node, end_node); XML_SetCharacterDataHandler( p, char_handler ); m_builder.reset(); m_name = ""; m_cbuf = ""; bool done = false; size_t len = 0; std::string buff; try { while( true ) { if( std::getline( is, buff ).eof() ) done = true; len = buff.size(); if( 0 < len ) if (XML_Parse(p, buff.c_str(), len, done) == XML_STATUS_ERROR) { std::ostringstream err; err << "Parse error at line " << XML_GetCurrentLineNumber(p) << ": " << XML_ErrorString(XML_GetErrorCode(p)) << ": buffer=["<<buff<<"]"; // EXPATDEBUG << err.str() << "\n"; throw std::runtime_error( err.str() ); } if( done ) break; } } catch( std::runtime_error & ex ) { CERR << "EXCEPTION while XML_Parsing input: " << ex.what() << "!\n"; m_builder.auto_delete( true ); m_builder.reset(); } XML_ParserFree( p ); m_builder.auto_delete( false ); return m_builder.root_node(); } /** Overridden to parse src using this object's grammar rules. */ virtual node_type * deserialize( std::istream & src ) { return this->expat_parse_stream( src ); } private: size_t m_depth; static data_node_tree_builder<node_type> m_builder; static std::string m_name; // current node's name static std::string m_cbuf; // cdata buffer }; template <typename NodeT> data_node_tree_builder<NodeT> expat_serializer<NodeT>::m_builder; template <typename NodeT> std::string expat_serializer<NodeT>::m_name; template <typename NodeT> std::string expat_serializer<NodeT>::m_cbuf; } // namespace io }} // namespace P::s11n #undef EXPATDEBUG #undef EXPAT_CLASS_ATTRIBUTE #endif // s11n_EXPAT_SERIALIZER_HPP_INCLUDED |