// $Id: IDbiBinaryFile.cxx,v 1.1 2011/01/18 05:49:19 finch Exp $ #include #include "TClass.h" #include "TObject.h" #include "TSystem.h" #include "IDbiBinaryFile.hxx" #include "IDbiTableRow.hxx" #include #include using std::endl; #include "IVldRange.hxx" #include "IVldTimeStamp.hxx" enum Markers { StartMarker = 0xaabbccdd, EndMarker = 0xddbbccaa}; // Local utilities. // *************** void* GetVTptr(const void* obj) { // Return an object's virtual table pointer. void* ptr; memcpy(&ptr,obj,4); return ptr; } void SetVTptr(void* obj, const void* vt) { // Set an object's virtual table pointer. memcpy(obj,&vt,4); } // Definition of static data members // ********************************* string COMET::IDbiBinaryFile::fgWorkDir; Bool_t COMET::IDbiBinaryFile::fgReadAccess = kTRUE; Bool_t COMET::IDbiBinaryFile::fgWriteAccess = kTRUE; // Definition of member functions (is same order as IDbiBinaryFile.hxx) // ***************************************************************** //..................................................................... COMET::IDbiBinaryFile::IDbiBinaryFile(const char* fileName, Bool_t input ) : fFile(0), fReading(input), fHasErrors(kFALSE), fArrayBuffer(0) { // // // Purpose: Default Constructor. // // Arguments: // fileName in File name (default: "" => file is a dummy) // input in true if reading (default = kTRUE) // Specification:- // ============= // // If file name or fgWorkDir is dummy, or the appropriate access is not set // then name is set to dummy otherwise fgWorkDir is prepended to the name. // Complete the file name. fFileName = fileName; if ( fFileName != "" ) { Bool_t access = input ? fgReadAccess : fgWriteAccess; if ( fgWorkDir == "" || ! access ) fFileName = ""; else fFileName = fgWorkDir + fFileName; } // Open the file. ios_base::openmode mode = ios_base::in|ios_base::binary; if ( ! input ) mode = ios_base::out|ios_base::binary; if ( fFileName == "" ) fHasErrors = kTRUE; else { fFile = new fstream(fFileName.c_str(),mode); if ( ! fFile->is_open() || ! fFile->good() ) { COMETDebug( "Cannot open " << fFileName << "; all I/O will fail." << " "); fHasErrors = kTRUE; } } } //..................................................................... /// Purpose: Default Destructor. COMET::IDbiBinaryFile::~IDbiBinaryFile() { // // delete[] fArrayBuffer; fArrayBuffer = 0; this->Close(); delete fFile; fFile = 0; } //..................................................................... /// Purpose: Close file. void COMET::IDbiBinaryFile::Close() { // // if ( fFile ) fFile->close(); } // Builtin data type I/O. // ********************** #define READ_BUILTIN(t) \ \ COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator >> (t& v) { \ UInt_t numBytes = sizeof(v); \ char* bytes = reinterpret_cast(&v); \ this->Read(bytes,numBytes); \ return *this; \ } #define WRITE_BUILTIN(t) \ \ COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator << (const t& v) { \ UInt_t numBytes = sizeof(v); \ const char* bytes = reinterpret_cast(&v); \ this->Write(bytes,numBytes); \ return *this; \ } READ_BUILTIN(Bool_t) WRITE_BUILTIN(Bool_t) READ_BUILTIN(Int_t) WRITE_BUILTIN(Int_t) READ_BUILTIN(UInt_t) WRITE_BUILTIN(UInt_t) READ_BUILTIN(Double_t) WRITE_BUILTIN(Double_t) // Simple Virtual object I/O // ************************* #define READ_SIMPLE(t) \ \ COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator >> (t& v) { \ void* vt = GetVTptr(&v); \ UInt_t numBytes = sizeof(v); \ char* bytes = reinterpret_cast(&v); \ this->Read(bytes,numBytes); \ SetVTptr(&v,vt); \ return *this; \ } #define WRITE_SIMPLE(t) \ \ COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator << (const t& v) { \ UInt_t numBytes = sizeof(v); \ const char* bytes = reinterpret_cast(&v); \ this->Write(bytes,numBytes); \ return *this; \ } READ_SIMPLE(COMET::IVldTimeStamp) WRITE_BUILTIN(COMET::IVldTimeStamp) // String I/O. // *********** //..................................................................... COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator >> (string& str) { if ( this->CanRead() ) { getline(*fFile,str,'\0'); this->CheckFileStatus(); } return *this; } //..................................................................... COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator << (const string& str) { UInt_t numBytes = str.size()+1; this->Write(str.c_str(),numBytes); return *this; } //..................................................................... COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator >> (COMET::IVldRange& vr) { if ( this->CanRead() ) { Int_t detectorMask; Int_t simMask; COMET::IVldTimeStamp timeStart; COMET::IVldTimeStamp timeEnd; string str; (*this) >> detectorMask >> simMask >> timeStart >> timeEnd >> str; TString dataSource(str.c_str()); COMET::IVldRange tmp(detectorMask,simMask,timeStart,timeEnd,dataSource); vr = tmp; } return *this; } //..................................................................... COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator << (const COMET::IVldRange& vr) { if ( this->CanWrite() ) { string str(vr.GetDataSource().Data()); (*this) << vr.GetDetectorMask() << vr.GetSimMask() << vr.GetTimeStart() << vr.GetTimeEnd() << str; } return *this; } //..................................................................... ///\verbatim /// Vector I/O. /// *********** /// /// /// Purpose: Read a vector of objects inheriting from COMET::IDbiTableRow. /// /// NB: On entry, array must be empty. /// /// /// The objects are written into a buffer that is a contiguous /// area of memory that is allocated to receive it. After a /// successful read the user must call ReleaseArrayBuffer to take /// control over this buffer as it will be automatically release /// when the next array input occurs otherwise. /// // For the format of record see the operator <<. ///\endverbatim COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator >> (vector& arr) { if ( ! this->CanRead() ) return *this; if ( arr.size() ) { COMETSevere( "Attempting to read into non-empty array" << " "); return *this; } // Check for start of array marker. UInt_t marker = 0; (*this) >> marker; if ( marker != StartMarker ) { COMETSevere( "Cannot find start of array marker" << " "); this->Close(); this->CheckFileStatus(); return *this; } // Get array size and deal with non-empty arrays. Int_t arrSize = 0; (*this) >> arrSize; if ( arrSize ) { Int_t objSize = 0; string objName; (*this) >> objName >> objSize; // Ensure that sizes look sensible and use ROOT to instatiate // an example object so that we can get the address of the // virtual table. TClass objClass(objName.c_str()); Int_t objSizefromRoot = objClass.Size(); void* obj = objClass.New(); void* vt = GetVTptr(obj); // This only works if the address of the sub-class object is the same // as the underlying base class, which should be true in this simple case. COMET::IDbiTableRow* tr = reinterpret_cast(obj); delete tr; COMETVerbose( "Restoring array of " << arrSize << " " << objName << " objects" << " VTaddr " << std::ios::hex << vt << std::ios::dec << " object size " << objSize << "(from file) " << objSizefromRoot << "(from ROOT)" << " "); if ( arrSize < 0 || objSize != objSizefromRoot ) { COMETSevere( "Illegal array size ("<< arrSize << ") or object size(" << objSize << "," << objSizefromRoot << ")" << " "); this->Close(); this->CheckFileStatus(); return *this; } // Allocate buffer and load in array. delete[] fArrayBuffer; Int_t buffSize = arrSize*objSize; fArrayBuffer = new char[buffSize]; this->Read(fArrayBuffer,buffSize); // Fix up VT pointers and populate the vector. char* elem = fArrayBuffer; arr.reserve(arrSize); for (int row = 0; row < arrSize; ++row ) { SetVTptr(elem,vt); arr.push_back(reinterpret_cast(elem)); elem += objSize; } } // Check for end of array marker. (*this) >> marker; if ( marker != EndMarker ) { COMETSevere( "Cannot find end of array marker" << " "); this->Close(); this->CheckFileStatus(); } return *this; } ///..................................................................... ///\verbatim /// /// Purpose: Write a vector of objects inheriting from COMET::IDbiTableRow. /// /// Format of record:- /// /// Int_t StartMarker Start of record marker = 0xaabbccdd /// Int_t arrSize Size of vector /// /// If size of vector > 0 this is folowed by:- /// /// string objName Name of object /// Int_t objSize Size of object /// char* The data arrSize*objSize bytes long /// /// The record concludes:- /// /// Int_t EndMarker End of record marker = 0xddbbccaa ///\endverbatim COMET::IDbiBinaryFile& COMET::IDbiBinaryFile::operator << (vector& arr) { if ( ! this->CanWrite() ) return *this; UInt_t marker = StartMarker; (*this) << marker; Int_t arrSize = arr.size(); (*this) << arrSize; if ( arrSize ) { COMET::IDbiTableRow* obj = arr[0]; Int_t objSize = obj->IsA()->Size(); string objName = obj->ClassName(); (*this) << objName << objSize; for (int row = 0; row < arrSize; ++row ) { obj = arr[row]; const char* p = reinterpret_cast(arr[row]); this->Write(p,objSize); } } marker = EndMarker; (*this) << marker; return *this; } // The functions that do the low-level I/O. // **************************************** //..................................................................... Bool_t COMET::IDbiBinaryFile::CanRead() { if ( ! fReading ) { COMETSevere( "Attempting to read from a write-only file" << " "); return kFALSE; } return this->IsOK(); } //..................................................................... Bool_t COMET::IDbiBinaryFile::CanWrite() { if ( fReading ) { COMETSevere( "Attempting to write to a read-only file" << " "); return kFALSE; } return this->IsOK(); } //..................................................................... void COMET::IDbiBinaryFile::CheckFileStatus() { // If file was good but has just gone bad, report and close it. // Delete it if writing. if ( fFile && ! fHasErrors && ( ! fFile->is_open() || ! fFile->good() ) ) { COMETSevere( "File not open or has gone bad," << " all further I/O will fail." << " "); fHasErrors = kTRUE; this->Close(); //Delete file if writing. if ( ! fReading ) { COMETSevere( "Erasing " << fFileName << " "); gSystem->Unlink(fFileName.c_str()); } } } //..................................................................... Bool_t COMET::IDbiBinaryFile::Read(char* bytes, UInt_t numBytes) { // // // Purpose: Low-level I/O with error checking. // if ( ! this->CanRead() ) return kFALSE; fFile->read(bytes,numBytes); this->CheckFileStatus(); return ! fHasErrors; } //..................................................................... Bool_t COMET::IDbiBinaryFile::Write(const char* bytes, UInt_t numBytes) { // // // Purpose: Low-level I/O with error checking. // if ( ! this->CanWrite() ) return kFALSE; fFile->write(bytes,numBytes); this->CheckFileStatus(); return ! fHasErrors; }