/* * DataTreeCore.cpp * * Created on: 5 Mar 2017 * Author: wentzelc */ // Standard C/C++ Libraries #include #include // redA Libraries #include "DataTreeCore.h" //--------------------------------------------------------------------------- CDataMember::CDataMember( const char * pName, const int pLen ) { if (pName) { NameLen = (pLen == -1)? strlen( pName ) : pLen ; Name = (char *)malloc( NameLen+1 ); memcpy( Name, pName, NameLen ); Name[ NameLen ] = 0; } else { Name = NULL; NameLen = 0; } Type = jtNull; Value = NULL; Len = 0; FirstChild = NULL; LastChild = NULL; Parent = NULL; PrevPeer = NULL; NextPeer = NULL; } //--------------------------------------------------------------------------- CDataMember::CDataMember( CDataMember * pParent, const char * pName, const int pLen ) { if (pName) { NameLen = (pLen == -1)? strlen( pName ) : pLen ; Name = (char *)malloc( NameLen+1 ); memcpy( Name, pName, NameLen ); Name[ NameLen ] = 0; } else { Name = NULL; NameLen = 0; } Type = jtNull; Value = NULL; Len = 0; FirstChild = NULL; LastChild = NULL; if (!pParent) { Parent = NULL; PrevPeer = NULL; NextPeer = NULL; } else { // Clear/reset parent if not object Parent = pParent; if ((Parent->Type != jtNull) && (Parent->Type != jtObject) && (Parent->Type != jtArray)) { Parent->Clear(); } // Insert into Parent & Peer lists Parent->Len++; if (!Parent->FirstChild) { PrevPeer = NULL; NextPeer = NULL; Parent->FirstChild = this; Parent->LastChild = this; } else { PrevPeer = Parent->LastChild; Parent->LastChild->NextPeer = this; NextPeer = NULL; Parent->LastChild = this; } } } //--------------------------------------------------------------------------- CDataMember::~CDataMember() { // Remove from parent if (Parent) { Parent->Len--; if (this == Parent->LastChild) { Parent->LastChild = PrevPeer; } if (this == Parent->FirstChild) { Parent->FirstChild = NextPeer; } } if (PrevPeer) { PrevPeer->NextPeer = NextPeer; } if (NextPeer) { NextPeer->PrevPeer = PrevPeer; } // Destroy value/children Clear(); // Destroy member if (Name) free( Name ); if (Value) free( Value ); } //--------------------------------------------------------------------------- CDataMember * CDataMember::CreateChild( const char * Name, const int Len ) { CDataMember * Member; Member = new CDataMember( this, Name, Len ); return Member; } //--------------------------------------------------------------------------- bool CDataMember::Clear() { if (Value) { free( Value ); Value = NULL; } while (FirstChild) { delete FirstChild; // FirstChild = NULL; // LastChild = NULL; // Len = 0; } Type = jtNull; return true; } //--------------------------------------------------------------------------- CDataMember * CDataMember::GetChild( const char * Path, bool Create ) { CDataMember * Member; CDataMember ** Child; char * Pos; char * EndPos; char * Key; unsigned short KeyLen; int Index; int Count; // Validate if (!Path || !*Path) { return this; } // Set init references Child = NULL; Member = this; // 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; Pos++; 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)->NextPeer); } } 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)->NextPeer); Count++; } } // Create element if needed if (!*Child && Create) { if ((Index == -1) || (Index == Count)) { *Child = new CDataMember( Member, NULL ); } } } 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++; } // Find next parent Child = &(Member->FirstChild); while (*Child && (((*Child)->NameLen != KeyLen) || strncasecmp( (*Child)->Name, Key, KeyLen ))) { Child = &((*Child)->NextPeer); } if (!*Child && Create) { *Child = new CDataMember( Member, Key, KeyLen ); } } // Next level Member = *Child; } return (Child)? *Child : NULL; } //--------------------------------------------------------------------------- CDataMember * CDataMember::GetChFirstChild( const char * Path, bool Create ) { CDataMember * Member = NULL; // Find member Member = (!Path || !*Path)? this : GetChild( Path, Create ); // Check if valid type if (!Member || ((Member->Type != jtObject) && (Member->Type != jtNull))) { return NULL; } else if (Create && (Member->Type == jtNull)) { Member->SetObject(); // Set newly created member to object } return Member->FirstChild; } //--------------------------------------------------------------------------- CDataMember * CDataMember::GetChElement( const char * Path, const int Index, bool Create ) { CDataMember * Member = NULL; CDataMember * Child = NULL; int Count; // Find Member Member = (!Path || !*Path)? this : GetChild( Path, Create ); // Check if valid type if (!Member || ((Member->Type != jtArray) && (Member->Type != jtNull))) { return NULL; } else if (Create && (Member->Type == jtNull)) { Member->SetArray(); // Set newly created member to array } // Find element at position Count = 0; Child = Member->FirstChild; while (Child && (Count < Index)) { Child = Child->NextPeer; Count++; } // Return child return Child; } //--------------------------------------------------------------------------- bool CDataMember::Delete( const char * Path ) { CDataMember * Member; if (!Path || !*Path) { // No path - destroy value Clear(); return true; } else if ((Member = GetChild( Path, false ))) { // If valid path, destroy member delete Member; return true; } else { return false; } } //--------------------------------------------------------------------------- bool CDataMember::SetValuePtr( EDataType pType, const char * pValue, int pLen ) { Clear(); Type = pType; if ((pType == jtString) || (pType == jtFloat) || (pType == jtInt) || (pType == jtBool)) { Len = (pLen == -1)? strlen(pValue) : pLen; Value = (char*)pValue; } return true; } //--------------------------------------------------------------------------- bool CDataMember::SetValue( EDataType pType, const char * pValue, int pLen ) { Clear(); Type = pType; if ((pType == jtString) || (pType == jtFloat) || (pType == jtInt) || (pType == jtBool)) { Len = (pLen == -1)? strlen(pValue) : pLen; Value = (char*)malloc( Len+1 ); memcpy( Value, pValue, Len ); Value[Len] = 0; } return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChObject( const char * Path ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Set as Object Member->SetValue( jtObject, NULL ); return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChArray( const char * Path ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Set as Object Member->SetValue( jtArray, NULL ); return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChStr( const char * Path, const char * Value, const int Len ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Create Value if (!Value) { Member->SetValue( jtString, "", 0 ); } else { Member->SetValue( jtString, Value, Len ); } return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChInt( const char * Path, const long Value, const char * Mask ) { CDataMember * Member; char ValueStr[20]; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Create Value sprintf( ValueStr, ((Mask)? Mask : "%ld"), Value ); Member->SetValue( jtInt, ValueStr ); return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChFloat( const char * Path, const double Value, const char * Mask ) { CDataMember * Member; char ValueStr[20]; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Create Value sprintf( ValueStr, ((Mask)? Mask : "%lf"), Value ); Member->SetValue( jtFloat, ValueStr ); return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChBool( const char * Path, const bool Value ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Create Value Member->SetValue( jtBool, ((Value == 0)? "0" : "1") ); return true; } //--------------------------------------------------------------------------- bool CDataMember::SetChNull( const char * Path ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, true ))) { return false; } // Create Value Member->SetValue( jtNull, NULL ); return true; } //--------------------------------------------------------------------------- const char * CDataMember::GetName( const char * Path ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, false ))) { return NULL; } return Member->Name; } //--------------------------------------------------------------------------- EDataType CDataMember::GetType( const char * Path ) { CDataMember * Member; // Validate if (!(Member = GetChild( Path, false ))) { return jtNull; } return Member->Type; } //--------------------------------------------------------------------------- const int CDataMember::GetLen( const char * Path ) { CDataMember * Member; // Validate if ((Member = GetChild( Path, false ))) { return Member->Len; } else { return 0; } } //--------------------------------------------------------------------------- const char * CDataMember::GetChStr( const char * Path, const char * Default, bool Create ) { CDataMember * Member; // Validate if ((Member = GetChild( Path, Create )) && ((Member->Type == jtString) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { return Member->Value; } else if (Member && Create && (Member->Type == jtNull)) { Member->SetStr( Default ); return Member->Value; } else { return Default; } } //--------------------------------------------------------------------------- const char * CDataMember::GetChStr( const char * Path, int &Len, const char * Default, bool Create ) { CDataMember * Member; // Validate if ((Member = GetChild( 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)) { Member->SetStr( Default ); Len = Member->Len; return Member->Value; } else { Len = 0; return Default; } } //--------------------------------------------------------------------------- const long CDataMember::GetChInt( const char * Path, long Default, bool Create, const char * Mask ) { CDataMember * Member; // Validate if ((Member = GetChild( Path, Create )) && ((Member->Type == jtString) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { return strtol( Member->Value, NULL, 10 ); } else if (Member && Create && (Member->Type == jtNull)) { char TempStr[20]; sprintf( TempStr, ((Mask)? Mask : "%ld"), Default ); Member->SetValue( jtInt, TempStr ); return Default; } else { return Default; } } //--------------------------------------------------------------------------- const double CDataMember::GetChFloat( const char * Path, double Default, bool Create, const char * Mask ) { CDataMember * Member; // Validate if ((Member = GetChild( Path, Create )) && ((Member->Type == jtString) || (Member->Type == jtFloat) || (Member->Type == jtInt) || (Member->Type == jtBool)) ) { return strtod( Member->Value, NULL ); } else if (Member && Create && (Member->Type == jtNull)) { char TempStr[20]; sprintf( TempStr, ((Mask)? Mask : "%lf"), Default ); Member->SetValue( jtFloat, TempStr ); return Default; } else { return Default; } } //--------------------------------------------------------------------------- const bool CDataMember::GetChBool( const char * Path, bool Default, bool Create ) { CDataMember * Member; // Validate if ((Member = GetChild( Path, Create ))) { if (Member->Type == jtString) { return ((!*Member->Value)? false : true); } else if (Member->Type == jtFloat) { return ((strtod( Member->Value, NULL ) == 0)? false : true ); } else if (Member->Type == jtInt) { return ((strtol( Member->Value, NULL, 10 ) == 0)? false : true ); } else if (Member->Type == jtBool) { return ((!strcasecmp( Member->Value, "0" ))? false : true ); } else if ((Member->Type == jtNull) && Create) { Member->SetValue( jtBool, ((Default)? "1" : "0") ); return Default; } else { return Default; } } else { return Default; } } //---------------------------------------------------------------------------