Sleds/libeye/eyejson.cpp

635 lines
18 KiB
C++

// Copyright (c) 2013-2015 IONU Security, Inc. All rights reserved.
// Copyright (c) 2016 Sequence Logic, Inc. All rights reserved.
//
// JSON utility class
#include <cstring>
#include "eyejson.h"
#include "eyelog.h"
#include "eyeutils.h"
using namespace sequencelogic;
EyeJSONNode::~EyeJSONNode()
{
}
// Convert JSON escape sequence to value, returns bytes processed and bytes put into value string
int EyeJSONNode::ProcessEscape (const char* jsonstr, char* value, int* escbytes)
{
int rc = 1;
*escbytes = 1;
unsigned char codepoint[2];
switch (*jsonstr) {
case '"' :
*value = '"';
break;
case '/' :
*value = '/';
break;
case '\\' :
*value = '\\';
break;
case 'b' :
*value = '\b';
break;
case 'f' :
*value = '\f';
break;
case 'n' :
*value = '\n';
break;
case 'r' :
*value = '\r';
break;
case 't' :
*value = '\t';
break;
case 'u' : // Unicode 4 hex digits
jsonstr++;
if (sequencelogic::HexToBinary (jsonstr, 4, codepoint)) {
//sequencelogic::DumpAsBinary (codepoint, 2);
if (codepoint[0] == 0 && codepoint[1] <= 0x7F) {
*value++ = (char)codepoint[1];
}
else if (codepoint[0] <= 0x7) { // 2 byte UTF-8
*value++ = (char)(0xC0 | (codepoint[0] << 2) | (codepoint[1] >> 6));
*value++ = (char)(0x80 | (codepoint[1] & 0x3F));
*escbytes = 2;
}
else { // 3 byte UTF-8
*value++ = (char)(0xE0 | (codepoint[0] >> 4));
*value++ = (char)(0x80 | (codepoint[0] << 2) | (codepoint[1] >> 6));
*value++ = (char)(0x80 | (codepoint[1] & 0x3F));
*escbytes = 3;
}
}
else {
IONUDEBUG ("EyeJSON(): invalid unicode sequence");
}
rc += 4;
break;
default:
IONUDEBUG ("EyeJSON(): invalid escaped character <%c> <<%s>>", *jsonstr, jsonstr-1);
break;
}
return rc;
}
char* EyeJSONNode::ParseString (const char* str)
{
if (!str)
return NULL;
char* retval = new char[strlen(str) + 1];
char* val = retval;
int escbytes = 0;
while (*str) {
if (*str == '\\') {
str++;
str += ProcessEscape (str, val, &escbytes);
val += escbytes;
}
else
*val++ = *str++;
}
*val = '\0';
return retval;
}
EyeJSONScalar::EyeJSONScalar (const char* key, const char* value, JSON_TYPE type)
{
_key = sequencelogic::StrDup (key);
//_key = ParseString (key);
_value = ParseString (value);
_type = type;
}
EyeJSONScalar::~EyeJSONScalar ()
{
if (_key)
delete[] _key;
if (_value)
delete[] _value;
_type = JSON_NULL;
_key = NULL;
_value = NULL;
}
void EyeJSONScalar::ReplaceValue (const char* value)
{
if (sequencelogic::StrCmp (_value, value) == 0)
return; // Already set to this value
else if (_value)
delete[] _value;
_value = sequencelogic::StrDup (value);
}
void EyeJSONScalar::ReplaceKey (const char* key)
{
if (sequencelogic::StrCmp (_key, key) == 0)
return; // Already set to this value
else if (_key)
delete[] _key;
_key = sequencelogic::StrDup (key);
}
void EyeJSONScalar::GetJSONString (std::string& json)
{
if (!_value)
return;
char* vptr = _value;
unsigned char codepoint[2];
char hex[5];
switch (_type) {
case JSON_STRING :
if (_key) {
json = "\"";
json += _key;
json += "\":\""; // key:value pair
}
else
json = "\""; // value
if (vptr) {
while (*vptr) {
switch (*vptr) {
case '"' :
json += "\\\"";
break;
case '/' :
json += "\\/";
break;
case '\\' :
json += "\\\\";
break;
case '\b' :
json += "\\b";
break;
case '\f' :
json += "\\f";
break;
case '\n' :
json += "\\n";
break;
case '\r' :
json += "\\r";
break;
case '\t' :
json += "\\t";
break;
default :
// Look for UTF-8 encoded data
if ((*vptr & 0x80) == 0x80) {
if ((*vptr & 0xe0) == 0xe0) { // 3 byte encoding
codepoint[0] = (unsigned char)(*vptr++ << 4);
codepoint[0] |= (unsigned char)((*vptr >> 2) & 0x0f);
codepoint[1] = (unsigned char)(*vptr++ << 6);
codepoint[1] |= (unsigned char)(*vptr & 0x3f);
}
else if ((*vptr & 0xc0) == 0xc0) { // 2 byte encoding
codepoint[0] = (unsigned char)((*vptr >> 2) & 0x7);
codepoint[1] = (unsigned char)(*vptr++ << 6);
codepoint[1] |= (unsigned char)(*vptr & 0x3f);
}
else {
IONUDEBUG ("Invalid UTF8 encoding");
codepoint[0] = 0;
codepoint[1] = 0;
}
sequencelogic::BinaryToHex (codepoint, 2, hex);
json += "\\u";
json += hex;
}
else
json += *vptr;
break;
}
vptr++;
}
}
json += '"';
break;
case JSON_BOOL :
case JSON_INT :
case JSON_FLOAT :
case JSON_NULL :
if (_key) {
json = "\"";
json += _key;
json += "\":";
json += _value;
}
else
json = _value;
break;
case JSON_ARRAY :
case JSON_OBJECT :
break;
}
}
// Create a content object from a JSON str
EyeJSONObject::EyeJSONObject (const char* jsonstr)
{
_key = NULL;
_parent = NULL;
_type = JSON_OBJECT;
bool errflag = false;
std::string kbuff = "";
std::string vbuff = "";
JSON_TYPE type = JSON_NULL;
EyeJSONNode* jsonValue = NULL;
EyeJSONObject* jsonObject = NULL;
if (jsonstr) {
while (*jsonstr && !errflag) {
char c = *jsonstr;
switch (c) {
case '{' :
case '[' :
jsonstr++; // Skip '{' or '['
type = (c == '{' ? JSON_OBJECT : JSON_ARRAY);
if (jsonObject) {
EyeJSONObject* obj = new EyeJSONObject (kbuff.c_str(), type, jsonObject);
jsonObject->AddMember (obj);
jsonObject = obj;
kbuff = "";
}
else {
jsonObject = this;
_type = type;
}
break;
case '}' :
case ']' :
if (jsonObject && (jsonObject->GetType() == JSON_OBJECT || jsonObject->GetType() == JSON_ARRAY)) {
if (jsonObject->GetType() == JSON_ARRAY && kbuff.size() > 0) {
jsonValue = new EyeJSONScalar (NULL, kbuff.c_str(), JSON_STRING);
jsonObject->AddMember (jsonValue);
kbuff = "";
vbuff = "";
}
jsonstr++; // Skip '}' or ']' and then done, go back to parent
jsonObject = jsonObject->GetParent();
if (jsonObject)
type = jsonObject->GetType();
else
type = _type;
}
else {
IONUDEBUG ("EyeJSONObject: expecting object/array end");
errflag = true;
}
break;
case 'n' :
case 't' :
case 'f' :
if (c == 't') {
jsonstr += 4;
type = JSON_BOOL;
vbuff = (char*)"true";
}
else if (c == 'f') {
jsonstr += 5;
type = JSON_BOOL;
vbuff = (char*)"false";
}
else if (c == 'n') {
jsonstr += 4;
type = JSON_NULL;
vbuff = (char*)"null";
}
if (jsonObject && (jsonObject->GetType() == JSON_OBJECT || jsonObject->GetType() == JSON_ARRAY)) {
jsonValue = new EyeJSONScalar ((kbuff.size() > 0 ? kbuff.c_str() : NULL), vbuff.c_str(), type);
jsonObject->AddMember (jsonValue);
kbuff = "";
vbuff = "";
}
else {
IONUDEBUG ("EyeJSONObject: expecting object or array");
errflag = true;
}
break;
case '"' :
jsonstr++; // Skip '"'
if (kbuff.size() == 0 && type != JSON_ARRAY) {
while (*jsonstr) {
if (*jsonstr == '\\') {
kbuff += *jsonstr++;
kbuff += *jsonstr++;
}
else if (*jsonstr == '"') {
jsonstr++; // Skip '"'
break;
}
else
kbuff += *jsonstr++;
}
}
else if (vbuff.size() == 0) {
while (*jsonstr) {
if (*jsonstr == '\\') {
vbuff += *jsonstr++;
vbuff += *jsonstr++;
}
else if (*jsonstr == '"') {
jsonstr++; // Skip '"'
if (jsonObject && (jsonObject->GetType() == JSON_OBJECT || jsonObject->GetType() == JSON_ARRAY)) {
jsonValue = new EyeJSONScalar ((kbuff.size() > 0 ? kbuff.c_str() : NULL), vbuff.c_str(), JSON_STRING);
jsonObject->AddMember (jsonValue);
kbuff = "";
vbuff = "";
}
else {
IONUDEBUG ("EyeJSONObject: expecting object or array for string");
errflag = true;
}
break;
}
else
vbuff += *jsonstr++;
}
}
break;
case '-' :
case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' :
case '9' :
type = JSON_INT;
if (jsonObject && (jsonObject->GetType() == JSON_OBJECT || jsonObject->GetType() == JSON_ARRAY)) {
while (*jsonstr) {
char d = *jsonstr;
if (d == '.' || d == 'e' || d == 'E')
type = JSON_FLOAT;
if (d == ' ' || d == '\t' || d == '\n' || d == ',' || d == ']' || d == '}') {
jsonValue = new EyeJSONScalar ((kbuff.size() > 0 ? kbuff.c_str() : NULL), vbuff.c_str(), type);
jsonObject->AddMember (jsonValue);
kbuff = "";
vbuff = "";
break;
}
else
vbuff += *jsonstr++;
}
}
else {
IONUDEBUG ("EyeJSONObject: number <%c> not in object or array", c);
errflag = true;
}
break;
case ':' :
case ',' :
case ' ' :
case '\t' :
case '\n' :
case '\r' :
jsonstr++;
break;
default : // Error
//IONUDEBUG ("EyeJSONObject: unexpected character <%c>" , c);
errflag = true;
break;
}
}
}
if (errflag && jsonObject) {
if (_key) {
delete[] _key;
_key = NULL;
}
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr)
delete *itr;
_members.clear();
}
}
EyeJSONObject::EyeJSONObject(const char* key, JSON_TYPE type, EyeJSONObject* parent)
{
if (key && *key)
_key = sequencelogic::StrDup (key);
else
_key = NULL;
_type = type;
_parent = parent;
}
EyeJSONObject::~EyeJSONObject()
{
if (_key) {
delete[] _key;
_key = NULL;
}
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr)
delete *itr;
_members.clear();
}
bool EyeJSONObject::AddMember (EyeJSONNode* member)
{
if (!member)
return false;
JSON_TYPE mtype = member->GetType();
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr) {
char* key = (*itr)->GetKey();
JSON_TYPE type = (*itr)->GetType();
if (key && sequencelogic::StrCmp (key, member->GetKey()) == 0) {
if (mtype == type && type != JSON_OBJECT && type != JSON_ARRAY) {
EyeJSONScalar* replacement = dynamic_cast<EyeJSONScalar*>(*itr);
if (replacement) {
replacement->ReplaceValue (dynamic_cast<EyeJSONScalar*>(member)->GetValue());
return true;
}
}
}
}
_members.push_back (member);
return true;
}
bool EyeJSONObject::RemoveMember (size_t member)
{
bool rc = true;
if (member < _members.size()) {
EyeJSONNode* node = _members[member];
_members.erase (_members.begin() + member);
delete node;
}
else
rc = false;
return rc;
}
bool EyeJSONObject::RemoveMember (const char* member)
{
if (!member)
return false;
size_t pos = 0;
bool found = false;
char* key = NULL;
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr) {
if (_type == JSON_ARRAY)
key = dynamic_cast<EyeJSONScalar*>(*itr)->GetValue();
else
key = (*itr)->GetKey();
if (sequencelogic::StrCmp (key, member) == 0) {
EyeJSONNode* node = _members[pos];
_members.erase (_members.begin() + pos);
delete node;
found = true;
break;
}
pos++;
}
return found;
}
bool EyeJSONObject::UpdateMember (EyeJSONNode* member)
{
if (!member)
return false;
size_t i = 0;
bool rc = false;
if (member) {
if (member->GetType() == JSON_ARRAY && GetType() == JSON_ARRAY) {
// Clear out old array values
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr)
delete *itr;
_members.clear();
EyeJSONObject* arr = dynamic_cast<EyeJSONObject*>(member);
for (i = 0; i < arr->GetNumMembers(); ++i) {
EyeJSONScalar* val = dynamic_cast<EyeJSONScalar*>(arr->GetMember(i));
AddMember (new EyeJSONScalar (NULL, val->GetValue(), val->GetType()));
}
rc = true;
}
else if (member->GetType() == JSON_OBJECT) {
EyeJSONObject* obj = dynamic_cast<EyeJSONObject*>(member);
for (i = 0; i < obj->GetNumMembers(); ++i) {
EyeJSONNode* node = obj->GetMember(i);
EyeJSONScalar* replacement = dynamic_cast<EyeJSONScalar*>(GetMember (node->GetKey()));
if (replacement && replacement->GetType() == node->GetType()) {
replacement->ReplaceValue (dynamic_cast<EyeJSONScalar*>(node)->GetValue());
rc = true;
}
else if (!replacement) {
EyeJSONScalar* item = dynamic_cast<EyeJSONScalar*>(node);
AddMember (new EyeJSONScalar (item->GetKey(), item->GetValue(), item->GetType()));
}
}
}
else if (member->GetType() != JSON_NULL) {
EyeJSONScalar* replacement = dynamic_cast<EyeJSONScalar*>(GetMember (member->GetKey()));
if (replacement && replacement->GetType() == member->GetType()) {
replacement->ReplaceValue (dynamic_cast<EyeJSONScalar*>(member)->GetValue());
rc = true;
}
else if (!replacement) {
EyeJSONScalar* item = dynamic_cast<EyeJSONScalar*>(member);
AddMember (new EyeJSONScalar (item->GetKey(), item->GetValue(), item->GetType()));
}
}
}
return rc;
}
EyeJSONNode* EyeJSONObject::GetMember (size_t member)
{
if (member < _members.size())
return _members[member];
else
return NULL;
}
EyeJSONNode* EyeJSONObject::GetMember (const char* member)
{
if (!member)
return NULL;
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr) {
char* key = (*itr)->GetKey();
JSON_TYPE type = (*itr)->GetType();
if (sequencelogic::StrCmp (key, member) == 0)
return *itr;
if (type == JSON_ARRAY || type == JSON_OBJECT) {
EyeJSONObject* container = dynamic_cast<EyeJSONObject*>(*itr);
EyeJSONNode* node = container->GetMember (member);
if (node)
return node;
}
}
return NULL;
}
void EyeJSONObject::Empty()
{
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr)
delete *itr;
_members.clear();
}
void EyeJSONObject::ReplaceKey (const char* key)
{
if (sequencelogic::StrCmp (_key, key) == 0)
return; // Already set to this value
else if (_key)
delete[] _key;
_key = sequencelogic::StrDup (key);
}
void EyeJSONObject::GetJSONString (std::string& json)
{
if (_type == JSON_OBJECT) {
if (_key && *_key && _parent) {
json = "\"";
json += _key;
json += "\":{";
}
else
json = "{";
}
else {
if (_key && *_key && _parent) {
json = "\"";
json += _key;
json += "\":[";
}
else
json = "[";
}
for (std::vector<EyeJSONNode*>::const_iterator itr = _members.begin(); itr != _members.end(); ++itr) {
if (itr != _members.begin())
json += ",";
std::string mjson;
(*itr)->GetJSONString (mjson);
json += mjson;
}
if (_type == JSON_OBJECT)
json += "}";
else
json += "]";
}
std::string EyeJSONObject::Stringify ()
{
std::string json;
GetJSONString (json);
return json;
}