#ifndef __CONNECTION_H__ #define __CONNECTION_H__ #include "../global.h" #include #include #include #include #include //XXX this is in namespace std if you want w/o use typeinfo.h? #include #include #include #include #include #include #include #include #include #include #include const ui32 version = 713; class CConnection; class CGObjectInstance; class CGameState; namespace mpl = boost::mpl; /* * Connection.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ namespace boost { namespace asio { namespace ip { class tcp; } class io_service; template class stream_socket_service; template class basic_stream_socket; template class socket_acceptor_service; template class basic_socket_acceptor; } class mutex; }; enum SerializationLvl { Wrong=0, Primitive, Array, Pointer, Serializable }; struct TypeComparer { bool operator()(const std::type_info *a, const std::type_info *b) const { return a->before(*b); } }; class DLL_EXPORT CTypeList { typedef std::multimap TTypeMap; TTypeMap types; public: CTypeList(); ui16 registerType(const std::type_info *type); template ui16 registerType(const T * t = NULL) { return registerType(getTypeInfo(t)); } ui16 getTypeID(const std::type_info *type); template ui16 getTypeID(const T * t) { return getTypeID(getTypeInfo(t)); } template const std::type_info * getTypeInfo(const T * t = NULL) { if(t) return &typeid(*t); else return &typeid(T); } }; extern DLL_EXPORT CTypeList typeList; template struct SavePrimitive { static void invoke(Ser &s, const T &data) { s.savePrimitive(data); } }; template struct SaveSerializable { static void invoke(Ser &s, const T &data) { s.saveSerializable(data); } }; template struct LoadPrimitive { static void invoke(Ser &s, T &data) { s.loadPrimitive(data); } }; template struct SavePointer { static void invoke(Ser &s, const T &data) { s.savePointer(data); } }; template struct LoadPointer { static void invoke(Ser &s, T &data) { s.loadPointer(data); } }; template struct SaveArray { static void invoke(Ser &s, const T &data) { s.saveArray(data); } }; template struct LoadArray { static void invoke(Ser &s, T &data) { s.loadArray(data); } }; template struct LoadSerializable { static void invoke(Ser &s, T &data) { s.loadSerializable(data); } }; template struct SaveWrong { static void invoke(Ser &s, const T &data) { throw std::string("Wrong save serialization call!"); } }; template struct LoadWrong { static void invoke(Ser &s, const T &data) { throw std::string("Wrong load serialization call!"); } }; template struct SerializationLevel { typedef mpl::integral_c_tag tag; typedef typename mpl::eval_if< boost::is_fundamental, mpl::int_, //else typename mpl::eval_if< boost::is_class, mpl::int_, //else typename mpl::eval_if< boost::is_array, mpl::int_, //else typename mpl::eval_if< boost::is_pointer, mpl::int_, //else typename mpl::eval_if< boost::is_enum, mpl::int_, //else mpl::int_ > > > > >::type type; static const int value = SerializationLevel::type::value; }; class DLL_EXPORT CSerializerBase { public: }; class DLL_EXPORT CSaverBase : public virtual CSerializerBase { }; class CBasicPointerSaver { public: virtual void savePtr(CSaverBase &ar, const void *data) const =0; }; template class CPointerSaver : public CBasicPointerSaver { public: void savePtr(CSaverBase &ar, const void *data) const { Serializer &s = static_cast(ar); const T *ptr = static_cast(data); //T is most derived known type, it's time to call actual serialize const_cast(*ptr).serialize(s,version); } }; template class DLL_EXPORT COSer : public CSaverBase { public: bool saving; std::map savers; // typeID => CPointerSaver COSer() { saving=true; } template void registerType(const T * t=NULL) { ui16 ID = typeList.registerType(t); savers[ID] = new CPointerSaver,T>; } Serializer * This() { return static_cast(this); } template Serializer & operator<<(const T &t) { this->This()->save(t); return * this->This(); } template COSer & operator&(const T & t) { return * this->This() << t; } int write(const void * data, unsigned size); template void savePrimitive(const T &data) { this->This()->write(&data,sizeof(data)); } template void savePointer(const T &data) { //write if pointer is not NULL ui8 hlp = (data!=NULL); *this << hlp; //if pointer is NULL then we don't need anything more... if(!hlp) return; //write type identifier ui16 tid = typeList.getTypeID(data); *this << tid; This()->savePointerHlp(tid, data); } //that part of ptr serialization was extracted to allow customization of its behavior in derived classes template void savePointerHlp(ui16 tid, const T &data) { if(!tid) *this << *data; //if type is unregistered simply write all data in a standard way else savers[tid]->savePtr(*this,data); //call serializer specific for our real type } template void saveArray(const T &data) { ui32 size = ARRAY_COUNT(data); for(ui32 i=0; i < size; i++) *this << data[i]; } template void save(const T &data) { typedef //if typename mpl::eval_if< mpl::equal_to,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else mpl::identity > > > > >::type typex; typex::invoke(* this->This(), data); } template void saveSerializable(const T &data) { const_cast(data).serialize(*this,version); } template void saveSerializable(const std::vector &data) { boost::uint32_t length = data.size(); *this << length; for(ui32 i=0;i void saveSerializable(const std::set &data) { std::set &d = const_cast &>(data); boost::uint32_t length = d.size(); *this << length; for(typename std::set::iterator i=d.begin();i!=d.end();i++) *this << *i; } template void saveSerializable(const std::list &data) { std::list &d = const_cast &>(data); boost::uint32_t length = d.size(); *this << length; for(typename std::list::iterator i=d.begin();i!=d.end();i++) *this << *i; } void saveSerializable(const std::string &data) { *this << ui32(data.length()); this->This()->write(data.c_str(),data.size()); } template void saveSerializable(const std::pair &data) { *this << data.first << data.second; } template void saveSerializable(const std::map &data) { *this << ui32(data.size()); for(typename std::map::const_iterator i=data.begin();i!=data.end();i++) *this << i->first << i->second; } }; class DLL_EXPORT CLoaderBase : public virtual CSerializerBase {}; class CBasicPointerLoader { public: virtual void loadPtr(CLoaderBase &ar, void *data) const =0; //data is pointer to the ACTUAL POINTER }; template class CPointerLoader : public CBasicPointerLoader { public: void loadPtr(CLoaderBase &ar, void *data) const //data is pointer to the ACTUAL POINTER { Serializer &s = static_cast(ar); T *&ptr = *static_cast(data); //create new object under pointer typedef typename boost::remove_pointer::type npT; ptr = new npT; //T is most derived known type, it's time to call actual serialize ptr->serialize(s,version); } }; template class DLL_EXPORT CISer : public CLoaderBase { public: bool saving; std::map loaders; // typeID => CPointerSaver ui32 myVersion; CISer() { saving = false; myVersion = version; } ~CISer() { std::map::iterator iter; for(iter = loaders.begin(); iter != loaders.end(); iter++) delete iter->second; } template void registerType(const T * t=NULL) { ui16 ID = typeList.registerType(t); loaders[ID] = new CPointerLoader,T>; } Serializer * This() { return static_cast(this); } template Serializer & operator>>(T &t) { this->This()->load(t); return * this->This(); } template CISer & operator&(T & t) { return * this->This() >> t; } int write(const void * data, unsigned size); template void load(T &data) { typedef //if typename mpl::eval_if< mpl::equal_to,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else if typename mpl::eval_if,mpl::int_ >, mpl::identity >, //else mpl::identity > > > > >::type typex; typex::invoke(* this->This(), data); } template void loadPrimitive(T &data) { this->This()->read(&data,sizeof(data)); } template void loadSerializable(T &data) { ////that const cast would be evil because it allows to implicitly overwrite const objects when deserializing //typedef typename boost::remove_const::type nonConstT; //nonConstT &hlp = const_cast(data); //hlp.serialize(*this,myVersion); data.serialize(*this,myVersion); } template void loadArray(T &data) { ui32 size = ARRAY_COUNT(data); for(ui32 i=0; i < size; i++) *this >> data[i]; } template void loadPointer(T &data) { ui8 hlp; *this >> hlp; if(!hlp) { data = NULL; return; } //get type id ui16 tid; *this >> tid; This()->loadPointerHlp(tid, data); } //that part of ptr deserialization was extracted to allow customization of its behavior in derived classes template void loadPointerHlp( ui16 tid, T & data ) { if(!tid) { typedef typename boost::remove_pointer::type npT; data = new npT; *this >> *data; } else { loaders[tid]->loadPtr(*this,&data); } } template void loadSerializable(std::vector &data) { boost::uint32_t length; *this >> length; data.resize(length); for(ui32 i=0;i> data[i]; } template void loadSerializable(std::set &data) { boost::uint32_t length; *this >> length; T ins; for(ui32 i=0;i> ins; data.insert(ins); } } template void loadSerializable(std::list &data) { boost::uint32_t length; *this >> length; T ins; for(ui32 i=0;i> ins; data.push_back(ins); } } template void loadSerializable(std::pair &data) { *this >> data.first >> data.second; } template void loadSerializable(std::map &data) { ui32 length; *this >> length; T1 t; for(ui32 i=0;i> t; *this >> data[t]; } } void loadSerializable(std::string &data) { ui32 length; *this >> length; data.resize(length); this->This()->read((void*)data.c_str(),length); } }; class DLL_EXPORT CSaveFile : public COSer { void dummyMagicFunction() { *this << std::string("This function makes stuff working."); } public: std::ofstream *sfile; CSaveFile(const std::string &fname); ~CSaveFile(); int write(const void * data, unsigned size); }; class DLL_EXPORT CLoadFile : public CISer { void dummyMagicFunction() { std::string dummy = "This function makes stuff working."; *this >> dummy; } public: std::ifstream *sfile; CLoadFile(const std::string &fname); ~CLoadFile(); int read(const void * data, unsigned size); }; class DLL_EXPORT CConnection :public CISer, public COSer { CGameState *gs; CConnection(void); void init(); public: boost::mutex *rmx, *wmx; // read/write mutexes boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service > * socket; bool logging; bool connected; bool myEndianess, contactEndianess; //true if little endian, if ednianess is different we'll have to revert recieved multi-byte vars boost::asio::io_service *io_service; std::string name; //who uses this connection CConnection (std::string host, std::string port, std::string Name); CConnection (boost::asio::basic_socket_acceptor > * acceptor, boost::asio::io_service *Io_service, std::string Name); CConnection (boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service > * Socket, std::string Name); //use immediately after accepting connection into socket int write(const void * data, unsigned size); int read(void * data, unsigned size); int readLine(void * data, unsigned maxSize); void close(); template CConnection &operator&(const T&); ~CConnection(void); void setGS(CGameState *state); CGObjectInstance *loadObject(); //reads id from net and returns that obj void saveObject(const CGObjectInstance *data); template struct loadObjectHelper { static void invoke(CConnection &s, T &data, ui16 tid) { data = static_cast(s.loadObject()); } }; template struct loadRestHelper { static void invoke(CConnection &s, T &data, ui16 tid) { s.CISer::loadPointerHlp(tid, data); } }; template struct saveObjectHelper { static void invoke(CConnection &s, const T &data, ui16 tid) { //CGObjectInstance *&hlp = const_cast(data); //for loading pointer to const obj we must remove the qualifier s.saveObject(data); } }; template struct saveRestHelper { static void invoke(CConnection &s, const T &data, ui16 tid) { s.COSer::savePointerHlp(tid, data); } }; //"overload" loading pointer procedure template void loadPointerHlp( ui16 tid, T & data ) { typedef typename //if mpl::eval_if< boost::is_base_of::type>, mpl::identity >, //else mpl::identity > >::type typex; typex::invoke(*this, data, tid); } //"overload" saving pointer procedure template void savePointerHlp( ui16 tid, const T & data ) { typedef typename //if mpl::eval_if< boost::is_base_of::type>, mpl::identity >, //else mpl::identity > >::type typex; typex::invoke(*this, data, tid); } }; #endif // __CONNECTION_H__