basic message encoding (incomplete)
authorKonrad Rosenbaum <konrad@silmor.de>
Fri, 27 Jun 2014 06:13:21 +0000 (08:13 +0200)
committerKonrad Rosenbaum <konrad@silmor.de>
Fri, 27 Jun 2014 06:13:21 +0000 (08:13 +0200)
network/include/skid-connection.h
network/include/skid-message.h [new file with mode: 0644]
network/include/skidnet.h
network/network.pro
network/src/skid-connection.cpp
network/src/skid-message.cpp [new file with mode: 0644]

index cb49755..18e4464 100644 (file)
@@ -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 (file)
index 0000000..a518bdc
--- /dev/null
@@ -0,0 +1,130 @@
+// network message include file for SKID
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2014
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef SKID_NETWORK_MESSAGE_H
+#define SKID_NETWORK_MESSAGE_H
+
+#include <QList>
+#include <QMap>
+#include <QPair>
+#include <QString>
+#include <QStringList>
+#include <QUuid>
+
+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<DataItem>&l){setList(l);}
+                DataItem(const QMap<QString,DataItem>&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<DataItem>&);
+                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<QString,DataItem>&);
+                void addMapItem(const QString&,const DataItem&);
+                void removeMapItems(const QString&);
+                bool hasMapItem(const QString&);
+                void clearMap(){msubitems.clear();}
+                DataItem getMapItem(const QString&)const;
+                QList<DataItem> getMapItems(const QString&)const;
+                QStringList getMapKeys()const;
+                
+                QByteArray encode()const;
+                static DataItem decode(const QByteArray&);
+                
+        private:
+                Type mtype=Type::Null;
+                QByteArray mbytes;
+                QList<QPair<QString,DataItem>>msubitems;
+                
+                QByteArray encodeBytes()const;
+                QByteArray encodeScalar()const;
+                QByteArray encodeComplex()const;
+};
+        
+class Message {};
+
+//end of namespace
+}}
+
+#endif
index 5d4c7a5..c0ce6d9 100644 (file)
 
 ///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"
index b57a467..8d033a7 100644 (file)
@@ -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
index 9deb637..5eb2a0d 100644 (file)
@@ -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 (file)
index 0000000..9f82d57
--- /dev/null
@@ -0,0 +1,188 @@
+// network message include file for SKID
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2014
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "skid-message.h"
+
+#include <QDebug>
+
+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<DataItem>&l)
+{
+        msubitems.clear();
+        mbytes.clear();
+        mtype=Type::List;
+        for(const DataItem&item:l)
+                msubitems.append(QPair<QString,DataItem>(QString(),item));
+}
+
+void DataItem::addListItem(const DataItem&item)
+{
+        if(mtype!=Type::List)return;
+        msubitems.append(QPair<QString,DataItem>(QString(),item));
+}
+
+void DataItem::setMap(const QMap<QString,DataItem>&map)
+{
+        msubitems.clear();
+        mbytes.clear();
+        mtype=Type::KeyValue;
+        for(const QString&key:map.keys())
+                for(const DataItem&item:map.values(key))
+                        msubitems.append(QPair<QString,DataItem>(key,item));
+}
+
+void DataItem::addMapItem(const QString&key,const DataItem&item)
+{
+        msubitems.append(QPair<QString,DataItem>(key,item));
+}
+
+void DataItem::removeMapItems(const QString&key)
+{
+        QList<QPair<QString,DataItem>>tmp;
+        tmp.swap(msubitems);
+        for(const QPair<QString,DataItem>&item:tmp)
+                if(item.first!=key)
+                        msubitems.append(item);
+}
+
+bool DataItem::hasMapItem(const QString&key)
+{
+        for(const QPair<QString,DataItem>&item:msubitems)
+                if(item.first==key)
+                        return true;
+        return false;
+}
+
+DataItem DataItem::getMapItem(const QString&key)const
+{
+        for(const QPair<QString,DataItem>&item:msubitems)
+                if(item.first==key)
+                        return item.second;
+        return DataItem();
+}
+
+QList<DataItem> DataItem::getMapItems(const QString&key)const
+{
+        QList<DataItem>ret;
+        for(const QPair<QString,DataItem>&item:msubitems)
+                if(item.first==key)
+                        ret.append(item.second);
+        return ret;
+
+}
+
+QStringList DataItem::getMapKeys()const
+{
+        QStringList ret;
+        for(const QPair<QString,DataItem>&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:"<<size<<", data (hex):"<<mbytes.toHex();
+                        return QByteArray();
+        }
+        ret.append((char)type);
+        ret.append(mbytes);
+        return ret;
+}
+
+QByteArray DataItem::encodeComplex()const
+{
+        QByteArray ret;
+        //type
+#warning TODO
+        //amount of items
+        //items
+        for(const QPair<QString,DataItem>&item:msubitems){
+                if(mtype==Type::KeyValue)
+                        ret.append(encodeNetString(item.first));
+                ret.append(item.second.encode());
+        }
+        return ret;
+}