Important Update: (incomplete)

- Split CConfigCore into two classes:
  - DataTreeCore.h - Tree data structure and access
  - JSONparseCore.h - JSON parsing functionality
- Renamed TConfigParam struct to TDataMember
- Renamed most of CDataTreeCore methods
This commit is contained in:
Charl Wentzel
2017-03-23 20:53:32 +02:00
parent ad4d8e8b5f
commit b823bd7ea7
7 changed files with 1149 additions and 1073 deletions

View File

@@ -1,3 +1,3 @@
PROJECT(lib_redAcore) PROJECT(lib_redAcore)
ADD_LIBRARY(redAcore TimingCore.cpp DateTimeCore.cpp LogCore.cpp SignalCore.cpp ConfigCore.cpp BufferCore.cpp FunctionCore.cpp DeviceCore.cpp FileCore.cpp SelectCore.cpp SelectableCore.cpp) ADD_LIBRARY(redAcore TimingCore.cpp DateTimeCore.cpp LogCore.cpp SignalCore.cpp DataTreeCore.cpp JSONparseCore.cpp BufferCore.cpp FunctionCore.cpp DeviceCore.cpp FileCore.cpp SelectCore.cpp SelectableCore.cpp)

View File

@@ -1,942 +0,0 @@
/*
* ConfigCore.cpp
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
// redA Libraries
#include "ConfigCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
//---------------------------------------------------------------------------
CConfigCore::CConfigCore()
{
// Parameter tree
RootObject = CreateParam( NULL );
RootObject->Type = jtObject;
// File Operation
InputHandle = -1;
OutputHandle = -1;
Buffer = NULL;
BufEnd = NULL;
Level = 0;
// Parsing operation
BufPos = NULL;
LineMark = NULL;
LineNo = 0;
// Printing operation
Spacer[0] = 0;
SpacerLen = 0;
// Error reporting
Error = false;
ErrorText[0] = 0;
}
//---------------------------------------------------------------------------
CConfigCore::~CConfigCore()
{
// Destroy Params
DeleteAll();
DestroyParam( &RootObject );
}
//---------------------------------------------------------------------------
TConfigParam * CConfigCore::CreateParam( const char * Name )
{
TConfigParam * Param;
Param = (TConfigParam *)calloc( 1, sizeof(TConfigParam) );
if (Name && *Name)
{
Param->Name = (char *)malloc( strlen( Name )+1 );
strcpy( Param->Name, Name );
}
return Param;
}
//---------------------------------------------------------------------------
bool CConfigCore::DestroyParam( TConfigParam ** Param )
{
TConfigParam * NextParam;
// Valdate
if (!Param || !*Param)
return false;
// Get next param in list
NextParam = (*Param)->Next;
// Destroy
if ((*Param)->Name)
free( (*Param)->Name );
if ((*Param)->Value)
free( (*Param)->Value );
while ((*Param)->FirstObject) {
DestroyParam( &((*Param)->FirstObject) );
}
free( *Param );
// Restore list integrity
*Param = NextParam;
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::GetParent( const char * ParentPath, TConfigParam **Parent )
{
TConfigParam * Param;
char * ParentName;
char * Pos;
// Validate
if (!Parent) {
return false;
}
// Set first Parent
*Parent = RootObject;
// Split path
Pos = (char*)ParentPath;
while (*Pos)
{
// Set Name start
ParentName = Pos;
// Find delimeter
while (*Pos && (*Pos != '/')) {
Pos++;
}
// Zero terminate name
if (*Pos) {
*Pos = 0;
Pos++;
}
// Find next parent
Param = (*Parent)->FirstObject;
while (Param && strcasecmp( Param->Name, ParentName )) {
Param = Param->Next;
}
if (!Param) {
return false;
}
// Set Next parent
*Parent = Param;
}
return true;
}
//---------------------------------------------------------------------------
TConfigParam * CConfigCore::GetParam( TConfigParam * Parent, const char * Name )
{
TConfigParam * Param;
// Validate
if (!Parent || !Name || !*Name) {
return NULL;
}
// Get Param
Param = Parent->FirstObject;
while (Param && strcasecmp( Param->Name, Name ))
Param = Param->Next;
return Param;
}
//---------------------------------------------------------------------------
TConfigParam ** CConfigCore::GetParamPtr( TConfigParam * Parent, const char * Name )
{
TConfigParam ** Param;
// Validate
if (!Parent || !Name || !*Name) {
return NULL;
}
// Get Param
Param = &(Parent->FirstObject);
while (Param && strcasecmp( (*Param)->Name, Name ))
Param = &((*Param)->Next);
return Param;
}
//---------------------------------------------------------------------------
bool CConfigCore::DeleteParam( const char * ParentPath, const char * Name )
{
TConfigParam * Parent;
TConfigParam ** Param;
// Check if exists
if (!GetParent( ParentPath, &Parent ) ||
!(Param = GetParamPtr( Parent, Name ))) {
return false;
}
// Destroy
DestroyParam( Param );
Parent->Len--;
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::DeleteAll()
{
while (RootObject->FirstObject) {
DestroyParam( &(RootObject->FirstObject) );
}
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParam( TConfigParam * Param, EJSONtype Type, const char * Value, const int Len )
{
// Clear previous value
if (Param->Value != NULL) {
free( Param->Value );
}
// Set type
Param->Type = Type;
// Set new value
switch (Type) {
case jtNull:
case jtObject:
case jtArray:
Param->Len = 0;
Param->Value = NULL;
break;
case jtString:
case jtFloat:
case jtInt:
case jtBool:
Param->Len = (Len == -1)? strlen(Value) : Len;
Param->Value = (char *)malloc( sizeof(Param->Len+1) );
if (Value) {
memcpy( Param->Value, Value, Param->Len+1 );
} else {
memset( Param->Value, 0, Param->Len+1 );
}
Param->Value[Param->Len] = 0;
break;
}
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamObject( const char * ParentPath, const char * Name )
{
TConfigParam * Parent;
TConfigParam ** Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
SetParam( *Param, jtObject, NULL, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamStr( const char * ParentPath, const char * Name, const char * Value, const int Len )
{
TConfigParam * Parent;
TConfigParam ** Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
SetParam( *Param, jtString, Value, Len );
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamInt( const char * ParentPath, const char * Name, const long Value )
{
TConfigParam * Parent;
TConfigParam ** Param;
char ValueStr[50];
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
sprintf( ValueStr, "%ld", Value );
SetParam( *Param, jtInt, ValueStr, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamFloat( const char * ParentPath, const char * Name, const double Value )
{
TConfigParam * Parent;
TConfigParam ** Param;
char ValueStr[50];
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
sprintf( ValueStr, "%lf", Value );
SetParam( *Param, jtFloat, ValueStr, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamBool( const char * ParentPath, const char * Name, const bool Value )
{
TConfigParam * Parent;
TConfigParam ** Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
SetParam( *Param, jtBool, ((Value == 0)? "false" : "true"), -1 );
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SetParamNull( const char * ParentPath, const char * Name )
{
TConfigParam * Parent;
TConfigParam ** Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Param = GetParamPtr( Parent, Name ))) {
*Param = CreateParam( Name );
}
SetParam( *Param, jtNull, NULL, -1 );
return true;
}
//---------------------------------------------------------------------------
const EJSONtype CConfigCore::GetParamType( const char * ParentPath, const char * Name )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return jtNull;
}
// Return type
if ((Param = GetParam( Parent, Name ))) {
return Param->Type;
}
else {
return jtNull;
}
}
//---------------------------------------------------------------------------
const char * CConfigCore::GetParamStr( const char * ParentPath, const char * Name, const char * Default )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Param = GetParam( Parent, Name )) && (Param->Type == jtString)) {
return Param->Value;
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const char * CConfigCore::GetParamStr( const char * ParentPath, const char * Name, int &Len, const char * Default )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Param = GetParam( Parent, Name )) && (Param->Type == jtString)) {
Len = Param->Len;
return Param->Value;
}
else {
Len = strlen( Default );
return Default;
}
}
//---------------------------------------------------------------------------
const long CConfigCore::GetParamInt( const char * ParentPath, const char * Name, long Default )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Param = GetParam( Parent, Name )) && (Param->Type == jtInt)) {
return strtol( Param->Value, NULL, 10 );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const double CConfigCore::GetParamFloat( const char * ParentPath, const char * Name, double Default )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Param = GetParam( Parent, Name )) && (Param->Type == jtFloat)) {
return strtod( Param->Value, NULL );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const bool CConfigCore::GetParamBool( const char * ParentPath, const char * Name, bool Default )
{
TConfigParam * Parent;
TConfigParam * Param;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Param = GetParam( Parent, Name )) && (Param->Type == jtBool)) {
return ((!strcasecmp( Param->Value, "true" ))? true : false );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
bool CConfigCore::LoadFile( const char * FilePath, int pBufLen )
{
TConfigParam * Object = NULL;
// Validate
if (!FilePath || !FilePath[0]) {
Error = true;
sprintf( ErrorText, "No File path specified" );
return false;
}
// Open file
if (!(InputHandle = open( FilePath, O_RDONLY ))) {
Error = true;
sprintf( ErrorText, "Could not open file" );
return false;
}
// Load Buffer
CreateBuffer( pBufLen );
if (!FillBuffer()) {
Error = true;
sprintf( ErrorText, "Could not read from file" );
FreeBuffer();
return false;
}
// Reset values
LineNo = 1;
Error = false;
// Create Root object
DeleteAll();
Object = RootObject;
Level = 0;
// Parse Root Object
SkipWhiteSpace();
if (!ParseObject( Object )) {
if (!Error) {
Error = true;
sprintf( ErrorText, "First entry in file must be an Object on line %d:%ld", LineNo, BufPos-LineMark );
}
FreeBuffer();
return false;
}
// Ensure remainder of file is empty
SkipWhiteSpace();
if (*BufPos != 0) {
Error = true;
sprintf( ErrorText, "No content expected after Root object on line %d:%ld", LineNo, BufPos-LineMark );
FreeBuffer();
return false;
}
// Success
close( InputHandle );
FreeBuffer();
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::CreateBuffer( int pBufLen )
{
// Validate
if (!pBufLen)
return false;
// Create buffer
Buffer = new CShiftBuffer( pBufLen );
// Reset markers
Buffer->PeekDirect( &BufPos, 0 );
BufEnd = BufPos;
LineMark = BufPos;
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::FillBuffer()
{
// Read from file
Buffer->ReadFromFD( InputHandle );
// Update Markers
Buffer->PeekDirect( &BufEnd, Buffer->Len() );
Buffer->PeekDirect( &BufPos, 0 );
LineMark = BufPos;
return true;
}
//---------------------------------------------------------------------------
void CConfigCore::FreeBuffer()
{
// Destroy buffer
if (Buffer) {
delete Buffer;
Buffer = NULL;
// Update Markers
BufEnd = NULL;
BufPos = NULL;
LineMark = NULL;
}
}
//---------------------------------------------------------------------------
bool CConfigCore::ParseObject( TConfigParam * Object )
{
TConfigParam ** ParamPtr = NULL;
TConfigParam * 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++;
SetParam( 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->FirstObject);
while (*ParamPtr && strcasecmp( (*ParamPtr)->Name, ParamName )) {
ParamPtr = &((*ParamPtr)->Next);
}
// If not exist, add to end of list
if (!*ParamPtr) {
*ParamPtr = CreateParam( 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 CConfigCore::ParseString( char ** Value, int *pLen, EJSONtype *pType )
{
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Check for opening quote
if (*BufPos != '"') {
return false;
}
// Mark start of quote
Mark = BufPos;
BufPos++;
// Check for closing quote
while ((BufPos = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" )))
{
if (*BufPos == '"') {
// End of string found
BufPos++;
break;
}
else if (!*BufPos) {
Error = true;
sprintf( ErrorText, "Expect closing '\"' for string on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
else if (*BufPos == '\\') {
if (*(BufPos+1) == 'u') {
for (EndMark = BufPos+2; EndMark < BufPos+6; EndMark++) {
if (!isxdigit( *EndMark )) {
Error = true;
sprintf( ErrorText, "Expect 4-digit hex value for escape value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
BufPos += 6;
}
else if (strchr( "bfnrt/\\\"", *(BufPos+1) )) {
BufPos += 2;
}
else {
Error = true;
sprintf( ErrorText, "Invalid escape sequence on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
else {
Error = true;
sprintf( ErrorText, "Un-escaped special character in string on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
}
// Validate size of Param name
Len = BufPos-Mark-2;
// Create Return value pointer
*Value = (char*)malloc( Len+1 );
memcpy( *Value, Mark+1, Len );
(*Value)[Len] = 0;
// Set other parameters
if (pType)
*pType = jtString;
if (pLen)
*pLen = Len;
// Success
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::ParsePrimitive( char ** Value, int * pLen, EJSONtype * pType )
{
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Mark start of value
Mark = BufPos;
// Get end of value
while ((*BufPos != 0) && !isspace(*BufPos) && (*BufPos != ',')) {
BufPos++;
}
// Check length of value
Len = BufPos - Mark;
if (!Len) {
Error = true;
sprintf( ErrorText, "Missing param value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
// 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" );
}
else if ((Len == 4) && !strncasecmp( Mark, "true", 4 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 5 );
strcpy( *Value, "true" );
}
else if ((Len == 5) && !strncasecmp( Mark, "false", 5 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 6 );
strcpy( *Value, "false" );
}
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;
}
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;
}
else {
Error = true;
sprintf( ErrorText, "Invalid primitive param value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
}
// Success
return true;
}
//---------------------------------------------------------------------------
bool CConfigCore::SaveFile( const char * FilePath, const int Indent )
{
// Validate
if (!FilePath || !FilePath[0])
return false;
// Open file
if (!(OutputHandle = open( FilePath, O_WRONLY )))
return false;
// Save Root object
Level = 0;
SaveObject( RootObject, Indent );
// Close file
close( OutputHandle );
return false;
}
//---------------------------------------------------------------------------
bool CConfigCore::SaveObject( TConfigParam * Object, const int Indent )
{
TConfigParam * Param;
// Opening brace
dprintf( OutputHandle, "{\n" );
// Extend spacer
Level++;
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
// Save parameters
for (Param = Object->FirstObject; Param != NULL; (Param = Param->Next))
{
// Write parameter name
dprintf( OutputHandle, "%s\"%s\": ", Spacer, Param->Name );
switch (Param->Type)
{
case jtNull :
dprintf( OutputHandle, "%s,\n", "null" );
break;
case jtBool :
case jtInt :
case jtFloat :
dprintf( OutputHandle, "%s,\n", Param->Value );
break;
case jtString :
dprintf( OutputHandle, "\"%s\",\n", Param->Value );
break;
case jtArray :
dprintf( OutputHandle, "[],\n" );
break;
case jtObject :
SaveObject( Param, Indent );
break;
}
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
Level--;
// Closing brace
if (Level == 0) {
dprintf( OutputHandle, "%s}\n", Spacer );
}
else {
dprintf( OutputHandle, "%s},\n", Spacer );
}
return false;
}
//---------------------------------------------------------------------------

View File

@@ -1,130 +0,0 @@
/*
* ConfigCore.h
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
#ifndef REDACORE_CONFIGCORE_H_
#define REDACORE_CONFIGCORE_H_
// redA Libraries
#include <BufferCore.h>
// Standard C/C++ Libraries
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
//---------------------------------------------------------------------------
typedef enum { jtNull = 0, jtBool = 1, jtInt = 2, jtFloat = 3, jtString = 4, jtArray = 5, jtObject = 6 } EJSONtype;
//---------------------------------------------------------------------------
// Structure prototypes
typedef struct SConfigParam TConfigParam;
// One Config Parameters
struct SConfigParam
{
char * Name;
EJSONtype Type;
TConfigParam * FirstObject;
char * Value;
int Len;
TConfigParam * Next;
};
//---------------------------------------------------------------------------
class CConfigCore
{
private:
TConfigParam * RootObject;
// File operation
int InputHandle;
int OutputHandle;
CShiftBuffer * Buffer;
// Parsing operation
char * BufEnd;
char * BufPos;
char * LineMark;
int LineNo;
int Level;
// Printing Operation
char Spacer[100];
int SpacerLen;
// Error
bool Error;
char ErrorText[100];
// Manage Parameters
TConfigParam * CreateParam( const char * Name );
bool DestroyParam( TConfigParam ** Param );
// Find Param
bool GetParent( const char * ParentPath, TConfigParam **Parent );
TConfigParam * GetParam( TConfigParam * Parent, const char * Name );
TConfigParam ** GetParamPtr( TConfigParam * Parent, const char * Name );
// Set Param value
bool SetParam( TConfigParam * Param, EJSONtype Type, const char * Value, const int Len );
// File Buffer operation
bool CreateBuffer( int pBufLen );
bool FillBuffer();
void FreeBuffer();
// Parsing functions
inline void SkipWhiteSpace() {
while (isspace(*BufPos)) {
if (*BufPos == '\n') {
LineMark = BufPos;
LineNo++;
}
BufPos++;
}
}
bool ParseObject( TConfigParam * Object );
bool ParseString( char ** Value, int * pLen = NULL, EJSONtype * pType = NULL );
bool ParsePrimitive( char ** Value, int * pLen = NULL, EJSONtype * pType = NULL );
bool SaveObject( TConfigParam * Object, const int Indent );
public:
CConfigCore();
~CConfigCore();
bool SetParamObject( const char * ParentPath, const char * Name );
bool SetParamStr( const char * ParentPath, const char * Name, const char * Value = NULL, const int Len = -1 ); // Use Len param if Value contains NULL values
bool SetParamInt( const char * ParentPath, const char * Name, const long Value );
bool SetParamFloat( const char * ParentPath, const char * Name, const double Value );
bool SetParamBool( const char * ParentPath, const char * Name, const bool Value );
bool SetParamNull( const char * ParentPath, const char * Name );
const EJSONtype GetParamType( const char * ParentPath, const char * Name );
const char * GetParamStr( const char * ParentPath, const char * Name, const char * Default = NULL );
const char * GetParamStr( const char * ParentPath, const char * Name, int &Len, const char * Default = NULL );
const long GetParamInt( const char * ParentPath, const char * Name, long Default = 0 );
const double GetParamFloat( const char * ParentPath, const char * Name, double Default = 0.0 );
const bool GetParamBool( const char * ParentPath, const char * Name, bool Default = false );
bool DeleteParam( const char * ParentPath, const char * Name );
bool DeleteAll();
bool LoadFile( const char * FilePath, int pBufLen = 500 );
bool SaveFile( const char * FilePath, const int ValueTab = 20 );
const char * GetError() { return ((Error)? ErrorText : "Success"); };
};
#endif /* REDACORE_CONFIGCORE_H_ */

470
DataTreeCore.cpp Normal file
View File

@@ -0,0 +1,470 @@
/*
* DataTreeCore.cpp
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
// redA Libraries
#include "DataTreeCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
//---------------------------------------------------------------------------
CDataTree::CDataTree()
{
// Create Root member of tree
RootObject = CreateMember( NULL );
RootObject->Type = jtObject;
}
//---------------------------------------------------------------------------
CDataTree::~CDataTree()
{
// Destroy Members
DeleteAll();
DestroyMember( &RootObject );
}
//---------------------------------------------------------------------------
TDataMember * CDataTree::CreateMember( const char * Name )
{
TDataMember * Member;
Member = (TDataMember *)calloc( 1, sizeof(TDataMember) );
if (Name && *Name)
{
Member->Name = (char *)malloc( strlen( Name )+1 );
strcpy( Member->Name, Name );
}
return Member;
}
//---------------------------------------------------------------------------
bool CDataTree::DestroyMember( TDataMember ** Member )
{
TDataMember * NextMember;
// Valdate
if (!Member || !*Member)
return false;
// Get next param in list
NextMember = (*Member)->Next;
// Destroy
if ((*Member)->Name)
free( (*Member)->Name );
if ((*Member)->Value)
free( (*Member)->Value );
while ((*Member)->FirstChild) {
DestroyMember( &((*Member)->FirstChild) );
}
free( *Member );
// Restore list integrity
*Member = NextMember;
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::GetParent( const char * ParentPath, TDataMember **Parent )
{
TDataMember * Member;
char * ParentName;
char * Pos;
// Validate
if (!Parent) {
return false;
}
// Set first Parent
*Parent = RootObject;
// Check if path provided
if (!ParentPath || !*ParentPath) {
return true;
}
// Split path
Pos = (char*)ParentPath;
while (*Pos)
{
// Set Name start
ParentName = Pos;
// Find delimeter
while (*Pos && (*Pos != '/')) {
Pos++;
}
// Zero terminate name
if (*Pos) {
*Pos = 0;
Pos++;
}
// Find next parent
Member = (*Parent)->FirstChild;
while (Member && strcasecmp( Member->Name, ParentName )) {
Member = Member->Next;
}
if (!Member) {
return false;
}
// Set Next parent
*Parent = Member;
}
return true;
}
//---------------------------------------------------------------------------
TDataMember * CDataTree::GetMember( TDataMember * Parent, const char * Name )
{
TDataMember * Member;
// Validate
if (!Parent || !Name || !*Name) {
return NULL;
}
// Get Member
Member = Parent->FirstChild;
while (Member && strcasecmp( Member->Name, Name ))
Member = Member->Next;
return Member;
}
//---------------------------------------------------------------------------
TDataMember ** CDataTree::GetMemberPtr( TDataMember * Parent, const char * Name )
{
TDataMember ** Member;
// Validate
if (!Parent || !Name || !*Name) {
return NULL;
}
// Get Member
Member = &(Parent->FirstChild);
while (Member && strcasecmp( (*Member)->Name, Name ))
Member = &((*Member)->Next);
return Member;
}
//---------------------------------------------------------------------------
bool CDataTree::Delete( const char * ParentPath, const char * Name )
{
TDataMember * Parent;
TDataMember ** Member;
// Check if exists
if (!GetParent( ParentPath, &Parent ) ||
!(Member = GetMemberPtr( Parent, Name ))) {
return false;
}
// Destroy
DestroyMember( Member );
Parent->Len--;
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::DeleteAll()
{
while (RootObject->FirstChild) {
DestroyMember( &(RootObject->FirstChild) );
}
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetMember( TDataMember * Member, EDataType Type, const char * Value, const int Len )
{
// Clear previous value
if (Member->Value != NULL) {
free( Member->Value );
}
// Set type
Member->Type = Type;
// Set new value
switch (Type) {
case jtNull:
case jtObject:
case jtArray:
Member->Len = 0;
Member->Value = NULL;
break;
case jtString:
case jtFloat:
case jtInt:
case jtBool:
Member->Len = (Len == -1)? strlen(Value) : Len;
Member->Value = (char *)malloc( sizeof(Member->Len+1) );
if (Value) {
memcpy( Member->Value, Value, Member->Len+1 );
} else {
memset( Member->Value, 0, Member->Len+1 );
}
Member->Value[Member->Len] = 0;
break;
}
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetObject( const char * ParentPath, const char * Name )
{
TDataMember * Parent;
TDataMember ** Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtObject, NULL, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetStr( const char * ParentPath, const char * Name, const char * Value, const int Len )
{
TDataMember * Parent;
TDataMember ** Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtString, Value, Len );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetInt( const char * ParentPath, const char * Name, const long Value )
{
TDataMember * Parent;
TDataMember ** Member;
char ValueStr[50];
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
sprintf( ValueStr, "%ld", Value );
SetMember( *Member, jtInt, ValueStr, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetFloat( const char * ParentPath, const char * Name, const double Value )
{
TDataMember * Parent;
TDataMember ** Member;
char ValueStr[50];
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
sprintf( ValueStr, "%lf", Value );
SetMember( *Member, jtFloat, ValueStr, -1 );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetBool( const char * ParentPath, const char * Name, const bool Value )
{
TDataMember * Parent;
TDataMember ** Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtBool, ((Value == 0)? "0" : "1"), -1 );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetNull( const char * ParentPath, const char * Name )
{
TDataMember * Parent;
TDataMember ** Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return false;
}
// Create new param if it doesn't exist
if (!*(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtNull, NULL, -1 );
return true;
}
//---------------------------------------------------------------------------
const EDataType CDataTree::GetType( const char * ParentPath, const char * Name )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return jtNull;
}
// Return type
if ((Member = GetMember( Parent, Name ))) {
return Member->Type;
}
else {
return jtNull;
}
}
//---------------------------------------------------------------------------
const char * CDataTree::GetStr( const char * ParentPath, const char * Name, const char * Default )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) {
return Member->Value;
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const char * CDataTree::GetStr( const char * ParentPath, const char * Name, int &Len, const char * Default )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) {
Len = Member->Len;
return Member->Value;
}
else {
Len = strlen( Default );
return Default;
}
}
//---------------------------------------------------------------------------
const long CDataTree::GetInt( const char * ParentPath, const char * Name, long Default )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtInt)) {
return strtol( Member->Value, NULL, 10 );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const double CDataTree::GetFloat( const char * ParentPath, const char * Name, double Default )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtFloat)) {
return strtod( Member->Value, NULL );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------
const bool CDataTree::GetBool( const char * ParentPath, const char * Name, bool Default )
{
TDataMember * Parent;
TDataMember * Member;
// Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtBool)) {
return ((!strcasecmp( Member->Value, "0" ))? false : true );
}
else {
return Default;
}
}
//---------------------------------------------------------------------------

83
DataTreeCore.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* DataTreeCore.h
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
#ifndef REDACORE_DATATREECORE_H_
#define REDACORE_DATATREECORE_H_
// redA Libraries
#include <BufferCore.h>
// Standard C/C++ Libraries
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
//---------------------------------------------------------------------------
typedef enum { jtNull = 0, jtBool = 1, jtInt = 2, jtFloat = 3, jtString = 4, jtArray = 5, jtObject = 6 } EDataType;
//---------------------------------------------------------------------------
// Structure prototypes
typedef struct SDataMember TDataMember;
// One Config Members
struct SDataMember
{
char * Name;
EDataType Type;
TDataMember * FirstChild;
char * Value;
int Len;
TDataMember * Next;
};
//---------------------------------------------------------------------------
class CDataTree
{
private:
TDataMember * RootObject;
// Manage Members
TDataMember * CreateMember( const char * Name );
bool DestroyMember( TDataMember ** Member );
// Find Member
bool GetParent( const char * ParentPath, TDataMember **Parent );
TDataMember * GetMember( TDataMember * Parent, const char * Name );
TDataMember ** GetMemberPtr( TDataMember * Parent, const char * Name );
// Set Member value
bool SetMember( TDataMember * Member, EDataType Type, const char * Value, const int Len );
public:
CDataTree();
~CDataTree();
bool SetObject( const char * ParentPath, const char * Name );
bool SetStr( const char * ParentPath, const char * Name, const char * Value = NULL, const int Len = -1 ); // Use Len param if Value contains NULL values
bool SetInt( const char * ParentPath, const char * Name, const long Value );
bool SetFloat( const char * ParentPath, const char * Name, const double Value );
bool SetBool( const char * ParentPath, const char * Name, const bool Value );
bool SetNull( const char * ParentPath, const char * Name );
const EDataType GetType( const char * ParentPath, const char * Name );
const char * GetStr( const char * ParentPath, const char * Name, const char * Default = NULL );
const char * GetStr( const char * ParentPath, const char * Name, int &Len, const char * Default = NULL );
const long GetInt( const char * ParentPath, const char * Name, long Default = 0 );
const double GetFloat( const char * ParentPath, const char * Name, double Default = 0.0 );
const bool GetBool( const char * ParentPath, const char * Name, bool Default = false );
bool Delete( const char * ParentPath, const char * Name );
bool DeleteAll();
};
#endif /* REDACORE_DATATREECORE_H_ */

515
JSONparseCore.cpp Normal file
View File

@@ -0,0 +1,515 @@
/*
* JSONparseCore.cpp
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
// redA Libraries
#include "JSONparseCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
//---------------------------------------------------------------------------
CJSONparse::CJSONparse( CDataTree * pDataTree )
{
// Parameter tree
DataTree = pDataTree;
// File Operation
InputHandle = -1;
OutputHandle = -1;
Buffer = NULL;
BufEnd = NULL;
Level = 0;
// Parsing operation
BufPos = NULL;
LineMark = NULL;
LineNo = 0;
// Printing operation
Spacer[0] = 0;
SpacerLen = 0;
// Error reporting
Error = false;
ErrorText[0] = 0;
}
//---------------------------------------------------------------------------
CJSONparse::~CJSONparse()
{
// Destroy buffer
if (Buffer) {
delete Buffer;
}
}
//---------------------------------------------------------------------------
bool CJSONparse::LoadFile( const char * FilePath, int pBufLen )
{
TDataMember * RootObject = NULL;
// Validate
if (!FilePath || !FilePath[0]) {
Error = true;
sprintf( ErrorText, "No File path specified" );
return false;
}
// Open file
if (!(InputHandle = open( FilePath, O_RDONLY ))) {
Error = true;
sprintf( ErrorText, "Could not open file" );
return false;
}
// Load Buffer
CreateBuffer( pBufLen );
if (!FillBuffer()) {
Error = true;
sprintf( ErrorText, "Could not read from file" );
FreeBuffer();
return false;
}
// Reset values
LineNo = 1;
Error = false;
// Create Root object
DataTree->DeleteAll();
DataTree->GetParent( NULL, &RootObject );
Level = 0;
// Parse Root Object
SkipWhiteSpace();
if (!ParseObject( RootObject )) {
if (!Error) {
Error = true;
sprintf( ErrorText, "First entry in file must be an Object on line %d:%ld", LineNo, BufPos-LineMark );
}
FreeBuffer();
return false;
}
// Ensure remainder of file is empty
SkipWhiteSpace();
if (*BufPos != 0) {
Error = true;
sprintf( ErrorText, "No content expected after Root object on line %d:%ld", LineNo, BufPos-LineMark );
FreeBuffer();
return false;
}
// Success
close( InputHandle );
FreeBuffer();
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::CreateBuffer( int pBufLen )
{
// Validate
if (!pBufLen)
return false;
// Create buffer
Buffer = new CShiftBuffer( pBufLen );
// Reset markers
Buffer->PeekDirect( &BufPos, 0 );
BufEnd = BufPos;
LineMark = BufPos;
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::FillBuffer()
{
// Read from file
Buffer->ReadFromFD( InputHandle );
// Update Markers
Buffer->PeekDirect( &BufEnd, Buffer->Len() );
Buffer->PeekDirect( &BufPos, 0 );
LineMark = BufPos;
return true;
}
//---------------------------------------------------------------------------
void CJSONparse::FreeBuffer()
{
// Destroy buffer
if (Buffer) {
delete Buffer;
Buffer = NULL;
// Update Markers
BufEnd = NULL;
BufPos = NULL;
LineMark = NULL;
}
}
//---------------------------------------------------------------------------
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 )
{
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Check for opening quote
if (*BufPos != '"') {
return false;
}
// Mark start of quote
Mark = BufPos;
BufPos++;
// Check for closing quote
while ((BufPos = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" )))
{
if (*BufPos == '"') {
// End of string found
BufPos++;
break;
}
else if (!*BufPos) {
Error = true;
sprintf( ErrorText, "Expect closing '\"' for string on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
else if (*BufPos == '\\') {
if (*(BufPos+1) == 'u') {
for (EndMark = BufPos+2; EndMark < BufPos+6; EndMark++) {
if (!isxdigit( *EndMark )) {
Error = true;
sprintf( ErrorText, "Expect 4-digit hex value for escape value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
BufPos += 6;
}
else if (strchr( "bfnrt/\\\"", *(BufPos+1) )) {
BufPos += 2;
}
else {
Error = true;
sprintf( ErrorText, "Invalid escape sequence on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
else {
Error = true;
sprintf( ErrorText, "Un-escaped special character in string on line %d:%ld", LineNo, BufPos-LineMark );
return false;
}
}
// Validate size of Param name
Len = BufPos-Mark-2;
// Create Return value pointer
*Value = (char*)malloc( Len+1 );
memcpy( *Value, Mark+1, Len );
(*Value)[Len] = 0;
// Set other parameters
if (pType)
*pType = jtString;
if (pLen)
*pLen = Len;
// Success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ParsePrimitive( char ** Value, int * pLen, EDataType * pType )
{
char * Mark;
char * EndMark;
int Len;
// Clear value
Error = false;
*Value = NULL;
Len = 0;
// Mark start of value
Mark = BufPos;
// Get end of value
while ((*BufPos != 0) && !isspace(*BufPos) && (*BufPos != ',')) {
BufPos++;
}
// Check length of value
Len = BufPos - Mark;
if (!Len) {
Error = true;
sprintf( ErrorText, "Missing param value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
// 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" );
}
else if ((Len == 4) && !strncasecmp( Mark, "true", 4 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 5 );
strcpy( *Value, "true" );
}
else if ((Len == 5) && !strncasecmp( Mark, "false", 5 )) {
if (pType)
*pType = jtBool;
if (pLen)
*pLen = Len;
*Value = (char*)malloc( 6 );
strcpy( *Value, "false" );
}
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;
}
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;
}
else {
Error = true;
sprintf( ErrorText, "Invalid primitive param value on line %d:%ld", LineNo, Mark-LineMark );
return false;
}
}
}
// Success
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveFile( const char * FilePath, const int Indent )
{
TDataMember * RootObject;
// Validate
if (!FilePath || !FilePath[0])
return false;
// Open file
if (!(OutputHandle = open( FilePath, O_WRONLY )))
return false;
// Save Root object
Level = 0;
DataTree->GetParent( NULL, &RootObject );
SaveObject( RootObject, Indent );
// Close file
close( OutputHandle );
return false;
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveObject( TDataMember * Object, const int Indent )
{
TDataMember * Param;
// Opening brace
dprintf( OutputHandle, "{\n" );
// Extend spacer
Level++;
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
// Save parameters
for (Param = Object->FirstChild; Param != NULL; (Param = Param->Next))
{
// Write parameter name
dprintf( OutputHandle, "%s\"%s\": ", Spacer, Param->Name );
switch (Param->Type)
{
case jtNull :
dprintf( OutputHandle, "%s,\n", "null" );
break;
case jtBool :
case jtInt :
case jtFloat :
dprintf( OutputHandle, "%s,\n", Param->Value );
break;
case jtString :
dprintf( OutputHandle, "\"%s\",\n", Param->Value );
break;
case jtArray :
dprintf( OutputHandle, "[],\n" );
break;
case jtObject :
SaveObject( Param, Indent );
break;
}
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
Level--;
// Closing brace
if (Level == 0) {
dprintf( OutputHandle, "%s}\n", Spacer );
}
else {
dprintf( OutputHandle, "%s},\n", Spacer );
}
return false;
}
//---------------------------------------------------------------------------

80
JSONparseCore.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* JSONparseCore.h
*
* Created on: 5 Mar 2017
* Author: wentzelc
*/
#ifndef REDACORE_JSONPARSECORE_H_
#define REDACORE_JSONPARSECORE_H_
// redA Libraries
#include <BufferCore.h>
#include <DataTreeCore.h>
// Standard C/C++ Libraries
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
//---------------------------------------------------------------------------
class CJSONparse
{
private:
CDataTree * DataTree;
// File operation
int InputHandle;
int OutputHandle;
CShiftBuffer * Buffer;
// Parsing operation
char * BufEnd;
char * BufPos;
char * LineMark;
int LineNo;
int Level;
// Printing Operation
char Spacer[100];
int SpacerLen;
// Error
bool Error;
char ErrorText[100];
// File Buffer operation
bool CreateBuffer( int pBufLen );
bool FillBuffer();
void FreeBuffer();
// Parsing functions
inline void SkipWhiteSpace() {
while (isspace(*BufPos)) {
if (*BufPos == '\n') {
LineMark = BufPos;
LineNo++;
}
BufPos++;
}
}
bool ParseObject( TDataMember * Object );
bool ParseString( char ** Value, int * pLen = NULL, EDataType * pType = NULL );
bool ParsePrimitive( char ** Value, int * pLen = NULL, EDataType * pType = NULL );
bool SaveObject( TDataMember * Object, const int Indent );
public:
CJSONparse( CDataTree * pDataTree );
~CJSONparse();
bool LoadFile( const char * FilePath, int pBufLen = 500 );
bool SaveFile( const char * FilePath, const int ValueTab = 20 );
const char * GetError() { return ((Error)? ErrorText : "Success"); };
};
#endif /* REDACORE_JSONPARSECORE_H_ */