--- /dev/null
+// 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
--- /dev/null
+// 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;
+}