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
This commit is contained in:
Charl Wentzel
2017-04-05 08:07:53 +02:00
parent 66fc4bc123
commit 200f7e1f8b
3 changed files with 99 additions and 53 deletions

View File

@@ -40,7 +40,8 @@ TDataMember * CDataTree::CreateMember( const char * Name )
Member = (TDataMember *)calloc( 1, sizeof(TDataMember) ); Member = (TDataMember *)calloc( 1, sizeof(TDataMember) );
if (Name && *Name) 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 ); strcpy( Member->Name, Name );
} }
return Member; return Member;
@@ -119,12 +120,12 @@ bool CDataTree::DestroyValue( TDataMember * Member )
TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent ) TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent )
{ {
char * WorkPath = NULL;
TDataMember * Member; TDataMember * Member;
TDataMember ** Child = NULL; TDataMember ** Child = NULL;
char * Pos; char * Pos;
char * EndPos; char * EndPos;
char * MemberName; char * Key;
unsigned short KeyLen;
int Index; int Index;
int Count; int Count;
bool Last = false; bool Last = false;
@@ -134,8 +135,6 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char *
if (Parent) *Parent = NULL; if (Parent) *Parent = NULL;
return NULL; return NULL;
} }
WorkPath = (char*)malloc( strlen(Path)+1 );
strcpy( WorkPath, Path );
// Set init references // Set init references
if (Parent) *Parent = NULL; if (Parent) *Parent = NULL;
@@ -143,15 +142,12 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char *
Member = (BaseMember)? BaseMember : RootMember; Member = (BaseMember)? BaseMember : RootMember;
// Split path // Split path
Pos = (char*)WorkPath; Pos = (char*)Path;
while (Member && *Pos) while (Member && *Pos)
{ {
// Reset Child reference // Reset Child reference
Child = NULL; Child = NULL;
// Set Name start
MemberName = Pos;
// Find delimiter // Find delimiter
if (*Pos == '[') if (*Pos == '[')
{ {
@@ -163,40 +159,61 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char *
break; // Can't convert something else to an array break; // Can't convert something else to an array
} }
// Set Index start
Pos++;
Key = Pos;
// Get Index value // Get Index value
Pos++; while (*Pos && (*Pos != ']'))
while (*Pos && (*Pos != ']')) {
Pos++; Pos++;
} if (!*Pos)
if (*Pos != ']') {
break; break;
}
Index = (int)strtoul( Pos, &EndPos, 10 ); // Check if last
if (EndPos != Pos) {
break;
}
Pos++; Pos++;
if (!*Pos) { if (!*Pos)
// Last element
Last = true; 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 // Create element if needed
Child = &(Member->FirstChild);
Count = 0;
while (*Child && (Count < Index)) {
Child = &((*Child)->Next);
Count++;
}
if (!*Child && Create) { if (!*Child && Create) {
if (!Index || (Index = Count + 1)) { if (!Index || (Index = Count + 1)) {
*Child = CreateMember( NULL ); *Child = CreateMember( NULL );
Member->Value++; Member->Len++;
} }
} }
} }
else else
{ {
// Skip separator
if (*Pos == '/') {
Pos++;
}
// Validate // Validate
if (Create && (Member->Type == jtNull)) { if (Create && (Member->Type == jtNull)) {
Member->Type = jtObject; // Convert to object Member->Type = jtObject; // Convert to object
@@ -206,26 +223,25 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char *
} }
// Get key value // Get key value
Key = Pos;
KeyLen = 0;
while (*Pos && (*Pos != '/') && (*Pos != '[')) { while (*Pos && (*Pos != '/') && (*Pos != '[')) {
KeyLen++;
Pos++; Pos++;
} }
// More elements?
if (!*Pos) { if (!*Pos) {
// Last element
Last = true; Last = true;
} }
else {
// Zero terminate name
*Pos = 0;
Pos++;
}
// Find next parent // Find next parent
Child = &(Member->FirstChild); Child = &(Member->FirstChild);
while (*Child && strcasecmp( (*Child)->Name, MemberName )) { while (*Child && ((*Child)->NameLen != KeyLen) && strncasecmp( (*Child)->Name, Key, KeyLen )) {
Child = &((*Child)->Next); Child = &((*Child)->Next);
} }
if (!*Child && Create) { if (!*Child && Create) {
*Child = CreateMember( MemberName ); *Child = CreateMember( Key );
Member->Len++; Member->Len++;
} }
} }
@@ -238,10 +254,6 @@ TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char *
// Next level // Next level
Member = *Child; Member = *Child;
} }
// Destroy temp path
free( WorkPath );
return Child; return Child;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -30,10 +30,12 @@ typedef struct SDataMember TDataMember;
struct SDataMember struct SDataMember
{ {
char * Name; char * Name;
unsigned short NameLen;
EDataType Type; EDataType Type;
TDataMember * FirstChild; TDataMember * FirstChild;
char * Value; char * Value;
int Len; unsigned short Len;
TDataMember * Next; TDataMember * Next;
}; };
@@ -65,6 +67,7 @@ public:
EDataType GetType( TDataMember * BaseMember, const char * Path ); EDataType GetType( TDataMember * BaseMember, const char * Path );
TDataMember * GetMember( TDataMember * BaseMember, const char * Path, bool Create = false ); 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, 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 char * GetStr( TDataMember * BaseMember, const char * Path, int &Len, const char * Default = NULL, bool Create = false );

View File

@@ -158,6 +158,7 @@ bool CJSONparse::ReadFromFile( const char * RootPath, const char * Path, const c
bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath ) bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath )
{ {
int Handle = -1; int Handle = -1;
bool result = false;
// Validate // Validate
if (!DataTree) { if (!DataTree) {
@@ -182,16 +183,18 @@ bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath )
} }
// Continuously refill buffer while loading // Continuously refill buffer while loading
ReadFromHandle( RootPath, Handle, true ); result = ReadFromHandle( RootPath, Handle, true );
// Close File // Close File
close( Handle ); close( Handle );
return true; return result;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefillBuffer ) bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefillBuffer )
{ {
bool result = false;
// Clear Error // Clear Error
Error = false; Error = false;
@@ -214,14 +217,14 @@ bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefill
// Continuously refill buffer while loading // Continuously refill buffer while loading
RefillBuffer = pRefillBuffer; RefillBuffer = pRefillBuffer;
ReadFromBuffer( RootPath ); result = ReadFromBuffer( RootPath );
RefillBuffer = false; RefillBuffer = false;
// Destroy buffer // Destroy buffer
FreeBuffer(); FreeBuffer();
InputHandle = -1; InputHandle = -1;
return true; return result;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -768,6 +771,7 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
TDataMember * Member; TDataMember * Member;
bool First = true; bool First = true;
bool Last = false; bool Last = false;
bool MultiLine = false;
int Count = 0; int Count = 0;
// Opening brace // Opening brace
@@ -781,6 +785,7 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
} }
// Save parameters // Save parameters
MultiLine = (Object->Len > 1)? true : false;
for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next)) for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next))
{ {
// Whitespace around first bracket // Whitespace around first bracket
@@ -791,6 +796,9 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
write( OutputHandle, "\n", 1 ); write( OutputHandle, "\n", 1 );
write( OutputHandle, Spacer, SpacerLen ); write( OutputHandle, Spacer, SpacerLen );
} }
else if (MultiLine) {
write( OutputHandle, Spacer, Indent-1 );
}
else { else {
write( OutputHandle, " ", 1 ); write( OutputHandle, " ", 1 );
} }
@@ -828,15 +836,17 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
case jtArray : case jtArray :
PrintArray( Member, Indent ); PrintArray( Member, Indent );
if (!MultiLine && Member->Len > 1) MultiLine = true;
break; break;
case jtObject : case jtObject :
PrintObject( Member, Indent ); PrintObject( Member, Indent );
if (!MultiLine && Member->Len > 1) MultiLine = true;
break; break;
} }
if (!Last) if (!Last)
write( OutputHandle, ",", 1 ); write( OutputHandle, ",", 1 );
if (Indent) if (Indent && MultiLine)
write( OutputHandle, "\n", 1 ); write( OutputHandle, "\n", 1 );
} }
@@ -847,8 +857,11 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
} }
// Closing brace // Closing brace
if (Object->Len) { if (Indent) {
write( OutputHandle, Spacer, SpacerLen ); if (!MultiLine)
write( OutputHandle, " ", 1 );
else
write( OutputHandle, Spacer, SpacerLen );
} }
write( OutputHandle, "}", 1 ); write( OutputHandle, "}", 1 );
return true; return true;
@@ -860,6 +873,7 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
TDataMember * Member; TDataMember * Member;
bool First = true; bool First = true;
bool Last = false; bool Last = false;
bool MultiLine = false;
int Count = 0; int Count = 0;
// Opening brace // Opening brace
@@ -873,15 +887,27 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
} }
// Save parameters // Save parameters
MultiLine = (Array->Len > 1)? true : false;
for (Member = Array->FirstChild; Member != NULL; (Member = Member->Next)) for (Member = Array->FirstChild; Member != NULL; (Member = Member->Next))
{ {
// Whitespace around brace // Whitespace around brace
if (Indent) { if (Indent) {
if (First) { if (First) {
First = false; 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); Last = (++Count >= Array->Len);
@@ -905,15 +931,17 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
case jtArray : case jtArray :
PrintArray( Member, Indent ); PrintArray( Member, Indent );
if (!MultiLine && Member->Len > 1) MultiLine = true;
break; break;
case jtObject : case jtObject :
PrintObject( Member, Indent ); PrintObject( Member, Indent );
if (!MultiLine && Member->Len > 1) MultiLine = true;
break; break;
} }
if (!Last) if (!Last)
write( OutputHandle, ",", 1 ); write( OutputHandle, ",", 1 );
if (Indent) if (Indent && MultiLine)
write( OutputHandle, "\n", 1 ); write( OutputHandle, "\n", 1 );
} }
@@ -924,8 +952,11 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
} }
// Closing brace // Closing brace
if (Array->Len) { if (Indent) {
write( OutputHandle, Spacer, SpacerLen ); if (!MultiLine)
write( OutputHandle, " ", 1 );
else
write( OutputHandle, Spacer, SpacerLen );
} }
write( OutputHandle, "]", 1 ); write( OutputHandle, "]", 1 );
return true; return true;