// COMPILE_LINE: g++ -g serial_test.cc -I.. -o serial_test ../lib/libretroshare.a -lssl -lcrypto -lstdc++ -lpthread // // #include #include "util/rsmemory.h" #include "util/rsprint.h" #include "serialiser/rsserial.h" #include "rsserializer.h" #include "rstypeserializer.h" static const uint16_t RS_SERVICE_TYPE_TEST = 0xffff; static const uint8_t RS_ITEM_SUBTYPE_TEST1 = 0x01 ; // Template serialization of RsTypeSerialiser::serial_process() for unknown/new types // Here we do it for std::set as an example. // template<> uint32_t RsTypeSerializer::serial_size(const std::set& s) { return s.size() * 4 + 4 ; } template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const std::set& member) { uint32_t tlvsize = serial_size(member) ; bool ok = true ; uint32_t offset_save = offset ; if(tlvsize + offset > size) { std::cerr << "RsTypeSerializer::serialize: error. tlvsize+offset > size, where tlvsize=" << tlvsize << ", offset=" << offset << ", size=" << size << std::endl; return false ; } ok = ok && RsTypeSerializer::serialize(data,size,offset,member.size()) ; for(std::set::const_iterator it(member.begin());it!=member.end();++it) ok = ok && RsTypeSerializer::serialize(data,size,offset,*it) ; if(!ok) { std::cerr << "(EE) Cannot serialize std::set" << std::endl; offset = offset_save ; // return the data in the same condition } return ok ; } template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, std::set& member) { bool ok = true ; uint32_t n = 0 ; uint32_t offset_save = offset ; member.clear(); ok = ok && RsTypeSerializer::deserialize(data,size,offset,n); for(uint32_t i=0;i" << std::endl; offset = offset_save ; // return the data in the same condition } return ok; } // New item class. This class needs to define: // - a serial_process method that tells which members to serialize // - overload the clear() and print() methods of RsItem // class RsTestItem: public RsItem { public: RsTestItem() : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_TEST,RS_ITEM_SUBTYPE_TEST1) { str = "test string"; ts = time(NULL) ; int_set.insert(lrand48()) ; int_set.insert(lrand48()) ; int_set.insert(lrand48()) ; } // Derived from RsItem // virtual void serial_process(RsItem::SerializeJob j, SerializeContext& ctx) { RsTypeSerializer::TlvString tt(str,TLV_TYPE_STR_DESCR) ; RsTypeSerializer::serial_process(j,ctx,ts ) ; RsTypeSerializer::serial_process(j,ctx,tt ) ; RsTypeSerializer::serial_process(j,ctx,int_set ) ; } // Derived from RsItem // virtual void clear() {} virtual std::ostream& print(std::ostream&,uint16_t indent) {} private: std::string str ; uint64_t ts ; std::set int_set ; friend int main(int argc,char *argv[]); }; // New user-defined serializer class. // The only required member is the create_item() method, which creates the correct RsItem // that corresponds to a specific (service,subtype) couple. // class RsTestSerializer: public RsSerializer { public: RsTestSerializer() : RsSerializer(RS_SERVICE_TYPE_TEST) {} virtual RsItem *create_item(uint16_t service_id,uint8_t subtype) { if(service_id != RS_SERVICE_TYPE_TEST) return NULL ; switch(subtype) { case RS_ITEM_SUBTYPE_TEST1: return new RsTestItem(); default: return NULL ; } } }; // Methods to check the equality of items. // void check(const std::string& s1,const std::string& s2) { assert(s1 == s2) ; } void check(const uint64_t& s1,const uint64_t& s2) { assert(s1 == s2) ; } void check(const std::set& s1,const std::set& s2) { assert(s1 == s2) ; } int main(int argc,char *argv[]) { try { RsTestItem t1 ; uint32_t size = RsTestSerializer().size(&t1); std::cerr << "t1.serial_size() = " << size << std::endl; // Allocate some memory to serialise to // RsTemporaryMemory mem1(size); RsTestSerializer().serialise(&t1,mem1,mem1.size()) ; std::cerr << "Serialized t1: " << RsUtil::BinToHex(mem1,mem1.size()) << std::endl; // Now deserialise into a new item // RsItem *t2 = RsTestSerializer().deserialise(mem1,mem1.size()) ; // make sure t1 is equal to t2 // check(t1.str,dynamic_cast(t2)->str) ; check(t1.ts,dynamic_cast(t2)->ts) ; check(t1.int_set,dynamic_cast(t2)->int_set) ; delete t2; return 0; } catch(std::exception& e) { std::cerr << "Exception caught: " << e.what() << std::endl; return 1; } }