// // The developer of the original code and/or files is Tripwire, Inc. // Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire, // Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights // reserved. // // This program is free software. The contents of this file are subject // to the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. You may redistribute it and/or modify it // only in compliance with the GNU General Public License. // // This program is distributed in the hope that it will be useful. // However, this program is distributed AS-IS WITHOUT ANY // WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. Please see the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // Nothing in the GNU General Public License or any other license to use // the code or files shall permit you to use Tripwire's trademarks, // service marks, or other intellectual property without Tripwire's // prior written consent. // // If you have any questions, please contact Tripwire, Inc. at either // info@tripwire.org or www.tripwire.org. // /////////////////////////////////////////////////////////////////////////////// // hierdatabase.h // #ifndef __HIERDATABASE_H #define __HIERDATABASE_H #ifndef __BLOCKRECORDFILE_H #include "blockrecordfile.h" #endif #ifndef __HIERDBNODE_H #include "hierdbnode.h" #endif #ifndef __ERROR_H #include "core/error.h" #endif #ifndef __HIERDBPATH_H #include "hierdbpath.h" #endif #if HAVE_STRINGS_H // RTEMS needs this for strcasecmp # include #endif class cHierDatabaseIter; class cErrorBucket; TSS_EXCEPTION( eHierDatabase, eError ); TSS_EXCEPTION( eHierDbInternal, eHierDatabase ); // not used TSS_EXCEPTION( eHierDbDupeName, eHierDatabase ); // // TODO -- store some header info with the root node -- at least whether the db is case-sensitive or not // and what the delimiting character is // //----------------------------------------------------------------------------- // cHierDatabase -- a hierarchical database class //----------------------------------------------------------------------------- class cHierDatabase : public cBlockRecordFile { public: cHierDatabase( bool bCaseSensitive = true, TCHAR delChar = _T('/') ); // NOTE -- these two parameters are only used if the database is being created; otherwise, they // are overwritten when Open() is called. virtual ~cHierDatabase(); // // overrides from base class // virtual void Open ( const TSTRING& fileName, int numPages = 5, bool bTruncate = false ); //throw (eArchive, eHierDatabase) virtual void Open ( cBidirArchive* pArch, int numPages = 5 ); //throw (eArchive, eHierDatabase) // for the second Open(), this class owns the destruction of the archive //TODO -- make numPages the last parameter bool IsCaseSensitive() const { return mbCaseSensitive; } TCHAR GetDelimitingChar() const { return mDelimitingChar; } enum { INVALID_INDEX = -1 }; typedef cHierDatabaseIter iterator; typedef cBlockRecordFile inherited; private: cHierAddr mRootArrayAddr; // this is the address of the top-level array bool mbCaseSensitive; TCHAR mDelimitingChar; cHierDatabase ( const cHierDatabase& rhs ); //not impl void operator= ( const cHierDatabase& rhs ); //not impl void OpenImpl ( bool bTruncate ); //throw (eArchive, eHierDatabase) // both Open() methods call this to initialize the class after calling // inherited::Open() friend class cHierDatabaseIter; }; //----------------------------------------------------------------------------- // cHierDatabaseIter -- the iterator class //----------------------------------------------------------------------------- class cHierDatabaseIter { public: cHierDatabaseIter( cHierDatabase* pDb ); //throw (eArchive) ~cHierDatabaseIter(); // // copying // cHierDatabaseIter ( const cHierDatabaseIter& rhs ); cHierDatabaseIter& operator=( const cHierDatabaseIter& rhs ); // // name characteristics -- these are alternatives to specifying in the ctor // void SetCaseSensitive ( bool bCaseSensitive ); bool IsCaseSensitive ( void ) const; void SetDelimitingChar ( TCHAR c ); TCHAR GetDelimitingChar ( void ) const; // // traverse up and down the hierarchy // bool AtRoot() const; //throw (eHierDatabase) bool CanDescend() const; void Descend() ; void Ascend() ; // // traverse my peers (objects in the same directory as me) // void SeekBegin(); bool Done() const; void Next(); bool SeekTo(const TCHAR* pName); // seeks to the named peer; returns false and is positioned in an undefined // place if it can't find the peer. // it is either case sensitive or insensitive, depending on what was passed to the // ctor. void SeekToRoot(); //throw (eArchive) // positions the iterator at the root node void Refresh(); //throw (eArchive, eHierDatabase) // refresh the iterator's contents in case the db has changed since we first entered // this directory. // note that this will move the iterator back to the beginning of the array // // getting at the entry's data... // const TCHAR* GetName() const; const TSTRING GetCwd() const; // // creating arrays and entries (ie directories and files) // void CreateChildArray(); //throw (eArchive, eHierDatabase) void CreateEntry ( const TSTRING& name );//throw (eArchive, eHierDatabase) // after the entry is added, this iterator points at it. // if the entry already exists in the database, an error is added to pError. // // getting and setting the data associated with a given entry // int8* GetData(int32& length) const; //throw (eArchive, eHierDatabase) // returns the data associated with the current entry; this asserts that the iterator is // not done and the current entry has data associated with it bool HasData() const ; // returns true if the current entry has data void SetData(int8* pData, int32 length); //throw (eArchive, eHierDatabase) void RemoveData(); //throw (eArchive, eHierDatabase) // removes the data associated with the current entry; this asserts that the current // entry actually _has_ data // // deleting arrays and entries // void DeleteEntry(); //throw (eArchive, eHierDatabase) // deletes the currently pointed-at entry; this assumes that Done() is not true, and // advances to the next node. bool ChildArrayEmpty(); //throw (eArchive, eHierDatabase) // returns true if the node's child array is empty void DeleteChildArray(); //throw (eArchive, eHierDatabase) // this method deletes the child array of the current object. This method asserts that // Done() is not true, that the current node has a child, and that the child array is // empty (TODO -- perhaps in the future we will want to make the equivalant of "rm -rf" // // util function for sorting/searching // bool CompareForUpperBound( const cHierEntry& he, const TCHAR* pchName ) const; // compares shortname of FCO to pchName. returns < == or > 0 as strcmp does. protected: cHierAddr GetCurrentAddr() const; // returns the address of the current cHierEntry by examining either the previous pNext pointer or the // array info pointer if the first entry is current. This asserts (! Done()) //------------------------------------------------------------------------- // member data //------------------------------------------------------------------------- // TODO -- maybe this should be a fully insulated class? // TODO -- maybe this should be a set to reduce insert and lookup time? typedef std::vector EntryArray; cHierDatabase* mpDb; // the database EntryArray mEntries; // vector of entries for the current level cHierArrayInfo mInfo; cHierAddr mInfoAddr; EntryArray::iterator mIter; // my current position in the array cHierDbPath mCurPath; // The current working directory. //------------------------------------------------------------------------- // helper methods //------------------------------------------------------------------------- void LoadArrayAt(const cHierAddr& addr); //throw (eArchive, eHierDatabase) // initializes the iterator so that it is pointing at the array named by addr. int Compare( const TCHAR* pc1, const TCHAR* pc2 ) const; // this acts just like strcmp, but takes into account whether the database is case-sensitive or not. EntryArray::iterator UpperBound( const TCHAR* pchName ); // same as std::upper_bound except it calls CompareForUpperBound() to // do its comparison. }; //############################################################################# // inline implementation //############################################################################# inline void cHierDatabaseIter::Refresh() { cHierAddr infoAddr = mInfoAddr; LoadArrayAt( infoAddr ); } inline void cHierDatabaseIter::SetCaseSensitive ( bool bCaseSensitive ) { mCurPath.SetCaseSensitive( bCaseSensitive ); } inline bool cHierDatabaseIter::IsCaseSensitive( void ) const { return mCurPath.IsCaseSensitive(); } inline void cHierDatabaseIter::SetDelimitingChar( TCHAR c ) { mCurPath.SetDelimiter( c ); } inline TCHAR cHierDatabaseIter::GetDelimitingChar( void ) const { return mCurPath.GetDelimiter(); } /////////////////////////////////////////////////////////////////////////////// // Compare /////////////////////////////////////////////////////////////////////////////// inline int cHierDatabaseIter::Compare( const TCHAR* pc1, const TCHAR* pc2 ) const { if( mCurPath.IsCaseSensitive() ) { return ( _tcscmp( pc1, pc2 ) ); } else { return ( _tcsicmp( pc1, pc2 ) ); } } #endif //__HIERDATABASE_H