Added DTMI support to JSON library.

This commit is contained in:
Thulinma 2012-08-23 11:07:49 +02:00
parent 36c7eed7e3
commit 0c5f449963
2 changed files with 208 additions and 0 deletions

View file

@ -4,6 +4,7 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> //for uint64_t
int JSON::Value::c2hex(int c){ int JSON::Value::c2hex(int c){
if (c >= '0' && c <= '9') return c - '0'; if (c >= '0' && c <= '9') return c - '0';
@ -342,6 +343,49 @@ JSON::Value & JSON::Value::operator[](unsigned int i){
return arrVal[i]; return arrVal[i];
} }
/// 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.
std::string JSON::Value::toPacked(){
std::string r;
if (isInt() || isNull() || isBool()){
r += 0x01;
uint64_t numval = intVal;
r += *(((char*)&numval)+7); r += *(((char*)&numval)+6);
r += *(((char*)&numval)+5); r += *(((char*)&numval)+4);
r += *(((char*)&numval)+3); r += *(((char*)&numval)+2);
r += *(((char*)&numval)+1); r += *(((char*)&numval));
}
if (isString()){
r += 0x02;
r += strVal.size() / (256*256*256);
r += strVal.size() / (256*256);
r += strVal.size() / 256;
r += strVal.size() % 256;
r += strVal;
}
if (isObject()){
r += 0xE0;
if (objVal.size() > 0){
for (JSON::ObjIter it = objVal.begin(); it != objVal.end(); it++){
r += it->first.size() / 256;
r += it->first.size() % 256;
r += it->first;
r += it->second.toPacked();
}
}
r += (char)0x0; r += (char)0x0; r += (char)0xEE;
}
if (isArray()){
r += 0x0A;
for (JSON::ArrIter it = arrVal.begin(); it != arrVal.end(); it++){
r += it->toPacked();
}
r += (char)0x0; r += (char)0x0; r += (char)0xEE;
}
return r;
};//toPacked
/// Converts this JSON::Value to valid JSON notation and returns it. /// Converts this JSON::Value to valid JSON notation and returns it.
/// Makes absolutely no attempts to pretty-print anything. :-) /// Makes absolutely no attempts to pretty-print anything. :-)
std::string JSON::Value::toString(){ std::string JSON::Value::toString(){
@ -390,6 +434,63 @@ std::string JSON::Value::toString(){
return "null";//should never get here... return "null";//should never get here...
} }
/// Converts this JSON::Value to valid JSON notation and returns it.
/// Makes an attempt at pretty-printing.
std::string JSON::Value::toPrettyString(int indentation){
switch (myType){
case INTEGER: {
std::stringstream st;
st << intVal;
return st.str();
break;
}
case STRING: {
for (int i = 0; i < 5 && i < strVal.size(); ++i){
if (strVal[i] < 32 || strVal[i] > 125){
return JSON::Value((long long int)strVal.size()).asString()+" bytes of binary data";
}
}
return string_escape(strVal);
break;
}
case ARRAY: {
if (arrVal.size() > 0){
std::string tmp = "[\n";
for (ArrIter it = ArrBegin(); it != ArrEnd(); it++){
tmp += std::string(indentation+2, ' ')+it->toPrettyString(indentation+2);
if (it + 1 != ArrEnd()){tmp += ",\n";}
}
tmp += "\n"+std::string(indentation, ' ')+"]";
return tmp;
}else{
return "[]";
}
break;
}
case OBJECT: {
if (objVal.size() > 0){
std::string tmp2 = "{\n";
ObjIter it3 = ObjEnd();
--it3;
for (ObjIter it2 = ObjBegin(); it2 != ObjEnd(); it2++){
tmp2 += std::string(indentation+2, ' ')+"\"" + it2->first + "\":";
tmp2 += it2->second.toPrettyString(indentation+2);
if (it2 != it3){tmp2 += ",\n";}
}
tmp2 += "\n"+std::string(indentation, ' ')+"}";
return tmp2;
}else{
return "{}";
}
break;
}
case EMPTY:
default:
return "null";
}
return "null";//should never get here...
}
/// Appends the given value to the end of this JSON::Value array. /// Appends the given value to the end of this JSON::Value array.
/// Turns this value into an array if it is not already one. /// Turns this value into an array if it is not already one.
void JSON::Value::append(const JSON::Value & rhs){ void JSON::Value::append(const JSON::Value & rhs){
@ -439,6 +540,36 @@ bool JSON::Value::isMember(const std::string & name) const{
return objVal.count(name) > 0; return objVal.count(name) > 0;
} }
/// Returns true if this object is an integer.
bool JSON::Value::isInt() const{
return (myType == INTEGER);
}
/// Returns true if this object is a string.
bool JSON::Value::isString() const{
return (myType == STRING);
}
/// Returns true if this object is a bool.
bool JSON::Value::isBool() const{
return (myType == BOOL);
}
/// Returns true if this object is an object.
bool JSON::Value::isObject() const{
return (myType == OBJECT);
}
/// Returns true if this object is an array.
bool JSON::Value::isArray() const{
return (myType == ARRAY);
}
/// Returns true if this object is null.
bool JSON::Value::isNull() const{
return (myType == EMPTY);
}
/// Returns an iterator to the begin of the object map, if any. /// Returns an iterator to the begin of the object map, if any.
JSON::ObjIter JSON::Value::ObjBegin(){ JSON::ObjIter JSON::Value::ObjBegin(){
return objVal.begin(); return objVal.begin();
@ -488,3 +619,70 @@ JSON::Value JSON::fromFile(std::string filename){
File.close(); File.close();
return ret; return ret;
} }
/// Parses a single DTMI type - used recursively by the JSON::fromDTMI functions.
/// This function updates i every call with the new position in the data.
/// \param data The raw data to parse.
/// \param len The size of the raw data.
/// \param i Current parsing position in the raw data (defaults to 0).
/// \returns A single JSON::Value, parsed from the raw data.
JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i){
#if DEBUG >= 10
fprintf(stderr, "Note: AMF type %hhx found. %i bytes left\n", data[i], len-i);
#endif
switch (data[i]){
case 0x01:{//integer
unsigned char tmpdbl[8];
tmpdbl[7] = data[i+1];
tmpdbl[6] = data[i+2];
tmpdbl[5] = data[i+3];
tmpdbl[4] = data[i+4];
tmpdbl[3] = data[i+5];
tmpdbl[2] = data[i+6];
tmpdbl[1] = data[i+7];
tmpdbl[0] = data[i+8];
i+=9;//skip 8(an uint64_t)+1 forwards
uint64_t * d = (uint64_t*)tmpdbl;
return JSON::Value((long long int)*d);
} break;
case 0x02:{//string
unsigned int tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];//set tmpi to UTF-8-long length
std::string tmpstr = std::string((const char *)data+i+5, (size_t)tmpi);//set the string data
i += tmpi + 5;//skip length+size+1 forwards
return JSON::Value(tmpstr);
} break;
case 0xFF://also object
case 0xE0:{//object
++i;
JSON::Value ret;
while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE)
unsigned int tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length
std::string tmpstr = std::string((const char *)data+i+2, (size_t)tmpi);//set the string data
i += tmpi + 2;//skip length+size forwards
ret[tmpstr] = fromDTMI(data, len, i);//add content, recursively parsed, updating i, setting indice to tmpstr
}
i += 3;//skip 0x0000EE
return ret;
} break;
case 0x0A:{//array
JSON::Value ret;
++i;
while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE)
ret.append(fromDTMI(data, len, i));//add content, recursively parsed, updating i
}
i += 3;//skip 0x0000EE
return ret;
} break;
}
#if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented DTMI type %hhx - returning.\n", data[i]);
#endif
return JSON::Value();
}//fromOneDTMI
/// Parses a std::string to a valid JSON::Value.
/// This function will find one DTMI object in the string and return it.
JSON::Value JSON::fromDTMI(std::string data){
unsigned int i = 0;
return fromDTMI((const unsigned char*)data.c_str(), data.size(), i);
}//fromDTMI

View file

@ -59,12 +59,20 @@ namespace JSON{
Value & operator[](const char * i); Value & operator[](const char * i);
Value & operator[](unsigned int i); Value & operator[](unsigned int i);
//handy functions and others //handy functions and others
std::string toPacked();
std::string toString(); std::string toString();
std::string toPrettyString(int indentation = 0);
void append(const Value & rhs); void append(const Value & rhs);
void prepend(const Value & rhs); void prepend(const Value & rhs);
void shrink(unsigned int size); void shrink(unsigned int size);
void removeMember(const std::string & name); void removeMember(const std::string & name);
bool isMember(const std::string & name) const; bool isMember(const std::string & name) const;
bool isInt() const;
bool isString() const;
bool isBool() const;
bool isObject() const;
bool isArray() const;
bool isNull() const;
ObjIter ObjBegin(); ObjIter ObjBegin();
ObjIter ObjEnd(); ObjIter ObjEnd();
ArrIter ArrBegin(); ArrIter ArrBegin();
@ -73,6 +81,8 @@ namespace JSON{
void null(); void null();
}; };
Value fromDTMI(std::string data);
Value fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i);
Value fromString(std::string json); Value fromString(std::string json);
Value fromFile(std::string filename); Value fromFile(std::string filename);