/* * DataTreeCore.cpp * * Created on: 5 Mar 2017 * Author: wentzelc */ // redA Libraries #include "DataTreeCore.h" // Standard C/C++ Libraries #include #include #include #include #include //--------------------------------------------------------------------------- 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 ) { TDataMember * Member; Member = (TDataMember *)calloc( 1, sizeof(TDataMember) ); if (Name && *Name) { Member->Name = (char *)malloc( strlen( Name )+1 ); strcpy( Member->Name, Name ); } 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 ) { 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 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; } // Destroy temp path free( WorkPath ); return Child; } //--------------------------------------------------------------------------- TDataMember * CDataTree::GetMember( TDataMember * BaseMember, const char * Path, bool Create ) { TDataMember ** Member; // Get Child Member = GetMemberPtr( BaseMember, Path, Create ); return *Member; } //--------------------------------------------------------------------------- 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) { 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)) { return Member->Value; } else if (Member && Create && (Member->Type == jtNull)) { SetValue( Member, jtString, Default ); return Default; } 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)) { Len = Member->Len; return Member->Value; } else if (Member && Create && (Member->Type == jtNull)) { SetValue( Member, jtString, Default ); Len = Member->Len; return Default; } else { Len = strlen( Default ); return Default; } } //--------------------------------------------------------------------------- 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; } } //---------------------------------------------------------------------------