Add automatic JSON serialization/deserialization

Abstract serialization concept to pure virtaul class RsSerializable
  from which every other serializable class must inherit from
Use RapidJSON for JSON manipulation
Add TO_JSON and FROM_JSON SerializeJob
Deprecate unused SerializationFormat
Remove some unused old piece of code
Adjust many lines to max 80 columns for better readability on little
  screens
Clean up documentation and code, remove old cruft
Add copyright notice on edited files that miss it
This commit is contained in:
Gioacchino Mazzurco 2018-01-16 03:31:03 +01:00
parent 49cacc41a1
commit 5cdc5aa58d
12 changed files with 1384 additions and 405 deletions

View File

@ -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,

View File

@ -1,6 +1,6 @@
/*
* GXS Mailing Service
* Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2016-2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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);

View File

@ -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 \

View File

@ -1,3 +1,23 @@
/*
* rsgxsifacetypes.h
*
* Copyright (C) 2013 crispy
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/*
* rsgxsifacetypes.h
*
@ -13,8 +33,10 @@
#include <string>
#include <inttypes.h>
#include <retroshare/rstypes.h>
#include <retroshare/rsids.h>
#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<RsGxsGroupId, std::vector<RsMsgMetaData> > 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);
}
};

View File

@ -6,7 +6,8 @@
*
* RetroShare C++ Interface.
*
* Copyright 2012-2012 by Robert Fernie.
* Copyright (C) 2012 Robert Fernie.
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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<std::string> mRecognTags;
RS_DEPRECATED std::list<std::string> 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<RsRecognTag> mRecognTags;
/// @deprecated Recogn details.
RS_DEPRECATED std::list<RsRecognTag> 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<RsIdentityUsage,time_t> mUseCases ;
time_t mLastUsageTS;
std::map<RsIdentityUsage,time_t> 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() {}

View File

@ -1,76 +1,96 @@
#pragma once
/*
* RetroShare Serialiser.
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <typeinfo> // for typeid
#include "util/smallobject.h"
#include "retroshare/rstypes.h"
#include "serialiser/rsserializer.h"
#include "serialiser/rsserializable.h"
#include "util/stacktrace.h"
#include <typeinfo>
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?

View File

@ -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))

View File

@ -0,0 +1,137 @@
#pragma once
/*
* RetroShare Serialiser.
* Copyright (C) 2016-2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<T>(j, ctx, reinterpret_cast<T&>(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<uint64_t, RsChatMsgItem>`
*
* @code{.cpp}
struct PrivateOugoingMapItem : RsChatItem
{
PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {}
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx );
std::map<uint64_t, RsChatMsgItem> 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<T>( \
RsGenericSerializer::SerializeJob j,\
RsGenericSerializer::SerializeContext& ctx, T& item,\
const std::string& objName ) \
{ \
RsTypeSerializer::serial_process<RsSerializable>( j, \
ctx, static_cast<RsSerializable&>(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<T>( \
RsGenericSerializer::SerializeJob j,\
RsGenericSerializer::SerializeContext& ctx, T& item,\
const std::string& /*objName*/ );

View File

@ -3,7 +3,8 @@
*
* RetroShare Serialiser.
*
* Copyright 2016 by Cyril Soler
* Copyright (C) 2016 Cyril Soler
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <string.h>
#include <iostream>
#include <string>
#include <rapidjson/document.h>
#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);
};

View File

@ -3,7 +3,8 @@
*
* RetroShare Serialiser.
*
* Copyright 2017 by Cyril Soler
* Copyright (C) 2017 Cyril Soler
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <iomanip>
#include <typeinfo>
#include <time.h>
#include <string>
#include <typeinfo> // for typeid
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
//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 <<std::setw(4)<<std::setfill('0') << type_substring << std::dec << " s=\"" << V<< "\"" << std::endl;
std::cerr << " [TlvString ] " << n << ": type=" << std::hex <<std::setw(4)<<std::setfill('0') << type_substring << std::dec << " s=\"" << V<< "\"" << std::endl;
}
//=================================================================================================//
// TlvInt with subtype //
//=================================================================================================//
template<> 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<std::string>(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<std::string>(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 <<std::setw(4)<<std::setfill('0') << sub_type << std::dec << " s=\"" << V<< "\"" << std::endl;
std::cerr << " [TlvUInt32 ] " << n << ": type=" << std::hex
<< std::setw(4) << std::setfill('0') << sub_type << std::dec
<< " s=\"" << V << "\"" << std::endl;
}
//=================================================================================================//
// std::string //
//=================================================================================================//
template<> 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<uint32_t>(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<uint32_t>(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<RsItem&>(s).serial_process(RsGenericSerializer::SIZE_ESTIMATE,
ctx);
const_cast<RsSerializable&>(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<RsItem&>(s).serial_process(RsGenericSerializer::SERIALIZE,
ctx);
const_cast<RsSerializable&>(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<uint8_t*>(data), size,
RsGenericSerializer::FORMAT_BINARY,
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
ctx.mOffset = offset;
const_cast<RsItem&>(s).serial_process(RsGenericSerializer::DESERIALIZE,
ctx);
const_cast<RsSerializable&>(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<RsItem&>(s).serial_process(RsGenericSerializer::PRINT,
ctx);
const_cast<RsSerializable&>(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<RsSerializable&>(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<RsSerializable>(
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<rapidjson::StringBuffer> writer(buffer);
jDoc.Accept(writer);
return out << buffer.GetString();
}

View File

@ -3,7 +3,8 @@
*
* RetroShare Serialiser.
*
* Copyright 2017 by Cyril Soler
* Copyright (C) 2017 Cyril Soler
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <rapidjson/document.h>
/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
* 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<T&>(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}<T>
* Can't use a template function because std::{vector,list,set}<T> 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<T>(j, ctx, reinterpret_cast<T&>(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<uint64_t, RsChatMsgItem>`
*
* @code{.cpp}
struct PrivateOugoingMapItem : RsChatItem
{
PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {}
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx );
std::map<uint64_t, RsChatMsgItem> 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<T>( \
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<void*&,uint32_t&>
struct TlvMemBlock_proxy : std::pair<void*&,uint32_t&>
{
TlvMemBlock_proxy(void*& p, uint32_t& s) :
std::pair<void*&,uint32_t&>(p,s) {}
@ -120,7 +129,7 @@ struct RsTypeSerializer
template<typename T>
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<T,U>& 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<T,U>::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<T>(j, kCtx, const_cast<T&>(kv.first), "key");
RsGenericSerializer::SerializeContext vCtx(
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
&allocator );
serial_process<U>(j, vCtx, const_cast<U&>(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<T,U>(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<T>& 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<v.size();++i)
serial_process(j,ctx,v[i],member_name);
serial_process(j,ctx,v[i],memberName);
break;
}
case RsGenericSerializer::DESERIALIZE:
@ -268,7 +380,7 @@ struct RsTypeSerializer
serial_process(j,ctx,n,"temporary size");
v.resize(n);
for(uint32_t i=0;i<v.size();++i)
serial_process(j,ctx,v[i],member_name);
serial_process(j,ctx,v[i],memberName);
break;
}
case RsGenericSerializer::SERIALIZE:
@ -276,7 +388,7 @@ struct RsTypeSerializer
uint32_t n=v.size();
serial_process(j,ctx,n,"temporary size");
for(uint32_t i=0; i<v.size(); ++i)
serial_process(j,ctx,v[i],member_name);
serial_process(j,ctx,v[i],memberName);
break;
}
case RsGenericSerializer::PRINT:
@ -289,10 +401,16 @@ struct RsTypeSerializer
for(uint32_t i=0;i<v.size();++i)
{
std::cerr << " " ;
serial_process(j,ctx,v[i],member_name);
serial_process(j,ctx,v[i],memberName);
}
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;
}
}
@ -301,7 +419,7 @@ struct RsTypeSerializer
template<typename T>
static void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx,
std::set<T>& v, const std::string& member_name )
std::set<T>& v, const std::string& memberName )
{
switch(j)
{
@ -311,7 +429,7 @@ struct RsTypeSerializer
for(typename std::set<T>::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<T&>(*it) ,member_name);
serial_process(j,ctx,const_cast<T&>(*it) ,memberName);
break;
}
case RsGenericSerializer::DESERIALIZE:
@ -321,7 +439,7 @@ struct RsTypeSerializer
for(uint32_t i=0; i<n; ++i)
{
T tmp;
serial_process<T>(j,ctx,tmp,member_name);
serial_process<T>(j,ctx,tmp,memberName);
v.insert(tmp);
}
break;
@ -333,7 +451,7 @@ struct RsTypeSerializer
for(typename std::set<T>::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<T&>(*it) ,member_name);
serial_process(j,ctx,const_cast<T&>(*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<T>& 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<T>::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<n;++i)
{
T tmp;
serial_process<T>(j,ctx,tmp,member_name);
serial_process<T>(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<T>::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<N>& 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<N>(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<typename T> static bool serialize(
uint8_t data[], uint32_t size, uint32_t &offset, const T& member );
@ -442,17 +583,41 @@ protected:
template<typename T> static void print_data(
const std::string& name, const T& member);
template<typename T> static bool to_JSON( const std::string& membername,
const T& member, RsJson& jDoc );
template<typename T> static bool from_JSON( const std::string& memberName,
T& member, RsJson& jDoc );
//============================================================================//
// Generic types + type_id declarations //
//============================================================================//
template<typename T> static bool serialize(
uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id,
const T& member );
template<typename T> static bool deserialize(
const uint8_t data[], uint32_t size, uint32_t &offset,
uint16_t type_id, T& member );
template<typename T> static uint32_t serial_size(
uint16_t type_id,const T& member );
template<typename T> static void print_data(
const std::string& name,uint16_t type_id,const T& member );
template<typename T> static void print_data( const std::string& n,
uint16_t type_id,const T& member );
template<typename T> static bool to_JSON( const std::string& membername,
uint16_t type_id,
const T& member, RsJson& jVal );
template<typename T> static bool from_JSON( const std::string& memberName,
uint16_t type_id,
T& member, RsJson& jDoc );
//============================================================================//
// t_RsGenericId<...> declarations //
//============================================================================//
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
static bool serialize(
@ -466,13 +631,29 @@ protected:
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
static uint32_t serial_size(
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
const t_RsGenericIdType<
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
static void print_data(
const std::string& name,
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
static bool to_JSON(
const std::string& membername,
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
RsJson& jVal );
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
static bool from_JSON(
const std::string& memberName,
t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
RsJson& jDoc );
//============================================================================//
// t_RsTlvList<...> declarations //
//============================================================================//
template<class TLV_CLASS,uint32_t TLV_TYPE>
static bool serialize(
@ -491,16 +672,33 @@ protected:
static void print_data(
const std::string& name,
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& member);
template<class TLV_CLASS,uint32_t TLV_TYPE>
static bool to_JSON( const std::string& membername,
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
RsJson& jVal );
template<class TLV_CLASS,uint32_t TLV_TYPE>
static bool from_JSON( const std::string& memberName,
t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
RsJson& jDoc );
};
//============================================================================//
// t_RsGenericId<...> //
//============================================================================//
// t_RsGenericId<>
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
bool RsTypeSerializer::serialize (
uint8_t data[], uint32_t size, uint32_t &offset,
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member )
{ return (*const_cast<const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER> *>(&member)).serialise(data,size,offset); }
const t_RsGenericIdType<
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member )
{
return (*const_cast<const t_RsGenericIdType<
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER> *>(&member)
).serialise(data,size,offset);
}
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
bool RsTypeSerializer::deserialize(
@ -522,8 +720,45 @@ void RsTypeSerializer::print_data(
<< member << std::endl;
}
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
bool RsTypeSerializer::to_JSON( const std::string& memberName,
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& 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<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
bool RsTypeSerializer::from_JSON( const std::string& membername,
t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& 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<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>(std::string(v.GetString())), false);
}
return ret;
}
//============================================================================//
// t_RsTlvList<...> //
//============================================================================//
// t_RsTlvList<>
template<class TLV_CLASS,uint32_t TLV_TYPE>
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<class TLV_CLASS,uint32_t TLV_TYPE> /* static */
bool RsTypeSerializer::to_JSON( const std::string& memberName,
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& 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<class TLV_CLASS,uint32_t TLV_TYPE>
bool RsTypeSerializer::from_JSON( const std::string& memberName,
t_RsTlvList<TLV_CLASS,TLV_TYPE>& 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<typename T> /*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<typename T> /*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;
}

View File

@ -3,7 +3,8 @@
*
* Id interface for RetroShare.
*
* Copyright 2012-2012 by Robert Fernie.
* Copyright (C) 2012 Robert Fernie
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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)