From a22f60b152ff749d6f8ecfdcf9807fd7b9aa578e Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Sun, 26 Mar 2017 22:26:52 +0200 Subject: [PATCH] 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 --- BufferCore.cpp | 2 +- DataTreeCore.cpp | 498 ++++++++++++++++++++++++--------------------- DataTreeCore.h | 41 ++-- JSONparseCore.cpp | 508 ++++++++++++++++++++++++++++++---------------- JSONparseCore.h | 15 +- 5 files changed, 640 insertions(+), 424 deletions(-) diff --git a/BufferCore.cpp b/BufferCore.cpp index 86c1967..c6bdf60 100644 --- a/BufferCore.cpp +++ b/BufferCore.cpp @@ -794,7 +794,7 @@ int CShiftBuffer::ReadFromFD( int Handle, int MaxRead ) } // Read file descriptor into buffer - DataRemain = (MaxRead > BufSize-BufLen)? BufSize-BufLen : MaxRead; + DataRemain = ((MaxRead < 0) || (MaxRead > BufSize-BufLen))? BufSize-BufLen : MaxRead; while (DataRemain) { // Read from file descriptor diff --git a/DataTreeCore.cpp b/DataTreeCore.cpp index 2c59f26..8b3c103 100644 --- a/DataTreeCore.cpp +++ b/DataTreeCore.cpp @@ -20,8 +20,8 @@ CDataTree::CDataTree() { // Create Root member of tree - RootObject = CreateMember( NULL ); - RootObject->Type = jtObject; + RootMember = CreateMember( NULL ); + RootMember->Type = jtObject; } //--------------------------------------------------------------------------- @@ -29,7 +29,7 @@ CDataTree::~CDataTree() { // Destroy Members 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 ) { 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; - char * ParentName; - char * Pos; - - // Validate - if (!Parent) { + // Valdate + if (!Member) return false; + + // Destroy values + if (Member->Value) { + free( Member->Value ); + Member->Value = NULL; } - - // 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; + while (Member->FirstChild) { + DestroyMember( &(Member->FirstChild) ); } + Member->Len = 0; return true; } //--------------------------------------------------------------------------- -TDataMember * CDataTree::GetMember( TDataMember * Parent, const char * Name ) +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 (!Parent || !Name || !*Name) { + if (!Path || !*Path) { + if (Parent) *Parent = NULL; return NULL; } + WorkPath = (char*)malloc( strlen(Path)+1 ); + strcpy( WorkPath, Path ); - // Get Member - Member = Parent->FirstChild; - while (Member && strcasecmp( Member->Name, Name )) - Member = Member->Next; - return Member; + // Set init references + if (Parent) *Parent = NULL; + Child = NULL; + Member = (BaseMember)? BaseMember : RootMember; + + // Split path + Pos = (char*)WorkPath; + while (Member && *Pos) + { + // Reset Child reference + Child = NULL; + + // Set Name start + MemberName = 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 + *Pos = 0; + Pos++; + } + + // Find next parent + Child = &(Member->FirstChild); + while (*Child && strcasecmp( (*Child)->Name, MemberName )) { + Child = &((*Child)->Next); + } + if (!*Child && Create) { + *Child = CreateMember( MemberName ); + Member->Len++; + } + } + + // Set Parent + if (Last && Parent) { + *Parent = Member; + } + + // Next level + Member = *Child; + } + + return Child; } //--------------------------------------------------------------------------- -TDataMember ** CDataTree::GetMemberPtr( 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; + // Get Child + Member = GetMemberPtr( BaseMember, Path, Create ); + return *Member; } //--------------------------------------------------------------------------- -bool CDataTree::Delete( const char * ParentPath, const char * Name ) +bool CDataTree::Delete( TDataMember * BaseMember, const char * Path ) { TDataMember * Parent; TDataMember ** Member; // Check if exists - if (!GetParent( ParentPath, &Parent ) || - !(Member = GetMemberPtr( Parent, Name ))) { + if (!(Member = GetMemberPtr( BaseMember, Path, false, &Parent ))) { return false; } @@ -183,224 +272,179 @@ bool CDataTree::Delete( const char * ParentPath, const char * Name ) bool CDataTree::DeleteAll() { - while (RootObject->FirstChild) { - DestroyMember( &(RootObject->FirstChild) ); + // Delete all except root member + while (RootMember->FirstChild) { + DestroyMember( &(RootMember->FirstChild) ); } 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 if (Member->Value != NULL) { - free( Member->Value ); + DestroyValue( Member ); } // 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; - } - + Member->Type = Type; + Member->Value = Value; + Member->Len = Len; return true; } //--------------------------------------------------------------------------- -bool CDataTree::SetObject( const char * ParentPath, const char * Name ) +bool CDataTree::SetValue( TDataMember * Member, EDataType Type, const char * Value, const int Len ) { - TDataMember * Parent; - TDataMember ** Member; + char * NewValue = NULL; - // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return false; + if ((Type == jtString) || (Type == jtFloat) || (Type == jtInt) || (Type == jtBool)) + { + // Create copy of value + NewValue = (char *)malloc( sizeof(Member->Len+1) ); + if (Value) { + memcpy( NewValue, Value, Len ); + } else { + memset( NewValue, 0, Len ); + } + NewValue[Len] = 0; + SetValuePtr( Member, Type, NewValue, Len ); } - - // Create new param if it doesn't exist - if (!(Member = GetMemberPtr( Parent, Name ))) { - *Member = CreateMember( Name ); + else { + // Set null value + SetValuePtr( Member, Type, NULL, 0 ); } - SetMember( *Member, jtObject, NULL, -1 ); return true; } //--------------------------------------------------------------------------- -bool CDataTree::SetStr( const char * ParentPath, const char * Name, const char * Value, const int Len ) +bool CDataTree::SetObject( TDataMember * BaseMember, const char * Path ) { - TDataMember * Parent; - TDataMember ** Member; + TDataMember * Member; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { + if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } - - // Create new param if it doesn't exist - if (!(Member = GetMemberPtr( Parent, Name ))) { - *Member = CreateMember( Name ); - } - SetMember( *Member, jtString, Value, Len ); + SetValue( Member, jtObject, NULL, -1 ); return true; } //--------------------------------------------------------------------------- -bool CDataTree::SetInt( const char * ParentPath, const char * Name, const long Value ) +bool CDataTree::SetStr( TDataMember * BaseMember, const char * Path, const char * Value, const int Len ) { - TDataMember * Parent; - TDataMember ** Member; - char ValueStr[50]; + TDataMember * Member; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { + if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } + SetValue( Member, jtString, Value, Len ); + return true; +} +//--------------------------------------------------------------------------- - // Create new param if it doesn't exist - if (!(Member = GetMemberPtr( Parent, Name ))) { - *Member = CreateMember( Name ); +bool CDataTree::SetInt( TDataMember * BaseMember, const char * Path, const long Value ) +{ + TDataMember * Member; + char ValueStr[20]; + + // Validate + if (!(Member = GetMember( BaseMember, Path, true ))) { + return false; } sprintf( ValueStr, "%ld", Value ); - SetMember( *Member, jtInt, ValueStr, -1 ); + SetValue( Member, jtInt, ValueStr, -1 ); 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; - char ValueStr[50]; + TDataMember * Member; + char ValueStr[20]; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { + if (!(Member = GetMember( BaseMember, Path, true ))) { 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 ); + SetValue( Member, jtFloat, ValueStr, -1 ); 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; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return jtNull; - } - - // Return type - if ((Member = GetMember( Parent, Name ))) { - return Member->Type; - } - else { - return jtNull; + if (!(Member = GetMember( BaseMember, Path, true ))) { + return false; } + SetValue( Member, jtBool, ((Value == 0)? "0" : "1"), -1 ); + return true; } //--------------------------------------------------------------------------- -const char * CDataTree::GetStr( const char * ParentPath, const char * Name, const char * Default ) +bool CDataTree::SetNull( TDataMember * BaseMember, const char * Path ) { - TDataMember * Parent; TDataMember * Member; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return Default; + if (!(Member = GetMember( BaseMember, Path, true ))) { + return false; } + SetValue( Member, jtNull, NULL, -1 ); + return true; +} +//--------------------------------------------------------------------------- - // Return value - if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) { +EDataType CDataTree::GetType( TDataMember * BaseMember, const char * Path ) +{ + TDataMember * Member; + + // Validate + if (!(Member = GetMember( BaseMember, Path, false ))) { + return jtNull; + } + return Member->Type; +} +//--------------------------------------------------------------------------- + +const char * CDataTree::GetStr( TDataMember * BaseMember, const char * Path, const char * Default, bool Create ) +{ + TDataMember * Member; + + // Validate + if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtString)) { return Member->Value; } + else if (Member && Create && (Member->Type == jtNull)) { + SetValue( Member, jtString, Default, strlen(Default) ); + return Default; + } else { 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; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return Default; - } - - // Return value - if ((Member = GetMember( Parent, Name )) && (Member->Type == jtString)) { + if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtString)) { Len = Member->Len; return Member->Value; } + else if (Member && Create && (Member->Type == jtNull)) { + SetValue( Member, jtString, Default, strlen(Default) ); + Len = Member->Len; + return Default; + } else { Len = strlen( 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; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return Default; - } - - // Return value - if ((Member = GetMember( Parent, Name )) && (Member->Type == jtInt)) { + if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtInt)) { 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 { 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; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return Default; - } - - // Return value - if ((Member = GetMember( Parent, Name )) && (Member->Type == jtFloat)) { + if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtFloat)) { 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 { 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; // Validate - if (!Name || !*Name || !GetParent( ParentPath, &Parent )) { - return Default; - } - - // Return value - if ((Member = GetMember( Parent, Name )) && (Member->Type == jtBool)) { + if ((Member = GetMember( BaseMember, Path, Create )) && (Member->Type == jtBool)) { return ((!strcasecmp( Member->Value, "0" ))? false : true ); } + else if (Member && Create && (Member->Type == jtNull)) { + SetValue( Member, jtInt, ((Default)? "1" : "0"), 1 ); + return Default; + } else { return Default; } diff --git a/DataTreeCore.h b/DataTreeCore.h index d9d7e08..27a0540 100644 --- a/DataTreeCore.h +++ b/DataTreeCore.h @@ -43,41 +43,46 @@ struct SDataMember class CDataTree { private: - TDataMember * RootObject; + TDataMember * RootMember; // Manage Members TDataMember * CreateMember( const char * Name ); + bool AddMember( TDataMember * Parent, TDataMember * Member ); bool DestroyMember( TDataMember ** Member ); + bool DestroyValue( 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 ); + TDataMember * GetRootMember() { return RootMember; }; + TDataMember ** GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent = NULL ); // 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: 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 ); + EDataType GetType( TDataMember * BaseMember, const char * Path ); + TDataMember * GetMember( TDataMember * BaseMember, const char * Path, bool Create = false ); - 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 ); - 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 SetObject( TDataMember * BaseMember, const char * Path ); + bool SetStr( TDataMember * BaseMember, const char * Path, const char * Value = NULL, const int Len = -1 ); // Use Len param if Value contains NULL values + bool SetInt( TDataMember * BaseMember, const char * Path, const long Value ); + bool SetFloat( TDataMember * BaseMember, const char * Path, const double Value ); + 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(); + + friend class CJSONparse; }; #endif /* REDACORE_DATATREECORE_H_ */ diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index 600a69a..3a346ee 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -19,7 +19,7 @@ CJSONparse::CJSONparse( CDataTree * pDataTree ) { - // Parameter tree + // Object tree DataTree = pDataTree; // 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; + // Clear Error + Error = false; + // Validate if (!FilePath || !FilePath[0]) { Error = true; @@ -87,7 +90,7 @@ bool CJSONparse::LoadFile( const char * FilePath, int pBufLen ) // Create Root object DataTree->DeleteAll(); - DataTree->GetParent( NULL, &RootObject ); + RootObject = DataTree->GetRootMember(); Level = 0; // Parse Root Object @@ -112,6 +115,7 @@ bool CJSONparse::LoadFile( const char * FilePath, int pBufLen ) // Success close( InputHandle ); + InputHandle = -1; FreeBuffer(); return true; } @@ -164,119 +168,21 @@ void CJSONparse::FreeBuffer() } //--------------------------------------------------------------------------- -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 ) +bool CJSONparse::ParseString( char ** Value, int &pLen ) { char * Mark; char * EndMark; int Len; - // Clear value - Error = false; - *Value = NULL; - Len = 0; - // Check for opening quote if (*BufPos != '"') { return false; } + // Clear values + *Value = NULL; + Len = 0; + // Mark start of quote Mark = 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; // Create Return value pointer @@ -330,26 +236,186 @@ bool CJSONparse::ParseString( char ** Value, int *pLen, EDataType *pType ) (*Value)[Len] = 0; // Set other parameters - if (pType) - *pType = jtString; - if (pLen) - *pLen = Len; + pLen = Len; // Success 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 * EndMark; - int Len; - - // Clear value - Error = false; - *Value = NULL; - Len = 0; // Mark start of value Mark = BufPos; @@ -369,52 +435,31 @@ bool CJSONparse::ParsePrimitive( char ** Value, int * pLen, EDataType * pType ) // 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" ); + DataTree->SetValuePtr( Member, jtNull, NULL, -1 ); } else if ((Len == 4) && !strncasecmp( Mark, "true", 4 )) { - if (pType) - *pType = jtBool; - if (pLen) - *pLen = Len; - *Value = (char*)malloc( 5 ); - strcpy( *Value, "true" ); + DataTree->SetValue( Member, jtBool, "1", 1 ); } else if ((Len == 5) && !strncasecmp( Mark, "false", 5 )) { - if (pType) - *pType = jtBool; - if (pLen) - *pLen = Len; - *Value = (char*)malloc( 6 ); - strcpy( *Value, "false" ); + DataTree->SetValue( Member, jtBool, "0", 1 ); } 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; + Value = (char*)malloc( Len+1 ); + memcpy( Value, Mark, Len ); + Value[Len] = 0; + DataTree->SetValuePtr( Member, jtInt, Value, Len ); } 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; + Value = (char*)malloc( Len+1 ); + memcpy( Value, Mark, Len ); + Value[Len] = 0; + DataTree->SetValuePtr( Member, jtFloat, Value, Len ); } else { 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; @@ -443,73 +507,173 @@ bool CJSONparse::SaveFile( const char * FilePath, const int Indent ) // Save Root object Level = 0; - DataTree->GetParent( NULL, &RootObject ); - SaveObject( RootObject, Indent ); + RootObject = DataTree->GetRootMember(); + PrintObject( RootObject, Indent ); // Close file close( OutputHandle ); + OutputHandle = -1; 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 - dprintf( OutputHandle, "{\n" ); + write( OutputHandle, "{", 1 ); + Level++; // Extend spacer - Level++; memset( &Spacer[SpacerLen], ' ', 2 ); SpacerLen += 2; Spacer[SpacerLen] = 0; // Save parameters - for (Param = Object->FirstChild; Param != NULL; (Param = Param->Next)) + for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next)) { // 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 : - dprintf( OutputHandle, "%s,\n", "null" ); + write( OutputHandle, "null", 4 ); break; case jtBool : case jtInt : case jtFloat : - dprintf( OutputHandle, "%s,\n", Param->Value ); + write( OutputHandle, Member->Value, Member->Len ); break; case jtString : - dprintf( OutputHandle, "\"%s\",\n", Param->Value ); + write( OutputHandle, "\"", 1 ); + write( OutputHandle, Member->Value, Member->Len ); + write( OutputHandle, "\"", 1 ); break; case jtArray : - dprintf( OutputHandle, "[],\n" ); + PrintArray( Member, Indent ); break; case jtObject : - SaveObject( Param, Indent ); + PrintObject( Member, Indent ); break; } + if (!Last) { + write( OutputHandle, ",", 1 ); + } + write( OutputHandle, "\n", 1 ); } // Shorten spacer SpacerLen -= 2; Spacer[SpacerLen] = 0; - Level--; // Closing brace - if (Level == 0) { - dprintf( OutputHandle, "%s}\n", Spacer ); + Level--; + if (Object->Len) { + write( OutputHandle, Spacer, SpacerLen ); } - else { - dprintf( OutputHandle, "%s},\n", Spacer ); - } - return false; + write( OutputHandle, "}", 1 ); + return true; +} +//--------------------------------------------------------------------------- + +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; } //--------------------------------------------------------------------------- diff --git a/JSONparseCore.h b/JSONparseCore.h index 6f0d3f7..603292b 100644 --- a/JSONparseCore.h +++ b/JSONparseCore.h @@ -61,18 +61,23 @@ private: BufPos++; } } + bool ParseString( char ** Value, int &pLen ); 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 ParseArray( TDataMember * Array ); + 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: CJSONparse( CDataTree * pDataTree ); ~CJSONparse(); - bool LoadFile( const char * FilePath, int pBufLen = 500 ); - bool SaveFile( const char * FilePath, const int ValueTab = 20 ); + bool PrintToScreen( const int Indent ); + + bool LoadFromFile( const char * FilePath, int pBufLen = 500 ); + bool SaveToFile( const char * FilePath, const int Indent = 2 ); const char * GetError() { return ((Error)? ErrorText : "Success"); }; };