From 200f7e1f8bc5b4626da2a4dd5c188b5e22328c67 Mon Sep 17 00:00:00 2001 From: Charl Wentzel Date: Wed, 5 Apr 2017 08:07:53 +0200 Subject: [PATCH] Important Update: - Improve "printing" for JSON with single & multi line objects - Fix bugs in getting, setting & creating array elements - "array[]" allowed to create/add element at end of an array - No longer duplicate get() path (reduce memory allocation) - added NameLen to TMember to eliminate zero-terminate requirement - Fix ReadfromXXX() return values --- DataTreeCore.cpp | 92 ++++++++++++++++++++++++++--------------------- DataTreeCore.h | 5 ++- JSONparseCore.cpp | 55 +++++++++++++++++++++------- 3 files changed, 99 insertions(+), 53 deletions(-) diff --git a/DataTreeCore.cpp b/DataTreeCore.cpp index c4662fd..6b95668 100644 --- a/DataTreeCore.cpp +++ b/DataTreeCore.cpp @@ -40,7 +40,8 @@ TDataMember * CDataTree::CreateMember( const char * Name ) Member = (TDataMember *)calloc( 1, sizeof(TDataMember) ); if (Name && *Name) { - Member->Name = (char *)malloc( strlen( Name )+1 ); + Member->Len = strlen( Name ); + Member->Name = (char *)malloc( Member->Len+1 ); strcpy( Member->Name, Name ); } return Member; @@ -119,12 +120,12 @@ bool CDataTree::DestroyValue( TDataMember * Member ) 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; + char * Key; + unsigned short KeyLen; int Index; int Count; bool Last = false; @@ -134,8 +135,6 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * if (Parent) *Parent = NULL; return NULL; } - WorkPath = (char*)malloc( strlen(Path)+1 ); - strcpy( WorkPath, Path ); // Set init references if (Parent) *Parent = NULL; @@ -143,15 +142,12 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * Member = (BaseMember)? BaseMember : RootMember; // Split path - Pos = (char*)WorkPath; + Pos = (char*)Path; while (Member && *Pos) { // Reset Child reference Child = NULL; - // Set Name start - MemberName = Pos; - // Find delimiter if (*Pos == '[') { @@ -163,40 +159,61 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * break; // Can't convert something else to an array } + // Set Index start + Pos++; + Key = Pos; + // Get Index value - Pos++; - while (*Pos && (*Pos != ']')) { + while (*Pos && (*Pos != ']')) Pos++; - } - if (*Pos != ']') { + if (!*Pos) break; - } - Index = (int)strtoul( Pos, &EndPos, 10 ); - if (EndPos != Pos) { - break; - } + + // Check if last Pos++; - if (!*Pos) { - // Last element + if (!*Pos) Last = true; + + if (Pos == Key+1) { + // Empty bracket only allowed for create + if (!Create) + break; + + // find end of list + Child = &(Member->FirstChild); + while (*Child) + Child = &((*Child)->Next); + } + else { + // Get requested index + Index = (int)strtoul( Key, &EndPos, 10 ); + if (EndPos != Pos-1) + break; + + // Find element at requested index + Child = &(Member->FirstChild); + Count = 0; + while (*Child && (Count < Index)) { + Child = &((*Child)->Next); + Count++; + } } - // Find next parent - Child = &(Member->FirstChild); - Count = 0; - while (*Child && (Count < Index)) { - Child = &((*Child)->Next); - Count++; - } + // Create element if needed if (!*Child && Create) { if (!Index || (Index = Count + 1)) { *Child = CreateMember( NULL ); - Member->Value++; + Member->Len++; } } } else { + // Skip separator + if (*Pos == '/') { + Pos++; + } + // Validate if (Create && (Member->Type == jtNull)) { Member->Type = jtObject; // Convert to object @@ -206,26 +223,25 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * } // Get key value + Key = Pos; + KeyLen = 0; while (*Pos && (*Pos != '/') && (*Pos != '[')) { + KeyLen++; Pos++; } + + // More elements? 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 )) { + while (*Child && ((*Child)->NameLen != KeyLen) && strncasecmp( (*Child)->Name, Key, KeyLen )) { Child = &((*Child)->Next); } if (!*Child && Create) { - *Child = CreateMember( MemberName ); + *Child = CreateMember( Key ); Member->Len++; } } @@ -238,10 +254,6 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * // Next level Member = *Child; } - - // Destroy temp path - free( WorkPath ); - return Child; } //--------------------------------------------------------------------------- diff --git a/DataTreeCore.h b/DataTreeCore.h index 78aa057..52309c4 100644 --- a/DataTreeCore.h +++ b/DataTreeCore.h @@ -30,10 +30,12 @@ typedef struct SDataMember TDataMember; struct SDataMember { char * Name; + unsigned short NameLen; EDataType Type; + TDataMember * FirstChild; char * Value; - int Len; + unsigned short Len; TDataMember * Next; }; @@ -65,6 +67,7 @@ public: EDataType GetType( TDataMember * BaseMember, const char * Path ); TDataMember * GetMember( TDataMember * BaseMember, const char * Path, bool Create = false ); + TDataMember * GetFirstChild( TDataMember * BaseMember, const char * Path, bool Create = false ); 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 ); diff --git a/JSONparseCore.cpp b/JSONparseCore.cpp index bf60320..3574ae2 100644 --- a/JSONparseCore.cpp +++ b/JSONparseCore.cpp @@ -158,6 +158,7 @@ bool CJSONparse::ReadFromFile( const char * RootPath, const char * Path, const c bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath ) { int Handle = -1; + bool result = false; // Validate if (!DataTree) { @@ -182,16 +183,18 @@ bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath ) } // Continuously refill buffer while loading - ReadFromHandle( RootPath, Handle, true ); + result = ReadFromHandle( RootPath, Handle, true ); // Close File close( Handle ); - return true; + return result; } //--------------------------------------------------------------------------- bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefillBuffer ) { + bool result = false; + // Clear Error Error = false; @@ -214,14 +217,14 @@ bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefill // Continuously refill buffer while loading RefillBuffer = pRefillBuffer; - ReadFromBuffer( RootPath ); + result = ReadFromBuffer( RootPath ); RefillBuffer = false; // Destroy buffer FreeBuffer(); InputHandle = -1; - return true; + return result; } //--------------------------------------------------------------------------- @@ -768,6 +771,7 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent ) TDataMember * Member; bool First = true; bool Last = false; + bool MultiLine = false; int Count = 0; // Opening brace @@ -781,6 +785,7 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent ) } // Save parameters + MultiLine = (Object->Len > 1)? true : false; for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next)) { // Whitespace around first bracket @@ -791,6 +796,9 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent ) write( OutputHandle, "\n", 1 ); write( OutputHandle, Spacer, SpacerLen ); } + else if (MultiLine) { + write( OutputHandle, Spacer, Indent-1 ); + } else { write( OutputHandle, " ", 1 ); } @@ -828,15 +836,17 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent ) case jtArray : PrintArray( Member, Indent ); + if (!MultiLine && Member->Len > 1) MultiLine = true; break; case jtObject : PrintObject( Member, Indent ); + if (!MultiLine && Member->Len > 1) MultiLine = true; break; } if (!Last) write( OutputHandle, ",", 1 ); - if (Indent) + if (Indent && MultiLine) write( OutputHandle, "\n", 1 ); } @@ -847,8 +857,11 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent ) } // Closing brace - if (Object->Len) { - write( OutputHandle, Spacer, SpacerLen ); + if (Indent) { + if (!MultiLine) + write( OutputHandle, " ", 1 ); + else + write( OutputHandle, Spacer, SpacerLen ); } write( OutputHandle, "}", 1 ); return true; @@ -860,6 +873,7 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent ) TDataMember * Member; bool First = true; bool Last = false; + bool MultiLine = false; int Count = 0; // Opening brace @@ -873,15 +887,27 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent ) } // Save parameters + MultiLine = (Array->Len > 1)? true : false; for (Member = Array->FirstChild; Member != NULL; (Member = Member->Next)) { // Whitespace around brace if (Indent) { if (First) { First = false; - write( OutputHandle, "\n", 1 ); + if (Array->Name) { + write( OutputHandle, "\n", 1 ); + write( OutputHandle, Spacer, SpacerLen ); + } + else if (MultiLine) { + write( OutputHandle, Spacer, Indent-1 ); + } + else { + write( OutputHandle, " ", 1 ); + } + } + else { + write( OutputHandle, Spacer, SpacerLen ); } - write( OutputHandle, Spacer, SpacerLen ); } Last = (++Count >= Array->Len); @@ -905,15 +931,17 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent ) case jtArray : PrintArray( Member, Indent ); + if (!MultiLine && Member->Len > 1) MultiLine = true; break; case jtObject : PrintObject( Member, Indent ); + if (!MultiLine && Member->Len > 1) MultiLine = true; break; } if (!Last) write( OutputHandle, ",", 1 ); - if (Indent) + if (Indent && MultiLine) write( OutputHandle, "\n", 1 ); } @@ -924,8 +952,11 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent ) } // Closing brace - if (Array->Len) { - write( OutputHandle, Spacer, SpacerLen ); + if (Indent) { + if (!MultiLine) + write( OutputHandle, " ", 1 ); + else + write( OutputHandle, Spacer, SpacerLen ); } write( OutputHandle, "]", 1 ); return true;