/* * DataTreeCore.cpp * * Created on: 5 Mar 2017 * Author: wentzelc */ // Standard C/C++ Libraries #include #include // redA Libraries #include "DataTreeCore.h" //--------------------------------------------------------------------------- CDataTree::CDataTree() { // Create Root member of tree RootMember = CreateMember( NULL ); RootMember->Type = jtObject; } //--------------------------------------------------------------------------- CDataTree::~CDataTree() { // Destroy Members DeleteAll(); DestroyMember( &RootMember ); } //--------------------------------------------------------------------------- TDataMember * CDataTree::CreateMember( const char * Name, const int Len ) { TDataMember * Member; // Create data structure Member = (TDataMember *)calloc( 1, sizeof(TDataMember) ); // Set name if (Name) { Member->NameLen = (Len == -1)? strlen( Name ) : Len ; Member->Name = (char *)malloc( Member->NameLen+1 ); memcpy( Member->Name, Name, Member->NameLen ); Member->Name[ Member->NameLen ] = 0; } return Member; } //--------------------------------------------------------------------------- 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; // Valdate if (!Member || !*Member) return false; // Get next param in list NextMember = (*Member)->Next; // Destroy if ((*Member)->Name) free( (*Member)->Name ); if ((*Member)->Value) free( (*Member)->Value ); while ((*Member)->FirstChild) { DestroyMember( &((*Member)->FirstChild) ); } free( *Member ); // Restore list integrity *Member = NextMember; return true; } //--------------------------------------------------------------------------- bool CDataTree::DestroyValue( TDataMember * Member ) { // Valdate if (!Member) return false; // Destroy values if (Member->Value) { free( Member->Value ); Member->Value = NULL; } while (Member->FirstChild) { DestroyMember( &(Member->FirstChild) ); } Member->Len = 0; return true; } //--------------------------------------------------------------------------- TDataMember ** CDataTree::GetMemberPtr( TDataMember * BaseMember, const char * Path, bool Create, TDataMember ** Parent ) { TDataMember * Member; TDataMember ** Child = NULL; char * Pos; char * EndPos; char * Key; unsigned short KeyLen; int Index; int Count; bool Last = false; // Validate if (!Path || !*Path) { if (Parent) *Parent = NULL; return NULL; } // Set init references if (Parent) *Parent = NULL; Child = NULL; Member = (BaseMember)? BaseMember : RootMember; // Split path Pos = (char*)Path; while (Member && *Pos) { // Reset Child reference Child = NULL; // 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 } // Set Index start Pos++; Key = Pos; // Get Index value while (*Pos && (*Pos != ']')) Pos++; if (!*Pos) break; // Check if last Pos++; if (!*Pos) Last = true; if (Pos == Key+1) { // Empty bracket only allowed for create if (!Create) break; Index = -1; // 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++; } } // Create element if needed if (!*Child && Create) { if ((Index == -1) || (Index = Count + 1)) { *Child = CreateMember( NULL ); Member->Len++; } } } else { // Skip separator if (*Pos == '/') { Pos++; } // 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 Key = Pos; KeyLen = 0; while (*Pos && (*Pos != '/') && (*Pos != '[')) { KeyLen++; Pos++; } // More elements? if (!*Pos) { Last = true; } // Find next parent Child = &(Member->FirstChild); while (*Child && (((*Child)->NameLen != KeyLen) || strncasecmp( (*Child)->Name, Key, KeyLen ))) { Child = &((*Child)->Next); } if (!*Child && Create) { *Child = CreateMember( Key, KeyLen ); Member->Len++; } } // Set Parent if (Last && Parent) { *Parent = Member; } // Next level Member = *Child; } return Child; } //--------------------------------------------------------------------------- TDataMember * CDataTree::GetMember( TDataMember * BaseMember, const char * Path, bool Create ) { TDataMember ** Member; // Get Child Member = GetMemberPtr( BaseMember, Path, Create ); return ((Member)? *Member : NULL); } //--------------------------------------------------------------------------- TDataMember * CDataTree::GetIndexChild( TDataMember * Parent, const int Index ) { TDataMember * Child; int Count; // Get Parent if (!Parent) return NULL; // Get Indexed child Count = 0; Child = Parent->FirstChild; while (Child && (Count < Index)) { Child = Child->Next; Count++; } // Return child return Child; } //--------------------------------------------------------------------------- TDataMember * CDataTree::GetFirstChild( TDataMember * BaseMember, const char * Path, bool Create ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, Create ))) { return NULL; } // Return child return Member->FirstChild; } //--------------------------------------------------------------------------- bool CDataTree::Delete( TDataMember * BaseMember, const char * Path ) { TDataMember * Parent; TDataMember ** Member; // Validate if (!BaseMember && (!Path || !*Path)) { return false; } if (!Path || !*Path) { // No path - destroy value DestroyValue( BaseMember ); return true; } else if ((Member = GetMemberPtr( BaseMember, Path, false, &Parent ))) { // If valid path, destroy member DestroyMember( Member ); Parent->Len--; return true; } else { return false; } } //--------------------------------------------------------------------------- bool CDataTree::DeleteAll() { // Delete all except root member while (RootMember->FirstChild) { DestroyMember( &(RootMember->FirstChild) ); } return true; } //--------------------------------------------------------------------------- bool CDataTree::SetValuePtr( TDataMember * Member, EDataType Type, char * Value, int Len ) { // Clear previous value if (Member->Value != NULL || (Member->FirstChild != NULL)) { DestroyValue( Member ); } // Set type Member->Type = Type; Member->Value = Value; Member->Len = Len; return true; } //--------------------------------------------------------------------------- bool CDataTree::SetValue( TDataMember * Member, EDataType Type, const char * Value, int Len ) { char * NewValue = NULL; if ((Type == jtString) || (Type == jtFloat) || (Type == jtInt) || (Type == jtBool)) { // Validate if (!Value) { return false; } // Check Length if (Len == -1) { Len = strlen(Value); } // Create copy of value NewValue = (char*)malloc( Len+1 ); if (Value) { memcpy( NewValue, Value, Len ); } else { memset( NewValue, 0, Len ); } NewValue[Len] = 0; SetValuePtr( Member, Type, NewValue, Len ); } else { // Set null value SetValuePtr( Member, Type, NULL, 0 ); } return true; } //--------------------------------------------------------------------------- bool CDataTree::SetObject( TDataMember * BaseMember, const char * Path ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Set as Object SetValue( Member, jtObject, NULL ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetArray( TDataMember * BaseMember, const char * Path ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Set as Object SetValue( Member, jtArray, NULL ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetStr( TDataMember * BaseMember, const char * Path, const char * Value, const int Len ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Create Value SetValue( Member, jtString, Value, Len ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetInt( TDataMember * BaseMember, const char * Path, const long Value, const char * Mask ) { TDataMember * Member; char ValueStr[20]; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Create Value sprintf( ValueStr, ((Mask)? Mask : "%ld"), Value ); SetValue( Member, jtInt, ValueStr ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetFloat( TDataMember * BaseMember, const char * Path, const double Value, const char * Mask ) { TDataMember * Member; char ValueStr[20]; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Create Value sprintf( ValueStr, ((Mask)? Mask : "%lf"), Value ); SetValue( Member, jtFloat, ValueStr ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetBool( TDataMember * BaseMember, const char * Path, const bool Value ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Create Value SetValue( Member, jtBool, ((Value == 0)? "0" : "1") ); return true; } //--------------------------------------------------------------------------- bool CDataTree::SetNull( TDataMember * BaseMember, const char * Path ) { TDataMember * Member; // Validate if (!(Member = GetMember( BaseMember, Path, true ))) { return false; } // Create Value SetValue( Member, jtNull, NULL ); return true; } //--------------------------------------------------------------------------- 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) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { return Member->Value; } else if (Member && Create && (Member->Type == jtNull)) { SetValue( Member, jtString, Default ); return Member->Value; } else { return Default; } } //--------------------------------------------------------------------------- const char * CDataTree::GetStr( TDataMember * BaseMember, const char * Path, int &Len, const char * Default, bool Create ) { TDataMember * Member; // Validate if ((Member = GetMember( BaseMember, Path, Create )) && ((Member->Type == jtString) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { Len = Member->Len; return Member->Value; } else if (Member && Create && (Member->Type == jtNull)) { SetValue( Member, jtString, Default ); Len = Member->Len; return Member->Value; } else { Len = 0; return Default; } } //--------------------------------------------------------------------------- const int CDataTree::GetLen( TDataMember * BaseMember, const char * Path ) { TDataMember * Member; // Validate if ((Member = GetMember( BaseMember, Path, false )) && ((Member->Type == jtString) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { return Member->Len; } else { return 0; } } //--------------------------------------------------------------------------- const long CDataTree::GetInt( TDataMember * BaseMember, const char * Path, long Default, bool Create, const char * Mask ) { TDataMember * Member; // Validate 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, ((Mask)? Mask : "%ld"), Default ); SetValue( Member, jtInt, TempStr ); return Default; } else { return Default; } } //--------------------------------------------------------------------------- const double CDataTree::GetFloat( TDataMember * BaseMember, const char * Path, double Default, bool Create, const char * Mask ) { TDataMember * Member; // Validate 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, ((Mask)? Mask : "%lf"), Default ); SetValue( Member, jtFloat, TempStr ); return Default; } else { return Default; } } //--------------------------------------------------------------------------- const bool CDataTree::GetBool( TDataMember * BaseMember, const char * Path, bool Default, bool Create ) { TDataMember * Member; // Validate 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, jtBool, ((Default)? "1" : "0") ); return Default; } else { return Default; } } //---------------------------------------------------------------------------