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:
@@ -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)
|
||||||
|
|||||||
942
ConfigCore.cpp
942
ConfigCore.cpp
@@ -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;
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
130
ConfigCore.h
130
ConfigCore.h
@@ -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
470
DataTreeCore.cpp
Normal 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
83
DataTreeCore.h
Normal 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
515
JSONparseCore.cpp
Normal 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
80
JSONparseCore.h
Normal 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_ */
|
||||||
Reference in New Issue
Block a user