Major Update:

- Bug fix: BufferCore - set correct auto buffer size
- Change Get/Set methods to use BaseReference and full path instead of
    ParentPath and MemberName
- Add Create param to all Get methods (create if not found)
- Implement arrays & parsing of arrays
- Set CJSONparse as friend class to DataTree (access protected methods)
- Print JSON to screen
This commit is contained in:
Charl Wentzel
2017-03-26 22:26:52 +02:00
parent b823bd7ea7
commit a22f60b152
5 changed files with 640 additions and 424 deletions

View File

@@ -19,7 +19,7 @@
CJSONparse::CJSONparse( CDataTree * pDataTree )
{
// Parameter tree
// Object tree
DataTree = pDataTree;
// File Operation
@@ -54,10 +54,13 @@ CJSONparse::~CJSONparse()
}
//---------------------------------------------------------------------------
bool CJSONparse::LoadFile( const char * FilePath, int pBufLen )
bool CJSONparse::LoadFromFile( const char * FilePath, int pBufLen )
{
TDataMember * RootObject = NULL;
// Clear Error
Error = false;
// Validate
if (!FilePath || !FilePath[0]) {
Error = true;
@@ -87,7 +90,7 @@ bool CJSONparse::LoadFile( const char * FilePath, int pBufLen )
// Create Root object
DataTree->DeleteAll();
DataTree->GetParent( NULL, &RootObject );
RootObject = DataTree->GetRootMember();
Level = 0;
// Parse Root Object
@@ -112,6 +115,7 @@ bool CJSONparse::LoadFile( const char * FilePath, int pBufLen )
// Success
close( InputHandle );
InputHandle = -1;
FreeBuffer();
return true;
}
@@ -164,119 +168,21 @@ void CJSONparse::FreeBuffer()
}
//---------------------------------------------------------------------------
bool CJSONparse::ParseObject( TDataMember * Object )
{
TDataMember ** ParamPtr = NULL;
TDataMember * Param = NULL;
char * ParamName = NULL;
int Len = 0;
// Clear Values
Error = false;
// Check for start of Object
if (*BufPos != '{') {
return false;
}
BufPos++;
// Set Type
Level++;
DataTree->SetMember( Object, jtObject, NULL, -1 );
while (true)
{
// Look for Param Name
SkipWhiteSpace();
if (*BufPos == '}') {
break;
}
else if (!ParseString( &ParamName, &Len )) {
if (!Error) {
Error = true;
sprintf( ErrorText, "Expect quoted key name on line %d:%ld", LineNo, BufPos-LineMark );
}
return false;
}
else if (!Len) {
Error = true;
sprintf( ErrorText, "Empty parameter name on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
// Check if Param exists
ParamPtr = &(Object->FirstChild);
while (*ParamPtr && strcasecmp( (*ParamPtr)->Name, ParamName )) {
ParamPtr = &((*ParamPtr)->Next);
}
// If not exist, add to end of list
if (!*ParamPtr) {
*ParamPtr = DataTree->CreateMember( NULL );
(*ParamPtr)->Name = ParamName;
}
Param = *ParamPtr;
// Check for delimiter
SkipWhiteSpace();
if (*BufPos != ':') {
Error = true;
sprintf( ErrorText, "Expected ':' delimiter on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
BufPos++;
// Get Value
SkipWhiteSpace();
if (!ParseObject( Param ) &&
!Error &&
!ParseString( &Param->Value, &Param->Len, &Param->Type ) &&
!Error &&
!ParsePrimitive( &Param->Value, &Param->Len, &Param->Type )) {
return false;
}
// One item added
Object->Len++;
// Check if more parameters to follow
SkipWhiteSpace();
if (*BufPos != ',') {
// No more parameters
break;
}
BufPos++;
}
// Expect end of object
if (*BufPos != '}') {
Error = true;
sprintf( ErrorText, "Closing brace for object '}' expected on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
BufPos++;
Level--;
// success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParseString( char ** Value, int *pLen, EDataType *pType )
bool CJSONparse::ParseString( char ** Value, int &pLen )
{
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Check for opening quote
if (*BufPos != '"') {
return false;
}
// Clear values
*Value = NULL;
Len = 0;
// Mark start of quote
Mark = BufPos;
BufPos++;
@@ -321,7 +227,7 @@ bool CJSONparse::ParseString( char ** Value, int *pLen, EDataType *pType )
}
}
// Validate size of Param name
// Validate size of name
Len = BufPos-Mark-2;
// Create Return value pointer
@@ -330,26 +236,186 @@ bool CJSONparse::ParseString( char ** Value, int *pLen, EDataType *pType )
(*Value)[Len] = 0;
// Set other parameters
if (pType)
*pType = jtString;
if (pLen)
*pLen = Len;
pLen = Len;
// Success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParsePrimitive( char ** Value, int * pLen, EDataType * pType )
bool CJSONparse::ParseObject( TDataMember * Object )
{
TDataMember * Member = NULL;
char * MemberName = NULL;
int Len = 0;
// Check for start of Object
if (*BufPos != '{') {
return false;
}
BufPos++;
// Set Type
Level++;
DataTree->SetValue( Object, jtObject, NULL, -1 );
while (true)
{
// Look for Member Name
SkipWhiteSpace();
if (*BufPos == '}') {
break;
}
else if (!ParseString( &MemberName, Len )) {
if (!Error) {
Error = true;
sprintf( ErrorText, "Expect quoted key name on line %d:%ld", LineNo, BufPos-LineMark );
}
return false;
}
else if (!Len) {
Error = true;
sprintf( ErrorText, "Empty parameter name on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
// Check if Member exists
Member = DataTree->GetMember( Object, MemberName, true );
// Check for delimiter
SkipWhiteSpace();
if (*BufPos != ':') {
Error = true;
sprintf( ErrorText, "Expected ':' delimiter on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
BufPos++;
// Get Value
SkipWhiteSpace();
if (!ParseObject( Member ) &&
!Error &&
!ParseArray( Member ) &&
!Error &&
!ParseString( Member ) &&
!Error &&
!ParsePrimitive( Member ))
{
DataTree->Delete( Object, MemberName );
return false;
}
// Check if more parameters to follow
SkipWhiteSpace();
if (*BufPos != ',') {
// No more parameters
break;
}
BufPos++;
}
// Expect end of object
if (*BufPos != '}') {
Error = true;
sprintf( ErrorText, "Closing brace for object '}' expected on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
BufPos++;
Level--;
// success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParseArray( TDataMember * Array )
{
TDataMember * Member = NULL;
// Check for start of Object
if (*BufPos != '[') {
return false;
}
BufPos++;
// Set Type
Level++;
DataTree->SetValue( Array, jtArray, NULL, -1 );
while (true)
{
// Look for Member Name
SkipWhiteSpace();
if (*BufPos == ']') {
break;
}
// Add new element
Member = DataTree->CreateMember( NULL );
// Get Value
SkipWhiteSpace();
if (!ParseObject( Member ) &&
!Error &&
!ParseArray( Member ) &&
!Error &&
!ParseString( Member ) &&
!Error &&
!ParsePrimitive( Member ))
{
DataTree->DestroyMember( &Member );
return false;
}
else {
DataTree->AddMember( Array, Member );
}
// Check if more parameters to follow
SkipWhiteSpace();
if (*BufPos != ',') {
// No more parameters
break;
}
BufPos++;
}
// Expect end of object
if (*BufPos != ']') {
Error = true;
sprintf( ErrorText, "Closing brace for array ']' expected on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
BufPos++;
Level--;
// success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParseString( TDataMember * Member )
{
char * Value = NULL;
int Len = 0;
// Try to parse
if (!ParseString( &Value, Len )) {
return false;
}
// Set string
DataTree->SetValuePtr( Member, jtString, Value, Len );
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParsePrimitive( TDataMember * Member )
{
char * Value = NULL;
int Len = 0;
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Mark start of value
Mark = BufPos;
@@ -369,52 +435,31 @@ bool CJSONparse::ParsePrimitive( char ** Value, int * pLen, EDataType * pType )
// Check for primitive values
if ((Len == 4) && !strncasecmp( Mark, "null", 4 )) {
if (pType)
*pType = jtNull;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 5 );
strcpy( *Value, "null" );
DataTree->SetValuePtr( Member, jtNull, NULL, -1 );
}
else if ((Len == 4) && !strncasecmp( Mark, "true", 4 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 5 );
strcpy( *Value, "true" );
DataTree->SetValue( Member, jtBool, "1", 1 );
}
else if ((Len == 5) && !strncasecmp( Mark, "false", 5 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 6 );
strcpy( *Value, "false" );
DataTree->SetValue( Member, jtBool, "0", 1 );
}
else {
// Try conversion to int
strtol( Mark, &EndMark, 10 );
if (EndMark == BufPos) {
if (pType)
*pType = jtInt;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( Len+1 );
memcpy( *Value, Mark, Len );
(*Value)[Len] = 0;
Value = (char*)malloc( Len+1 );
memcpy( Value, Mark, Len );
Value[Len] = 0;
DataTree->SetValuePtr( Member, jtInt, Value, Len );
}
else {
// Try conversion to float
strtod( Mark, &EndMark );
if (EndMark == BufPos) {
if (pType)
*pType = jtFloat;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( Len+1 );
memcpy( *Value, Mark, Len );
(*Value)[Len] = 0;
Value = (char*)malloc( Len+1 );
memcpy( Value, Mark, Len );
Value[Len] = 0;
DataTree->SetValuePtr( Member, jtFloat, Value, Len );
}
else {
Error = true;
@@ -429,7 +474,26 @@ bool CJSONparse::ParsePrimitive( char ** Value, int * pLen, EDataType * pType )
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveFile( const char * FilePath, const int Indent )
bool CJSONparse::PrintToScreen( const int Indent )
{
TDataMember * RootObject;
// Set to StdOut
OutputHandle = 1;
// Save Root object
Level = 0;
RootObject = DataTree->GetRootMember();
PrintObject( RootObject, Indent );
// Close file
close( OutputHandle );
OutputHandle = -1;
return false;
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveToFile( const char * FilePath, const int Indent )
{
TDataMember * RootObject;
@@ -443,73 +507,173 @@ bool CJSONparse::SaveFile( const char * FilePath, const int Indent )
// Save Root object
Level = 0;
DataTree->GetParent( NULL, &RootObject );
SaveObject( RootObject, Indent );
RootObject = DataTree->GetRootMember();
PrintObject( RootObject, Indent );
// Close file
close( OutputHandle );
OutputHandle = -1;
return false;
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveObject( TDataMember * Object, const int Indent )
bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
{
TDataMember * Param;
TDataMember * Member;
bool First = true;
bool Last = false;
int Count = 0;
// Opening brace
dprintf( OutputHandle, "{\n" );
write( OutputHandle, "{", 1 );
Level++;
// Extend spacer
Level++;
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
// Save parameters
for (Param = Object->FirstChild; Param != NULL; (Param = Param->Next))
for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next))
{
// Write parameter name
dprintf( OutputHandle, "%s\"%s\": ", Spacer, Param->Name );
if (First) {
First = false;
if (Object->Name) {
write( OutputHandle, "\n", 1 );
write( OutputHandle, Spacer, SpacerLen );
}
else {
write( OutputHandle, " ", 1 );
}
}
else {
write( OutputHandle, Spacer, SpacerLen );
}
switch (Param->Type)
// Print key name
write( OutputHandle, "\"", 1 );
write( OutputHandle, Member->Name, strlen(Member->Name) );
write( OutputHandle, "\" : ", 4 );
// Print value
Last = (++Count >= Object->Len);
switch (Member->Type)
{
case jtNull :
dprintf( OutputHandle, "%s,\n", "null" );
write( OutputHandle, "null", 4 );
break;
case jtBool :
case jtInt :
case jtFloat :
dprintf( OutputHandle, "%s,\n", Param->Value );
write( OutputHandle, Member->Value, Member->Len );
break;
case jtString :
dprintf( OutputHandle, "\"%s\",\n", Param->Value );
write( OutputHandle, "\"", 1 );
write( OutputHandle, Member->Value, Member->Len );
write( OutputHandle, "\"", 1 );
break;
case jtArray :
dprintf( OutputHandle, "[],\n" );
PrintArray( Member, Indent );
break;
case jtObject :
SaveObject( Param, Indent );
PrintObject( Member, Indent );
break;
}
if (!Last) {
write( OutputHandle, ",", 1 );
}
write( OutputHandle, "\n", 1 );
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
Level--;
// Closing brace
if (Level == 0) {
dprintf( OutputHandle, "%s}\n", Spacer );
Level--;
if (Object->Len) {
write( OutputHandle, Spacer, SpacerLen );
}
else {
dprintf( OutputHandle, "%s},\n", Spacer );
}
return false;
write( OutputHandle, "}", 1 );
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
{
TDataMember * Member;
bool First = true;
bool Last = false;
int Count = 0;
// Opening brace
write( OutputHandle, "[", 1 );
Level++;
// Extend spacer
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
// Save parameters
for (Member = Array->FirstChild; Member != NULL; (Member = Member->Next))
{
// Write parameter name
if (First) {
First = false;
write( OutputHandle, "\n", 1 );
}
write( OutputHandle, Spacer, SpacerLen );
Last = (++Count >= Array->Len);
switch (Member->Type)
{
case jtNull :
write( OutputHandle, "null", 4 );
break;
case jtBool :
case jtInt :
case jtFloat :
write( OutputHandle, Member->Value, Member->Len );
break;
case jtString :
write( OutputHandle, "\"", 1 );
write( OutputHandle, Member->Value, Member->Len );
write( OutputHandle, "\"", 1 );
break;
case jtArray :
PrintArray( Member, Indent );
break;
case jtObject :
PrintObject( Member, Indent );
break;
}
if (!Last) {
write( OutputHandle, ",", 1 );
}
write( OutputHandle, "\n", 1 );
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
// Closing brace
Level--;
if (Array->Len) {
write( OutputHandle, Spacer, SpacerLen );
}
write( OutputHandle, "]", 1 );
return true;
}
//---------------------------------------------------------------------------