From 33d3775c94279fceda74acf284740c4eaaab2d02 Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Fri, 27 Jun 2014 08:13:21 +0200 Subject: [PATCH] basic message encoding (incomplete) --- network/include/skid-connection.h | 5 +- network/include/skid-message.h | 130 +++++++++++++++++++++++++ network/include/skidnet.h | 5 +- network/network.pro | 6 +- network/src/skid-connection.cpp | 2 + network/src/skid-message.cpp | 188 +++++++++++++++++++++++++++++++++++++ 6 files changed, 331 insertions(+), 5 deletions(-) create mode 100644 network/include/skid-message.h create mode 100644 network/src/skid-message.cpp diff --git a/network/include/skid-connection.h b/network/include/skid-connection.h index cb49755..18e4464 100644 --- a/network/include/skid-connection.h +++ b/network/include/skid-connection.h @@ -17,7 +17,7 @@ class QTcpSocket; class QLocalSocket; class QSslSocket; -namespace Skid { +namespace Skid {namespace Network { class Connection:public QObject { Q_OBJECT @@ -27,6 +27,7 @@ class Connection:public QObject void readData(); }; -} +//end of namespace +}} #endif diff --git a/network/include/skid-message.h b/network/include/skid-message.h new file mode 100644 index 0000000..a518bdc --- /dev/null +++ b/network/include/skid-message.h @@ -0,0 +1,130 @@ +// network message include file for SKID +// +// +// Author: Konrad Rosenbaum , (C) 2014 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef SKID_NETWORK_MESSAGE_H +#define SKID_NETWORK_MESSAGE_H + +#include +#include +#include +#include +#include +#include + +namespace Skid {namespace Network { + +class DataItem +{ + public: + enum class Type { + Null=0xff, + KeyValue=0, + List=1, + Bytes=2, + String=3, + Integer=4, + Uuid=5, + Reserved2=6, + Reserved3=7, + }; + DataItem(){} + DataItem(const DataItem&)=default; + DataItem(DataItem&&)=default; + DataItem(qint64 i):mtype(Type::Integer){setInt(i);} + DataItem(const QString &s){setString(s);} + DataItem(const QByteArray&a){setBytes(a);} + DataItem(const QList&l){setList(l);} + DataItem(const QMap&m){setMap(m);} + + DataItem& operator=(const DataItem&)=default; + DataItem& operator=(DataItem&&)=default; + + Type type()const{return mtype;} + qint64 getInt()const; + QString getString()const + { + if(mtype==Type::String) + return QString::fromUtf8(mbytes); + else + return QString(); + } + QByteArray getBytes()const + { + if(mtype==Type::Bytes) + return mbytes; + else + return QByteArray(); + } + QUuid getUuid()const + { + if(mtype==Type::Uuid) + return QUuid::fromRfc4122(mbytes); + else + return QUuid(); + } + + int listSize()const{return msubitems.size();} + int mapSize()const{return listSize();} + + void setInt(qint64); + void setString(const QString&s) + { + msubitems.clear(); + mtype=Type::String; + mbytes=s.toUtf8(); + } + + void setBytes(const QByteArray&b) + { + msubitems.clear(); + mtype=Type::Bytes; + mbytes=b; + } + + void setUuid(QUuid id) + { + msubitems.clear(); + mtype=Type::Uuid; + mbytes=id.toRfc4122(); + } + + void setList(const QList&); + void addListItem(const DataItem&); + void removeListItem(int i){msubitems.removeAt(i);} + void clearList(){msubitems.clear();} + DataItem getListItem(int i)const{return msubitems.at(i).second;} + + void setMap(const QMap&); + void addMapItem(const QString&,const DataItem&); + void removeMapItems(const QString&); + bool hasMapItem(const QString&); + void clearMap(){msubitems.clear();} + DataItem getMapItem(const QString&)const; + QList getMapItems(const QString&)const; + QStringList getMapKeys()const; + + QByteArray encode()const; + static DataItem decode(const QByteArray&); + + private: + Type mtype=Type::Null; + QByteArray mbytes; + QList>msubitems; + + QByteArray encodeBytes()const; + QByteArray encodeScalar()const; + QByteArray encodeComplex()const; +}; + +class Message {}; + +//end of namespace +}} + +#endif diff --git a/network/include/skidnet.h b/network/include/skidnet.h index 5d4c7a5..c0ce6d9 100644 --- a/network/include/skidnet.h +++ b/network/include/skidnet.h @@ -18,7 +18,10 @@ ///This is the main namespace in which all SKID specific functions and classes exist. namespace Skid { -}; +///This is the namespace for network functionality. +namespace Network { +} +} #include "skid-connection.h" diff --git a/network/network.pro b/network/network.pro index b57a467..8d033a7 100644 --- a/network/network.pro +++ b/network/network.pro @@ -46,7 +46,9 @@ DEPENDPATH += $$INCLUDEPATH #sources SOURCES += \ - src/skid-connection.cpp + src/skid-connection.cpp \ + src/skid-message.cpp HEADERS += \ - include/skid-connection.h \ No newline at end of file + include/skid-connection.h \ + include/skid-message.h \ No newline at end of file diff --git a/network/src/skid-connection.cpp b/network/src/skid-connection.cpp index 9deb637..5eb2a0d 100644 --- a/network/src/skid-connection.cpp +++ b/network/src/skid-connection.cpp @@ -10,6 +10,8 @@ #include "skidnet.h" +using namespace Skid::Network; + Connection::Connection ( QTcpSocket*, QObject *parent ) :QObject(parent) { diff --git a/network/src/skid-message.cpp b/network/src/skid-message.cpp new file mode 100644 index 0000000..9f82d57 --- /dev/null +++ b/network/src/skid-message.cpp @@ -0,0 +1,188 @@ +// network message include file for SKID +// +// +// Author: Konrad Rosenbaum , (C) 2014 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "skid-message.h" + +#include + +using namespace Skid::Network; + +qint64 DataItem::getInt()const +{ + qint64 v=0; + for(unsigned char c:mbytes){ + v<<=8; + v|=c; + } + return v; +} + +void DataItem::setInt(qint64 val) +{ + mtype=Type::Integer; + msubitems.clear(); + mbytes.clear(); + //TODO: use a more efficient encoding for small ints + for(int i=0;i<8;i++){ + mbytes.prepend((char)(val&0xff)); + val>>=8; + } +} + +void DataItem::setList(const QList&l) +{ + msubitems.clear(); + mbytes.clear(); + mtype=Type::List; + for(const DataItem&item:l) + msubitems.append(QPair(QString(),item)); +} + +void DataItem::addListItem(const DataItem&item) +{ + if(mtype!=Type::List)return; + msubitems.append(QPair(QString(),item)); +} + +void DataItem::setMap(const QMap&map) +{ + msubitems.clear(); + mbytes.clear(); + mtype=Type::KeyValue; + for(const QString&key:map.keys()) + for(const DataItem&item:map.values(key)) + msubitems.append(QPair(key,item)); +} + +void DataItem::addMapItem(const QString&key,const DataItem&item) +{ + msubitems.append(QPair(key,item)); +} + +void DataItem::removeMapItems(const QString&key) +{ + QList>tmp; + tmp.swap(msubitems); + for(const QPair&item:tmp) + if(item.first!=key) + msubitems.append(item); +} + +bool DataItem::hasMapItem(const QString&key) +{ + for(const QPair&item:msubitems) + if(item.first==key) + return true; + return false; +} + +DataItem DataItem::getMapItem(const QString&key)const +{ + for(const QPair&item:msubitems) + if(item.first==key) + return item.second; + return DataItem(); +} + +QList DataItem::getMapItems(const QString&key)const +{ + QListret; + for(const QPair&item:msubitems) + if(item.first==key) + ret.append(item.second); + return ret; + +} + +QStringList DataItem::getMapKeys()const +{ + QStringList ret; + for(const QPair&item:msubitems) + if(!ret.contains(item.first)) + ret.append(item.first); + return ret; +} + +QByteArray DataItem::encode()const +{ + switch(mtype){ + case Type::Bytes: + case Type::String: + return encodeBytes(); + case Type::Integer: + case Type::Uuid: + return encodeScalar(); + case Type::List: + case Type::KeyValue: + return encodeComplex(); + default:return QByteArray(); + } +} + +static inline QByteArray encodeNetString(const QString&s) +{ + QByteArray a=s.toUtf8(); + if(a.size()>127)a.truncate(127); + a.prepend((char)a.size()); + return a; +} + +QByteArray DataItem::encodeBytes()const +{ + QByteArray ret; + //type: + quint8 type=(int)mtype|0x08; + int lbytes=1,size=mbytes.size(); + if(size<256)type|=0x40; + else if(size<65536){type|=0x80;lbytes=2;} + else {type|=0xc0;lbytes=4;} + ret.append((char)type); + //length bytes + for(int i=(lbytes-1)*8;i>=0;i-=8) + ret.append(char((size>>i)&0xff)); + //data + ret.append(mbytes); + return ret; +} + +QByteArray DataItem::encodeScalar()const +{ + QByteArray ret; + //type: + quint8 type=(int)mtype; + int size=mbytes.size(); + switch(size){ + case 1:type|=0x08;break; + case 2:type|=0x10;break; + case 4:type|=0x18;break; + case 8:type|=0x20;break; + case 16:type|=0x28;break; + default: + qDebug()<<"Unrecognized size of a scalar:"<&item:msubitems){ + if(mtype==Type::KeyValue) + ret.append(encodeNetString(item.first)); + ret.append(item.second.encode()); + } + return ret; +} -- 1.7.2.5