404 lines
11 KiB
C++
404 lines
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright(c) 2015, 2016 Sequence Logic.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "jsonobject.h"
|
|
|
|
#include <sstream>
|
|
#ifdef WIN32
|
|
#include <regex>
|
|
#endif
|
|
|
|
using namespace sequencelogic;
|
|
|
|
namespace
|
|
{
|
|
#ifdef WIN32
|
|
const std::regex JSON_ARRAY_PAT ("^([^\\[]+)\\[([\\d]+)\\](.*)");
|
|
#endif
|
|
int SplitString(const std::string &strToSplit, const char ch, std::vector<std::string> &splitStrings)
|
|
{
|
|
int nRetVal = 0;
|
|
splitStrings.clear();
|
|
|
|
std::string::size_type nStart = 0;
|
|
while (strToSplit.find(ch, nStart) != std::string::npos)
|
|
{
|
|
splitStrings.push_back(strToSplit.substr(nStart, strToSplit.find(ch, nStart) - nStart));
|
|
++nRetVal;
|
|
nStart = strToSplit.find(ch, nStart)+1;
|
|
}
|
|
|
|
// Check for a last arg...
|
|
if (nStart < strToSplit.length())
|
|
{
|
|
splitStrings.push_back(strToSplit.substr(nStart));
|
|
++nRetVal;
|
|
}
|
|
return nRetVal;
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// JSONArray...
|
|
|
|
/**
|
|
* Does this array contain the passed in string?
|
|
*/
|
|
bool JSONArray::hasString(const std::string &str) const
|
|
{
|
|
//return (const_cast<JSONArray *>(this)->search(str.c_str()) != NULL);
|
|
bool bRetVal = false;
|
|
for (unsigned int i = 0; !bRetVal && (i < data.size()); ++i)
|
|
{
|
|
T_JSON *pObj = data[i];
|
|
if ((pObj != NULL) && (pObj->gettype() == J_STRING))
|
|
bRetVal = (str == pObj->getstring());
|
|
}
|
|
return bRetVal;
|
|
}
|
|
|
|
/**
|
|
* Remove an element from the array...
|
|
*/
|
|
void JSONArray::removeElement(const std::string &elem)
|
|
{
|
|
T_JSON *pVal = NULL;
|
|
for (T_JSON::IntData::iterator iter = data.begin(); iter != data.end(); ++iter)
|
|
{
|
|
if (::strcmp((*iter)->getstring(), elem.c_str()) == 0)
|
|
{
|
|
pVal = *iter;
|
|
data.erase(iter);
|
|
delete pVal;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// JSONObject...
|
|
// Load JSON from a file.
|
|
JSONObject::JSONObject(const std::string &jsonStr)
|
|
{
|
|
if (jsonStr != "")
|
|
loadFromString(jsonStr.c_str());
|
|
}
|
|
|
|
/**
|
|
* Make this into a JSON string.
|
|
*/
|
|
std::string JSONObject::toString(bool bPrettyPrint /*= false*/) const
|
|
{
|
|
std::stringstream outStr;
|
|
print(outStr, 4, bPrettyPrint);
|
|
std::string retVal = outStr.str();
|
|
|
|
// It seems that the name of the object/array tags along, if the object/array is embedded in another object.
|
|
if ((parent != NULL) && (retVal != "") &&
|
|
(retVal[0] != '{') && (retVal[0] != '['))
|
|
{
|
|
std::string::size_type nOpenIdx = (type == J_OBJECT) ? retVal.find('{') : retVal.find('[');
|
|
if (nOpenIdx > retVal.find(':'))
|
|
retVal.erase(0, retVal.find(':')+1);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool JSONObject::LoadFromFile(const std::string &fileName)
|
|
{
|
|
return load(fileName.c_str());
|
|
}
|
|
|
|
// Save JSON to a file.
|
|
bool JSONObject::SaveToFile(const std::string &fileName, bool bPretty /*= true*/)
|
|
{
|
|
return store(fileName.c_str(), bPretty);
|
|
}
|
|
|
|
/*
|
|
* Create an empty array with the provided key. If an array already exists, it is not touched.
|
|
*/
|
|
void JSONObject::setJSONArray(const char *pKey)
|
|
{
|
|
if (search(pKey) == NULL)
|
|
{
|
|
T_JSON *pObj = new T_JSON(T_JSON::J_ARRAY);
|
|
pObj->setname(pKey);
|
|
add(pObj);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set a JSON array.
|
|
*/
|
|
void JSONObject::setJSONValue(const char *pKey, const JSONArray &value)
|
|
{
|
|
if (search(pKey) != NULL)
|
|
erase(pKey);
|
|
T_JSON *pObj = new T_JSON(static_cast<const T_JSON &>(value));
|
|
pObj->setname(pKey);
|
|
add(pObj);
|
|
}
|
|
/*
|
|
* Set a JSON object.
|
|
*/
|
|
void JSONObject::setJSONValue(const char *pKey, const JSONObject &value)
|
|
{
|
|
if (search(pKey) != NULL)
|
|
erase(pKey);
|
|
T_JSON *pObj = new T_JSON(static_cast<const T_JSON &>(value));
|
|
pObj->setname(pKey);
|
|
add(pObj);
|
|
}
|
|
|
|
/*
|
|
* Get a JSON object from this one.
|
|
*/
|
|
JSONObject& JSONObject::getJSONObject(const char *pKey)
|
|
{
|
|
static JSONObject emptyObj;
|
|
emptyObj.free();
|
|
|
|
T_JSON *pTmpObj;
|
|
if (((pTmpObj = search(pKey)) != NULL) &&
|
|
((pTmpObj->gettype() == T_JSON::J_OBJECT) || (pTmpObj->gettype() == T_JSON::J_ARRAY)))
|
|
return reinterpret_cast<JSONObject &>(*pTmpObj);
|
|
else
|
|
return emptyObj;
|
|
}
|
|
|
|
/*
|
|
* Get a JSON array from this one.
|
|
*/
|
|
JSONArray& JSONObject::getJSONArray(const char *pKey)
|
|
{
|
|
static JSONArray emptyArray;
|
|
emptyArray.free();
|
|
|
|
T_JSON *pTmpObj;
|
|
if (((pTmpObj = search(pKey)) != NULL) && (pTmpObj->gettype() == T_JSON::J_ARRAY))
|
|
return reinterpret_cast<JSONArray &>(*pTmpObj);
|
|
else
|
|
return emptyArray;
|
|
}
|
|
|
|
/*
|
|
* Merge another JSON object with this one. Replace any data in this object with the other, if keys match.
|
|
*/
|
|
void JSONObject::mergeWith(const JSONObject &other)
|
|
{
|
|
for (unsigned int i = 0; i < other.data.size(); ++i)
|
|
{
|
|
T_JSON *pOther = other.data[i];
|
|
if (search(pOther->getname()) != NULL)
|
|
erase(pOther->getname());
|
|
add(new T_JSON(*pOther));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get a string value from the JSON object.
|
|
*/
|
|
std::string JSONObject::getJSONString(const char *pKey, const std::string &altVal /*= ""*/) const
|
|
{
|
|
std::string retVal = altVal;
|
|
const T_JSON *pVal = NULL;
|
|
if (std::string(pKey).find('.') != std::string::npos)
|
|
{
|
|
std::vector<std::string> pathParts;
|
|
SplitString(pKey, '.', pathParts);
|
|
pVal = this;
|
|
for (unsigned int i = 0; (pVal != NULL) && (i < pathParts.size()); ++i)
|
|
{
|
|
T_JSON *pTmpMember = pVal->search(pathParts[i].c_str());
|
|
|
|
if (pTmpMember != NULL)
|
|
pVal = pTmpMember;
|
|
else
|
|
pVal = NULL;
|
|
}
|
|
}
|
|
else
|
|
pVal = search(pKey);
|
|
if (pVal != NULL)
|
|
{
|
|
if (pVal->gettype() == J_NUMBER)
|
|
{
|
|
std::stringstream tmpStr;
|
|
if (pVal->getint() == pVal->getdouble())
|
|
tmpStr << pVal->getint();
|
|
else
|
|
tmpStr << pVal->getdouble();
|
|
retVal = tmpStr.str();
|
|
}
|
|
else
|
|
retVal = pVal->getstring();
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
std::string JSONObject::getJSONStringPath(const char *pKey, const std::string &altVal /*= ""*/) const
|
|
{
|
|
std::string retVal = altVal;
|
|
T_JSON *pVal =
|
|
const_cast<JSONObject *>(this)->findValuePath(const_cast<JSONObject *>(this), pKey, false);
|
|
if (pVal != NULL)
|
|
retVal = pVal->getstring();
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool JSONObject::getJSONBoolPath(const char *pKey, bool bAltVal /*= true*/) const
|
|
{
|
|
bool retVal = bAltVal;
|
|
T_JSON *pVal =
|
|
const_cast<JSONObject *>(this)->findValuePath(const_cast<JSONObject *>(this), pKey, false);
|
|
if (pVal != NULL)
|
|
retVal = pVal->getboolean();
|
|
|
|
return retVal;
|
|
}
|
|
|
|
unsigned int JSONObject::getJSONUIntPath(const char *pKey, unsigned int nAltVal /*= 0*/) const
|
|
{
|
|
unsigned int retVal = nAltVal;
|
|
T_JSON *pVal =
|
|
const_cast<JSONObject *>(this)->findValuePath(const_cast<JSONObject *>(this), pKey, false);
|
|
if (pVal != NULL)
|
|
retVal = pVal->getint();
|
|
|
|
return retVal;
|
|
}
|
|
|
|
unsigned long long JSONObject::getJSONUInt64Path(const char *pKey, unsigned long long nAltVal /*= 0*/) const
|
|
{
|
|
unsigned long long retVal = nAltVal;
|
|
T_JSON *pVal =
|
|
const_cast<JSONObject *>(this)->findValuePath(const_cast<JSONObject *>(this), pKey, false);
|
|
if (pVal != NULL)
|
|
retVal = pVal->getint();
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void JSONObject::setJSONValuePath(const char *pKey, const char *pValue)
|
|
{
|
|
T_JSON *pVal = findValuePath(this, pKey, true);
|
|
if (pVal != NULL)
|
|
pVal->setstring(pValue);
|
|
}
|
|
void JSONObject::setJSONValuePath(const char *pKey, bool bVal)
|
|
{
|
|
T_JSON *pVal = findValuePath(this, pKey, true);
|
|
if (pVal != NULL)
|
|
pVal->setboolean(bVal);
|
|
}
|
|
void JSONObject::setJSONValuePath(const char *pKey, unsigned long long nVal)
|
|
{
|
|
T_JSON *pVal = findValuePath(this, pKey, true);
|
|
if (pVal != NULL)
|
|
pVal->setnumber(static_cast<int64_t>(nVal));
|
|
}
|
|
#endif
|
|
|
|
namespace sequencelogic
|
|
{
|
|
/*std::ostream& operator<<(std::ostream &out, const boost::property_tree::ptree &obj)
|
|
{
|
|
boost::property_tree::json_parser::write_json(out, obj, false);
|
|
return out;
|
|
}*/
|
|
std::ostream& operator<<(std::ostream &out, const JSONObject &obj)
|
|
{
|
|
if (obj.empty())
|
|
out << "{}";
|
|
else
|
|
out << obj.toString();
|
|
return out;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream &out, const JSONArray &obj)
|
|
{
|
|
if (obj.empty())
|
|
out << "[]";
|
|
else
|
|
out << obj.toString();
|
|
return out;
|
|
}
|
|
}
|
|
|
|
#ifdef WIN32
|
|
T_JSON *JSONObject::findValuePath(T_JSON *pStartVal, const char *pPath, bool bCreateIfNecessary)
|
|
{
|
|
T_JSON *pRetVal = NULL;
|
|
std::cmatch matchRes;
|
|
if (std::regex_match(pPath, matchRes, JSON_ARRAY_PAT))
|
|
{
|
|
std::string var;
|
|
int nIdx = 0;
|
|
std::string tail;
|
|
{
|
|
std::cmatch::const_iterator iter = matchRes.cbegin();
|
|
++iter;
|
|
var = *iter;
|
|
++iter;
|
|
|
|
std::stringstream tmpStr(*iter);
|
|
tmpStr >> nIdx;
|
|
++iter;
|
|
tail = *iter;
|
|
}
|
|
|
|
T_JSON *pTmpMember = findValuePath(pStartVal, var.c_str(), bCreateIfNecessary);
|
|
if (bCreateIfNecessary && (pTmpMember == NULL))
|
|
{
|
|
pTmpMember = new T_JSON(var.c_str(), T_JSON::J_ARRAY);
|
|
pStartVal->add(pTmpMember);
|
|
for (int i = 0; i < nIdx+1; ++i)
|
|
pTmpMember->add(new T_JSON());
|
|
}
|
|
else if (bCreateIfNecessary && (nIdx >= pTmpMember->getnumelements()))
|
|
{
|
|
pTmpMember->settype(T_JSON::J_ARRAY);
|
|
for (int i = nIdx; i <= nIdx+1; ++i)
|
|
pTmpMember->add(new T_JSON("", ""));
|
|
}
|
|
else if (pTmpMember == NULL)
|
|
pRetVal = NULL;
|
|
|
|
if ((pTmpMember != NULL) && (nIdx < pTmpMember->getnumelements()))
|
|
{
|
|
pRetVal = pTmpMember->get(nIdx);
|
|
if ((tail != "") && (tail[0] == '.'))
|
|
{
|
|
tail.erase(tail.begin());
|
|
if (bCreateIfNecessary && (pRetVal->gettype() != T_JSON::J_OBJECT))
|
|
pRetVal->settype(T_JSON::J_OBJECT);
|
|
pRetVal = findValuePath(pRetVal, tail.c_str(), bCreateIfNecessary);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> pathParts;
|
|
SplitString(pPath, '.', pathParts);
|
|
pRetVal = pStartVal;
|
|
for (unsigned int i = 0; (pRetVal != NULL) && (i < pathParts.size()); ++i)
|
|
{
|
|
T_JSON *pTmpMember = pRetVal->search(pathParts[i].c_str());
|
|
|
|
if (bCreateIfNecessary && (pTmpMember == NULL))
|
|
pRetVal->add(pTmpMember = new T_JSON(pathParts[i].c_str(), T_JSON::J_OBJECT));
|
|
|
|
if (pTmpMember != NULL)
|
|
pRetVal = pTmpMember;
|
|
else
|
|
pRetVal = NULL;
|
|
}
|
|
}
|
|
return pRetVal;
|
|
}
|
|
#endif
|