- Implemented full support for multi-layer objects - Implemented RootObject for all other elements - Added method CreateParam() - Converted GetParam methods from inline to normal methods - Added GetParent method - Use Object->Len to count no of child objects
951 lines
24 KiB
C++
951 lines
24 KiB
C++
/*
|
|
* 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>
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
CConfigCore::CConfigCore()
|
|
{
|
|
// Parameter tree
|
|
RootObject = CreateParam( NULL );
|
|
RootObject->Type = jtObject;
|
|
|
|
// File Operation
|
|
InputFile = NULL;
|
|
OutputFile = NULL;
|
|
BufLen = 500;
|
|
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 (!(InputFile = fopen( FilePath, "r" ))) {
|
|
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
|
|
fclose( InputFile );
|
|
FreeBuffer();
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CConfigCore::CreateBuffer( int pBufLen )
|
|
{
|
|
// Validate
|
|
if (!pBufLen)
|
|
return false;
|
|
|
|
// Create buffer
|
|
BufLen = pBufLen;
|
|
Buffer = (char*)malloc( BufLen+1 );
|
|
|
|
// Reset markers
|
|
BufEnd = Buffer;
|
|
*BufEnd = 0;
|
|
BufPos = Buffer;
|
|
LineMark = Buffer;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CConfigCore::FillBuffer()
|
|
{
|
|
int BufCount = 0;
|
|
|
|
// Read from file
|
|
BufCount = fread( Buffer, 1, BufLen, InputFile );
|
|
if (BufCount < 1) {
|
|
return false;
|
|
}
|
|
|
|
// Update Markers
|
|
BufEnd = Buffer + BufCount;
|
|
*BufEnd = 0;
|
|
BufPos = Buffer;
|
|
LineMark = Buffer;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CConfigCore::FreeBuffer()
|
|
{
|
|
// Destroy buffer
|
|
if (Buffer) {
|
|
free( Buffer );
|
|
Buffer = NULL;
|
|
|
|
// Update Markers
|
|
BufEnd = NULL;
|
|
BufPos = NULL;
|
|
LineMark = NULL;
|
|
}
|
|
BufLen = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
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 (!(OutputFile = fopen( FilePath, "w" )))
|
|
return false;
|
|
|
|
// Save Root object
|
|
Level = 0;
|
|
SaveObject( RootObject, Indent );
|
|
|
|
// Close file
|
|
fclose( OutputFile );
|
|
return false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CConfigCore::SaveObject( TConfigParam * Object, const int Indent )
|
|
{
|
|
TConfigParam * Param;
|
|
|
|
// Opening brace
|
|
fprintf( OutputFile, "{\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
|
|
fprintf( OutputFile, "%s\"%s\": ", Spacer, Param->Name );
|
|
|
|
switch (Param->Type)
|
|
{
|
|
case jtNull :
|
|
fprintf( OutputFile, "%s,\n", "null" );
|
|
break;
|
|
|
|
case jtBool :
|
|
case jtInt :
|
|
case jtFloat :
|
|
fprintf( OutputFile, "%s,\n", Param->Value );
|
|
break;
|
|
|
|
case jtString :
|
|
fprintf( OutputFile, "\"%s\",\n", Param->Value );
|
|
break;
|
|
|
|
case jtArray :
|
|
fprintf( OutputFile, "[],\n" );
|
|
break;
|
|
|
|
case jtObject :
|
|
SaveObject( Param, Indent );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Shorten spacer
|
|
SpacerLen -= 2;
|
|
Spacer[SpacerLen] = 0;
|
|
Level--;
|
|
|
|
// Closing brace
|
|
if (Level == 0) {
|
|
fprintf( OutputFile, "%s}\n", Spacer );
|
|
}
|
|
else {
|
|
fprintf( OutputFile, "%s},\n", Spacer );
|
|
}
|
|
return false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|