Last active
October 10, 2016 22:39
-
-
Save thennequin/499e8eedd6feb0c9c85fbcba44c15fae to your computer and use it in GitHub Desktop.
JsonStthm: Easy to use Json parser/writer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "JsonStthm.h" | |
namespace JsonStthm | |
{ | |
JsonValue::JsonMember::JsonMember(const ImwChar* pName, JsonValue* pValue) | |
{ | |
m_pName = NULL; | |
SetName(pName); | |
m_pValue = pValue; | |
} | |
JsonValue::JsonMember::JsonMember(const JsonMember& oSource) | |
{ | |
m_pName = NULL; | |
SetName(oSource.m_pName); | |
m_pValue = new JsonValue(*oSource.m_pValue); | |
} | |
JsonValue::JsonMember::~JsonMember() | |
{ | |
ImwSafeFree(m_pName); | |
delete m_pValue; | |
} | |
void JsonValue::JsonMember::SetName(const ImwChar* pName) | |
{ | |
ImwSafeFree(m_pName); | |
if (pName != NULL) | |
{ | |
int iSize = (strlen(pName) + 1) * sizeof(ImwChar); | |
m_pName = (ImwChar*)ImwMalloc(iSize); | |
memcpy(m_pName, pName, iSize); | |
} | |
} | |
JsonValue JsonValue::INVALID = JsonValue::CreateConst(); | |
JsonValue::JsonValue() | |
{ | |
m_bConst = false; | |
m_eType = E_TYPE_INVALID; | |
m_pName = NULL; | |
m_pNext = NULL; | |
} | |
JsonValue::JsonValue(const JsonValue& oSource) : JsonValue() | |
{ | |
m_bConst = oSource.m_bConst; | |
*this = oSource; | |
} | |
JsonValue::JsonValue(bool bValue) : JsonValue() | |
{ | |
*this = bValue; | |
} | |
JsonValue::JsonValue(const ImwString& sValue) : JsonValue() | |
{ | |
*this = sValue; | |
} | |
JsonValue::JsonValue(const ImwChar* pValue) : JsonValue() | |
{ | |
*this = pValue; | |
} | |
JsonValue::JsonValue(long iValue) : JsonValue() | |
{ | |
*this = iValue; | |
} | |
JsonValue::JsonValue(double fValue) : JsonValue() | |
{ | |
*this = fValue; | |
} | |
JsonValue::~JsonValue() | |
{ | |
Reset(); | |
} | |
JsonValue JsonValue::CreateConst() | |
{ | |
JsonValue oValue; | |
oValue.m_bConst = true; | |
return oValue; | |
} | |
void JsonValue::InitType(EType eType) | |
{ | |
if (m_eType != eType) | |
{ | |
Reset(); | |
m_eType = eType; | |
switch (m_eType) | |
{ | |
case E_TYPE_OBJECT: | |
case E_TYPE_ARRAY: | |
m_pChild = NULL; | |
m_pChildLast = NULL; | |
break; | |
case E_TYPE_STRING: | |
m_pString = NULL; | |
break; | |
} | |
} | |
} | |
void JsonValue::Reset() | |
{ | |
if (m_eType != E_TYPE_INVALID) | |
{ | |
switch (m_eType) | |
{ | |
case E_TYPE_OBJECT: | |
case E_TYPE_ARRAY: | |
{ | |
JsonValue* pChild = m_pChild; | |
while (pChild != NULL) | |
{ | |
JsonValue* pTemp = pChild->m_pNext; | |
delete pChild; | |
pChild = pTemp; | |
} | |
m_pChild = NULL; | |
m_pChildLast = NULL; | |
} | |
break; | |
case E_TYPE_STRING: | |
ImwSafeFree(m_pString); | |
break; | |
} | |
m_eType = E_TYPE_INVALID; | |
} | |
} | |
void JsonValue::SetString(const ImwChar* pString) | |
{ | |
ImwSafeFree(m_pString); | |
if (NULL != pString) | |
{ | |
size_t iLen = sizeof(ImwChar) * (1 + strlen(pString)); | |
m_pString = (ImwChar*)ImwMalloc(iLen); | |
memcpy(m_pString, pString, iLen); | |
} | |
} | |
void JsonValue::Write(ImwString& sOutJson, int iIndent, bool bCompact) | |
{ | |
if (m_eType == E_TYPE_OBJECT) | |
{ | |
ImwString sIndent(iIndent, '\t'); | |
ImwString sIndent2(iIndent + 1, '\t'); | |
sOutJson += "{"; | |
//JsonMembers& oMembers = *m_pObject; | |
JsonValue* pChild = m_pChild; | |
bool bFirst = true; | |
//for (JsonMembers::iterator it = oMembers.begin(), itEnd = oMembers.end(); it != itEnd; ++it) | |
while (pChild != NULL) | |
{ | |
if (!bFirst) | |
{ | |
sOutJson += ","; | |
} | |
else | |
{ | |
bFirst = false; | |
} | |
if (!bCompact) | |
{ | |
sOutJson += "\n"; | |
sOutJson += sIndent2; | |
} | |
sOutJson += "\""; | |
WriteStringEscaped(sOutJson, pChild->m_pName); | |
sOutJson += "\": "; | |
pChild->Write(sOutJson, iIndent + 1, bCompact); | |
pChild = pChild->m_pNext; | |
} | |
if (!bCompact) | |
{ | |
sOutJson += "\n"; | |
sOutJson += sIndent; | |
} | |
sOutJson += "}"; | |
} | |
else if (m_eType == E_TYPE_ARRAY) | |
{ | |
ImwString sIndent(iIndent, '\t'); | |
ImwString sIndent2(iIndent + 1, '\t'); | |
sOutJson += "["; | |
//JsonArray& oArray = *m_pArray; | |
JsonValue* pChild = m_pChild; | |
bool bFirst = true; | |
//for (JsonArray::iterator it = oArray.begin(), itEnd = oArray.end(); it != itEnd; ++it) | |
while (pChild != NULL) | |
{ | |
if (!bFirst) | |
{ | |
sOutJson += ","; | |
} | |
else | |
{ | |
bFirst = false; | |
} | |
if (!bCompact) | |
{ | |
sOutJson += "\n"; | |
sOutJson += sIndent2; | |
} | |
pChild->Write(sOutJson, iIndent + 1, bCompact); | |
pChild = pChild->m_pNext; | |
} | |
if (!bCompact) | |
{ | |
sOutJson += "\n"; | |
sOutJson += sIndent; | |
} | |
sOutJson += "]"; | |
} | |
else if (m_eType == E_TYPE_STRING) | |
{ | |
sOutJson += "\""; | |
WriteStringEscaped(sOutJson, m_pString); | |
sOutJson += "\""; | |
} | |
else if (m_eType == E_TYPE_BOOLEAN) | |
{ | |
if (m_bBoolean) | |
{ | |
sOutJson += "true"; | |
} | |
else | |
{ | |
sOutJson += "false"; | |
} | |
} | |
else if (m_eType == E_TYPE_INTEGER) | |
{ | |
ImwChar sBuffer[256]; | |
sprintf_s(sBuffer, 256, "%d", m_iInteger); | |
sOutJson += sBuffer; | |
} | |
else if (m_eType == E_TYPE_FLOAT) | |
{ | |
ImwChar sBuffer[256]; | |
sprintf_s(sBuffer, 256, "%.17Lg", m_fFloat); | |
sOutJson += sBuffer; | |
} | |
else | |
{ | |
sOutJson += "null"; | |
} | |
} | |
void JsonValue::WriteStringEscaped(ImwString& sOutJson, const ImwString& sInput) | |
{ | |
const ImwChar* pString = sInput.c_str(); | |
while (*pString != '\0') | |
{ | |
ImwChar cChar = *pString; | |
if (cChar == '\n') | |
sOutJson += "\\n"; | |
else if (cChar == '\r') | |
sOutJson += "\\r"; | |
else if (cChar == '\t') | |
sOutJson += "\\t"; | |
else if (cChar == '\b') | |
sOutJson += "\\b"; | |
else if (cChar == '\f') | |
sOutJson += "\\f"; | |
else if (cChar == '"') | |
sOutJson += "\\\""; | |
else if (cChar == '\\') | |
sOutJson += "\\\\"; | |
else if ((uint8_t)cChar < 0x80) | |
sOutJson += cChar; | |
else | |
{ | |
sOutJson += "\\u"; | |
unsigned int iChar = (unsigned char)cChar; | |
if ((iChar & 0xF0) == 0xF0) // 4 bytes | |
{ | |
iChar = ((((uint8_t)*(pString)) & 0x07) << 18) + ((((uint8_t)*(pString + 1)) & 0x3F) << 12) + ((((uint8_t)*(pString + 2)) & 0x3F) << 6) + ((((uint8_t)*(pString + 3)) & 0x3F)); | |
pString += 3; | |
} | |
else if ((iChar & 0xF0) == 0xE0) // 3 bytes | |
{ | |
iChar = ((((uint8_t)*(pString)) & 0x0F) << 12) + ((((uint8_t)*(pString + 1)) & 0x3F) << 6) + ((((uint8_t)*(pString + 2)) & 0x3F)); | |
pString += 2; | |
} | |
else if ((iChar & 0xF0) == 0xC0) // 2 byte | |
{ | |
iChar = ((((uint8_t)*(pString)) & 0x1F) << 6) + ((((uint8_t)*(pString + 1)) & 0x3F)); | |
pString += 1; | |
} | |
ImwChar sHexa[5]; | |
const char* const pHexa = "0123456789ABCDEF"; | |
sHexa[0] = pHexa[(iChar >> 12) & 0x0f]; | |
sHexa[1] = pHexa[(iChar >> 8) & 0x0f]; | |
sHexa[2] = pHexa[(iChar >> 4) & 0x0f]; | |
sHexa[3] = pHexa[(iChar) & 0x0f]; | |
sHexa[4] = '\0'; | |
sOutJson += sHexa; | |
} | |
++pString; | |
} | |
} | |
void JsonValue::WriteString(ImwString& sOutJson, bool bCompact) | |
{ | |
Write(sOutJson, 0, bCompact); | |
} | |
bool JsonValue::WriteFile(const ImwChar* pFilename, bool bCompact) | |
{ | |
FILE* pFile = fopen(pFilename, "w"); | |
if (NULL != pFile) | |
{ | |
ImwString sJson; | |
WriteString(sJson); | |
bool bRet = fwrite(sJson.c_str(), sizeof(ImwChar), sJson.length(), pFile) == (sizeof(ImwChar) * sJson.length()); | |
fclose(pFile); | |
return bRet; | |
} | |
return false; | |
} | |
size_t JsonValue::GetMemberCount() const | |
{ | |
/*if (m_eType == E_TYPE_OBJECT) | |
{ | |
JsonMembers& oMembers = *m_pObject; | |
return oMembers.size(); | |
} | |
else if (m_eType == E_TYPE_ARRAY) | |
{ | |
JsonArray& oArray = *m_pArray; | |
return oArray.size(); | |
}*/ | |
int iCount = 0; | |
if (m_eType == E_TYPE_OBJECT || m_eType == E_TYPE_ARRAY) | |
{ | |
JsonValue* pChild = m_pChild; | |
while (pChild != NULL) | |
{ | |
++iCount; | |
pChild = pChild->m_pNext; | |
} | |
} | |
return iCount; | |
} | |
const JsonValue& JsonValue::operator[](const ImwChar* pName) const | |
{ | |
if (m_eType == E_TYPE_OBJECT) | |
{ | |
JsonValue* pChild = m_pChild; | |
while (pChild != NULL) | |
{ | |
if (strcmp(pChild->m_pName, pName) == 0) | |
return *pChild; | |
if (pChild->m_pNext == NULL) | |
break; | |
pChild = pChild->m_pNext; | |
} | |
} | |
return JsonValue::INVALID; | |
} | |
JsonValue& JsonValue::operator[](const ImwChar* pName) | |
{ | |
if (m_eType == E_TYPE_INVALID) | |
InitType(E_TYPE_OBJECT); | |
if (m_eType == E_TYPE_OBJECT) | |
{ | |
JsonValue* pChild = m_pChild; | |
while (pChild != NULL) | |
{ | |
if (strcmp(pChild->m_pName, pName) == 0) | |
return *pChild; | |
if (pChild->m_pNext == NULL) | |
break; | |
pChild = pChild->m_pNext; | |
} | |
if (!m_bConst) | |
{ | |
JsonValue* pNewMember = new JsonValue(); | |
pNewMember->m_pName = strdup(pName); | |
if (NULL != m_pChildLast) | |
m_pChildLast->m_pNext = pNewMember; | |
else | |
m_pChild = pNewMember; | |
m_pChildLast = pNewMember; | |
return *pNewMember; | |
} | |
} | |
return JsonValue::INVALID; | |
} | |
const JsonValue& JsonValue::operator [](int iIndex) const | |
{ | |
if (m_eType == E_TYPE_OBJECT || m_eType == E_TYPE_ARRAY) | |
{ | |
JsonValue* pChild = m_pChild; | |
int iCurrent = 0; | |
while (pChild != NULL) | |
{ | |
if (iCurrent++ == iIndex) | |
return *pChild; | |
pChild = pChild->m_pNext; | |
} | |
} | |
return JsonValue::INVALID; | |
} | |
JsonValue& JsonValue::operator[](int iIndex) | |
{ | |
if (m_eType == E_TYPE_INVALID) | |
InitType(E_TYPE_ARRAY); | |
if (m_eType == E_TYPE_OBJECT || m_eType == E_TYPE_ARRAY) | |
{ | |
JsonValue* pChild = m_pChild; | |
int iCurrent = 0; | |
while (pChild != NULL) | |
{ | |
if (iCurrent++ == iIndex) | |
return *pChild; | |
if (pChild->m_pNext == NULL) | |
break; | |
pChild = pChild->m_pNext; | |
} | |
if (m_eType == E_TYPE_ARRAY) | |
{ | |
do | |
{ | |
JsonValue* pNewChild = new JsonValue(); | |
if (NULL != m_pChildLast) | |
m_pChildLast->m_pNext = pNewChild; | |
else | |
m_pChild = pNewChild; | |
m_pChildLast = pNewChild; | |
} | |
while (iCurrent++ != iIndex); | |
return *m_pChildLast; | |
} | |
} | |
return JsonValue::INVALID; | |
} | |
JsonValue& JsonValue::operator =(const JsonValue& oValue) | |
{ | |
if (oValue.m_pName != NULL) | |
{ | |
m_pName = strdup(oValue.m_pName); | |
} | |
if (oValue.m_eType == E_TYPE_OBJECT || oValue.m_eType == E_TYPE_ARRAY) | |
{ | |
InitType(oValue.m_eType); | |
JsonValue* pSourceChild = oValue.m_pChild;; | |
JsonValue* pChild = NULL; | |
while (pSourceChild != NULL) | |
{ | |
JsonValue* pNewChild = new JsonValue(*pSourceChild); | |
if (NULL != m_pChildLast) | |
m_pChildLast->m_pNext = pNewChild; | |
else | |
m_pChild = pNewChild; | |
m_pChildLast = pNewChild; | |
pSourceChild = pSourceChild->m_pNext; | |
} | |
} | |
else if (oValue.m_eType == E_TYPE_BOOLEAN) | |
{ | |
*this = (bool)oValue; | |
} | |
else if (oValue.m_eType == E_TYPE_STRING) | |
{ | |
*this = (ImwString)oValue; | |
} | |
else if (oValue.m_eType == E_TYPE_INTEGER) | |
{ | |
*this = (long)oValue; | |
} | |
else if (oValue.m_eType == E_TYPE_FLOAT) | |
{ | |
*this = (double)oValue; | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator =(const ImwString& sValue) | |
{ | |
if (!m_bConst) | |
{ | |
InitType(E_TYPE_STRING); | |
SetString(sValue.c_str()); | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator =(const ImwChar* pValue) | |
{ | |
if (!m_bConst) | |
{ | |
if (NULL != pValue) | |
{ | |
InitType(E_TYPE_STRING); | |
SetString(pValue); | |
} | |
else | |
{ | |
InitType(E_TYPE_INVALID); | |
} | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator =(bool bValue) | |
{ | |
if (!m_bConst) | |
{ | |
InitType(E_TYPE_BOOLEAN); | |
m_bBoolean = bValue; | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator =(long iValue) | |
{ | |
if (!m_bConst) | |
{ | |
InitType(E_TYPE_INTEGER); | |
m_iInteger = iValue; | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator =(double fValue) | |
{ | |
if (!m_bConst) | |
{ | |
InitType(E_TYPE_FLOAT); | |
m_fFloat = fValue; | |
} | |
return *this; | |
} | |
JsonValue& JsonValue::operator +=(const JsonValue& oValue) | |
{ | |
if (m_eType == E_TYPE_ARRAY) | |
{ | |
JsonValue* pNewValue = new JsonValue(oValue); | |
if (NULL != m_pChildLast) | |
m_pChildLast->m_pNext = pNewValue; | |
else | |
m_pChild = pNewValue; | |
m_pChildLast = pNewValue; | |
} | |
else if (m_eType == E_TYPE_STRING) | |
{ | |
if (oValue.IsString()) | |
{ | |
ImwString sValue = m_pString; | |
sValue += (ImwString)oValue; | |
SetString(sValue.c_str()); | |
} | |
} | |
return *this; | |
} | |
JsonValue::operator const char*() const | |
{ | |
if (m_eType == E_TYPE_STRING) | |
return m_pString; | |
return NULL; | |
} | |
JsonValue::operator bool() const | |
{ | |
if (m_eType == E_TYPE_BOOLEAN) | |
return m_bBoolean; | |
return false; | |
} | |
JsonValue::operator long() const | |
{ | |
if (m_eType == E_TYPE_INTEGER) | |
return m_iInteger; | |
return 0; | |
} | |
JsonValue::operator double() const | |
{ | |
if (m_eType == E_TYPE_FLOAT) | |
return m_fFloat; | |
return 0.0; | |
} | |
//Reading | |
bool JsonValue::IsSpace(ImwChar cChar) { | |
return cChar == ' ' || (cChar >= '\t' && cChar <= '\r'); | |
} | |
bool JsonValue::IsDigit(ImwChar cChar) | |
{ | |
return (cChar >= '0' && cChar <= '9'); | |
} | |
bool JsonValue::IsXDigit(ImwChar cChar) | |
{ | |
return (cChar >= '0' && cChar <= '9') || ((cChar & ~' ') >= 'A' && (cChar & ~' ') <= 'F') || ((cChar & ~' ') >= 'a' && (cChar & ~' ') <= 'f'); | |
} | |
int JsonValue::CharToInt(ImwChar cChar) | |
{ | |
if (cChar <= '9') | |
return cChar - '0'; | |
else | |
return (cChar & ~' ') - 'A' + 10; | |
} | |
void JsonValue::SkipSpaces(const ImwChar*& pString) | |
{ | |
while (IsSpace(*pString)) ++pString; | |
} | |
bool JsonValue::ReadSpecialChar(const ImwChar*& pString, CharBuffer& oTempBuffer) | |
{ | |
if (*pString == 'n') oTempBuffer += '\n'; | |
else if (*pString == 'r') oTempBuffer += '\r'; | |
else if (*pString == 't') oTempBuffer += '\t'; | |
else if (*pString == 'b') oTempBuffer += '\b'; | |
else if (*pString == 'f') oTempBuffer += '\f'; | |
else if (*pString == '"') oTempBuffer += '"'; | |
else if (*pString == '\\') oTempBuffer += '\\'; | |
else if (*pString == 'u') | |
{ | |
int iChar = 0; | |
for (int i = 0; i < 4; ++i) | |
{ | |
if (IsXDigit(*++pString)) | |
iChar = iChar * 16 + CharToInt((unsigned char)*pString); | |
else | |
return false; | |
} | |
if (iChar < 0x0080) | |
{ | |
oTempBuffer += iChar; | |
} | |
else if (iChar >= 0x80 && iChar < 0x800) | |
{ | |
oTempBuffer += 0xC0 | (iChar >> 6); | |
oTempBuffer += 0x80 | (iChar & 0x3F); | |
} | |
else if (iChar >= 0x800 && iChar < 0x7FFF) | |
{ | |
oTempBuffer += 0xE0 | (iChar >> 12); | |
oTempBuffer += 0x80 | ((iChar >> 6) & 0x3F); | |
oTempBuffer += 0x80 | (iChar & 0x3F); | |
} | |
else if (iChar >= 0x8000 && iChar < 0x7FFFF) | |
{ | |
oTempBuffer += 0xF0 | (iChar >> 18); | |
oTempBuffer += 0xE0 | ((iChar >> 12) & 0x3F); | |
oTempBuffer += 0x80 | ((iChar >> 6) & 0x3F); | |
oTempBuffer += 0x80 | (iChar & 0x3F); | |
} | |
else | |
{ | |
return false; | |
} | |
return true; | |
} | |
else | |
return false; | |
return true; | |
} | |
bool JsonValue::ReadStringValue(const ImwChar*& pString, CharBuffer& oTempBuffer) | |
{ | |
oTempBuffer.Clear(); | |
while (*pString != 0) | |
{ | |
if (*pString == '\\') | |
{ | |
++pString; | |
if (!ReadSpecialChar(pString, oTempBuffer)) | |
return false; | |
++pString; | |
} | |
else if (*pString == '"') | |
{ | |
oTempBuffer += '\0'; | |
++pString; | |
return true; | |
} | |
else if ((unsigned int)*pString < ' ' || *pString == '\x7F') | |
{ | |
return false; | |
} | |
else | |
{ | |
oTempBuffer += *pString; | |
++pString; | |
} | |
} | |
return false; | |
} | |
bool JsonValue::ReadStringValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer) | |
{ | |
if (ReadStringValue(pString, oTempBuffer)) | |
{ | |
oValue.InitType(E_TYPE_STRING); | |
oValue.m_pString = oTempBuffer.Take(); | |
//oValue = oTempBuffer.Data();//Use Take(); | |
return true; | |
} | |
return false; | |
} | |
bool JsonValue::ReadNumericValue(const ImwChar*& pString, JsonValue& oValue) | |
{ | |
bool bNeg = false; | |
bool bHasSeparator = false; | |
long lValue = 0; | |
if (*pString == '-') | |
{ | |
++pString; | |
bNeg = true; | |
} | |
while (IsDigit(*pString)) | |
lValue = lValue * 10 + (*pString++ - '0'); | |
if (*pString == '.') | |
{ | |
++pString; | |
double fValue = (double)lValue; | |
double fFraction = 1; | |
while (IsDigit(*pString)) | |
{ | |
fFraction *= 0.1; | |
fValue += (*pString++ - '0') * fFraction; | |
} | |
if (*pString == 'e' || *pString == 'E') | |
{ | |
++pString; | |
double fBase = 10; | |
if (*pString == '+') | |
{ | |
++pString; | |
} | |
else if (*pString == '-') | |
{ | |
++pString; | |
fBase = 0.1; | |
} | |
unsigned int iExponent = 0; | |
while (*pString != 0 && IsDigit(*pString)) | |
iExponent = (iExponent * 10) + (*pString++ - '0'); | |
double fPow = 1; | |
for (; iExponent; iExponent >>= 1, fBase *= fBase) | |
if (iExponent & 1) | |
fPow *= fBase; | |
fValue *= fPow; | |
} | |
oValue = bNeg ? -fValue : fValue; | |
} | |
else | |
{ | |
//TODO manage E/e for long? | |
oValue = bNeg ? -lValue : lValue; | |
} | |
return true; | |
} | |
bool JsonValue::ReadObjectValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer) | |
{ | |
oValue.InitType(JsonValue::E_TYPE_OBJECT); | |
while (*pString != 0) | |
{ | |
SkipSpaces(pString); | |
// Read member name | |
if (*pString != '"' || !ReadStringValue(++pString, oTempBuffer)) | |
return false; | |
JsonValue* pNewMember = new JsonValue(); | |
pNewMember->m_pName = oTempBuffer.Take(); | |
SkipSpaces(pString); | |
if (*pString != ':') | |
return false; | |
++pString; | |
SkipSpaces(pString); | |
if (!pNewMember->Parse(pString, oTempBuffer)) | |
{ | |
delete pNewMember; | |
return false; | |
} | |
if (oValue.m_pChild == NULL) | |
{ | |
oValue.m_pChild = pNewMember; | |
} | |
else | |
{ | |
oValue.m_pChildLast->m_pNext = pNewMember; | |
} | |
oValue.m_pChildLast = pNewMember; | |
SkipSpaces(pString); | |
if (*pString == '}') | |
{ | |
++pString; | |
return true; | |
} | |
else if (*pString != ',') | |
{ | |
return false; | |
} | |
++pString; | |
} | |
return false; | |
} | |
bool JsonValue::ReadArrayValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer) | |
{ | |
oValue.InitType(JsonValue::E_TYPE_ARRAY); | |
while (*pString != 0) | |
{ | |
SkipSpaces(pString); | |
JsonValue* pNewValue = new JsonValue(); | |
if (!pNewValue->Parse(pString, oTempBuffer)) | |
{ | |
delete pNewValue; | |
return false; | |
} | |
if (oValue.m_pChild == NULL) | |
{ | |
oValue.m_pChild = pNewValue; | |
} | |
else | |
{ | |
oValue.m_pChildLast->m_pNext = pNewValue; | |
} | |
oValue.m_pChildLast = pNewValue; | |
SkipSpaces(pString); | |
if (*pString == ']') | |
{ | |
++pString; | |
return true; | |
} | |
else if (*pString != ',') | |
{ | |
return false; | |
} | |
++pString; | |
} | |
return false; | |
} | |
int JsonValue::ReadString(const ImwChar* pJson) | |
{ | |
if (pJson != NULL) | |
{ | |
CharBuffer oTempBuffer; | |
Reset(); | |
const ImwChar* pEnd = pJson; | |
if (!Parse(pEnd, oTempBuffer)) | |
{ | |
int iLine = 1; | |
int iReturn = 1; | |
while (pJson != pEnd) | |
{ | |
if (*pJson == '\n') | |
++iLine; | |
else if (*pJson == '\r') | |
++iReturn; | |
++pJson; | |
} | |
if (iReturn > iLine) | |
iLine = iReturn; | |
return iLine; | |
} | |
return 0; | |
} | |
return -1; | |
} | |
const bool JsonValue::Parse(const ImwChar*& pString, CharBuffer& oTempBuffer) | |
{ | |
bool bOk = pString != NULL && *pString != 0; | |
while (*pString != 0 && bOk) | |
{ | |
while (IsSpace(*pString)) ++pString; | |
if (*pString == '"') | |
{ | |
++pString; | |
if (!ReadStringValue(pString, *this, oTempBuffer)) | |
bOk = false; | |
break; | |
} | |
else if (IsDigit(*pString) || *pString == '-') | |
{ | |
if (!ReadNumericValue(pString, *this)) | |
bOk = false; | |
break; | |
} | |
else if (pString[0] == 't' && pString[1] == 'r' && pString[2] == 'u' && pString[3] == 'e') | |
{ | |
pString += 4; | |
*this = true; | |
break; | |
} | |
else if (pString[0] == 'f' && pString[1] == 'a' && pString[2] == 'l' && pString[3] == 's' && pString[4] == 'e') | |
{ | |
pString += 5; | |
*this = false; | |
break; | |
} | |
else if (pString[0] == 'n' && pString[1] == 'u' && pString[2] == 'l' && pString[3] == 'l') | |
{ | |
pString += 4; | |
InitType(E_TYPE_INVALID); | |
break; | |
} | |
else if (*pString == '{') | |
{ | |
++pString; | |
if (!ReadObjectValue(pString, *this, oTempBuffer)) | |
{ | |
bOk = false; | |
} | |
break; | |
} | |
else if (*pString == '[') | |
{ | |
++pString; | |
if (!ReadArrayValue(pString, *this, oTempBuffer)) | |
bOk = false; | |
break; | |
} | |
else | |
{ | |
//Error | |
bOk = false; | |
break; | |
} | |
} | |
return bOk; | |
} | |
int JsonValue::ReadFile(const ImwChar* pFilename) | |
{ | |
FILE* pFile = fopen(pFilename, "r"); | |
if (NULL != pFile) | |
{ | |
Reset(); | |
fseek(pFile, 0, SEEK_END); | |
long iSize = ftell(pFile); | |
fseek(pFile, 0, SEEK_SET); | |
ImwChar* pString = new ImwChar[iSize / sizeof(ImwChar)]; | |
fread(pString, 1, iSize, pFile); | |
fclose(pFile); | |
int iLine = ReadString(pString); | |
delete pString; | |
return iLine; | |
} | |
return -1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __IMW_JSON_VALUE_H__ | |
#define __IMW_JSON_VALUE_H__ | |
#include "ImwConfig.h" | |
#ifndef ImwChar | |
#define ImwChar char | |
#endif // ImwChar | |
#define ImwMalloc(iSize) malloc(iSize) | |
#define ImwFree(pObj) free(pObj) | |
#define ImwSafeFree(pObj) {free(pObj); pObj = NULL;} | |
namespace JsonStthm | |
{ | |
class JsonValue | |
{ | |
protected: | |
template <typename T, int HeapSize = 1024> | |
struct Buffer | |
{ | |
public: | |
Buffer(int iReserve = 8) | |
{ | |
m_pData = NULL; | |
m_iSize = m_iCapacity = 0; | |
m_bUseHeap = true; | |
Reserve(iReserve); | |
} | |
~Buffer() | |
{ | |
ImwSafeFree(m_pData); | |
} | |
Buffer<T>& operator +=(const T& oValue) | |
{ | |
Push(oValue); | |
return *this; | |
} | |
void Push(const T& oValue) | |
{ | |
Resize(m_iSize + 1); | |
if (m_bUseHeap) | |
m_pHeapData[m_iSize - 1] = oValue; | |
else | |
m_pData[m_iSize - 1] = oValue; | |
} | |
int Size() const | |
{ | |
return m_iSize; | |
} | |
void Reserve(int iCapacity, bool bForceAlloc = false) | |
{ | |
if (iCapacity != m_iCapacity) | |
{ | |
if (!m_bUseHeap || iCapacity >= HeapSize || bForceAlloc) | |
{ | |
T* pTemp = (T*)ImwMalloc(iCapacity * sizeof(T)); | |
if (NULL != m_pData) | |
{ | |
memcpy(pTemp, m_pData, (m_iCapacity > iCapacity ? m_iCapacity : iCapacity) * sizeof(T)); | |
ImwFree(m_pData); | |
} | |
m_pData = pTemp; | |
} | |
m_iCapacity = iCapacity; | |
} | |
} | |
void Resize(int iSize) | |
{ | |
int iNewCapacity = m_iCapacity > 0 ? m_iCapacity : 8; | |
while (iSize > iNewCapacity) | |
iNewCapacity *= 2; | |
if (iNewCapacity != m_iCapacity) | |
Reserve(iNewCapacity); | |
m_iSize = iSize; | |
} | |
const T* Data() const { return m_bUseHeap ? m_pHeapData : m_pData; } | |
T* Take() | |
{ | |
ImwChar* pTemp; | |
if (m_bUseHeap) | |
{ | |
pTemp = (T*)ImwMalloc(m_iSize * sizeof(T)); | |
memcpy(pTemp, m_pHeapData, m_iSize * sizeof(T)); | |
} | |
else | |
{ | |
pTemp = m_pData; | |
m_pData = NULL; | |
} | |
m_iCapacity = 0; | |
m_iSize = 0; | |
m_bUseHeap = true; | |
return pTemp; | |
} | |
void Clear() | |
{ | |
m_iSize = 0; | |
} | |
protected: | |
T m_pHeapData[HeapSize]; | |
T* m_pData; | |
int m_iSize; | |
int m_iCapacity; | |
bool m_bUseHeap; | |
}; | |
typedef Buffer<ImwChar> CharBuffer; | |
struct JsonMember | |
{ | |
public: | |
JsonMember(const ImwChar* pName = NULL, JsonValue* pValue = NULL); | |
JsonMember(const JsonMember& oSource); | |
~JsonMember(); | |
void SetName(const ImwChar* pName); | |
ImwChar* m_pName; | |
JsonValue* m_pValue; | |
}; | |
struct ParseInfos; | |
public: | |
enum EType | |
{ | |
E_TYPE_INVALID, //null | |
E_TYPE_OBJECT, //JsonMembers | |
E_TYPE_ARRAY, //JsonArray | |
E_TYPE_STRING, //ImwString | |
E_TYPE_BOOLEAN, //bool | |
E_TYPE_INTEGER, //long | |
E_TYPE_FLOAT //double | |
}; | |
static JsonValue INVALID; | |
public: | |
JsonValue(); | |
JsonValue(const JsonValue& oSource); | |
JsonValue(bool bValue); | |
JsonValue(const ImwString& sValue); | |
JsonValue(const ImwChar* pValue); | |
JsonValue(long iValue); | |
JsonValue(double fValue); | |
~JsonValue(); | |
void InitType(EType eType); | |
int ReadString(const ImwChar* pJson); | |
int ReadFile(const ImwChar* pFilename); | |
void WriteString(ImwString& sOutJson, bool bCompact = false); | |
bool WriteFile(const ImwChar* pFilename, bool bCompact = false); | |
bool IsObject() const { return m_eType == E_TYPE_OBJECT; } | |
bool IsArray() const { return m_eType == E_TYPE_ARRAY; } | |
bool IsBoolean() const { return m_eType == E_TYPE_BOOLEAN; } | |
bool IsString() const { return m_eType == E_TYPE_STRING; } | |
bool IsIntefer() const { return m_eType == E_TYPE_INTEGER; } | |
bool IsFloat() const { return m_eType == E_TYPE_FLOAT; } | |
size_t GetMemberCount() const; | |
const JsonValue& operator [](const ImwChar* pName) const; | |
JsonValue& operator [](const ImwChar* pName); | |
const JsonValue& operator [](int iIndex) const; | |
JsonValue& operator [](int iIndex); | |
JsonValue& operator =(const JsonValue& oValue); | |
JsonValue& operator =(const ImwString& sValue); | |
JsonValue& operator =(const ImwChar* pValue); | |
JsonValue& operator =(bool bValue); | |
JsonValue& operator =(long iValue); | |
JsonValue& operator =(double fValue); | |
JsonValue& operator +=(const JsonValue& oValue); | |
operator const char*() const; | |
operator bool() const; | |
operator long() const; | |
operator double() const; | |
protected: | |
static JsonValue CreateConst(); | |
void Reset(); | |
void SetString(const ImwChar* pString); | |
void Write(ImwString& sOutJson, int iIndent, bool bCompact); | |
static void WriteStringEscaped(ImwString& sOutJson, const ImwString& sInput); | |
bool m_bConst; | |
EType m_eType; | |
ImwChar* m_pName; | |
JsonValue* m_pNext; | |
union | |
{ | |
struct | |
{ | |
JsonValue* m_pChild; | |
JsonValue* m_pChildLast; | |
}; | |
ImwChar* m_pString; | |
bool m_bBoolean; | |
long m_iInteger; | |
double m_fFloat; | |
}; | |
const bool Parse(const ImwChar*& pString, CharBuffer& oTempBuffer); | |
static inline bool IsSpace(ImwChar cChar); | |
static inline bool IsDigit(ImwChar cChar); | |
static inline bool IsXDigit(ImwChar cChar); | |
static inline int CharToInt(ImwChar cChar); | |
static inline void SkipSpaces(const ImwChar*& pString); | |
static inline bool ReadSpecialChar(const ImwChar*& pString, CharBuffer& oTempBuffer); | |
static inline bool ReadStringValue(const ImwChar*& pString, CharBuffer& oTempBuffer); | |
static inline bool ReadStringValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer); | |
static inline bool ReadNumericValue(const ImwChar*& pString, JsonValue& oValue); | |
static inline bool ReadObjectValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer); | |
static inline bool ReadArrayValue(const ImwChar*& pString, JsonValue& oValue, CharBuffer& oTempBuffer); | |
}; | |
} | |
#endif // __IMW_JSON_VALUE_H__ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment