From d44af92235db228fb1c138247678a63141c3bafc Mon Sep 17 00:00:00 2001 From: Praveen Babu J D Date: Fri, 30 May 2025 17:02:01 -0700 Subject: [PATCH] + Added Generic Encoder/Decoder and Base64 Encoder/Decoder + Added ability to test for keys before extracting them Change-Id: I83b4a40776c5c32567f7bd48f046a480f28de422 --- pjsonlib/include/pjson.h | 269 +++++--- pjsonlib/src/pjson.cpp | 1352 +++++++++++++++++++++++--------------- 2 files changed, 987 insertions(+), 634 deletions(-) diff --git a/pjsonlib/include/pjson.h b/pjsonlib/include/pjson.h index ae373b4..2681136 100644 --- a/pjsonlib/include/pjson.h +++ b/pjsonlib/include/pjson.h @@ -26,114 +26,167 @@ namespace ByteDance { //==[Interface]============================================================ -class pjson { - public: - enum jsonType : int64_t { - jsonNull, - jsonString, - jsonNumberInt, - jsonNumberFloat, - jsonBoolean, - jsonArray, //[ ] array - jsonMap, // { ... } map + class pjson { + public: + enum jsonType : int64_t { + jsonNull, + jsonString, + jsonNumberInt, + jsonNumberFloat, + jsonBoolean, + jsonArray, //[ ] array + jsonMap, // { ... } map + }; + typedef std::vector PJSONARRAY; + //typedef std::unordered_map PJSONMAP; + typedef std::map PJSONMAP; + + pjson(); // Default Constructor + ~pjson(); // Destructor + pjson(const pjson& aFrom); // Copy Constructor + pjson(pjson&& aFrom); // Move constructor + pjson& operator=(const pjson& aFrom); // Copy assignment + pjson& operator=(pjson&& a); // Move assignment + + static pjson* CreateFromString(const std::string& aStr); + static pjson* CreateFromString(const char* aSrc, size_t a_iSize); + + jsonType getType() const; + std::string toString(bool bPretty = false) const; + void copyFrom(const pjson& aFrom); + + PJSONARRAY* getArray(); + PJSONMAP* getMap(); + + float getFloat(); + int getInt(); + bool getBool(); + std::string getString(); + + // Extracting from a Map + bool hasKey(const std::string& aKey); + bool hasKey(const char* aKey); + + bool getIfExist(const std::string& aKey, float& a_rResult); + bool getIfExist(const std::string& aKey, int& a_rResult); + bool getIfExist(const std::string& aKey, bool& a_rResult); + bool getIfExist(const std::string& aKey, std::string& a_rResult); + bool getIfExist(const std::string& aKey, std::vector& a_rResult); + bool getIfExist(const std::string& aKey, std::vector& a_rResult); + bool getIfExist(const std::string& aKey, std::vector& a_rResult); + bool getIfExist(const std::string& aKey, std::vector& a_rResult); + + bool getIfExist(const char* aKey, float& a_rResult); + bool getIfExist(const char* aKey, int& a_rResult); + bool getIfExist(const char* aKey, bool& a_rResult); + bool getIfExist(const char* aKey, std::string& a_rResult); + bool getIfExist(const char* aKey, std::vector& a_rResult); + bool getIfExist(const char* aKey, std::vector& a_rResult); + bool getIfExist(const char* aKey, std::vector& a_rResult); + bool getIfExist(const char* aKey, std::vector& a_rResult); + + void reset(); + void resetTo(jsonType aeType); + + pjson& at(const std::string& aString); + pjson& at(const char* aSkey); + pjson& at(int index); + + //Assignment overload + pjson& operator[] (const std::string& aString); + pjson& operator[] (const char* aSkey); + pjson& operator[] (int index); + + pjson& operator=(const std::string& aString); + pjson& operator=(const char* aCString); + pjson& operator=(const int aInt); + pjson& operator=(const float aFloat); + pjson& operator=(const bool aBool); + + pjson& operator=(const std::vector& aValueArray); + pjson& operator=(const std::vector& aValueArray); + pjson& operator=(const std::vector& aValueArray); + pjson& operator=(const std::vector& aValueArray); + pjson& operator=(const std::vector& aValueArray); + pjson& operator=(const std::vector& aValueArray); + + pjson& operator+=(const std::string& aValue); + pjson& operator+=(const char* aValue); + pjson& operator+=(const int aValue); + pjson& operator+=(const float aValue); + pjson& operator+=(const bool aValue); + + pjson& operator+=(const std::vector& aValueArray); + pjson& operator+=(const std::vector& aValueArray); + pjson& operator+=(const std::vector& aValueArray); + pjson& operator+=(const std::vector& aValueArray); + pjson& operator+=(const std::vector& aValueArray); + pjson& operator+=(const std::vector& aValueArray); + + bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); + bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); + bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); + bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); + + /* + * Encodes a data buffer as a JSON-safe string by escaping special characters + * @param data Pointer to the data buffer + * @param length Length of the data buffer + * @return JSON-safe string representation + */ + static std::string EncodeForJSON(const char* data, size_t length); + + /* + * Encodes a data buffer as a Base64 string for JSON embedding + * @param data Pointer to the data buffer + * @param length Length of the data buffer + * @return Base64-encoded string + */ + static std::string EncodeBase64ForJSON(const char* data, size_t length); + + /* + * Decodes a JSON-safe string back to its original form + * @param jsonStr The JSON-encoded string + * @return The decoded string + */ + static std::string DecodeFromJSON(const std::string& jsonStr); + + /* + * Decodes a Base64 string back to its original binary data + * @param base64Str The Base64-encoded string + * @return The decoded binary data as a string + */ + static std::string DecodeBase64FromJSON(const std::string& base64Str); + + private: + std::string _toString(int a_iIndent) const; + void _resetIfneeded(jsonType aeType); + static bool _CreateFromString(const char* aSrc, size_t& a_iStart, size_t a_iEnd, pjson*& a_rResult); + + static bool _ScanPastColon(const char* aSrc, size_t& a_iStart,const size_t a_iEnd); + static bool _ExtractString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, std::string& aStrResult); + static bool _ScanString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rStrResult); + static bool _ScanBool(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rBoolResult); + static bool _ScanToNext(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, char& a_rResult); + static bool _ScanNull(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rNUllResult); + static bool _ScanNumber(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rNumResult); + static bool _ScanArray(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult); + static bool _ScanObject(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult); + + private: + + jsonType _eType = jsonType::jsonNull; + union { + void* _pValueRaw = nullptr; + PJSONMAP* _pValueMap; + PJSONARRAY* _pValueArray; + int* _pValueInt; + float* _pValueFloat; + bool* _pValueBool; + std::string* _pValueString; + /* data */ + }; }; - typedef std::vector PJSONARRAY; - //typedef std::unordered_map PJSONMAP; - typedef std::map PJSONMAP; - - pjson(); // Default Constructor - ~pjson(); // Destructor - pjson(const pjson& aFrom); // Copy Constructor - pjson(pjson&& aFrom); // Move constructor - pjson& operator=(const pjson& aFrom); // Copy assignment - pjson& operator=(pjson&& a); // Move assignment - - static pjson* CreateFromString(const std::string& aStr); - static pjson* CreateFromString(const char* aSrc, size_t a_iSize); - - jsonType getType() const; - std::string toString(bool bPretty = false) const; - void copyFrom(const pjson& aFrom); - - PJSONARRAY* getArray(); - PJSONMAP* getMap(); - float getFloat(); - int getInt(); - bool getBool(); - std::string getString(); - - void reset(); - void resetTo(jsonType aeType); - - pjson& at(const std::string& aString); - pjson& at(const char* aSkey); - pjson& at(int index); - - //Assignment overload - pjson& operator[] (const std::string& aString); - pjson& operator[] (const char* aSkey); - pjson& operator[] (int index); - - pjson& operator=(const std::string& aString); - pjson& operator=(const char* aCString); - pjson& operator=(const int aInt); - pjson& operator=(const float aFloat); - pjson& operator=(const bool aBool); - - pjson& operator=(const std::vector& aValueArray); - pjson& operator=(const std::vector& aValueArray); - pjson& operator=(const std::vector& aValueArray); - pjson& operator=(const std::vector& aValueArray); - pjson& operator=(const std::vector& aValueArray); - pjson& operator=(const std::vector& aValueArray); - - pjson& operator+=(const std::string& aValue); - pjson& operator+=(const char* aValue); - pjson& operator+=(const int aValue); - pjson& operator+=(const float aValue); - pjson& operator+=(const bool aValue); - - pjson& operator+=(const std::vector& aValueArray); - pjson& operator+=(const std::vector& aValueArray); - pjson& operator+=(const std::vector& aValueArray); - pjson& operator+=(const std::vector& aValueArray); - pjson& operator+=(const std::vector& aValueArray); - pjson& operator+=(const std::vector& aValueArray); - - bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); - bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); - bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); - bool getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest); - - private: - std::string _toString(int a_iIndent) const; - void _resetIfneeded(jsonType aeType); - static bool _CreateFromString(const char* aSrc, size_t& a_iStart, size_t a_iEnd, pjson*& a_rResult); - - static bool _ScanPastColon(const char* aSrc, size_t& a_iStart,const size_t a_iEnd); - static bool _ExtractString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, std::string& aStrResult); - static bool _ScanString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rStrResult); - static bool _ScanBool(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rBoolResult); - static bool _ScanToNext(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, char& a_rResult); - static bool _ScanNull(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rNUllResult); - static bool _ScanNumber(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rNumResult); - static bool _ScanArray(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult); - static bool _ScanObject(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult); - - private: - - jsonType _eType = jsonType::jsonNull; - union { - void* _pValueRaw = nullptr; - PJSONMAP* _pValueMap; - PJSONARRAY* _pValueArray; - int* _pValueInt; - float* _pValueFloat; - bool* _pValueBool; - std::string* _pValueString; - /* data */ - }; -}; //======================================================================== };// end namespace ByteDance -#endif /* !PRAVEENJSON_H */ \ No newline at end of file +#endif /* !PRAVEENJSON_H */ diff --git a/pjsonlib/src/pjson.cpp b/pjsonlib/src/pjson.cpp index c4a7267..a1cbed4 100644 --- a/pjsonlib/src/pjson.cpp +++ b/pjsonlib/src/pjson.cpp @@ -21,318 +21,318 @@ using namespace ByteDance; //----------------------------------------------------------------- pjson::pjson() -: _eType(jsonType::jsonNull) -, _pValueRaw(nullptr) + : _eType(jsonType::jsonNull) + , _pValueRaw(nullptr) { } //----------------------------------------------------------------- pjson::~pjson() { - reset(); + reset(); } //----------------------------------------------------------------- pjson::pjson(const pjson& aFrom) -: _eType(jsonType::jsonNull) -, _pValueRaw(nullptr) -{ - copyFrom(aFrom); + : _eType(jsonType::jsonNull) + , _pValueRaw(nullptr) +{ + copyFrom(aFrom); } //----------------------------------------------------------------- // Move constructor pjson::pjson(pjson&& aFrom) { - _eType = aFrom._eType; - _pValueRaw = aFrom._pValueRaw; - aFrom._pValueRaw = nullptr; - aFrom._eType = jsonType::jsonNull; + _eType = aFrom._eType; + _pValueRaw = aFrom._pValueRaw; + aFrom._pValueRaw = nullptr; + aFrom._eType = jsonType::jsonNull; } //----------------------------------------------------------------- // Move assignment pjson& pjson::operator=(pjson&& aFrom) { -if (&aFrom == this) -return *this; + if (&aFrom == this) + return *this; - reset(); - _eType = aFrom._eType; - _pValueRaw = aFrom._pValueRaw; + reset(); + _eType = aFrom._eType; + _pValueRaw = aFrom._pValueRaw; - aFrom._eType = jsonType::jsonNull; - aFrom._pValueRaw = nullptr; + aFrom._eType = jsonType::jsonNull; + aFrom._pValueRaw = nullptr; -return *this; + return *this; } //----------------------------------------------------------------- // Copy assignment pjson& pjson::operator=(const pjson& aFrom) { - if (&aFrom == this) - return *this; + if (&aFrom == this) + return *this; - //reset(); // CopyFrom will do a reset anyways - copyFrom(aFrom); - return *this; + //reset(); // CopyFrom will do a reset anyways + copyFrom(aFrom); + return *this; } //----------------------------------------------------------------- -pjson::jsonType pjson::getType() const { - return _eType; +pjson::jsonType pjson::getType() const { + return _eType; }; //----------------------------------------------------------------- pjson::PJSONARRAY* pjson::getArray() { - if(_eType == jsonType::jsonArray) { - return _pValueArray; - } - return nullptr; + if(_eType == jsonType::jsonArray) { + return _pValueArray; + } + return nullptr; } //----------------------------------------------------------------- pjson::PJSONMAP* pjson::getMap() { - if(_eType == jsonType::jsonMap) { - return _pValueMap; - } - return nullptr; + if(_eType == jsonType::jsonMap) { + return _pValueMap; + } + return nullptr; } //----------------------------------------------------------------- float pjson::getFloat() { - if(_eType == jsonType::jsonNumberInt) { - return float(*_pValueInt); - } else if(_eType == jsonType::jsonNumberFloat) { - return *_pValueFloat; - } - return 0.0f; + if(_eType == jsonType::jsonNumberInt) { + return float(*_pValueInt); + } else if(_eType == jsonType::jsonNumberFloat) { + return *_pValueFloat; + } + return 0.0f; } //----------------------------------------------------------------- int pjson::getInt() { - if(_eType == jsonType::jsonNumberInt) { - return *_pValueInt; - } else if(_eType == jsonType::jsonNumberFloat) { - return int(*_pValueFloat); - } - return 0; + if(_eType == jsonType::jsonNumberInt) { + return *_pValueInt; + } else if(_eType == jsonType::jsonNumberFloat) { + return int(*_pValueFloat); + } + return 0; } //----------------------------------------------------------------- bool pjson::getBool() { - switch (_eType) { - case jsonType::jsonNull: { - return false; - } - case jsonType::jsonString: { - return (_pValueString->length() > 0); - } - case jsonType::jsonNumberInt: { - return bool(*_pValueInt); - } - case jsonType::jsonNumberFloat: { - return bool(*_pValueFloat); - } - case jsonType::jsonBoolean: { - return (*_pValueBool); + switch (_eType) { + case jsonType::jsonNull: { + return false; + } + case jsonType::jsonString: { + return (_pValueString->length() > 0); + } + case jsonType::jsonNumberInt: { + return bool(*_pValueInt); + } + case jsonType::jsonNumberFloat: { + return bool(*_pValueFloat); + } + case jsonType::jsonBoolean: { + return (*_pValueBool); + } + break; + case jsonType::jsonArray: + case jsonType::jsonMap: + default: + return false; + break; } - break; - case jsonType::jsonArray: - case jsonType::jsonMap: - default: - return false; - break; - } - return false; + return false; } //----------------------------------------------------------------- std::string pjson::getString() { - return (_eType == jsonType::jsonString)? (*_pValueString): ""; + return (_eType == jsonType::jsonString)? (*_pValueString): ""; } //----------------------------------------------------------------- void pjson::reset() { - resetTo(jsonType::jsonNull); + resetTo(jsonType::jsonNull); } //----------------------------------------------------------------- void pjson::_resetIfneeded(jsonType aeType) { - if(_eType != aeType) { - resetTo(aeType); - } + if(_eType != aeType) { + resetTo(aeType); + } } //----------------------------------------------------------------- void pjson::resetTo(pjson::jsonType aeType) { - switch(_eType) { - case jsonType::jsonNull: { _pValueRaw = nullptr; break; } - case jsonType::jsonString: { delete _pValueString; break; } - case jsonType::jsonNumberInt: { delete _pValueInt; break; } - case jsonType::jsonNumberFloat: { delete _pValueFloat; break; } - case jsonType::jsonBoolean: { delete _pValueBool; break; } - case jsonType::jsonArray: { - for(pjson* pj : *_pValueArray) { - delete pj; - } - delete _pValueArray; - break; - } - case jsonType::jsonMap: { - for (const auto& kv : *_pValueMap) { - delete kv.second; - } - delete _pValueMap; - break; - } - }//end switch - _pValueRaw = nullptr; + switch(_eType) { + case jsonType::jsonNull: { _pValueRaw = nullptr; break; } + case jsonType::jsonString: { delete _pValueString; break; } + case jsonType::jsonNumberInt: { delete _pValueInt; break; } + case jsonType::jsonNumberFloat: { delete _pValueFloat; break; } + case jsonType::jsonBoolean: { delete _pValueBool; break; } + case jsonType::jsonArray: { + for(pjson* pj : *_pValueArray) { + delete pj; + } + delete _pValueArray; + break; + } + case jsonType::jsonMap: { + for (const auto& kv : *_pValueMap) { + delete kv.second; + } + delete _pValueMap; + break; + } + }//end switch + _pValueRaw = nullptr; - switch(aeType) { - case jsonType::jsonNull: { /* _pValueRaw = nullptr; */ break; } - case jsonType::jsonString: { _pValueString = new std::string; break; } - case jsonType::jsonNumberInt: { _pValueInt = new int; break; } - case jsonType::jsonNumberFloat: { _pValueFloat = new float; break; } - case jsonType::jsonBoolean: { _pValueBool = new bool; break; } - case jsonType::jsonArray: { _pValueArray = new PJSONARRAY; break; } - case jsonType::jsonMap: { _pValueMap = new PJSONMAP; break; } - } //end switch - _eType = aeType; + switch(aeType) { + case jsonType::jsonNull: { /* _pValueRaw = nullptr; */ break; } + case jsonType::jsonString: { _pValueString = new std::string; break; } + case jsonType::jsonNumberInt: { _pValueInt = new int; break; } + case jsonType::jsonNumberFloat: { _pValueFloat = new float; break; } + case jsonType::jsonBoolean: { _pValueBool = new bool; break; } + case jsonType::jsonArray: { _pValueArray = new PJSONARRAY; break; } + case jsonType::jsonMap: { _pValueMap = new PJSONMAP; break; } + } //end switch + _eType = aeType; } //----------------------------------------------------------------- void pjson::copyFrom(const pjson& aFrom) { - resetTo(aFrom.getType()); + resetTo(aFrom.getType()); - switch(_eType) { - case jsonType::jsonNull: { /* _pValueRaw = nullptr; */ break; } - case jsonType::jsonString: { *_pValueString = *(aFrom._pValueString); break; } - case jsonType::jsonNumberInt: { *_pValueInt = *(aFrom._pValueInt); break; } - case jsonType::jsonNumberFloat: { *_pValueFloat = *(aFrom._pValueFloat); break; } - case jsonType::jsonBoolean: { *_pValueBool = *(aFrom._pValueBool); break; } - case jsonType::jsonArray: { - for (auto it : *(aFrom._pValueArray)) { - pjson* pObj = new pjson(); - pObj->copyFrom(*it); - _pValueArray->push_back(pObj); - } - break; - } - case jsonType::jsonMap: { - for (auto const& it : *(aFrom._pValueMap)) { - pjson* pObj = new pjson(); - pObj->copyFrom(*(it.second)); - (*_pValueMap)[it.first] = pObj; - } - break; - } - } //end switch + switch(_eType) { + case jsonType::jsonNull: { /* _pValueRaw = nullptr; */ break; } + case jsonType::jsonString: { *_pValueString = *(aFrom._pValueString); break; } + case jsonType::jsonNumberInt: { *_pValueInt = *(aFrom._pValueInt); break; } + case jsonType::jsonNumberFloat: { *_pValueFloat = *(aFrom._pValueFloat); break; } + case jsonType::jsonBoolean: { *_pValueBool = *(aFrom._pValueBool); break; } + case jsonType::jsonArray: { + for (auto it : *(aFrom._pValueArray)) { + pjson* pObj = new pjson(); + pObj->copyFrom(*it); + _pValueArray->push_back(pObj); + } + break; + } + case jsonType::jsonMap: { + for (auto const& it : *(aFrom._pValueMap)) { + pjson* pObj = new pjson(); + pObj->copyFrom(*(it.second)); + (*_pValueMap)[it.first] = pObj; + } + break; + } + } //end switch } //----------------------------------------------------------------- std::string pjson::toString(bool bPretty /*=false*/) const { - int iIndent = bPretty?0:-1; - return _toString(iIndent); + int iIndent = bPretty?0:-1; + return _toString(iIndent); } //----------------------------------------------------------------- std::string pjson::_toString(int a_iIndent) const { - std::string sOut; + std::string sOut; - switch(_eType) { - case jsonType::jsonNull: { sOut += "null"; break; } - case jsonType::jsonString: { sOut += "\"" + (*_pValueString) + "\""; break; } - case jsonType::jsonNumberInt: { sOut += std::to_string(*_pValueInt); break; } - case jsonType::jsonNumberFloat: { sOut += std::to_string(*_pValueFloat); break; } - case jsonType::jsonBoolean: { sOut += (*_pValueBool)?"true":"false"; break; } - case jsonType::jsonArray: { - sOut += "["; - std::string spaces; - if(a_iIndent >=0) { - spaces = std::string(a_iIndent, ' '); - } + switch(_eType) { + case jsonType::jsonNull: { sOut += "null"; break; } + case jsonType::jsonString: { sOut += "\"" + (*_pValueString) + "\""; break; } + case jsonType::jsonNumberInt: { sOut += std::to_string(*_pValueInt); break; } + case jsonType::jsonNumberFloat: { sOut += std::to_string(*_pValueFloat); break; } + case jsonType::jsonBoolean: { sOut += (*_pValueBool)?"true":"false"; break; } + case jsonType::jsonArray: { + sOut += "["; + std::string spaces; + if(a_iIndent >=0) { + spaces = std::string(a_iIndent, ' '); + } - bool bFirstElement = true; - for (auto it = _pValueArray->begin(); it != _pValueArray->end(); it++) { - if(!bFirstElement) { - sOut += ","; - } + bool bFirstElement = true; + for (auto it = _pValueArray->begin(); it != _pValueArray->end(); it++) { + if(!bFirstElement) { + sOut += ","; + } - int iIndent = a_iIndent; - if(a_iIndent >=0) { - sOut += "\n" + spaces; - iIndent += 1; - } + int iIndent = a_iIndent; + if(a_iIndent >=0) { + sOut += "\n" + spaces; + iIndent += 1; + } - sOut += " "; - sOut += (*it)->_toString(iIndent); - sOut += " "; - bFirstElement = false; - } + sOut += " "; + sOut += (*it)->_toString(iIndent); + sOut += " "; + bFirstElement = false; + } - if(bFirstElement) { - sOut += " ]"; // no elements - } else { - if(a_iIndent >=0) { - sOut += "\n" + spaces; - } - sOut += "]"; - } - break; - } - case jsonType::jsonMap: { - sOut += "{"; - std::string spaces; - if(a_iIndent >=0) { - spaces = std::string(a_iIndent, ' '); - } - bool bFirstElement = true; - for (auto it = _pValueMap->begin(); it != _pValueMap->end(); it++) { - if(!bFirstElement) { - sOut += ","; + if(bFirstElement) { + sOut += " ]"; // no elements + } else { + if(a_iIndent >=0) { + sOut += "\n" + spaces; + } + sOut += "]"; + } + break; } + case jsonType::jsonMap: { + sOut += "{"; + std::string spaces; + if(a_iIndent >=0) { + spaces = std::string(a_iIndent, ' '); + } + bool bFirstElement = true; + for (auto it = _pValueMap->begin(); it != _pValueMap->end(); it++) { + if(!bFirstElement) { + sOut += ","; + } - if(a_iIndent >=0) { - sOut += "\n" + spaces; - } - sOut += " \""; - int iLen = it->first.length(); - sOut += it->first; - sOut += "\" : "; + if(a_iIndent >=0) { + sOut += "\n" + spaces; + } + sOut += " \""; + int iLen = it->first.length(); + sOut += it->first; + sOut += "\" : "; - int iIndent = a_iIndent; - if(a_iIndent >=0) { - iIndent += iLen + 6; - } - sOut += it->second->_toString(iIndent); - sOut += " "; - bFirstElement = false; - } // end for + int iIndent = a_iIndent; + if(a_iIndent >=0) { + iIndent += iLen + 6; + } + sOut += it->second->_toString(iIndent); + sOut += " "; + bFirstElement = false; + } // end for - if(bFirstElement) { - sOut += " }"; // no elements - } else { - if(a_iIndent >=0) { - sOut += "\n" + spaces; + if(bFirstElement) { + sOut += " }"; // no elements + } else { + if(a_iIndent >=0) { + sOut += "\n" + spaces; + } + sOut += "}"; + } + break; } - sOut += "}"; - } - break; - } - }//end switch + }//end switch - return sOut; + return sOut; } //----------------------------------------------------------------- pjson& pjson::operator=(const std::string& aString) { - _resetIfneeded(jsonType::jsonString); - *_pValueString = aString; - return *this; + _resetIfneeded(jsonType::jsonString); + *_pValueString = aString; + return *this; } //----------------------------------------------------------------- pjson& pjson::operator=(const char* aCString) { - _resetIfneeded(jsonType::jsonString); - *_pValueString = aCString; - return *this; + _resetIfneeded(jsonType::jsonString); + *_pValueString = aCString; + return *this; } //----------------------------------------------------------------- pjson& pjson::operator=(const int aInt) { - _resetIfneeded(jsonType::jsonNumberInt); - *_pValueInt = aInt; - return *this; + _resetIfneeded(jsonType::jsonNumberInt); + *_pValueInt = aInt; + return *this; } //----------------------------------------------------------------- pjson& pjson::operator=(const float aFloat) { - _resetIfneeded(jsonType::jsonNumberFloat); - *_pValueFloat = aFloat; - return *this; + _resetIfneeded(jsonType::jsonNumberFloat); + *_pValueFloat = aFloat; + return *this; } //----------------------------------------------------------------- pjson& pjson::operator=(const bool aBool) { - _resetIfneeded(jsonType::jsonBoolean); - *_pValueBool = aBool; - return *this; + _resetIfneeded(jsonType::jsonBoolean); + *_pValueBool = aBool; + return *this; } //----------------------------------------------------------------- #define PJSON_VALUE_ARRAY_SET_ITERATOR \ @@ -345,27 +345,27 @@ pjson& pjson::operator=(const bool aBool) { return *this; //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_SET_ITERATOR + PJSON_VALUE_ARRAY_SET_ITERATOR } //----------------------------------------------------------------- #define PJSON_VALUE_ARRAY_APPEND_ITERATOR \ @@ -376,23 +376,23 @@ pjson& pjson::operator=(const std::vector& aValueArray) { return *this; //----------------------------------------------------------------- pjson& pjson::operator+=(const std::string& aValue) { - PJSON_VALUE_ARRAY_APPEND_ITERATOR + PJSON_VALUE_ARRAY_APPEND_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator+=(const char* aValue) { - PJSON_VALUE_ARRAY_APPEND_ITERATOR + PJSON_VALUE_ARRAY_APPEND_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator+=(const int aValue) { - PJSON_VALUE_ARRAY_APPEND_ITERATOR + PJSON_VALUE_ARRAY_APPEND_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator+=(const float aValue) { - PJSON_VALUE_ARRAY_APPEND_ITERATOR + PJSON_VALUE_ARRAY_APPEND_ITERATOR } //----------------------------------------------------------------- pjson& pjson::operator+=(const bool aValue) { - PJSON_VALUE_ARRAY_APPEND_ITERATOR + PJSON_VALUE_ARRAY_APPEND_ITERATOR } //----------------------------------------------------------------- #define PJSON_VALUE_ARRAY_APPEND_ARRAY \ @@ -405,27 +405,27 @@ pjson& pjson::operator+=(const bool aValue) { return *this; //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- pjson& pjson::operator+=(const std::vector& aValueArray) { - PJSON_VALUE_ARRAY_APPEND_ARRAY + PJSON_VALUE_ARRAY_APPEND_ARRAY } //----------------------------------------------------------------- #define PJSON_VALUE_ARRAY_EXTRACT(pjsonfuncname) \ @@ -438,387 +438,687 @@ pjson& pjson::operator+=(const std::vector& aValueArray) { for(size_t i = aFrom; i<=aTo; ++i) { \ aDest.push_back((*_pValueArray)[i]->pjsonfuncname()); \ } \ - return true; + return true; //----------------------------------------------------------------- bool pjson::getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest) { - PJSON_VALUE_ARRAY_EXTRACT(getString) + PJSON_VALUE_ARRAY_EXTRACT(getString) } //----------------------------------------------------------------- bool pjson::getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest) { - PJSON_VALUE_ARRAY_EXTRACT(getInt) + PJSON_VALUE_ARRAY_EXTRACT(getInt) } //----------------------------------------------------------------- bool pjson::getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest){ - PJSON_VALUE_ARRAY_EXTRACT(getFloat) + PJSON_VALUE_ARRAY_EXTRACT(getFloat) } //----------------------------------------------------------------- bool pjson::getArrayValues(size_t aFrom, size_t aTo, std::vector& aDest){ - PJSON_VALUE_ARRAY_EXTRACT(getBool) + PJSON_VALUE_ARRAY_EXTRACT(getBool) } //----------------------------------------------------------------- pjson& pjson::at(const std::string& aString) { - const char* cStr = aString.c_str(); - _resetIfneeded(jsonType::jsonMap); - PJSONMAP::iterator it = _pValueMap->find(cStr); - if(it != _pValueMap->end()) { - return *((*_pValueMap)[cStr]); - } - pjson* pNew = new pjson(); - (*_pValueMap)[cStr] = pNew; - return *pNew; + const char* cStr = aString.c_str(); + _resetIfneeded(jsonType::jsonMap); + PJSONMAP::iterator it = _pValueMap->find(cStr); + if(it != _pValueMap->end()) { + return *((*_pValueMap)[cStr]); + } + pjson* pNew = new pjson(); + (*_pValueMap)[cStr] = pNew; + return *pNew; } //----------------------------------------------------------------- pjson& pjson::at(const char* aSkey) { - _resetIfneeded(jsonType::jsonMap); - PJSONMAP::iterator it = _pValueMap->find(aSkey); - if(it != _pValueMap->end()) { - return *((*_pValueMap)[aSkey]); - } - pjson* pNew = new pjson(); - (*_pValueMap)[aSkey] = pNew; - return *pNew; + _resetIfneeded(jsonType::jsonMap); + PJSONMAP::iterator it = _pValueMap->find(aSkey); + if(it != _pValueMap->end()) { + return *((*_pValueMap)[aSkey]); + } + pjson* pNew = new pjson(); + (*_pValueMap)[aSkey] = pNew; + return *pNew; } //----------------------------------------------------------------- pjson& pjson::at(int index) { - _resetIfneeded(jsonType::jsonArray); - int iSize = static_cast(_pValueArray->size()); - if(index < 0) { - if(iSize > 0) { - index = (iSize - (index % iSize)) % iSize; - } else { - index = 0; + _resetIfneeded(jsonType::jsonArray); + int iSize = static_cast(_pValueArray->size()); + if(index < 0) { + if(iSize > 0) { + index = (iSize - (index % iSize)) % iSize; + } else { + index = 0; + } } - } - if(index >= iSize) { - int iAdd = 1 + index - iSize; - for(int i=iAdd;i--;) { - _pValueArray->push_back(new pjson()); + if(index >= iSize) { + int iAdd = 1 + index - iSize; + for(int i=iAdd;i--;) { + _pValueArray->push_back(new pjson()); + } } - } - return *(*_pValueArray)[static_cast(index)]; + return *(*_pValueArray)[static_cast(index)]; } //----------------------------------------------------------------- pjson& pjson::operator[] (int index) { - return at(index); + return at(index); } //----------------------------------------------------------------- pjson& pjson::operator[] (const std::string& aString) { - return at(aString); + return at(aString); } //----------------------------------------------------------------- pjson& pjson::operator[] (const char* aSkey) { - return at(aSkey); + return at(aSkey); } //----------------------------------------------------------------- /*static*/ pjson* pjson::CreateFromString(const std::string& aStr) { - return CreateFromString(aStr.c_str(), aStr.length()); + return CreateFromString(aStr.c_str(), aStr.length()); } //----------------------------------------------------------------- /*static*/ pjson* pjson::CreateFromString(const char* aSrc, size_t a_iSize) { - size_t iStart =0; - size_t iEnd =a_iSize; - pjson* pResult = nullptr; - /*bool bSuccess = */ - _CreateFromString(aSrc, iStart, iEnd, pResult); - return pResult; + size_t iStart =0; + size_t iEnd =a_iSize; + pjson* pResult = nullptr; + /*bool bSuccess = */ + _CreateFromString(aSrc, iStart, iEnd, pResult); + return pResult; } //----------------------------------------------------------------- /*static*/ bool pjson::_CreateFromString(const char* aSrc, size_t& a_iStart,size_t a_iEnd, pjson*& a_rResult) { - //1. Scan for fundametal type - char aChar; - while (_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { - aChar = tolower(aChar); - if('\"' == aChar) { - return _ScanString(aSrc, a_iStart, a_iEnd, a_rResult); - } - else if('n' == aChar) { - return _ScanNull(aSrc, a_iStart, a_iEnd, a_rResult); - } - else if('t' == aChar || 'f' == aChar) { - return _ScanBool(aSrc, a_iStart, a_iEnd, a_rResult); - } - else if('+' == aChar || '-' == aChar || '.' == aChar || ('0' <= aChar && '9' >= aChar)) { - return _ScanNumber(aSrc, a_iStart, a_iEnd, a_rResult); - } else if('{' == aChar) { - return _ScanObject(aSrc, a_iStart, a_iEnd, a_rResult); - } else if('[' == aChar) { - return _ScanArray(aSrc, a_iStart, a_iEnd, a_rResult); - } else { - //unknown - break; - } - } // end while + //1. Scan for fundametal type + char aChar; + while (_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { + aChar = tolower(aChar); + if('\"' == aChar) { + return _ScanString(aSrc, a_iStart, a_iEnd, a_rResult); + } + else if('n' == aChar) { + return _ScanNull(aSrc, a_iStart, a_iEnd, a_rResult); + } + else if('t' == aChar || 'f' == aChar) { + return _ScanBool(aSrc, a_iStart, a_iEnd, a_rResult); + } + else if('+' == aChar || '-' == aChar || '.' == aChar || ('0' <= aChar && '9' >= aChar)) { + return _ScanNumber(aSrc, a_iStart, a_iEnd, a_rResult); + } else if('{' == aChar) { + return _ScanObject(aSrc, a_iStart, a_iEnd, a_rResult); + } else if('[' == aChar) { + return _ScanArray(aSrc, a_iStart, a_iEnd, a_rResult); + } else { + //unknown + break; + } + } // end while - return false; + return false; } //----------------------------------------------------------------- /*static*/ bool pjson::_ScanBool(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rBoolResult) { - if((a_iEnd - a_iStart) >= 4 - && 't' == tolower(aSrc[a_iStart]) - && 'r' == tolower(aSrc[a_iStart+1]) - && 'u' == tolower(aSrc[a_iStart+2]) - && 'e' == tolower(aSrc[a_iStart+3])) { - a_rBoolResult = new pjson(); - *a_rBoolResult = bool(true); - a_iStart+=4; - return true; - } - if((a_iEnd - a_iStart) >= 5 - && 'f' == tolower(aSrc[a_iStart]) - && 'a' == tolower(aSrc[a_iStart+1]) - && 'l' == tolower(aSrc[a_iStart+2]) - && 's' == tolower(aSrc[a_iStart+3]) - && 'e' == tolower(aSrc[a_iStart+4])) { - a_rBoolResult = new pjson(); - *a_rBoolResult = bool(false); - a_iStart+=5; - return true; - } - return false; + if((a_iEnd - a_iStart) >= 4 + && 't' == tolower(aSrc[a_iStart]) + && 'r' == tolower(aSrc[a_iStart+1]) + && 'u' == tolower(aSrc[a_iStart+2]) + && 'e' == tolower(aSrc[a_iStart+3])) { + a_rBoolResult = new pjson(); + *a_rBoolResult = bool(true); + a_iStart+=4; + return true; + } + if((a_iEnd - a_iStart) >= 5 + && 'f' == tolower(aSrc[a_iStart]) + && 'a' == tolower(aSrc[a_iStart+1]) + && 'l' == tolower(aSrc[a_iStart+2]) + && 's' == tolower(aSrc[a_iStart+3]) + && 'e' == tolower(aSrc[a_iStart+4])) { + a_rBoolResult = new pjson(); + *a_rBoolResult = bool(false); + a_iStart+=5; + return true; + } + return false; } //----------------------------------------------------------------- /*static*/ bool pjson::_ExtractString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, std::string& aStrResult) { - if('\"' != aSrc[a_iStart]){ - return false; - } - ++a_iStart; - int iEnd = a_iStart; - int iStart = a_iStart; - while(a_iStart=0 && iEnd >=0) { + aStrResult = std::string(aSrc+iStart, iEnd-iStart); + return true; } - } - if(iStart=0 && iEnd >=0) { - aStrResult = std::string(aSrc+iStart, iEnd-iStart); - return true; - } - return false; + return false; } //----------------------------------------------------------------- /*static*/ bool pjson::_ScanString(const char* aSrc, size_t& a_iStart,const size_t a_iEnd, pjson*& a_rStrResult) { - std::string str; - if(_ExtractString(aSrc, a_iStart, a_iEnd, str)) { - a_rStrResult = new pjson(); - *a_rStrResult = str; - return true; - } - return false; + std::string str; + if(_ExtractString(aSrc, a_iStart, a_iEnd, str)) { + a_rStrResult = new pjson(); + *a_rStrResult = str; + return true; + } + return false; } //----------------------------------------------------------------- /*static*/ bool pjson::_ScanPastColon(const char* aSrc, size_t& a_iStart,const size_t a_iEnd) { - while(a_iStart= 4 - && 'n' == tolower(aSrc[a_iStart]) - && 'u' == tolower(aSrc[a_iStart+1]) - && 'l' == tolower(aSrc[a_iStart+2]) - && 'l' == tolower(aSrc[a_iStart+3]) - ) { - a_rNUllResult = new pjson(); - a_iStart+=4; - return true; - } - return false; + if((a_iEnd - a_iStart) >= 4 + && 'n' == tolower(aSrc[a_iStart]) + && 'u' == tolower(aSrc[a_iStart+1]) + && 'l' == tolower(aSrc[a_iStart+2]) + && 'l' == tolower(aSrc[a_iStart+3]) + ) { + a_rNUllResult = new pjson(); + a_iStart+=4; + return true; + } + return false; } //----------------------------------------------------------------- /*static*/ bool pjson::_ScanNumber(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rNumResult) { - bool bFloat = false; - int iEnd = a_iStart; - enum NumberSection : int { - NumberSectionSign = 0, - NumberSectionDigit, - NumberSectionDot, - NumberSectionDecimal, - NumberSectionExponential, - NumberSectionExponentialSign, - NumberSectionExponentialDigit, - NumberEnd - }; - int eSec = NumberSectionSign; + bool bFloat = false; + int iEnd = a_iStart; + enum NumberSection : int { + NumberSectionSign = 0, + NumberSectionDigit, + NumberSectionDot, + NumberSectionDecimal, + NumberSectionExponential, + NumberSectionExponentialSign, + NumberSectionExponentialDigit, + NumberEnd + }; + int eSec = NumberSectionSign; - for(int i = a_iStart; i= aSrc[i]) { - iEnd = ++i; + for(int i = a_iStart; i= aSrc[i]) { + iEnd = ++i; + } else { + ++eSec; + } + break; + } + case NumberSectionDot: { + if('.' == aSrc[i]) { + iEnd = ++i; + bFloat = true; + } + ++eSec; + break; + } + case NumberSectionDecimal: { + if('0' <= aSrc[i] && '9' >= aSrc[i]) { + iEnd = ++i; + bFloat = true; + } else { + ++eSec; + } + break; + } + case NumberSectionExponential: { + if('e' == tolower(aSrc[i])) { + iEnd = ++i; + bFloat = true; + } + ++eSec; + break; + } + case NumberSectionExponentialSign: { + if('+' == aSrc[i] || '-' == aSrc[i]) { + iEnd = ++i; + bFloat = true; + } + ++eSec; + break; + } + case NumberSectionExponentialDigit: { + if('0' <= aSrc[i] && '9' >= aSrc[i]) { + iEnd = ++i; + bFloat = true; + } else { + ++eSec; + } + break; + } + case NumberEnd: { + break; + } + } // end switch + } //end for + + if(iEnd > a_iStart) { + std::string sTemp = std::string(aSrc+a_iStart, iEnd-a_iStart); + a_rNumResult = new pjson(); + if(bFloat) { + *a_rNumResult = std::stof(sTemp); } else { - ++eSec; + *a_rNumResult = std::stoi(sTemp); } - break; - } - case NumberSectionDot: { - if('.' == aSrc[i]) { - iEnd = ++i; - bFloat = true; - } - ++eSec; - break; - } - case NumberSectionDecimal: { - if('0' <= aSrc[i] && '9' >= aSrc[i]) { - iEnd = ++i; - bFloat = true; + a_iStart = iEnd; + return true; + } + return false; +} +//----------------------------------------------------------------- +/*static*/ +bool pjson::_ScanArray(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult) { + a_rAResult = new pjson(); + a_rAResult->resetTo(jsonType::jsonArray); + bool bValid = false; + ++a_iStart; // ignore first char "[" + char aChar; + while(_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { + if(']' == aChar) { + ++a_iStart; + bValid = true; + break; + } else if(',' == aChar) { + ++a_iStart; //ignore commas } else { - ++eSec; + pjson* pTemp = nullptr; + if(_CreateFromString(aSrc, a_iStart,a_iEnd, pTemp)) { + a_rAResult->_pValueArray->push_back(pTemp); + } else { + break; + } } - break; - } - case NumberSectionExponential: { - if('e' == tolower(aSrc[i])) { - iEnd = ++i; - bFloat = true; - } - ++eSec; - break; - } - case NumberSectionExponentialSign: { - if('+' == aSrc[i] || '-' == aSrc[i]) { - iEnd = ++i; - bFloat = true; - } - ++eSec; - break; - } - case NumberSectionExponentialDigit: { - if('0' <= aSrc[i] && '9' >= aSrc[i]) { - iEnd = ++i; - bFloat = true; + } + if(!bValid) { + delete a_rAResult; + a_rAResult = nullptr; + } + + return bValid; +} +//----------------------------------------------------------------- +/*static*/ +bool pjson::_ScanObject(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult) { + a_rAResult = new pjson(); + a_rAResult->resetTo(jsonType::jsonMap); + bool bValid = false; + ++a_iStart; // ignore first char "{" + char aChar; + while(_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { + if('}' == aChar) { + ++a_iStart; + bValid = true; + break; + } else if(',' == aChar) { + ++a_iStart; // ignore commas } else { - ++eSec; + pjson* pVal = nullptr; + std::string mkey; + if(_ExtractString(aSrc, a_iStart, a_iEnd, mkey) + && _ScanPastColon(aSrc, a_iStart, a_iEnd) + && _CreateFromString(aSrc, a_iStart, a_iEnd, pVal)) { + //success + (*(a_rAResult->_pValueMap))[mkey.c_str()] = pVal; + } else { + delete a_rAResult; + a_rAResult = nullptr; + bValid = false; + break; + } } - break; - } - case NumberEnd: { - break; - } - } // end switch - } //end for - - if(iEnd > a_iStart) { - std::string sTemp = std::string(aSrc+a_iStart, iEnd-a_iStart); - a_rNumResult = new pjson(); - if(bFloat) { - *a_rNumResult = std::stof(sTemp); - } else { - *a_rNumResult = std::stoi(sTemp); } - a_iStart = iEnd; - return true; - } - return false; + return bValid; +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, float& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, int& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); } //----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, bool& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, std::string& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, std::vector& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, std::vector& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, std::vector& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const std::string& aKey, std::vector& a_rResult) { + return getIfExist(aKey.c_str(), a_rResult); +} +//----------------------------------------------------------------- +#define PJSON_VALUE_EXTRACT_IF_EXISTS(pjsontype,getfunc) \ +if(_eType == jsonType::jsonMap) { \ + auto it = _pValueMap->find(aKey); \ + if (it != _pValueMap->end() && it->second->getType()==jsonType::pjsontype) { \ + a_rResult = it->second->getfunc(); \ + return true; \ + } \ +} \ +return false; \ +// +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, float& a_rResult) { + if(_eType == jsonType::jsonMap) { + auto it = _pValueMap->find(aKey); + if (it != _pValueMap->end()) { + if(it->second->getType()==jsonType::jsonNumberFloat || + it->second->getType()==jsonType::jsonNumberInt) { + a_rResult = it->second->getFloat(); + return true; + } + } + } + return false; +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, int& a_rResult) { + PJSON_VALUE_EXTRACT_IF_EXISTS(jsonNumberInt, getInt) +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, bool& a_rResult) { + PJSON_VALUE_EXTRACT_IF_EXISTS(jsonBoolean, getBool) +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, std::string& a_rResult) { + PJSON_VALUE_EXTRACT_IF_EXISTS(jsonString, getString) +} +//----------------------------------------------------------------- +#define PJSON_ARRAY_VALUE_EXTRACT_IF_EXISTS \ +if (_eType == jsonType::jsonMap) { \ + auto it = _pValueMap->find(aKey); \ + if (it != _pValueMap->end() && it->second->getType()==jsonType::jsonArray) {\ + size_t arraylen = it->second->getArray()->size(); \ + a_rResult.clear(); \ + it->second->getArrayValues(0,arraylen-1,a_rResult); \ + return true; \ + } \ +} \ +return false; \ +// +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, std::vector& a_rResult) { + PJSON_ARRAY_VALUE_EXTRACT_IF_EXISTS +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, std::vector& a_rResult) { + PJSON_ARRAY_VALUE_EXTRACT_IF_EXISTS +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, std::vector& a_rResult) { + PJSON_ARRAY_VALUE_EXTRACT_IF_EXISTS +} +//----------------------------------------------------------------- +bool pjson::getIfExist(const char* aKey, std::vector& a_rResult) { + PJSON_ARRAY_VALUE_EXTRACT_IF_EXISTS +} +//----------------------------------------------------------------- +bool pjson::hasKey(const std::string& aKey) { + return hasKey(aKey.c_str()); +} +//----------------------------------------------------------------- +bool pjson::hasKey(const char* cStr) { + if(_eType == jsonType::jsonMap) { + auto it = _pValueMap->find(cStr); + return (it != _pValueMap->end()); + } + return false; +} +//----------------------------------------------------------------- +// JSON String Encoding Function +// +// I'll create a C++ function that encodes a data buffer into a +// string that can be safely embedded in a JSON file. This function +// will handle escaping special characters and converting binary +// data to a safe representation. +// +// Here's the implementation: +//----------------------------------------------------------------- /*static*/ -bool pjson::_ScanArray(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult) { - a_rAResult = new pjson(); - a_rAResult->resetTo(jsonType::jsonArray); - bool bValid = false; - ++a_iStart; // ignore first char "[" - char aChar; - while(_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { - if(']' == aChar) { - ++a_iStart; - bValid = true; - break; - } else if(',' == aChar) { - ++a_iStart; //ignore commas - } else { - pjson* pTemp = nullptr; - if(_CreateFromString(aSrc, a_iStart,a_iEnd, pTemp)) { - a_rAResult->_pValueArray->push_back(pTemp); - } else { - break; - } +std::string pjson::EncodeForJSON(const char* data, size_t length) { + std::string result; + result.reserve(length * 2); // Reserve space to avoid frequent reallocations + + for (size_t i = 0; i < length; ++i) { + char c = data[i]; + switch (c) { + case '\"': result += "\\\""; break; + case '\\': result += "\\\\"; break; + case '/': result += "\\/"; break; + case '\b': result += "\\b"; break; + case '\f': result += "\\f"; break; + case '\n': result += "\\n"; break; + case '\r': result += "\\r"; break; + case '\t': result += "\\t"; break; + default: + // Handle control characters and non-ASCII characters + if (static_cast(c) < 32 || static_cast(c) >= 128) { + char buf[7]; + snprintf(buf, sizeof(buf), "\\u%04x", static_cast(c)); + result += buf; + } else { + result += c; + } + break; + } } - } - if(!bValid) { - delete a_rAResult; - a_rAResult = nullptr; - } + + return result; +} - return bValid; +//----------------------------------------------------------------- +/*static*/ +std::string pjson::EncodeBase64ForJSON(const char* data, size_t length) { + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string result; + result.reserve((length + 2) / 3 * 4); // Reserve space for base64 output + + size_t i = 0; + while (i + 2 < length) { + // Process 3 bytes at a time + uint32_t triplet = (static_cast(data[i]) << 16) | + (static_cast(data[i+1]) << 8) | + (static_cast(data[i+2])); + + // Convert to 4 characters + result += base64_chars[(triplet >> 18) & 0x3F]; + result += base64_chars[(triplet >> 12) & 0x3F]; + result += base64_chars[(triplet >> 6) & 0x3F]; + result += base64_chars[triplet & 0x3F]; + + i += 3; + } + + // Handle remaining bytes + if (i + 1 == length) { + // 1 byte remaining + uint32_t pair = static_cast(data[i]) << 8; + result += base64_chars[(pair >> 10) & 0x3F]; + result += base64_chars[(pair >> 4) & 0x3F]; + result += '='; // Padding + result += '='; // Padding + } else if (i + 2 == length) { + // 2 bytes remaining + uint32_t triplet = (static_cast(data[i]) << 16) | + (static_cast(data[i+1]) << 8); + result += base64_chars[(triplet >> 18) & 0x3F]; + result += base64_chars[(triplet >> 12) & 0x3F]; + result += base64_chars[(triplet >> 6) & 0x3F]; + result += '='; // Padding + } + + return result; } //----------------------------------------------------------------- /*static*/ -bool pjson::_ScanObject(const char* aSrc, size_t& a_iStart, const size_t a_iEnd, pjson*& a_rAResult) { - a_rAResult = new pjson(); - a_rAResult->resetTo(jsonType::jsonMap); - bool bValid = false; - ++a_iStart; // ignore first char "{" - char aChar; - while(_ScanToNext(aSrc, a_iStart, a_iEnd, aChar)) { - if('}' == aChar) { - ++a_iStart; - bValid = true; - break; - } else if(',' == aChar) { - ++a_iStart; // ignore commas - } else { - pjson* pVal = nullptr; - std::string mkey; - if(_ExtractString(aSrc, a_iStart, a_iEnd, mkey) - && _ScanPastColon(aSrc, a_iStart, a_iEnd) - && _CreateFromString(aSrc, a_iStart, a_iEnd, pVal)) { - //success - (*(a_rAResult->_pValueMap))[mkey.c_str()] = pVal; - } else { - delete a_rAResult; - a_rAResult = nullptr; - bValid = false; - break; - } +std::string pjson::DecodeFromJSON(const std::string& jsonStr) { + std::string result; + result.reserve(jsonStr.length()); // Reserve space to avoid frequent reallocations + + for (size_t i = 0; i < jsonStr.length(); ++i) { + if (jsonStr[i] == '\\' && i + 1 < jsonStr.length()) { + char c = jsonStr[++i]; + switch (c) { + case '\"': result += '\"'; break; + case '\\': result += '\\'; break; + case '/': result += '/'; break; + case 'b': result += '\b'; break; + case 'f': result += '\f'; break; + case 'n': result += '\n'; break; + case 'r': result += '\r'; break; + case 't': result += '\t'; break; + case 'u': // Handle Unicode escape sequence + if (i + 4 < jsonStr.length()) { + // Parse the 4 hex digits + std::string hexStr = jsonStr.substr(i + 1, 4); + try { + int hexValue = std::stoi(hexStr, nullptr, 16); + // For simplicity, we're only handling single-byte characters + result += static_cast(hexValue); + } catch (...) { + // If parsing fails, just add the original sequence + result += "\\u" + hexStr; + } + i += 4; + } + break; + default: + // Unknown escape sequence, just add the character + result += c; + break; + } + } else { + result += jsonStr[i]; + } } - } - return bValid; + + return result; } + //----------------------------------------------------------------- +/*static*/ +std::string pjson::DecodeBase64FromJSON(const std::string& base64Str) { + static const unsigned char base64_index[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + std::string result; + result.reserve(base64Str.length() * 3 / 4); // Reserve space for decoded output + + size_t i = 0; + while (i < base64Str.length()) { + // Skip non-base64 characters + if (base64Str[i] == '=' || base64_index[static_cast(base64Str[i])] == 0) { + i++; + continue; + } + + // Ensure we have enough characters for a complete group + if (i + 1 >= base64Str.length()) break; + + // Decode a group of 4 characters into 3 bytes + unsigned char a = base64_index[static_cast(base64Str[i])]; + unsigned char b = base64_index[static_cast(base64Str[i+1])]; + + result += static_cast((a << 2) | (b >> 4)); + + if (i + 2 < base64Str.length() && base64Str[i+2] != '=') { + unsigned char c = base64_index[static_cast(base64Str[i+2])]; + result += static_cast(((b & 0x0F) << 4) | (c >> 2)); + + if (i + 3 < base64Str.length() && base64Str[i+3] != '=') { + unsigned char d = base64_index[static_cast(base64Str[i+3])]; + result += static_cast(((c & 0x03) << 6) | d); + } + } + + i += 4; + } + + return result; +} +//----------------------------------------------------------------- \ No newline at end of file