Major Update:

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

View File

@@ -794,7 +794,7 @@ int CShiftBuffer::ReadFromFD( int Handle, int MaxRead )
} }
// Read file descriptor into buffer // Read file descriptor into buffer
DataRemain = (MaxRead > BufSize-BufLen)? BufSize-BufLen : MaxRead; DataRemain = ((MaxRead < 0) || (MaxRead > BufSize-BufLen))? BufSize-BufLen : MaxRead;
while (DataRemain) while (DataRemain)
{ {
// Read from file descriptor // Read from file descriptor

View File

@@ -20,8 +20,8 @@
CDataTree::CDataTree() CDataTree::CDataTree()
{ {
// Create Root member of tree // Create Root member of tree
RootObject = CreateMember( NULL ); RootMember = CreateMember( NULL );
RootObject->Type = jtObject; RootMember->Type = jtObject;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -29,7 +29,7 @@ CDataTree::~CDataTree()
{ {
// Destroy Members // Destroy Members
DeleteAll(); DeleteAll();
DestroyMember( &RootObject ); DestroyMember( &RootMember );
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -47,6 +47,28 @@ TDataMember * CDataTree::CreateMember( const char * Name )
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::AddMember( TDataMember * Parent, TDataMember * Member )
{
TDataMember ** Child;
// Validate
if (!Parent || !Member) {
return false;
}
// Get end of list
Child = &(Parent->FirstChild);
while (*Child) {
Child = &((*Child)->Next);
}
// Add member
*Child = Member;
Parent->Len++;
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::DestroyMember( TDataMember ** Member ) bool CDataTree::DestroyMember( TDataMember ** Member )
{ {
TDataMember * NextMember; TDataMember * NextMember;
@@ -76,101 +98,168 @@ bool CDataTree::DestroyMember( TDataMember ** Member )
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::GetParent( const char * ParentPath, TDataMember **Parent ) bool CDataTree::DestroyValue( TDataMember * Member )
{ {
TDataMember * Member; // Valdate
char * ParentName; if (!Member)
char * Pos;
// Validate
if (!Parent) {
return false; return false;
// Destroy values
if (Member->Value) {
free( Member->Value );
Member->Value = NULL;
} }
while (Member->FirstChild) {
// Set first Parent DestroyMember( &(Member->FirstChild) );
*Parent = RootObject; }
Member->Len = 0;
// Check if path provided
if (!ParentPath || !*ParentPath) {
return true; return true;
} }
//---------------------------------------------------------------------------
TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent )
{
char * WorkPath = NULL;
TDataMember * Member;
TDataMember ** Child = NULL;
char * Pos;
char * EndPos;
char * MemberName;
int Index;
int Count;
bool Last = false;
// Validate
if (!Path || !*Path) {
if (Parent) *Parent = NULL;
return NULL;
}
WorkPath = (char*)malloc( strlen(Path)+1 );
strcpy( WorkPath, Path );
// Set init references
if (Parent) *Parent = NULL;
Child = NULL;
Member = (BaseMember)? BaseMember : RootMember;
// Split path // Split path
Pos = (char*)ParentPath; Pos = (char*)WorkPath;
while (*Pos) while (Member && *Pos)
{ {
// Set Name start // Reset Child reference
ParentName = Pos; Child = NULL;
// Find delimeter // Set Name start
while (*Pos && (*Pos != '/')) { MemberName = Pos;
Pos++;
// Find delimiter
if (*Pos == '[')
{
// Validate
if (Create && (Member->Type == jtNull)) {
Member->Type = jtArray; // Convert to array
}
if (Member->Type != jtArray) {
break; // Can't convert something else to an array
} }
// Get Index value
Pos++;
while (*Pos && (*Pos != ']')) {
Pos++;
}
if (*Pos != ']') {
break;
}
Index = (int)strtoul( Pos, &EndPos, 10 );
if (EndPos != Pos) {
break;
}
Pos++;
if (!*Pos) {
// Last element
Last = true;
}
// Find next parent
Child = &(Member->FirstChild);
Count = 0;
while (*Child && (Count < Index)) {
Child = &((*Child)->Next);
Count++;
}
if (!*Child && Create) {
if (!Index || (Index = Count + 1)) {
*Child = CreateMember( NULL );
Member->Value++;
}
}
}
else
{
// Validate
if (Create && (Member->Type == jtNull)) {
Member->Type = jtObject; // Convert to object
}
if (Member->Type != jtObject) {
break; // Can't convert something else to an object
}
// Get key value
while (*Pos && (*Pos != '/') && (*Pos != '[')) {
Pos++;
}
if (!*Pos) {
// Last element
Last = true;
}
else {
// Zero terminate name // Zero terminate name
if (*Pos) {
*Pos = 0; *Pos = 0;
Pos++; Pos++;
} }
// Find next parent // Find next parent
Member = (*Parent)->FirstChild; Child = &(Member->FirstChild);
while (Member && strcasecmp( Member->Name, ParentName )) { while (*Child && strcasecmp( (*Child)->Name, MemberName )) {
Member = Member->Next; Child = &((*Child)->Next);
}
if (!*Child && Create) {
*Child = CreateMember( MemberName );
Member->Len++;
} }
if (!Member) {
return false;
} }
// Set Next parent // Set Parent
if (Last && Parent) {
*Parent = Member; *Parent = Member;
} }
return true;
// Next level
Member = *Child;
}
return Child;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
TDataMember * CDataTree::GetMember( TDataMember * Parent, const char * Name ) TDataMember * CDataTree::GetMember( TDataMember * BaseMember, const char * Path, bool Create )
{
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; TDataMember ** Member;
// Validate // Get Child
if (!Parent || !Name || !*Name) { Member = GetMemberPtr( BaseMember, Path, Create );
return NULL; return *Member;
}
// 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 ) bool CDataTree::Delete( TDataMember * BaseMember, const char * Path )
{ {
TDataMember * Parent; TDataMember * Parent;
TDataMember ** Member; TDataMember ** Member;
// Check if exists // Check if exists
if (!GetParent( ParentPath, &Parent ) || if (!(Member = GetMemberPtr( BaseMember, Path, false, &Parent ))) {
!(Member = GetMemberPtr( Parent, Name ))) {
return false; return false;
} }
@@ -183,224 +272,179 @@ bool CDataTree::Delete( const char * ParentPath, const char * Name )
bool CDataTree::DeleteAll() bool CDataTree::DeleteAll()
{ {
while (RootObject->FirstChild) { // Delete all except root member
DestroyMember( &(RootObject->FirstChild) ); while (RootMember->FirstChild) {
DestroyMember( &(RootMember->FirstChild) );
} }
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetMember( TDataMember * Member, EDataType Type, const char * Value, const int Len ) bool CDataTree::SetValuePtr( TDataMember * Member, EDataType Type, char * Value, int Len )
{ {
// Clear previous value // Clear previous value
if (Member->Value != NULL) { if (Member->Value != NULL) {
free( Member->Value ); DestroyValue( Member );
} }
// Set type // Set type
Member->Type = Type; Member->Type = Type;
Member->Value = Value;
Member->Len = Len;
return true;
}
//---------------------------------------------------------------------------
// Set new value bool CDataTree::SetValue( TDataMember * Member, EDataType Type, const char * Value, const int Len )
switch (Type) { {
case jtNull: char * NewValue = NULL;
case jtObject:
case jtArray:
Member->Len = 0;
Member->Value = NULL;
break;
case jtString: if ((Type == jtString) || (Type == jtFloat) || (Type == jtInt) || (Type == jtBool))
case jtFloat: {
case jtInt: // Create copy of value
case jtBool: NewValue = (char *)malloc( sizeof(Member->Len+1) );
Member->Len = (Len == -1)? strlen(Value) : Len;
Member->Value = (char *)malloc( sizeof(Member->Len+1) );
if (Value) { if (Value) {
memcpy( Member->Value, Value, Member->Len+1 ); memcpy( NewValue, Value, Len );
} else { } else {
memset( Member->Value, 0, Member->Len+1 ); memset( NewValue, 0, Len );
} }
Member->Value[Member->Len] = 0; NewValue[Len] = 0;
break; SetValuePtr( Member, Type, NewValue, Len );
}
else {
// Set null value
SetValuePtr( Member, Type, NULL, 0 );
} }
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetObject( const char * ParentPath, const char * Name ) bool CDataTree::SetObject( TDataMember * BaseMember, const char * Path )
{ {
TDataMember * Parent; TDataMember * Member;
TDataMember ** Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if (!(Member = GetMember( BaseMember, Path, true ))) {
return false; return false;
} }
SetValue( Member, jtObject, NULL, -1 );
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtObject, NULL, -1 );
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetStr( const char * ParentPath, const char * Name, const char * Value, const int Len ) bool CDataTree::SetStr( TDataMember * BaseMember, const char * Path, const char * Value, const int Len )
{ {
TDataMember * Parent; TDataMember * Member;
TDataMember ** Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if (!(Member = GetMember( BaseMember, Path, true ))) {
return false; return false;
} }
SetValue( Member, jtString, Value, Len );
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
SetMember( *Member, jtString, Value, Len );
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetInt( const char * ParentPath, const char * Name, const long Value ) bool CDataTree::SetInt( TDataMember * BaseMember, const char * Path, const long Value )
{ {
TDataMember * Parent; TDataMember * Member;
TDataMember ** Member; char ValueStr[20];
char ValueStr[50];
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if (!(Member = GetMember( BaseMember, Path, true ))) {
return false; return false;
} }
// Create new param if it doesn't exist
if (!(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
sprintf( ValueStr, "%ld", Value ); sprintf( ValueStr, "%ld", Value );
SetMember( *Member, jtInt, ValueStr, -1 ); SetValue( Member, jtInt, ValueStr, -1 );
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetFloat( const char * ParentPath, const char * Name, const double Value ) bool CDataTree::SetFloat( TDataMember * BaseMember, const char * Path, const double Value )
{ {
TDataMember * Parent; TDataMember * Member;
TDataMember ** Member; char ValueStr[20];
char ValueStr[50];
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if (!(Member = GetMember( BaseMember, Path, true ))) {
return false; return false;
} }
// Create new param if it doesn't exist
if (!*(Member = GetMemberPtr( Parent, Name ))) {
*Member = CreateMember( Name );
}
sprintf( ValueStr, "%lf", Value ); sprintf( ValueStr, "%lf", Value );
SetMember( *Member, jtFloat, ValueStr, -1 ); SetValue( Member, jtFloat, ValueStr, -1 );
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CDataTree::SetBool( const char * ParentPath, const char * Name, const bool Value ) bool CDataTree::SetBool( TDataMember * BaseMember, const char * Path, 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; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if (!(Member = GetMember( BaseMember, Path, true ))) {
return false;
}
SetValue( Member, jtBool, ((Value == 0)? "0" : "1"), -1 );
return true;
}
//---------------------------------------------------------------------------
bool CDataTree::SetNull( TDataMember * BaseMember, const char * Path )
{
TDataMember * Member;
// Validate
if (!(Member = GetMember( BaseMember, Path, true ))) {
return false;
}
SetValue( Member, jtNull, NULL, -1 );
return true;
}
//---------------------------------------------------------------------------
EDataType CDataTree::GetType( TDataMember * BaseMember, const char * Path )
{
TDataMember * Member;
// Validate
if (!(Member = GetMember( BaseMember, Path, false ))) {
return jtNull; return jtNull;
} }
// Return type
if ((Member = GetMember( Parent, Name ))) {
return Member->Type; return Member->Type;
} }
else {
return jtNull;
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const char * CDataTree::GetStr( const char * ParentPath, const char * Name, const char * Default ) const char * CDataTree::GetStr( TDataMember * BaseMember, const char * Path, const char * Default, bool Create )
{ {
TDataMember * Parent;
TDataMember * Member; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtString)) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) {
return Member->Value; return Member->Value;
} }
else if (Member && Create && (Member->Type == jtNull)) {
SetValue( Member, jtString, Default, strlen(Default) );
return Default;
}
else { else {
return Default; return Default;
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const char * CDataTree::GetStr( const char * ParentPath, const char * Name, int &Len, const char * Default ) const char * CDataTree::GetStr( TDataMember * BaseMember, const char * Path, int &Len, const char * Default, bool Create )
{ {
TDataMember * Parent;
TDataMember * Member; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtString)) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) {
Len = Member->Len; Len = Member->Len;
return Member->Value; return Member->Value;
} }
else if (Member && Create && (Member->Type == jtNull)) {
SetValue( Member, jtString, Default, strlen(Default) );
Len = Member->Len;
return Default;
}
else { else {
Len = strlen( Default ); Len = strlen( Default );
return Default; return Default;
@@ -408,60 +452,58 @@ const char * CDataTree::GetStr( const char * ParentPath, const char * Name, int
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const long CDataTree::GetInt( const char * ParentPath, const char * Name, long Default ) const long CDataTree::GetInt( TDataMember * BaseMember, const char * Path, long Default, bool Create )
{ {
TDataMember * Parent;
TDataMember * Member; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtInt)) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtInt)) {
return strtol( Member->Value, NULL, 10 ); return strtol( Member->Value, NULL, 10 );
} }
else if (Member && Create && (Member->Type == jtNull)) {
char TempStr[20];
sprintf( TempStr, "%ld", Default );
SetValue( Member, jtInt, TempStr, strlen(TempStr) );
return Default;
}
else { else {
return Default; return Default;
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const double CDataTree::GetFloat( const char * ParentPath, const char * Name, double Default ) const double CDataTree::GetFloat( TDataMember * BaseMember, const char * Path, double Default, bool Create )
{ {
TDataMember * Parent;
TDataMember * Member; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtFloat)) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtFloat)) {
return strtod( Member->Value, NULL ); return strtod( Member->Value, NULL );
} }
else if (Member && Create && (Member->Type == jtNull)) {
char TempStr[20];
sprintf( TempStr, "%lf", Default );
SetValue( Member, jtInt, TempStr, strlen(TempStr) );
return Default;
}
else { else {
return Default; return Default;
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const bool CDataTree::GetBool( const char * ParentPath, const char * Name, bool Default ) const bool CDataTree::GetBool( TDataMember * BaseMember, const char * Path, bool Default, bool Create )
{ {
TDataMember * Parent;
TDataMember * Member; TDataMember * Member;
// Validate // Validate
if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtBool)) {
return Default;
}
// Return value
if ((Member = GetMember( Parent, Name )) && (Member->Type == jtBool)) {
return ((!strcasecmp( Member->Value, "0" ))? false : true ); return ((!strcasecmp( Member->Value, "0" ))? false : true );
} }
else if (Member && Create && (Member->Type == jtNull)) {
SetValue( Member, jtInt, ((Default)? "1" : "0"), 1 );
return Default;
}
else { else {
return Default; return Default;
} }

View File

@@ -43,41 +43,46 @@ struct SDataMember
class CDataTree class CDataTree
{ {
private: private:
TDataMember * RootObject; TDataMember * RootMember;
// Manage Members // Manage Members
TDataMember * CreateMember( const char * Name ); TDataMember * CreateMember( const char * Name );
bool AddMember( TDataMember * Parent, TDataMember * Member );
bool DestroyMember( TDataMember ** Member ); bool DestroyMember( TDataMember ** Member );
bool DestroyValue( TDataMember * Member );
// Find Member // Find Member
bool GetParent( const char * ParentPath, TDataMember **Parent ); TDataMember * GetRootMember() { return RootMember; };
TDataMember * GetMember( TDataMember * Parent, const char * Name ); TDataMember ** GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent = NULL );
TDataMember ** GetMemberPtr( TDataMember * Parent, const char * Name );
// Set Member value // Set Member value
bool SetMember( TDataMember * Member, EDataType Type, const char * Value, const int Len ); bool SetValue( TDataMember * Member, EDataType Type, const char * Value, const int Len );
bool SetValuePtr( TDataMember * Member, EDataType Type, char * Value, int Len );
public: public:
CDataTree(); CDataTree();
~CDataTree(); ~CDataTree();
bool SetObject( const char * ParentPath, const char * Name ); EDataType GetType( TDataMember * BaseMember, const char * Path );
bool SetStr( const char * ParentPath, const char * Name, const char * Value = NULL, const int Len = -1 ); // Use Len param if Value contains NULL values TDataMember * GetMember( TDataMember * BaseMember, const char * Path, bool Create = false );
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( TDataMember * BaseMember, const char * Path, const char * Default = NULL, bool Create = false );
const char * GetStr( TDataMember * BaseMember, const char * Path, int &Len, const char * Default = NULL, bool Create = false );
const long GetInt( TDataMember * BaseMember, const char * Path, long Default = 0, bool Create = false );
const double GetFloat( TDataMember * BaseMember, const char * Path, double Default = 0.0, bool Create = false );
const bool GetBool( TDataMember * BaseMember, const char * Path, bool Default = false, bool Create = false );
const char * GetStr( const char * ParentPath, const char * Name, const char * Default = NULL ); bool SetObject( TDataMember * BaseMember, const char * Path );
const char * GetStr( const char * ParentPath, const char * Name, int &Len, const char * Default = NULL ); bool SetStr( TDataMember * BaseMember, const char * Path, const char * Value = NULL, const int Len = -1 ); // Use Len param if Value contains NULL values
const long GetInt( const char * ParentPath, const char * Name, long Default = 0 ); bool SetInt( TDataMember * BaseMember, const char * Path, const long Value );
const double GetFloat( const char * ParentPath, const char * Name, double Default = 0.0 ); bool SetFloat( TDataMember * BaseMember, const char * Path, const double Value );
const bool GetBool( const char * ParentPath, const char * Name, bool Default = false ); bool SetBool( TDataMember * BaseMember, const char * Path, const bool Value );
bool SetNull( TDataMember * BaseMember, const char * Path );
bool Delete( const char * ParentPath, const char * Name ); bool Delete( TDataMember * BaseMember, const char * Path );
bool DeleteAll(); bool DeleteAll();
friend class CJSONparse;
}; };
#endif /* REDACORE_DATATREECORE_H_ */ #endif /* REDACORE_DATATREECORE_H_ */

View File

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

View File

@@ -61,18 +61,23 @@ private:
BufPos++; BufPos++;
} }
} }
bool ParseString( char ** Value, int &pLen );
bool ParseObject( TDataMember * Object ); bool ParseObject( TDataMember * Object );
bool ParseString( char ** Value, int * pLen = NULL, EDataType * pType = NULL ); bool ParseArray( TDataMember * Array );
bool ParsePrimitive( char ** Value, int * pLen = NULL, EDataType * pType = NULL ); bool ParseString( TDataMember * Member );
bool ParsePrimitive( TDataMember * Member );
bool SaveObject( TDataMember * Object, const int Indent ); bool PrintObject( TDataMember * Object, const int Indent );
bool PrintArray( TDataMember * Object, const int Indent );
public: public:
CJSONparse( CDataTree * pDataTree ); CJSONparse( CDataTree * pDataTree );
~CJSONparse(); ~CJSONparse();
bool LoadFile( const char * FilePath, int pBufLen = 500 ); bool PrintToScreen( const int Indent );
bool SaveFile( const char * FilePath, const int ValueTab = 20 );
bool LoadFromFile( const char * FilePath, int pBufLen = 500 );
bool SaveToFile( const char * FilePath, const int Indent = 2 );
const char * GetError() { return ((Error)? ErrorText : "Success"); }; const char * GetError() { return ((Error)? ErrorText : "Success"); };
}; };