From 7d5942adf1a0220738992e396f96a4ca552ccbb1 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 18 Nov 2013 13:13:21 +0100 Subject: [PATCH] Added support for sending JSON::Values over a socket in DTMI format without needing to convert in advance. --- lib/json.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++++++-- lib/json.h | 5 ++- 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/lib/json.cpp b/lib/json.cpp index cfd5b4bd..a0c19ed9 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -475,7 +475,7 @@ const JSON::Value & JSON::Value::operator[](unsigned int i) const{ /// Packs to a std::string for transfer over the network. /// If the object is a container type, this function will call itself recursively and contain all contents. /// As a side effect, this function clear the internal buffer of any object-types. -std::string JSON::Value::toPacked(){ +std::string JSON::Value::toPacked() const{ std::string r; if (isInt() || isNull() || isBool()){ r += 0x01; @@ -500,7 +500,7 @@ std::string JSON::Value::toPacked(){ if (isObject()){ r += 0xE0; if (objVal.size() > 0){ - for (JSON::ObjIter it = objVal.begin(); it != objVal.end(); it++){ + for (JSON::ObjConstIter it = objVal.begin(); it != objVal.end(); it++){ if (it->first.size() > 0){ r += it->first.size() / 256; r += it->first.size() % 256; @@ -512,11 +512,10 @@ std::string JSON::Value::toPacked(){ r += (char)0x0; r += (char)0x0; r += (char)0xEE; - strVal.clear(); } if (isArray()){ r += 0x0A; - for (JSON::ArrIter it = arrVal.begin(); it != arrVal.end(); it++){ + for (JSON::ArrConstIter it = arrVal.begin(); it != arrVal.end(); it++){ r += it->toPacked(); } r += (char)0x0; @@ -527,6 +526,115 @@ std::string JSON::Value::toPacked(){ } //toPacked +/// Packs and transfers over the network. +/// If the object is a container type, this function will call itself recursively for all contents. +void JSON::Value::sendTo(Socket::Connection & socket) const{ + if (isInt() || isNull() || isBool()){ + socket.SendNow("\001", 1); + int tmpHalf = htonl((int)(intVal >> 32)); + socket.SendNow((char*)&tmpHalf, 4); + tmpHalf = htonl((int)(intVal & 0xFFFFFFFF)); + socket.SendNow((char*)&tmpHalf, 4); + return; + } + if (isString()){ + socket.SendNow("\002", 1); + int tmpVal = htonl((int)strVal.size()); + socket.SendNow((char*)&tmpVal, 4); + socket.SendNow(strVal); + return; + } + if (isObject()){ + if (isMember("trackid") && isMember("time")){ + unsigned int trackid = objVal.find("trackid")->second.asInt(); + long long time = objVal.find("time")->second.asInt(); + unsigned int size = 16; + if (objVal.size() > 0){ + for (JSON::ObjConstIter it = objVal.begin(); it != objVal.end(); it++){ + if (it->first.size() > 0 && it->first != "trackid" && it->first != "time" && it->first != "datatype"){ + size += 2+it->first.size()+it->second.packedSize(); + } + } + } + socket.SendNow("DTP2", 4); + size = htonl(size); + socket.SendNow((char*)&size, 4); + trackid = htonl(trackid); + socket.SendNow((char*)&trackid, 4); + int tmpHalf = htonl((int)(time >> 32)); + socket.SendNow((char*)&tmpHalf, 4); + tmpHalf = htonl((int)(time & 0xFFFFFFFF)); + socket.SendNow((char*)&tmpHalf, 4); + socket.SendNow("\340", 1); + if (objVal.size() > 0){ + for (JSON::ObjConstIter it = objVal.begin(); it != objVal.end(); it++){ + if (it->first.size() > 0 && it->first != "trackid" && it->first != "time" && it->first != "datatype"){ + char sizebuffer[2] = {0, 0}; + sizebuffer[0] = (it->first.size() >> 8) & 0xFF; + sizebuffer[1] = it->first.size() & 0xFF; + socket.SendNow(sizebuffer, 2); + socket.SendNow(it->first); + it->second.sendTo(socket); + } + } + } + socket.SendNow("\000\000\356", 3); + return; + } + socket.SendNow("\340", 1); + if (objVal.size() > 0){ + for (JSON::ObjConstIter it = objVal.begin(); it != objVal.end(); it++){ + if (it->first.size() > 0){ + char sizebuffer[2] = {0, 0}; + sizebuffer[0] = (it->first.size() >> 8) & 0xFF; + sizebuffer[1] = it->first.size() & 0xFF; + socket.SendNow(sizebuffer, 2); + socket.SendNow(it->first); + it->second.sendTo(socket); + } + } + } + socket.SendNow("\000\000\356", 3); + return; + } + if (isArray()){ + socket.SendNow("\012", 1); + for (JSON::ArrConstIter it = arrVal.begin(); it != arrVal.end(); it++){ + it->sendTo(socket); + } + socket.SendNow("\000\000\356", 3); + return; + } +}//sendTo + +/// Returns the packed size of this Value. +unsigned int JSON::Value::packedSize() const{ + if (isInt() || isNull() || isBool()){ + return 9; + } + if (isString()){ + return 5 + strVal.size(); + } + if (isObject()){ + unsigned int ret = 4; + if (objVal.size() > 0){ + for (JSON::ObjConstIter it = objVal.begin(); it != objVal.end(); it++){ + if (it->first.size() > 0){ + ret += 2+it->first.size()+it->second.packedSize(); + } + } + } + return ret; + } + if (isArray()){ + unsigned int ret = 4; + for (JSON::ArrConstIter it = arrVal.begin(); it != arrVal.end(); it++){ + ret += it->packedSize(); + } + return ret; + } +}//packedSize + /// Pre-packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header. /// Non-object-types will print an error to stderr. /// The internal buffer is guaranteed to be up-to-date after this function is called. diff --git a/lib/json.h b/lib/json.h index fea93476..2f4db947 100644 --- a/lib/json.h +++ b/lib/json.h @@ -6,6 +6,7 @@ #include #include #include +#include "socket.h" //empty definition of DTSC::Stream so it can be a friend. namespace DTSC { @@ -73,7 +74,9 @@ namespace JSON { const Value & operator[](const char * i) const; const Value & operator[](unsigned int i) const; //handy functions and others - std::string toPacked(); + std::string toPacked() const; + void sendTo(Socket::Connection & socket) const; + unsigned int packedSize() const; void netPrepare(); std::string & toNetPacked(); std::string toString() const;