diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d9b8e8..72d4150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,3 @@ 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) diff --git a/ConfigCore.cpp b/ConfigCore.cpp deleted file mode 100644 index 2e74cd7..0000000 --- a/ConfigCore.cpp +++ /dev/null @@ -1,942 +0,0 @@ -/* - * ConfigCore.cpp - * - * Created on: 5 Mar 2017 - * Author: wentzelc - */ - -// redA Libraries -#include "ConfigCore.h" - -// Standard C/C++ Libraries -#include -#include -#include -#include -#include - -//--------------------------------------------------------------------------- - -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; -} -//--------------------------------------------------------------------------- - diff --git a/ConfigCore.h b/ConfigCore.h deleted file mode 100644 index e56bcf8..0000000 --- a/ConfigCore.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * ConfigCore.h - * - * Created on: 5 Mar 2017 - * Author: wentzelc - */ - -#ifndef REDACORE_CONFIGCORE_H_ -#define REDACORE_CONFIGCORE_H_ - -// redA Libraries -#include - -// Standard C/C++ Libraries -#include -#include -#include -#include - -//--------------------------------------------------------------------------- - -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_ */ diff --git a/DataTreeCore.cpp b/DataTreeCore.cpp new file mode 100644 index 0000000..2c59f26 --- /dev/null +++ b/DataTreeCore.cpp @@ -0,0 +1,470 @@ +/* + * DataTreeCore.cpp + * + * Created on: 5 Mar 2017 + * Author: wentzelc + */ + +// redA Libraries +#include "DataTreeCore.h" + +// Standard C/C++ Libraries +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------- + +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; + } +} +//--------------------------------------------------------------------------- + diff --git a/DataTreeCore.h b/DataTreeCore.h new file mode 100644 index 0000000..d9d7e08 --- /dev/null +++ b/DataTreeCore.h @@ -0,0 +1,83 @@ +/* + * DataTreeCore.h + * + * Created on: 5 Mar 2017 + * Author: wentzelc + */ + +#ifndef REDACORE_DATATREECORE_H_ +#define REDACORE_DATATREECORE_H_ + +// redA Libraries +#include + +// Standard C/C++ Libraries +#include +#include +#include +#include + +//--------------------------------------------------------------------------- + +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_ */ diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp new file mode 100644 index 0000000..600a69a --- /dev/null +++ b/JSONparseCore.cpp @@ -0,0 +1,515 @@ +/* + * JSONparseCore.cpp + * + * Created on: 5 Mar 2017 + * Author: wentzelc + */ + +// redA Libraries +#include "JSONparseCore.h" + +// Standard C/C++ Libraries +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------- + +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; +} +//--------------------------------------------------------------------------- + diff --git a/JSONparseCore.h b/JSONparseCore.h new file mode 100644 index 0000000..6f0d3f7 --- /dev/null +++ b/JSONparseCore.h @@ -0,0 +1,80 @@ +/* + * JSONparseCore.h + * + * Created on: 5 Mar 2017 + * Author: wentzelc + */ + +#ifndef REDACORE_JSONPARSECORE_H_ +#define REDACORE_JSONPARSECORE_H_ + +// redA Libraries +#include +#include + +// Standard C/C++ Libraries +#include +#include +#include +#include + +//--------------------------------------------------------------------------- + +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_ */