diff --git a/libretroshare/src/chat/rschatitems.cc b/libretroshare/src/chat/rschatitems.cc index 24aef56f9..370cef5d3 100644 --- a/libretroshare/src/chat/rschatitems.cc +++ b/libretroshare/src/chat/rschatitems.cc @@ -207,7 +207,7 @@ void RsPrivateChatMsgConfigItem::get(RsChatMsgItem *ci) /* Necessary to serialize `store` that is an STL container with RsChatMsgItem * inside which is a subtype of RsItem */ -RS_REGISTER_ITEM_TYPE(RsChatMsgItem) +RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsChatMsgItem) void PrivateOugoingMapItem::serial_process( RsGenericSerializer::SerializeJob j, diff --git a/libretroshare/src/gxstrans/p3gxstransitems.cc b/libretroshare/src/gxstrans/p3gxstransitems.cc index cebbd9e69..8ea0f4557 100644 --- a/libretroshare/src/gxstrans/p3gxstransitems.cc +++ b/libretroshare/src/gxstrans/p3gxstransitems.cc @@ -1,6 +1,6 @@ /* * GXS Mailing Service - * Copyright (C) 2016-2017 Gioacchino Mazzurco + * Copyright (C) 2016-2018 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -38,11 +38,15 @@ OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, memcpy(&mailData[0], data, size); } +// for mailItem +RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsGxsTransMailItem) -RS_REGISTER_ITEM_TYPE(RsGxsTransMailItem) // for mailItem -RS_REGISTER_ITEM_TYPE(RsNxsTransPresignedReceipt) // for presignedReceipt +// for presignedReceipt +RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsNxsTransPresignedReceipt) -void OutgoingRecord_deprecated::serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) +void OutgoingRecord_deprecated::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) { RS_REGISTER_SERIAL_MEMBER_TYPED(status, uint8_t); RS_REGISTER_SERIAL_MEMBER(recipient); diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 1521f5574..99499c686 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -553,7 +553,7 @@ SOURCES += ft/ftchunkmap.cc \ ft/ftfilesearch.cc \ ft/ftserver.cc \ ft/fttransfermodule.cc \ - ft/ftturtlefiletransferitem.cc + ft/ftturtlefiletransferitem.cc SOURCES += crypto/chacha20.cpp \ crypto/hashstream.cc @@ -648,6 +648,7 @@ SOURCES += serialiser/rsbaseserial.cc \ rsitems/rsgxsupdateitems.cc \ rsitems/rsserviceinfoitems.cc \ + SOURCES += services/autoproxy/rsautoproxymonitor.cc \ services/autoproxy/p3i2pbob.cc \ services/p3msgservice.cc \ @@ -786,7 +787,8 @@ SOURCES += gxstunnel/p3gxstunnel.cc \ gxstunnel/rsgxstunnelitems.cc # new serialization code -HEADERS += serialiser/rsserializer.h \ +HEADERS += serialiser/rsserializable.h \ + serialiser/rsserializer.h \ serialiser/rstypeserializer.h SOURCES += serialiser/rsserializer.cc \ diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index fd477fc9f..659a87e2f 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -1,3 +1,23 @@ +/* + * rsgxsifacetypes.h + * + * Copyright (C) 2013 crispy + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + /* * rsgxsifacetypes.h * @@ -13,8 +33,10 @@ #include #include -#include -#include +#include "retroshare/rstypes.h" +#include "retroshare/rsids.h" +#include "serialiser/rsserializable.h" +#include "serialiser/rstypeserializer.h" typedef GXSGroupId RsGxsGroupId; typedef Sha1CheckSum RsGxsMessageId; @@ -34,7 +56,7 @@ typedef std::map > MsgMetaResult; class RsGxsGrpMetaData; class RsGxsMsgMetaData; -struct RsGroupMetaData +struct RsGroupMetaData : RsSerializable { // (csoler) The correct default value to be used in mCircleType is GXS_CIRCLE_TYPE_PUBLIC, which is defined in rsgxscircles.h, // but because of a loop in the includes, I cannot include it here. So I replaced with its current value 0x0001. @@ -73,6 +95,30 @@ struct RsGroupMetaData std::string mServiceString; // Service Specific Free-Form extra storage. RsPeerId mOriginator; RsGxsCircleId mInternalCircle; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_REGISTER_SERIAL_MEMBER(mGroupId); + RS_REGISTER_SERIAL_MEMBER(mGroupName); + RS_REGISTER_SERIAL_MEMBER(mGroupFlags); + RS_REGISTER_SERIAL_MEMBER(mSignFlags); + RS_REGISTER_SERIAL_MEMBER(mPublishTs); + RS_REGISTER_SERIAL_MEMBER(mAuthorId); + RS_REGISTER_SERIAL_MEMBER(mCircleId); + RS_REGISTER_SERIAL_MEMBER(mCircleType); + RS_REGISTER_SERIAL_MEMBER(mAuthenFlags); + RS_REGISTER_SERIAL_MEMBER(mParentGrpId); + RS_REGISTER_SERIAL_MEMBER(mSubscribeFlags); + RS_REGISTER_SERIAL_MEMBER(mPop); + RS_REGISTER_SERIAL_MEMBER(mVisibleMsgCount); + RS_REGISTER_SERIAL_MEMBER(mLastPost); + RS_REGISTER_SERIAL_MEMBER(mGroupStatus); + RS_REGISTER_SERIAL_MEMBER(mServiceString); + RS_REGISTER_SERIAL_MEMBER(mOriginator); + RS_REGISTER_SERIAL_MEMBER(mInternalCircle); + } }; diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index bf650d462..b79cbe8fd 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -6,7 +6,8 @@ * * RetroShare C++ Interface. * - * Copyright 2012-2012 by Robert Fernie. + * Copyright (C) 2012 Robert Fernie. + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -36,6 +37,9 @@ #include "retroshare/rsids.h" #include "serialiser/rstlvimage.h" #include "retroshare/rsgxscommon.h" +#include "serialiser/rsserializable.h" +#include "serialiser/rstypeserializer.h" +#include "util/rsdeprecate.h" /* The Main Interface Class - for information about your Peers */ class RsIdentity; @@ -63,6 +67,7 @@ extern RsIdentity *rsIdentity; #define RSID_RELATION_OTHER 0x0008 #define RSID_RELATION_UNKNOWN 0x0010 +/// @deprecated remove toghether with RsGxsIdGroup::mRecognTags #define RSRECOGN_MAX_TAGINFO 5 // Unicode symbols. NOT utf-8 bytes, because of multi byte characters @@ -77,27 +82,36 @@ static const uint32_t RS_IDENTITY_FLAGS_PGP_KNOWN = 0x0004; static const uint32_t RS_IDENTITY_FLAGS_IS_OWN_ID = 0x0008; static const uint32_t RS_IDENTITY_FLAGS_IS_DEPRECATED= 0x0010; // used to denote keys with deprecated fingerprint format. -class GxsReputation +struct GxsReputation : RsSerializable { - public: - GxsReputation(); + GxsReputation(); - bool updateIdScore(bool pgpLinked, bool pgpKnown); - bool update(); // checks ranges and calculates overall score. - int mOverallScore; - int mIdScore; // PGP, Known, etc. - int mOwnOpinion; - int mPeerOpinion; + bool updateIdScore(bool pgpLinked, bool pgpKnown); + bool update(); /// checks ranges and calculates overall score. + + int32_t mOverallScore; + int32_t mIdScore; /// PGP, Known, etc. + int32_t mOwnOpinion; + int32_t mPeerOpinion; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_REGISTER_SERIAL_MEMBER(mOverallScore); + RS_REGISTER_SERIAL_MEMBER(mIdScore); + RS_REGISTER_SERIAL_MEMBER(mOwnOpinion); + RS_REGISTER_SERIAL_MEMBER(mPeerOpinion); + } }; -struct RsGxsIdGroup +struct RsGxsIdGroup : RsSerializable { RsGxsIdGroup() : mLastUsageTS(0), mPgpKnown(false), mIsAContact(false) {} ~RsGxsIdGroup() {} - RsGroupMetaData mMeta; // In GroupMetaData. @@ -120,7 +134,7 @@ struct RsGxsIdGroup std::string mPgpIdSign; // Recognition Strings. MAX# defined above. - std::list mRecognTags; + RS_DEPRECATED std::list mRecognTags; // Avatar RsGxsImage mImage ; @@ -131,8 +145,11 @@ struct RsGxsIdGroup bool mIsAContact; // change that into flags one day RsPgpId mPgpId; GxsReputation mReputation; -}; + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); +}; std::ostream &operator<<(std::ostream &out, const RsGxsIdGroup &group); @@ -149,12 +166,11 @@ class RsRecognTag }; -class RsRecognTagDetails +struct RsRecognTagDetails { - public: - RsRecognTagDetails() - :valid_from(0), valid_to(0), tag_class(0), tag_type(0), - is_valid(false), is_pending(false) { return; } + RsRecognTagDetails() : + valid_from(0), valid_to(0), tag_class(0), tag_type(0), is_valid(false), + is_pending(false) {} time_t valid_from; time_t valid_to; @@ -167,105 +183,168 @@ class RsRecognTagDetails bool is_pending; }; -class RsIdOpinion -{ - public: - RsGxsId id; - int rating; -}; - -class RsIdentityParameters +struct RsIdentityParameters { - public: - RsIdentityParameters(): isPgpLinked(false) { return; } + RsIdentityParameters() : + isPgpLinked(false) {} + bool isPgpLinked; - std::string nickname; - RsGxsImage mImage ; + std::string nickname; + RsGxsImage mImage; }; -class RsIdentityUsage +struct RsIdentityUsage : RsSerializable { -public: - enum UsageCode { UNKNOWN_USAGE = 0x00, - GROUP_ADMIN_SIGNATURE_CREATION = 0x01, // These 2 are normally not normal GXS identities, but nothing prevents it to happen either. - GROUP_ADMIN_SIGNATURE_VALIDATION = 0x02, - GROUP_AUTHOR_SIGNATURE_CREATION = 0x03, // not typically used, since most services do not require group author signatures - GROUP_AUTHOR_SIGNATURE_VALIDATION = 0x04, - MESSAGE_AUTHOR_SIGNATURE_CREATION = 0x05, // most common use case. Messages are signed by authors in e.g. forums. - MESSAGE_AUTHOR_SIGNATURE_VALIDATION = 0x06, - GROUP_AUTHOR_KEEP_ALIVE = 0x07, // Identities are stamped regularly by crawlign the set of messages for all groups. That helps keepign the useful identities in hand. - MESSAGE_AUTHOR_KEEP_ALIVE = 0x08, // Identities are stamped regularly by crawlign the set of messages for all groups. That helps keepign the useful identities in hand. - CHAT_LOBBY_MSG_VALIDATION = 0x09, // Chat lobby msgs are signed, so each time one comes, or a chat lobby event comes, a signature verificaiton happens. - GLOBAL_ROUTER_SIGNATURE_CHECK = 0x0a, // Global router message validation - GLOBAL_ROUTER_SIGNATURE_CREATION = 0x0b, // Global router message signature - GXS_TUNNEL_DH_SIGNATURE_CHECK = 0x0c, // - GXS_TUNNEL_DH_SIGNATURE_CREATION = 0x0d, // - IDENTITY_DATA_UPDATE = 0x0e, // Group update on that identity data. Can be avatar, name, etc. - IDENTITY_GENERIC_SIGNATURE_CHECK = 0x0f, // Any signature verified for that identity - IDENTITY_GENERIC_SIGNATURE_CREATION = 0x10, // Any signature made by that identity - IDENTITY_GENERIC_ENCRYPTION = 0x11, - IDENTITY_GENERIC_DECRYPTION = 0x12, - CIRCLE_MEMBERSHIP_CHECK = 0x13 - } ; + enum UsageCode : uint8_t + { + UNKNOWN_USAGE = 0x00, - explicit RsIdentityUsage(uint16_t service,const RsIdentityUsage::UsageCode& code,const RsGxsGroupId& gid=RsGxsGroupId(),const RsGxsMessageId& mid=RsGxsMessageId(),uint64_t additional_id=0,const std::string& comment = std::string()); + /** These 2 are normally not normal GXS identities, but nothing prevents + * it to happen either. */ + GROUP_ADMIN_SIGNATURE_CREATION = 0x01, + GROUP_ADMIN_SIGNATURE_VALIDATION = 0x02, - uint16_t mServiceId; // Id of the service using that identity, as understood by rsServiceControl - UsageCode mUsageCode; // Specific code to use. Will allow forming the correct translated message in the GUI if necessary. - RsGxsGroupId mGrpId; // Group ID using the identity + /** Not typically used, since most services do not require group author + * signatures */ + GROUP_AUTHOR_SIGNATURE_CREATION = 0x03, + GROUP_AUTHOR_SIGNATURE_VALIDATION = 0x04, - RsGxsMessageId mMsgId; // Message ID using the identity - uint64_t mAdditionalId; // Some additional ID. Can be used for e.g. chat lobbies. - std::string mComment ; // additional comment to be used mainly for debugging, but not GUI display + /// most common use case. Messages are signed by authors in e.g. forums. + MESSAGE_AUTHOR_SIGNATURE_CREATION = 0x05, + MESSAGE_AUTHOR_SIGNATURE_VALIDATION = 0x06, - bool operator<(const RsIdentityUsage& u) const - { - return mHash < u.mHash ; - } - RsFileHash mHash ; + /** Identities are stamped regularly by crawlign the set of messages for + * all groups. That helps keepign the useful identities in hand. */ + GROUP_AUTHOR_KEEP_ALIVE = 0x07, + MESSAGE_AUTHOR_KEEP_ALIVE = 0x08, + + /** Chat lobby msgs are signed, so each time one comes, or a chat lobby + * event comes, a signature verificaiton happens. */ + CHAT_LOBBY_MSG_VALIDATION = 0x09, + + /// Global router message validation + GLOBAL_ROUTER_SIGNATURE_CHECK = 0x0a, + + /// Global router message signature + GLOBAL_ROUTER_SIGNATURE_CREATION = 0x0b, + + GXS_TUNNEL_DH_SIGNATURE_CHECK = 0x0c, + GXS_TUNNEL_DH_SIGNATURE_CREATION = 0x0d, + + /// Group update on that identity data. Can be avatar, name, etc. + IDENTITY_DATA_UPDATE = 0x0e, + + /// Any signature verified for that identity + IDENTITY_GENERIC_SIGNATURE_CHECK = 0x0f, + + /// Any signature made by that identity + IDENTITY_GENERIC_SIGNATURE_CREATION = 0x10, + + IDENTITY_GENERIC_ENCRYPTION = 0x11, + IDENTITY_GENERIC_DECRYPTION = 0x12, + CIRCLE_MEMBERSHIP_CHECK = 0x13 + } ; + + RsIdentityUsage( uint16_t service, const RsIdentityUsage::UsageCode& code, + const RsGxsGroupId& gid = RsGxsGroupId(), + const RsGxsMessageId& mid = RsGxsMessageId(), + uint64_t additional_id=0, + const std::string& comment = std::string() ); + + /// Id of the service using that identity, as understood by rsServiceControl + uint16_t mServiceId; + + /** Specific code to use. Will allow forming the correct translated message + * in the GUI if necessary. */ + UsageCode mUsageCode; + + /// Group ID using the identity + RsGxsGroupId mGrpId; + + /// Message ID using the identity + RsGxsMessageId mMsgId; + + /// Some additional ID. Can be used for e.g. chat lobbies. + uint64_t mAdditionalId; + + /// additional comment to be used mainly for debugging, but not GUI display + std::string mComment; + + bool operator<(const RsIdentityUsage& u) const { return mHash < u.mHash; } + RsFileHash mHash ; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_REGISTER_SERIAL_MEMBER(mServiceId); + RS_REGISTER_SERIAL_MEMBER_TYPED(mUsageCode, uint8_t); + RS_REGISTER_SERIAL_MEMBER(mGrpId); + RS_REGISTER_SERIAL_MEMBER(mMsgId); + RS_REGISTER_SERIAL_MEMBER(mAdditionalId); + RS_REGISTER_SERIAL_MEMBER(mComment); + RS_REGISTER_SERIAL_MEMBER(mHash); + } + + friend class RsTypeSerializer; +private: + /** Accessible only to friend class RsTypeSerializer needed for + * deserialization */ + RsIdentityUsage(); }; -class RsIdentityDetails +RS_REGISTER_SERIALIZABLE_TYPE_DECL(RsIdentityUsage) + + +struct RsIdentityDetails : RsSerializable { -public: - RsIdentityDetails() - : mFlags(0), mLastUsageTS(0) { return; } + RsIdentityDetails() : mFlags(0), mLastUsageTS(0) {} RsGxsId mId; - // identity details. std::string mNickname; - uint32_t mFlags ; + uint32_t mFlags; - // PGP Stuff. - RsPgpId mPgpId; + RsPgpId mPgpId; - // Recogn details. - std::list mRecognTags; + /// @deprecated Recogn details. + RS_DEPRECATED std::list mRecognTags; - // Cyril: Reputation details. At some point we might want to merge information - // between the two into a single global score. Since the old reputation system - // is not finished yet, I leave this in place. We should decide what to do with it. - RsReputations::ReputationInfo mReputation; + /** Cyril: Reputation details. At some point we might want to merge + * information between the two into a single global score. Since the old + * reputation system is not finished yet, I leave this in place. We should + * decide what to do with it. + */ + RsReputations::ReputationInfo mReputation; - // avatar - RsGxsImage mAvatar ; + RsGxsImage mAvatar; - // last usage - time_t mLastUsageTS ; - std::map mUseCases ; + time_t mLastUsageTS; + + std::map mUseCases; + + /// @see RsSerializable + virtual void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) + { + RS_REGISTER_SERIAL_MEMBER(mId); + RS_REGISTER_SERIAL_MEMBER(mNickname); + RS_REGISTER_SERIAL_MEMBER(mFlags); + RS_REGISTER_SERIAL_MEMBER(mPgpId); + //RS_REGISTER_SERIAL_MEMBER_TYPED(mReputation, RsSerializable); + //RS_REGISTER_SERIAL_MEMBER_TYPED(mAvatar, RsSerializable); + RS_REGISTER_SERIAL_MEMBER(mLastUsageTS); + RS_REGISTER_SERIAL_MEMBER(mUseCases); + } }; -class RsIdentity: public RsGxsIfaceHelper +struct RsIdentity : RsGxsIfaceHelper { - -public: - explicit RsIdentity(RsGxsIface *gxs): RsGxsIfaceHelper(gxs) {} virtual ~RsIdentity() {} diff --git a/libretroshare/src/rsitems/rsitem.h b/libretroshare/src/rsitems/rsitem.h index 056bbe084..fb76d1562 100644 --- a/libretroshare/src/rsitems/rsitem.h +++ b/libretroshare/src/rsitems/rsitem.h @@ -1,76 +1,96 @@ #pragma once +/* + * RetroShare Serialiser. + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ #include // for typeid #include "util/smallobject.h" #include "retroshare/rstypes.h" #include "serialiser/rsserializer.h" +#include "serialiser/rsserializable.h" #include "util/stacktrace.h" #include -class RsItem: public RsMemoryManagement::SmallObject +struct RsItem : RsMemoryManagement::SmallObject, RsSerializable { - public: - explicit RsItem(uint32_t t); - RsItem(uint8_t ver, uint8_t cls, uint8_t t, uint8_t subtype); + explicit RsItem(uint32_t t); + RsItem(uint8_t ver, uint8_t cls, uint8_t t, uint8_t subtype); #ifdef DO_STATISTICS - void *operator new(size_t s) ; - void operator delete(void *,size_t s) ; + void *operator new(size_t s) ; + void operator delete(void *,size_t s) ; #endif - virtual ~RsItem(); + virtual ~RsItem(); - /// TODO: Do this make sense with the new serialization system? - virtual void clear() = 0; + /// TODO: Do this make sense with the new serialization system? + virtual void clear() = 0; - virtual std::ostream &print(std::ostream &out, uint16_t /* indent */ = 0) - { - RsGenericSerializer::SerializeContext ctx(NULL,0,RsGenericSerializer::FORMAT_BINARY,RsGenericSerializer::SERIALIZATION_FLAG_NONE); - serial_process(RsGenericSerializer::PRINT,ctx) ; - return out; - } + virtual std::ostream &print(std::ostream &out, uint16_t /* indent */ = 0) + { + RsGenericSerializer::SerializeContext ctx( + NULL, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + serial_process(RsGenericSerializer::PRINT,ctx); + return out; + } - void print_string(std::string &out, uint16_t indent = 0); + void print_string(std::string &out, uint16_t indent = 0); - /* source / destination id */ - const RsPeerId& PeerId() const { return peerId; } - void PeerId(const RsPeerId& id) { peerId = id; } + /// source / destination id + const RsPeerId& PeerId() const { return peerId; } + void PeerId(const RsPeerId& id) { peerId = id; } - /* complete id */ - uint32_t PacketId() const; + /// complete id + uint32_t PacketId() const; - /* id parts */ - uint8_t PacketVersion(); - uint8_t PacketClass(); - uint8_t PacketType(); - uint8_t PacketSubType() const; + /// id parts + uint8_t PacketVersion(); + uint8_t PacketClass(); + uint8_t PacketType(); + uint8_t PacketSubType() const; - /* For Service Packets */ - RsItem(uint8_t ver, uint16_t service, uint8_t subtype); - uint16_t PacketService() const; /* combined Packet class/type (mid 16bits) */ - void setPacketService(uint16_t service); + /// For Service Packets + RsItem(uint8_t ver, uint16_t service, uint8_t subtype); + uint16_t PacketService() const; /* combined Packet class/type (mid 16bits) */ + void setPacketService(uint16_t service); - inline uint8_t priority_level() const { return _priority_level ;} - inline void setPriorityLevel(uint8_t l) { _priority_level = l ;} + inline uint8_t priority_level() const { return _priority_level ;} + inline void setPriorityLevel(uint8_t l) { _priority_level = l ;} - /** - * TODO: This should be made pure virtual as soon as all the codebase - * is ported to the new serialization system - */ - virtual void serial_process(RsGenericSerializer::SerializeJob, - RsGenericSerializer::SerializeContext&)// = 0; - { - std::cerr << "(EE) RsItem::serial_process() called by an item using" - << "new serialization classes, but not derived! Class is " - << typeid(*this).name() << std::endl; - print_stacktrace(); - } + /** + * TODO: This default implementation should be removed and childs structs + * implement RsSerializable(...) as soon as all the codebase is ported to + * the new serialization system + */ + virtual void serial_process(RsGenericSerializer::SerializeJob, + RsGenericSerializer::SerializeContext&)// = 0; + { + std::cerr << "(EE) RsItem::serial_process(...) called by an item using" + << "new serialization classes, but not derived! Class is " + << typeid(*this).name() << std::endl; + print_stacktrace(); + } - protected: - uint32_t type; - RsPeerId peerId; - uint8_t _priority_level ; +protected: + uint32_t type; + RsPeerId peerId; + uint8_t _priority_level; }; /// TODO: Do this make sense with the new serialization system? diff --git a/libretroshare/src/serialiser/rsbaseserial.cc b/libretroshare/src/serialiser/rsbaseserial.cc index 44bd249d1..ef862db5c 100644 --- a/libretroshare/src/serialiser/rsbaseserial.cc +++ b/libretroshare/src/serialiser/rsbaseserial.cc @@ -238,8 +238,7 @@ uint32_t getRawStringSize(const std::string &outStr) bool getRawString(const void *data, uint32_t size, uint32_t *offset, std::string &outStr) { -#warning Gio: "I had to change this. It seems like a bug to not clear the string. Should make sure it's not introducing any side effect." - outStr.clear(); + outStr.clear(); uint32_t len = 0; if (!getRawUInt32(data, size, offset, &len)) diff --git a/libretroshare/src/serialiser/rsserializable.h b/libretroshare/src/serialiser/rsserializable.h new file mode 100644 index 000000000..b90e6c666 --- /dev/null +++ b/libretroshare/src/serialiser/rsserializable.h @@ -0,0 +1,137 @@ +#pragma once +/* + * RetroShare Serialiser. + * Copyright (C) 2016-2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "serialiser/rsserializer.h" + +/** @brief Minimal ancestor for all serializable structs in RetroShare + * If you want your struct to be easly serializable you should inherit from this + * struct. + */ +struct RsSerializable +{ + /** Register struct members to serialize in this method taking advantage of + * the helper macros + * @see RS_REGISTER_SERIAL_MEMBER(I) + * @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) + * @see RS_REGISTER_SERIALIZABLE_TYPE(T) + */ + virtual void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) = 0; +}; + + +/** @def RS_REGISTER_SERIAL_MEMBER(I) + * Use this macro to register the members of `YourSerializable` for serial + * processing inside `YourSerializable::serial_process(j, ctx)` + * + * Inspired by http://stackoverflow.com/a/39345864 + */ +#define RS_REGISTER_SERIAL_MEMBER(I) \ + do { RsTypeSerializer::serial_process(j, ctx, I, #I); } while(0) + + +/** @def RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) + * This macro usage is similar to @see RS_REGISTER_SERIAL_MEMBER(I) but it + * permit to force serialization/deserialization type, it is expecially useful + * with enum class members or RsTlvItem derivative members, be very careful with + * the type you pass, as reinterpret_cast on a reference is used that is + * expecially permissive so you can shot your feet if not carefull enough. + * + * If you are using this with an RsSerializable derivative (so passing + * RsSerializable as T) consider to register your item type with + * @see RS_REGISTER_SERIALIZABLE_TYPE(T) in + * association with @see RS_REGISTER_SERIAL_MEMBER(I) that rely on template + * function generation, as in this particular case + * RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) would cause the serial code rely on + * C++ dynamic dispatching that may have a noticeable impact on runtime + * performances. + */ +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#define RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) do {\ + RsTypeSerializer::serial_process(j, ctx, reinterpret_cast(I), #I);\ + } while(0) +#pragma GCC diagnostic pop + + +/** @def RS_REGISTER_SERIALIZABLE_TYPE(T) + * Use this macro into `youritem.cc` only if you need to process members of + * subtypes of RsSerializable. + * + * The usage of this macro is strictly needed only in some cases, for example if + * you are registering for serialization a member of a container that contains + * items of subclasses of RsSerializable like + * `std::map` + * + * @code{.cpp} +struct PrivateOugoingMapItem : RsChatItem +{ + PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {} + + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); + + std::map store; +}; + +RS_REGISTER_SERIALIZABLE_TYPE(RsChatMsgItem) + +void PrivateOugoingMapItem::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ + // store is of type + RS_REGISTER_SERIAL_MEMBER(store); +} + * @endcode + * + * If you use this macro with a lot of different item types this can cause the + * generated binary grow in size, consider the usage of + * @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) passing RsSerializable as type in + * that case. + */ +#define RS_REGISTER_SERIALIZABLE_TYPE_DEF(T) template<> /*static*/\ + void RsTypeSerializer::serial_process( \ + RsGenericSerializer::SerializeJob j,\ + RsGenericSerializer::SerializeContext& ctx, T& item,\ + const std::string& objName ) \ +{ \ + RsTypeSerializer::serial_process( j, \ + ctx, static_cast(item), objName ); \ +} + + +/** @def RS_REGISTER_SERIALIZABLE_TYPE_DECL(T) + * The usage of this macro into your header file is needed only in case you + * needed @see RS_REGISTER_SERIALIZABLE_TYPE_DEF(T) in your definitions file, + * but it was not enough and the compiler kept complanining about undefined + * references to serialize, deserialize, serial_size, print_data, to_JSON, + * from_JSON for your RsSerializable derrived type. + * + * One example of such case is RsIdentityUsage that is declared in + * retroshare/rsidentity.h but defined in services/p3idservice.cc, also if + * RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsIdentityUsage) was used in p3idservice.cc + * for some reason it was not enough for the compiler to see it so + * RS_REGISTER_SERIALIZABLE_TYPE_DECL(RsIdentityUsage) has been added in + * rsidentity.h too and now the compiler is happy. + */ +#define RS_REGISTER_SERIALIZABLE_TYPE_DECL(T) template<> /*static*/\ + void RsTypeSerializer::serial_process( \ + RsGenericSerializer::SerializeJob j,\ + RsGenericSerializer::SerializeContext& ctx, T& item,\ + const std::string& /*objName*/ ); diff --git a/libretroshare/src/serialiser/rsserializer.h b/libretroshare/src/serialiser/rsserializer.h index 2cae93ab7..63b565a9b 100644 --- a/libretroshare/src/serialiser/rsserializer.h +++ b/libretroshare/src/serialiser/rsserializer.h @@ -3,7 +3,8 @@ * * RetroShare Serialiser. * - * Copyright 2016 by Cyril Soler + * Copyright (C) 2016 Cyril Soler + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -153,9 +154,11 @@ #include #include #include +#include #include "retroshare/rsflags.h" #include "serialiser/rsserial.h" +#include "util/rsdeprecate.h" class RsItem ; @@ -194,106 +197,125 @@ class RsRawSerialiser: public RsSerialType virtual RsItem * deserialise(void *data, uint32_t *size); }; -// Top class for all services and config serializers. +typedef rapidjson::Document RsJson; -class RsGenericSerializer: public RsSerialType +/// Top class for all services and config serializers. +struct RsGenericSerializer : RsSerialType { -public: - typedef enum { SIZE_ESTIMATE = 0x01, SERIALIZE = 0x02, DESERIALIZE = 0x03, PRINT=0x04 } SerializeJob ; - typedef enum { FORMAT_BINARY = 0x01, FORMAT_JSON = 0x02 } SerializationFormat ; - - class SerializeContext - { - public: + typedef enum + { + SIZE_ESTIMATE = 0x01, + SERIALIZE = 0x02, + DESERIALIZE = 0x03, + PRINT = 0x04, + TO_JSON, + FROM_JSON + } SerializeJob; - SerializeContext(uint8_t *data,uint32_t size,SerializationFormat format,SerializationFlags flags) - : mData(data),mSize(size),mOffset(0),mOk(true),mFormat(format),mFlags(flags) {} + /** @deprecated use SerializeJob instead */ + RS_DEPRECATED typedef enum + { + FORMAT_BINARY = 0x01, + FORMAT_JSON = 0x02 + } SerializationFormat; - unsigned char *mData ; - uint32_t mSize ; - uint32_t mOffset ; - bool mOk ; - SerializationFormat mFormat ; - SerializationFlags mFlags ; - }; + struct SerializeContext + { + /** Allow shared allocator usage to avoid costly JSON deepcopy for + * nested RsSerializable */ + SerializeContext( + uint8_t *data, uint32_t size, SerializationFormat format, + SerializationFlags flags, + RsJson::AllocatorType* allocator = nullptr) : + mData(data), mSize(size), mOffset(0), mOk(true), mFormat(format), + mFlags(flags), mJson(rapidjson::kObjectType, allocator) {} - // These are convenience flags to be used by the items when processing the data. The names of the flags - // are not very important. What matters is that the serial_process() method of each item correctly - // deals with the data when it sees the flags, if the serialiser sets them. By default the flags are not - // set and shouldn't be handled. - // When deriving a new serializer, the user can set his own flags, using compatible values + unsigned char *mData; + uint32_t mSize; + uint32_t mOffset; + bool mOk; + RS_DEPRECATED SerializationFormat mFormat; + SerializationFlags mFlags; + RsJson mJson; + }; - static const SerializationFlags SERIALIZATION_FLAG_NONE ; // 0x0000 - static const SerializationFlags SERIALIZATION_FLAG_CONFIG ; // 0x0001 - static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE ; // 0x0002 - static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER ; // 0x0004 + /** These are convenience flags to be used by the items when processing the + * data. The names of the flags are not very important. What matters is that + * the serial_process() method of each item correctly deals with the data + * when it sees the flags, if the serialiser sets them. + * By default the flags are not set and shouldn't be handled. + * When deriving a new serializer, the user can set his own flags, using + * compatible values + */ + static const SerializationFlags SERIALIZATION_FLAG_NONE; // 0x0000 + static const SerializationFlags SERIALIZATION_FLAG_CONFIG; // 0x0001 + static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE; // 0x0002 + static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER; // 0x0004 - // The following functions overload RsSerialType. They *should not* need to be further overloaded. - - RsItem *deserialise(void *data,uint32_t *size) =0; - bool serialise(RsItem *item,void *data,uint32_t *size) ; - uint32_t size(RsItem *item) ; - void print(RsItem *item) ; + /** + * The following functions overload RsSerialType. + * They *should not* need to be further overloaded. + */ + RsItem *deserialise(void *data,uint32_t *size) = 0; + bool serialise(RsItem *item,void *data,uint32_t *size); + uint32_t size(RsItem *item); + void print(RsItem *item); protected: - RsGenericSerializer(uint8_t serial_class, - uint8_t serial_type, - SerializationFormat format, - SerializationFlags flags ) - : RsSerialType(RS_PKT_VERSION1,serial_class,serial_type), mFormat(format),mFlags(flags) - {} + RsGenericSerializer( + uint8_t serial_class, uint8_t serial_type, + SerializationFormat format, SerializationFlags flags ) : + RsSerialType( RS_PKT_VERSION1, serial_class, serial_type), + mFormat(format), mFlags(flags) {} - RsGenericSerializer(uint16_t service, - SerializationFormat format, - SerializationFlags flags ) - : RsSerialType(RS_PKT_VERSION_SERVICE,service), mFormat(format),mFlags(flags) - {} - - SerializationFormat mFormat ; - SerializationFlags mFlags ; + RsGenericSerializer( + uint16_t service, SerializationFormat format, + SerializationFlags flags ) : + RsSerialType( RS_PKT_VERSION_SERVICE, service ), mFormat(format), + mFlags(flags) {} + SerializationFormat mFormat; + SerializationFlags mFlags; }; -// Top class for service serializers. Derive your on service serializer from this class and overload creat_item(). -class RsServiceSerializer: public RsGenericSerializer +/** Top class for service serializers. + * Derive your on service serializer from this class and overload creat_item(). + */ +struct RsServiceSerializer : RsGenericSerializer { -public: - RsServiceSerializer(uint16_t service_id, - SerializationFormat format = FORMAT_BINARY, - SerializationFlags flags = SERIALIZATION_FLAG_NONE) + RsServiceSerializer( + uint16_t service_id, SerializationFormat format = FORMAT_BINARY, + SerializationFlags flags = SERIALIZATION_FLAG_NONE ) : + RsGenericSerializer(service_id, format, flags) {} - : RsGenericSerializer(service_id,format,flags) {} + /*! should be overloaded to create the correct type of item depending on the + * data */ + virtual RsItem *create_item( uint16_t /* service */, + uint8_t /* item_sub_id */ ) const = 0; - /*! create_item - * should be overloaded to create the correct type of item depending on the data - */ - virtual RsItem *create_item(uint16_t /* service */, uint8_t /* item_sub_id */) const=0; - - RsItem *deserialise(void *data,uint32_t *size) ; + RsItem *deserialise(void *data, uint32_t *size); }; -// Top class for config serializers. Config serializers are only used internally by RS core. The development of new services or plugins do not need this. -class RsConfigSerializer: public RsGenericSerializer +/** Top class for config serializers. + * Config serializers are only used internally by RS core. + * The development of new services or plugins do not need this. + */ +struct RsConfigSerializer : RsGenericSerializer { -public: RsConfigSerializer(uint8_t config_class, uint8_t config_type, SerializationFormat format = FORMAT_BINARY, - SerializationFlags flags = SERIALIZATION_FLAG_NONE) + SerializationFlags flags = SERIALIZATION_FLAG_NONE) : + RsGenericSerializer(config_class,config_type,format,flags) {} - : RsGenericSerializer(config_class,config_type,format,flags) {} + /*! should be overloaded to create the correct type of item depending on the + * data */ + virtual RsItem *create_item(uint8_t /* item_type */, + uint8_t /* item_sub_type */) const = 0; - /*! create_item - * should be overloaded to create the correct type of item depending on the data - */ - virtual RsItem *create_item(uint8_t /* item_type */, uint8_t /* item_sub_type */) const=0; - - RsItem *deserialise(void *data,uint32_t *size) ; + RsItem *deserialise(void *data,uint32_t *size); }; - - - diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 8be8660ae..c2b0ba905 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -3,7 +3,8 @@ * * RetroShare Serialiser. * - * Copyright 2017 by Cyril Soler + * Copyright (C) 2017 Cyril Soler + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,27 +27,48 @@ #include "serialiser/rstypeserializer.h" #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvkeys.h" - -#include "rsitems/rsitem.h" +#include "serialiser/rsserializable.h" #include "util/rsprint.h" #include #include #include +#include +#include // for typeid +#include +#include //static const uint32_t MAX_SERIALIZED_ARRAY_SIZE = 500 ; static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. -//=================================================================================================// -// Integer types // -//=================================================================================================// +#define SAFE_GET_JSON_V() \ + const char* mName = memberName.c_str(); \ + bool ret = jVal.HasMember(mName); \ + if(!ret) \ + { \ + std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName \ + << "\" not found in JSON:" << std::endl \ + << jVal << std::endl << std::endl; \ + print_stacktrace(); \ + return false; \ + } \ + rapidjson::Value& v = jVal[mName] + +//============================================================================// +// Integer types // +//============================================================================// template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const bool& member) { return setRawUInt8(data,size,&offset,member); } +template<> bool RsTypeSerializer::serialize(uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, const int32_t& /*member*/) +{ + // TODO: nice to have but not used ATM + return false; +} template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint8_t& member) { return setRawUInt8(data,size,&offset,member); @@ -70,10 +92,15 @@ template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint3 template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, bool& member) { - uint8_t m ; + uint8_t m; bool ok = getRawUInt8(data,size,&offset,&m); - member = m ; - return ok; + member = m; + return ok; +} +template<> bool RsTypeSerializer::deserialize(const uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, int32_t& /*member*/) +{ + // TODO: nice to have but not used ATM + return false; } template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint8_t& member) { @@ -100,6 +127,10 @@ template<> uint32_t RsTypeSerializer::serial_size(const bool& /* member*/) { return 1; } +template<> uint32_t RsTypeSerializer::serial_size(const int32_t& /* member*/) +{ + return 4; +} template<> uint32_t RsTypeSerializer::serial_size(const uint8_t& /* member*/) { return 1; @@ -125,6 +156,10 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const bool & { std::cerr << " [bool ] " << n << ": " << V << std::endl; } +template<> void RsTypeSerializer::print_data(const std::string& n, const int32_t& V) +{ + std::cerr << " [int32_t ] " << n << ": " << V << std::endl; +} template<> void RsTypeSerializer::print_data(const std::string& n, const uint8_t & V) { std::cerr << " [uint8_t ] " << n << ": " << V << std::endl; @@ -146,10 +181,104 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const time_t& std::cerr << " [time_t ] " << n << ": " << V << " (" << time(NULL)-V << " secs ago)" << std::endl; } +#define SIMPLE_TO_JSON_DEF(T) \ +template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ + const T& member, RsJson& jDoc ) \ +{ \ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); \ + \ + rapidjson::Value key; \ + key.SetString(memberName.c_str(), memberName.length(), allocator); \ + \ + rapidjson::Value value(member); \ + \ + jDoc.AddMember(key, value, allocator); \ + \ + return true; \ +} -//=================================================================================================// -// FLoats // -//=================================================================================================// +SIMPLE_TO_JSON_DEF(bool) +SIMPLE_TO_JSON_DEF(int32_t) +SIMPLE_TO_JSON_DEF(time_t) +SIMPLE_TO_JSON_DEF(uint8_t) +SIMPLE_TO_JSON_DEF(uint16_t) +SIMPLE_TO_JSON_DEF(uint32_t) +SIMPLE_TO_JSON_DEF(uint64_t) + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, bool& member, + RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsBool(); + if(ret) member = v.GetBool(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + int32_t& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsInt(); + if(ret) member = v.GetInt(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, time_t& member, + RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsUint(); + if(ret) member = v.GetUint(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint8_t& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsUint(); + if(ret) member = v.GetUint(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint16_t& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsUint(); + if(ret) member = v.GetUint(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint32_t& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsUint(); + if(ret) member = v.GetUint(); + return ret; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint64_t& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsUint(); + if(ret) member = v.GetUint(); + return ret; +} + + +//============================================================================// +// FLoats // +//============================================================================// template<> uint32_t RsTypeSerializer::serial_size(const float&){ return 4; } @@ -166,10 +295,75 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const float& std::cerr << " [float ] " << n << ": " << V << std::endl; } +SIMPLE_TO_JSON_DEF(float) -//=================================================================================================// -// TlvString with subtype // -//=================================================================================================// +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + float& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsFloat(); + if(ret) member = v.GetFloat(); + return ret; +} + + +//============================================================================// +// std::string // +//============================================================================// + +template<> uint32_t RsTypeSerializer::serial_size(const std::string& str) +{ + return getRawStringSize(str); +} +template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, + uint32_t& offset, + const std::string& str ) +{ + return setRawString(data, size, &offset, str); +} +template<> bool RsTypeSerializer::deserialize( const uint8_t data[], + uint32_t size, uint32_t &offset, + std::string& str ) +{ + return getRawString(data, size, &offset, str); +} +template<> void RsTypeSerializer::print_data( const std::string& n, + const std::string& str ) +{ + std::cerr << " [std::string] " << n << ": " << str << std::endl; +} +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& membername, + const std::string& member, RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString(membername.c_str(), membername.length(), allocator); + + rapidjson::Value value;; + value.SetString(member.c_str(), member.length(), allocator); + + jDoc.AddMember(key, value, allocator); + + return true; +} +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + std::string& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsString(); + if(ret) member = v.GetString(); + return ret; +} + + + +//============================================================================// +// TlvString with subtype // +//============================================================================// template<> uint32_t RsTypeSerializer::serial_size(uint16_t /* type_subtype */,const std::string& s) { @@ -188,46 +382,130 @@ template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t siz template<> void RsTypeSerializer::print_data(const std::string& n, uint16_t type_substring,const std::string& V) { - std::cerr << " [TlvString ] " << n << ": type=" << std::hex < uint32_t RsTypeSerializer::serial_size(uint16_t /* type_subtype */,const uint32_t& /*s*/) +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& memberName, + uint16_t /*sub_type*/, + const std::string& member, RsJson& jDoc ) { - return GetTlvUInt32Size() ; + return to_JSON(memberName, member, jDoc); } -template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset,uint16_t sub_type,const uint32_t& s) +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint16_t /*sub_type*/, + std::string& member, RsJson& jVal ) { - return SetTlvUInt32(data,size,&offset,sub_type,s) ; + return from_JSON(memberName, member, jVal); } -template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size,uint32_t& offset,uint16_t sub_type,uint32_t& s) +//============================================================================// +// TlvInt with subtype // +//============================================================================// + +template<> uint32_t RsTypeSerializer::serial_size( uint16_t /* type_subtype */, + const uint32_t& /*s*/ ) { - return GetTlvUInt32((void*)data,size,&offset,sub_type,&s) ; + return GetTlvUInt32Size(); +} + +template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, + uint32_t &offset,uint16_t sub_type, + const uint32_t& s) +{ + return SetTlvUInt32(data,size,&offset,sub_type,s); +} + +template<> bool RsTypeSerializer::deserialize( const uint8_t data[], + uint32_t size, uint32_t& offset, + uint16_t sub_type, uint32_t& s) +{ + return GetTlvUInt32((void*)data, size, &offset, sub_type, &s); } template<> void RsTypeSerializer::print_data(const std::string& n, uint16_t sub_type,const uint32_t& V) { - std::cerr << " [TlvUInt32 ] " << n << ": type=" << std::hex < void RsTypeSerializer::print_data(const std::string& n, const std::string& V) +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& memberName, + uint16_t /*sub_type*/, + const uint32_t& member, RsJson& jDoc ) { - std::cerr << " [std::string] " << n << ": " << V << std::endl; + return to_JSON(memberName, member, jDoc); } -//=================================================================================================// -// Binary blocks // -//=================================================================================================// +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + uint16_t /*sub_type*/, + uint32_t& member, RsJson& jVal ) +{ + return from_JSON(memberName, member, jVal); +} + + +//============================================================================// +// TlvItems // +//============================================================================// + +template<> uint32_t RsTypeSerializer::serial_size(const RsTlvItem& s) +{ + return s.TlvSize(); +} + +template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, + uint32_t &offset,const RsTlvItem& s) +{ + return s.SetTlv(data,size,&offset); +} + +template<> bool RsTypeSerializer::deserialize(const uint8_t data[], + uint32_t size,uint32_t& offset, + RsTlvItem& s) +{ + return s.GetTlv((void*)data,size,&offset) ; +} + +template<> void RsTypeSerializer::print_data( const std::string& n, + const RsTlvItem& s ) +{ + std::cerr << " [" << typeid(s).name() << "] " << n << std::endl; +} + +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& memberName, + const RsTlvItem& member, RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + rapidjson::Value value; + const char* tName = typeid(member).name(); + value.SetString(tName, allocator); + + jDoc.AddMember(key, value, allocator); + + return true; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/, + RsTlvItem& /*member*/, RsJson& /*jVal*/) +{ + return true; +} + + +//============================================================================// +// Binary blocks // +//============================================================================// template<> uint32_t RsTypeSerializer::serial_size(const RsTypeSerializer::TlvMemBlock_proxy& r) { return 4 + r.second ; } @@ -286,82 +564,141 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const RsTypeS std::cerr << " [Binary data] " << n << ", length=" << s.second << " data=" << RsUtil::BinToHex((uint8_t*)s.first,std::min(50u,s.second)) << ((s.second>50)?"...":"") << std::endl; } -//=================================================================================================// -// TlvItems // -//=================================================================================================// - -template<> uint32_t RsTypeSerializer::serial_size(const RsTlvItem& s) -{ - return s.TlvSize() ; -} - -template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset,const RsTlvItem& s) -{ - return s.SetTlv(data,size,&offset) ; -} - -template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size,uint32_t& offset,RsTlvItem& s) -{ - return s.GetTlv((void*)data,size,&offset) ; -} - -template<> void RsTypeSerializer::print_data(const std::string& n, const RsTlvItem& s) -{ - // can we call TlvPrint inside this? - - std::cerr << " [" << typeid(s).name() << "] " << n << std::endl; -} //============================================================================// -// RsItem and derivated // +// RsSerializable and derivated // //============================================================================// -template<> uint32_t RsTypeSerializer::serial_size(const RsItem& s) +template<> uint32_t RsTypeSerializer::serial_size(const RsSerializable& s) { RsGenericSerializer::SerializeContext ctx( NULL, 0, RsGenericSerializer::FORMAT_BINARY, RsGenericSerializer::SERIALIZATION_FLAG_NONE ); ctx.mOffset = 8; // header size - const_cast(s).serial_process(RsGenericSerializer::SIZE_ESTIMATE, - ctx); + const_cast(s).serial_process( + RsGenericSerializer::SIZE_ESTIMATE, ctx ); return ctx.mOffset; } template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, - uint32_t &offset, const RsItem& s ) + uint32_t &offset, + const RsSerializable& s ) { RsGenericSerializer::SerializeContext ctx( data, size, RsGenericSerializer::FORMAT_BINARY, RsGenericSerializer::SERIALIZATION_FLAG_NONE ); ctx.mOffset = offset; - const_cast(s).serial_process(RsGenericSerializer::SERIALIZE, - ctx); + const_cast(s).serial_process( + RsGenericSerializer::SERIALIZE, ctx ); return true; } template<> bool RsTypeSerializer::deserialize( const uint8_t data[], uint32_t size, uint32_t& offset, - RsItem& s ) + RsSerializable& s ) { RsGenericSerializer::SerializeContext ctx( const_cast(data), size, RsGenericSerializer::FORMAT_BINARY, RsGenericSerializer::SERIALIZATION_FLAG_NONE ); ctx.mOffset = offset; - const_cast(s).serial_process(RsGenericSerializer::DESERIALIZE, - ctx); + const_cast(s).serial_process( + RsGenericSerializer::DESERIALIZE, ctx ); return true; } template<> void RsTypeSerializer::print_data( const std::string& /*n*/, - const RsItem& s ) + const RsSerializable& s ) { RsGenericSerializer::SerializeContext ctx( NULL, 0, RsGenericSerializer::FORMAT_BINARY, RsGenericSerializer::SERIALIZATION_FLAG_NONE ); - const_cast(s).serial_process(RsGenericSerializer::PRINT, - ctx); + const_cast(s).serial_process( RsGenericSerializer::PRINT, + ctx ); +} + +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& memberName, + const RsSerializable& member, RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + // Reuse allocator to avoid deep copy later + RsGenericSerializer::SerializeContext ctx( + NULL, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE, + &allocator ); + + const_cast(member).serial_process( + RsGenericSerializer::TO_JSON, ctx ); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + /* Because the passed allocator is reused it doesn't go out of scope and + * there is no need of deep copy and we can take advantage of the much + * faster rapidjson move semantic */ + jDoc.AddMember(key, ctx.mJson, allocator); + + return ctx.mOk; +} + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + RsSerializable& member, RsJson& jVal ) +{ + SAFE_GET_JSON_V(); + + if(ret) + { + RsGenericSerializer::SerializeContext ctx( + NULL, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + + ctx.mJson.SetObject() = v; // Beware of move semantic!! + member.serial_process(RsGenericSerializer::FROM_JSON, ctx); + ret = ret && ctx.mOk; + } + + return ret; +} + +template<> /*static*/ +void RsTypeSerializer::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, RsSerializable& object, + const std::string& objName ) +{ + switch (j) + { + case RsGenericSerializer::SIZE_ESTIMATE: // fall-through + case RsGenericSerializer::SERIALIZE: // fall-through + case RsGenericSerializer::DESERIALIZE: // fall-through + case RsGenericSerializer::PRINT: // fall-through + object.serial_process(j, ctx); + break; + case RsGenericSerializer::TO_JSON: + ctx.mOk = ctx.mOk && to_JSON(objName, object, ctx.mJson); + break; + case RsGenericSerializer::FROM_JSON: + ctx.mOk = ctx.mOk && from_JSON(objName, object, ctx.mJson); + break; + default: break; + } +} + + +//============================================================================// +// RsJson std:ostream support // +//============================================================================// + +std::ostream &operator<<(std::ostream &out, const RsJson &jDoc) +{ + rapidjson::StringBuffer buffer; buffer.Clear(); + rapidjson::PrettyWriter writer(buffer); + jDoc.Accept(writer); + return out << buffer.GetString(); } diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index f4867f10f..1de678d50 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -3,7 +3,8 @@ * * RetroShare Serialiser. * - * Copyright 2017 by Cyril Soler + * Copyright (C) 2017 Cyril Soler + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,83 +33,91 @@ #include "retroshare/rsids.h" #include "serialiser/rsserializer.h" +#include "serialiser/rsserializable.h" -/** @def RS_REGISTER_SERIAL_MEMBER(I) - * Use this macro to register the members of `YourItem` for serial processing - * inside `YourItem::serial_process(j, ctx)` - * - * Inspired by http://stackoverflow.com/a/39345864 +#include + +/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} + * Can't use a template function because T is needed for const_cast */ +#define RsTypeSerializer_PRIVATE_TO_JSON_ARRAY() do \ +{ \ + using namespace rapidjson; \ +\ + Document::AllocatorType& allocator = ctx.mJson.GetAllocator(); \ +\ + Value arrKey; arrKey.SetString(memberName.c_str(), allocator); \ +\ + Value arr(kArrayType); \ +\ + for (auto& el : v) \ + { \ + /* Use same allocator to avoid deep copy */\ + RsGenericSerializer::SerializeContext elCtx(\ + nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\ + RsGenericSerializer::SERIALIZATION_FLAG_NONE,\ + &allocator );\ +\ + /* If el is const the default serial_process template is matched */ \ + /* also when specialization is necessary so the compilation break */ \ + serial_process(j, elCtx, const_cast(el), memberName); \ +\ + elCtx.mOk = elCtx.mOk && elCtx.mJson.HasMember(arrKey);\ + if(elCtx.mOk) arr.PushBack(elCtx.mJson[arrKey], allocator);\ + else\ + {\ + ctx.mOk = false;\ + break;\ + }\ + }\ +\ + ctx.mJson.AddMember(arrKey, arr, allocator);\ +} while (false) + +/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} + * Can't use a template function because std::{vector,list,set} has different + * name for insert/push_back function */ -#define RS_REGISTER_SERIAL_MEMBER(I) \ - do { RsTypeSerializer::serial_process(j, ctx, I, #I); } while(0) +#define RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(INSERT_FUN) do\ +{\ + using namespace rapidjson;\ +\ + bool& ok(ctx.mOk);\ + Document& jDoc(ctx.mJson);\ + Document::AllocatorType& allocator = jDoc.GetAllocator();\ +\ + Value arrKey;\ + arrKey.SetString(memberName.c_str(), memberName.length());\ +\ + ok = ok && jDoc.IsObject();\ + ok = ok && jDoc.HasMember(arrKey);\ +\ + if(ok && jDoc[arrKey].IsArray())\ + {\ + for (auto&& arrEl : jDoc[arrKey].GetArray())\ + {\ + RsGenericSerializer::SerializeContext elCtx(\ + nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\ + RsGenericSerializer::SERIALIZATION_FLAG_NONE,\ + &allocator );\ + elCtx.mJson.AddMember(arrKey, arrEl, allocator);\ +\ + T el;\ + serial_process(j, elCtx, el, memberName); \ + ok = ok && elCtx.mOk;\ +\ + if(ok) v.INSERT_FUN(el);\ + else break;\ + }\ + }\ +} while(false) -/** @def RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) - * This macro usage is similar to @see RS_REGISTER_SERIAL_MEMBER(I) but it - * permit to force serialization/deserialization type, it is expecially useful - * with enum class members or RsTlvItem derivative members, be very careful with - * the type you pass, as reinterpret_cast on a reference is used that is - * expecially permissive so you can shot your feet if not carefull enough. - * - * If you are using this with an RsItem derivative (so passing RsItem as T) - * consider to register your item type with @see RS_REGISTER_ITEM_TYPE(T) in - * association with @see RS_REGISTER_SERIAL_MEMBER(I) that rely on template - * function generation, as in this particular case - * RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) would cause the serial code rely on - * C++ dynamic dispatching that may have a noticeable impact on runtime - * performances. - */ -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#define RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) do {\ - RsTypeSerializer::serial_process(j, ctx, reinterpret_cast(I), #I);\ - } while(0) -#pragma GCC diagnostic pop - -/** @def RS_REGISTER_ITEM_TYPE(T) - * Use this macro into `youritem.cc` only if you need to process members of - * subtypes of RsItem. - * - * The usage of this macro is strictly needed only in some cases, for example if - * you are registering for serialization a member of a container that contains - * items of subclasses of RsItem like * `std::map` - * - * @code{.cpp} -struct PrivateOugoingMapItem : RsChatItem -{ - PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {} - - void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ); - - std::map store; -}; - -RS_REGISTER_ITEM_TYPE(RsChatMsgItem) - -void PrivateOugoingMapItem::serial_process( - RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) -{ - // store is of type - RS_REGISTER_SERIAL_MEMBER(store); -} - * @endcode - * - * If you use this macro with a lot of different item types this can cause the - * generated binary grow in size, consider the usage of - * @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) passing RsItem as type in that - * case. - */ -#define RS_REGISTER_ITEM_TYPE(T) template<> \ - void RsTypeSerializer::serial_process( \ - RsGenericSerializer::SerializeJob j,\ - RsGenericSerializer::SerializeContext& ctx, T& item,\ - const std::string& /*name*/) { item.serial_process(j, ctx); } +std::ostream &operator<<(std::ostream &out, const RsJson &jDoc); struct RsTypeSerializer { /** This type should be used to pass a parameter to drive the serialisation * if needed */ - struct TlvMemBlock_proxy: public std::pair + struct TlvMemBlock_proxy : std::pair { TlvMemBlock_proxy(void*& p, uint32_t& s) : std::pair(p,s) {} @@ -120,7 +129,7 @@ struct RsTypeSerializer template static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, - T& member,const std::string& member_name) + T& member, const std::string& member_name ) { switch(j) { @@ -138,6 +147,12 @@ struct RsTypeSerializer case RsGenericSerializer::PRINT: print_data(member_name,member); break; + case RsGenericSerializer::TO_JSON: + ctx.mOk = ctx.mOk && to_JSON(member_name, member, ctx.mJson); + break; + case RsGenericSerializer::FROM_JSON: + ctx.mOk = ctx.mOk && from_JSON(member_name, member, ctx.mJson); + break; default: ctx.mOk = false; throw std::runtime_error("Unknown serial job"); @@ -165,7 +180,15 @@ struct RsTypeSerializer serialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member); break; case RsGenericSerializer::PRINT: - print_data(member_name,type_id,member); + print_data(member_name, member); + break; + case RsGenericSerializer::TO_JSON: + ctx.mOk = ctx.mOk && + to_JSON(member_name, type_id, member, ctx.mJson); + break; + case RsGenericSerializer::FROM_JSON: + ctx.mOk = ctx.mOk && + from_JSON(member_name, type_id, member, ctx.mJson); break; default: ctx.mOk = false; @@ -178,7 +201,7 @@ struct RsTypeSerializer static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, std::map& v, - const std::string& member_name ) + const std::string& memberName ) { switch(j) { @@ -225,11 +248,11 @@ struct RsTypeSerializer case RsGenericSerializer::PRINT: { if(v.empty()) - std::cerr << " Empty map \"" << member_name << "\"" + std::cerr << " Empty map \"" << memberName << "\"" << std::endl; else std::cerr << " std::map of " << v.size() << " elements: \"" - << member_name << "\"" << std::endl; + << memberName << "\"" << std::endl; for(typename std::map::iterator it(v.begin());it!=v.end();++it) { @@ -242,6 +265,95 @@ struct RsTypeSerializer } break; } + case RsGenericSerializer::TO_JSON: + { + using namespace rapidjson; + + Document::AllocatorType& allocator = ctx.mJson.GetAllocator(); + Value arrKey; arrKey.SetString(memberName.c_str(), + memberName.length(), allocator); + Value arr(kArrayType); + + for (auto& kv : v) + { + // Use same allocator to avoid deep copy + RsGenericSerializer::SerializeContext kCtx( + nullptr, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE, + &allocator ); + serial_process(j, kCtx, const_cast(kv.first), "key"); + + RsGenericSerializer::SerializeContext vCtx( + nullptr, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE, + &allocator ); + serial_process(j, vCtx, const_cast(kv.second), "value"); + + if(kCtx.mOk && vCtx.mOk) + { + Value el(kObjectType); + el.AddMember("key", kCtx.mJson["key"], allocator); + el.AddMember("value", vCtx.mJson["value"], allocator); + + arr.PushBack(el, allocator); + } + } + + ctx.mJson.AddMember(arrKey, arr, allocator); + + break; + } + case RsGenericSerializer::FROM_JSON: + { + using namespace rapidjson; + + bool& ok(ctx.mOk); + Document& jDoc(ctx.mJson); + Document::AllocatorType& allocator = jDoc.GetAllocator(); + + Value arrKey; + arrKey.SetString(memberName.c_str(), memberName.length()); + + ok = ok && jDoc.IsObject(); + ok = ok && jDoc.HasMember(arrKey); + + if(ok && jDoc[arrKey].IsArray()) + { + for (auto&& kvEl : jDoc[arrKey].GetArray()) + { + ok = ok && kvEl.IsObject(); + ok = ok && kvEl.HasMember("key"); + ok = ok && kvEl.HasMember("value"); + if (!ok) break; + + RsGenericSerializer::SerializeContext kCtx( + nullptr, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE, + &allocator ); + ok && (kCtx.mJson. + AddMember("key", kvEl["key"], allocator), true); + + T key; + ok = ok && (serial_process(j, kCtx, key, "key"), kCtx.mOk); + + RsGenericSerializer::SerializeContext vCtx( + nullptr, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE, + &allocator ); + ok && (vCtx.mJson. + AddMember("value", kvEl["value"], allocator), true); + + U value; + ok = ok && ( serial_process(j, vCtx, value, "value"), + vCtx.mOk ); + + if(ok) v.insert(std::pair(key,value)); + else break; + } + } + + break; + } default: break; } } @@ -251,7 +363,7 @@ struct RsTypeSerializer static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, std::vector& v, - const std::string& member_name ) + const std::string& memberName ) { switch(j) { @@ -259,7 +371,7 @@ struct RsTypeSerializer { ctx.mOffset += 4; for(uint32_t i=0;i static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, - std::set& v, const std::string& member_name ) + std::set& v, const std::string& memberName ) { switch(j) { @@ -311,7 +429,7 @@ struct RsTypeSerializer for(typename std::set::iterator it(v.begin());it!=v.end();++it) // the const cast here is a hack to avoid serial_process to // instantiate serialise(const T&) - serial_process(j,ctx,const_cast(*it) ,member_name); + serial_process(j,ctx,const_cast(*it) ,memberName); break; } case RsGenericSerializer::DESERIALIZE: @@ -321,7 +439,7 @@ struct RsTypeSerializer for(uint32_t i=0; i(j,ctx,tmp,member_name); + serial_process(j,ctx,tmp,memberName); v.insert(tmp); } break; @@ -333,7 +451,7 @@ struct RsTypeSerializer for(typename std::set::iterator it(v.begin());it!=v.end();++it) // the const cast here is a hack to avoid serial_process to // instantiate serialise(const T&) - serial_process(j,ctx,const_cast(*it) ,member_name); + serial_process(j,ctx,const_cast(*it) ,memberName); break; } case RsGenericSerializer::PRINT: @@ -343,6 +461,12 @@ struct RsTypeSerializer << std::endl; break; } + case RsGenericSerializer::TO_JSON: + RsTypeSerializer_PRIVATE_TO_JSON_ARRAY(); + break; + case RsGenericSerializer::FROM_JSON: + RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(insert); + break; default: break; } } @@ -352,7 +476,7 @@ struct RsTypeSerializer static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, std::list& v, - const std::string& member_name ) + const std::string& memberName ) { switch(j) { @@ -360,7 +484,7 @@ struct RsTypeSerializer { ctx.mOffset += 4; for(typename std::list::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,*it ,member_name); + serial_process(j,ctx,*it ,memberName); break; } case RsGenericSerializer::DESERIALIZE: @@ -370,7 +494,7 @@ struct RsTypeSerializer for(uint32_t i=0;i(j,ctx,tmp,member_name); + serial_process(j,ctx,tmp,memberName); v.push_back(tmp); } break; @@ -380,7 +504,7 @@ struct RsTypeSerializer uint32_t n=v.size(); serial_process(j,ctx,n,"temporary size"); for(typename std::list::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,*it ,member_name); + serial_process(j,ctx,*it ,memberName); break; } case RsGenericSerializer::PRINT: @@ -390,6 +514,12 @@ struct RsTypeSerializer << std::endl; break; } + case RsGenericSerializer::TO_JSON: + RsTypeSerializer_PRIVATE_TO_JSON_ARRAY(); + break; + case RsGenericSerializer::FROM_JSON: + RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(push_back); + break; default: break; } } @@ -399,7 +529,7 @@ struct RsTypeSerializer static void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx, t_RsFlags32& v, - const std::string& /*member_name*/) + const std::string& memberName ) { switch(j) { @@ -421,16 +551,27 @@ struct RsTypeSerializer std::cerr << " Flags of type " << std::hex << N << " : " << v.toUInt32() << std::endl; break; + case RsGenericSerializer::TO_JSON: + ctx.mOk = to_JSON(memberName, v.toUInt32(), ctx.mJson); + break; + case RsGenericSerializer::FROM_JSON: + { + uint32_t f; + ctx.mOk = from_JSON(memberName, f, ctx.mJson); + v = t_RsFlags32(f); + break; + } + default: break; } } -/** TODO - * Serialization format is inside context, but context is not passed to - * following functions, that need to know the format to do the job, actually - * RsGenericSerializer::FORMAT_BINARY is assumed in all of them!! - */ protected: + +//============================================================================// +// Generic types declarations // +//============================================================================// + template static bool serialize( uint8_t data[], uint32_t size, uint32_t &offset, const T& member ); @@ -442,17 +583,41 @@ protected: template static void print_data( const std::string& name, const T& member); + template static bool to_JSON( const std::string& membername, + const T& member, RsJson& jDoc ); + + template static bool from_JSON( const std::string& memberName, + T& member, RsJson& jDoc ); + +//============================================================================// +// Generic types + type_id declarations // +//============================================================================// template static bool serialize( uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id, const T& member ); + template static bool deserialize( const uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id, T& member ); + template static uint32_t serial_size( uint16_t type_id,const T& member ); - template static void print_data( - const std::string& name,uint16_t type_id,const T& member ); + + template static void print_data( const std::string& n, + uint16_t type_id,const T& member ); + + template static bool to_JSON( const std::string& membername, + uint16_t type_id, + const T& member, RsJson& jVal ); + + template static bool from_JSON( const std::string& memberName, + uint16_t type_id, + T& member, RsJson& jDoc ); + +//============================================================================// +// t_RsGenericId<...> declarations // +//============================================================================// template static bool serialize( @@ -466,13 +631,29 @@ protected: template static uint32_t serial_size( - const t_RsGenericIdType& member ); + const t_RsGenericIdType< + ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member ); template static void print_data( const std::string& name, const t_RsGenericIdType& member ); + template + static bool to_JSON( + const std::string& membername, + const t_RsGenericIdType& member, + RsJson& jVal ); + + template + static bool from_JSON( + const std::string& memberName, + t_RsGenericIdType& member, + RsJson& jDoc ); + +//============================================================================// +// t_RsTlvList<...> declarations // +//============================================================================// template static bool serialize( @@ -491,16 +672,33 @@ protected: static void print_data( const std::string& name, const t_RsTlvList& member); + + template + static bool to_JSON( const std::string& membername, + const t_RsTlvList& member, + RsJson& jVal ); + + template + static bool from_JSON( const std::string& memberName, + t_RsTlvList& member, + RsJson& jDoc ); }; +//============================================================================// +// t_RsGenericId<...> // +//============================================================================// -// t_RsGenericId<> template bool RsTypeSerializer::serialize ( uint8_t data[], uint32_t size, uint32_t &offset, - const t_RsGenericIdType& member ) -{ return (*const_cast *>(&member)).serialise(data,size,offset); } + const t_RsGenericIdType< + ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member ) +{ + return (*const_cast *>(&member) + ).serialise(data,size,offset); +} template bool RsTypeSerializer::deserialize( @@ -522,8 +720,45 @@ void RsTypeSerializer::print_data( << member << std::endl; } +template +bool RsTypeSerializer::to_JSON( const std::string& memberName, + const t_RsGenericIdType& member, + RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + const std::string vStr = member.toStdString(); + rapidjson::Value value; + value.SetString(vStr.c_str(), vStr.length(), allocator); + + jDoc.AddMember(key, value, allocator); + + return true; +} + +template +bool RsTypeSerializer::from_JSON( const std::string& membername, + t_RsGenericIdType& member, + RsJson& jVal ) +{ + const char* mName = membername.c_str(); + bool ret = jVal.HasMember(mName); + if(ret) + { + rapidjson::Value& v = jVal[mName]; + ret = ret && v.IsString(); + ret && (member = t_RsGenericIdType(std::string(v.GetString())), false); + } + return ret; +} + +//============================================================================// +// t_RsTlvList<...> // +//============================================================================// -// t_RsTlvList<> template bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, uint32_t &offset, @@ -553,3 +788,76 @@ void RsTypeSerializer::print_data( std::cerr << " [t_RsTlvString<" << std::hex << TLV_TYPE << ">] : size=" << member.mList.size() << std::endl; } + +template /* static */ +bool RsTypeSerializer::to_JSON( const std::string& memberName, + const t_RsTlvList& member, + RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + rapidjson::Value value; + const char* tName = typeid(member).name(); + value.SetString(tName, allocator); + + jDoc.AddMember(key, value, allocator); + + std::cerr << __PRETTY_FUNCTION__ << " JSON serialization for type " + << typeid(member).name() << " " << memberName + << " not available." << std::endl; + print_stacktrace(); + return true; +} + +template +bool RsTypeSerializer::from_JSON( const std::string& memberName, + t_RsTlvList& member, + RsJson& /*jVal*/ ) +{ + std::cerr << __PRETTY_FUNCTION__ << " JSON deserialization for type " + << typeid(member).name() << " " << memberName + << " not available." << std::endl; + print_stacktrace(); + return true; +} + + +//============================================================================// +// Generic types // +//============================================================================// + +template /*static*/ +bool RsTypeSerializer::to_JSON(const std::string& memberName, const T& member, + RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + rapidjson::Value value; + const char* tName = typeid(member).name(); + value.SetString(tName, allocator); + + jDoc.AddMember(key, value, allocator); + + std::cerr << __PRETTY_FUNCTION__ << " JSON serialization for type " + << typeid(member).name() << " " << memberName + << " not available." << std::endl; + print_stacktrace(); + return true; +} + +template /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + T& member, RsJson& /*jDoc*/ ) +{ + std::cerr << __PRETTY_FUNCTION__ << " JSON deserialization for type " + << typeid(member).name() << " " << memberName + << " not available." << std::endl; + print_stacktrace(); + return true; +} diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 8695280a7..6dfb43ce8 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -3,7 +3,8 @@ * * Id interface for RetroShare. * - * Copyright 2012-2012 by Robert Fernie. + * Copyright (C) 2012 Robert Fernie + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -4505,11 +4506,30 @@ void p3IdService::handle_event(uint32_t event_type, const std::string &/*elabel* } } -RsIdentityUsage::RsIdentityUsage(uint16_t service,const RsIdentityUsage::UsageCode& code,const RsGxsGroupId& gid,const RsGxsMessageId& mid,uint64_t additional_id,const std::string& comment) - : mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid),mAdditionalId(additional_id),mComment(comment) +void RsGxsIdGroup::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ + RS_REGISTER_SERIAL_MEMBER_TYPED(mMeta, RsSerializable); + RS_REGISTER_SERIAL_MEMBER(mPgpIdHash); + //RS_REGISTER_SERIAL_MEMBER(mPgpIdSign); + RS_REGISTER_SERIAL_MEMBER(mRecognTags); + //RS_REGISTER_SERIAL_MEMBER(mImage); + RS_REGISTER_SERIAL_MEMBER(mLastUsageTS); + RS_REGISTER_SERIAL_MEMBER(mPgpKnown); + RS_REGISTER_SERIAL_MEMBER(mIsAContact); + RS_REGISTER_SERIAL_MEMBER(mPgpId); + RS_REGISTER_SERIAL_MEMBER_TYPED(mReputation, RsSerializable); +} + +RsIdentityUsage::RsIdentityUsage( + uint16_t service, const RsIdentityUsage::UsageCode& code, + const RsGxsGroupId& gid, const RsGxsMessageId& mid, + uint64_t additional_id,const std::string& comment ) : + mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid), + mAdditionalId(additional_id), mComment(comment) { #ifdef DEBUG_IDS - // This is a hack, since it will hash also mHash, but because it is initialized to 0, and only computed in the constructor here, it should be ok. std::cerr << "New identity usage: " << std::endl; std::cerr << " service=" << std::hex << service << std::endl; std::cerr << " code =" << std::hex << code << std::endl; @@ -4519,6 +4539,9 @@ RsIdentityUsage::RsIdentityUsage(uint16_t service,const RsIdentityUsage::UsageCo std::cerr << " commnt =\"" << std::hex << comment << "\"" << std::endl; #endif + /* This is a hack, since it will hash also mHash, but because it is + * initialized to 0, and only computed in the constructor here, it should + * be ok. */ librs::crypto::HashStream hs(librs::crypto::HashStream::SHA1) ; hs << (uint32_t)service ; @@ -4535,5 +4558,7 @@ RsIdentityUsage::RsIdentityUsage(uint16_t service,const RsIdentityUsage::UsageCo #endif } +RsIdentityUsage::RsIdentityUsage() : + mServiceId(0), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0) {} - +RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsIdentityUsage)