TDbiBinaryFile.cxx

Go to the documentation of this file.
00001 // $Id: TDbiBinaryFile.cxx,v 1.1 2011/01/18 05:49:19 finch Exp $
00002 
00003 #include <iostream>
00004 
00005 #include "TClass.h"
00006 #include "TObject.h"
00007 #include "Api.h"
00008 #include "TSystem.h"
00009 
00010 #include "TDbiBinaryFile.hxx"
00011 #include "TDbiTableRow.hxx"
00012 #include <TSK_DBI_Log.hxx>
00013 #include <MsgFormat.h>
00014 using std::endl;
00015 #include "TVldRange.hxx"
00016 #include "TVldTimeStamp.hxx"
00017 
00018 enum Markers { StartMarker = 0xaabbccdd,
00019                EndMarker   = 0xddbbccaa};
00020 
00021 //   Local utilities.
00022 //   ***************
00023 
00024 void* GetVTptr(const void* obj) {
00025 
00026 //  Return an object's virtual table pointer.
00027 
00028   void* ptr;
00029   memcpy(&ptr,obj,4);
00030   return ptr;
00031 
00032 }
00033 void SetVTptr(void* obj, const void* vt) {
00034 
00035 //  Set an object's virtual table pointer.
00036 
00037   memcpy(obj,&vt,4);
00038 
00039 }
00040 //   Definition of static data members
00041 //   *********************************
00042 
00043 string TDbiBinaryFile::fgWorkDir;
00044 Bool_t TDbiBinaryFile::fgReadAccess  = kTRUE;
00045 Bool_t TDbiBinaryFile::fgWriteAccess = kTRUE;
00046 
00047 
00048 
00049 // Definition of member functions (is same order as TDbiBinaryFile.hxx)
00050 // *****************************************************************
00051 
00052 
00053 //.....................................................................
00054 
00055 TDbiBinaryFile::TDbiBinaryFile(const char* fileName, Bool_t input ) :
00056 fFile(0),
00057 fReading(input),
00058 fHasErrors(kFALSE),
00059 fArrayBuffer(0)
00060 {
00061 //
00062 //
00063 //  Purpose:  Default Constructor.
00064 //
00065 //  Arguments:
00066 //    fileName     in    File name (default: "" => file is a dummy)
00067 //    input        in    true if reading (default = kTRUE)
00068 
00069 //  Specification:-
00070 //  =============
00071 //
00072 //  If file name or fgWorkDir is dummy, or the appropriate access is not set
00073 //  then name is set to dummy otherwise fgWorkDir is prepended to the name.
00074 
00075   // Complete the file name.
00076   fFileName = fileName;
00077   if ( fFileName != "" ) {
00078     Bool_t access = input ? fgReadAccess : fgWriteAccess;
00079     if ( fgWorkDir == "" || ! access ) fFileName = "";
00080     else                               fFileName = fgWorkDir +  fFileName;
00081   }
00082 
00083   // Open the file.
00084   ios_base::openmode mode = ios_base::in|ios_base::binary;
00085   if ( ! input ) mode = ios_base::out|ios_base::binary;
00086 
00087   if ( fFileName == "" ) fHasErrors = kTRUE;
00088   else {
00089     fFile = new fstream(fFileName.c_str(),mode);
00090     if ( ! fFile->is_open() || ! fFile->good() ) {
00091       SK_DBI_Debug( "Cannot open " << fFileName
00092                              << "; all I/O will fail." << "  ");
00093       fHasErrors = kTRUE;
00094     }
00095   }
00096 
00097 }
00098 //.....................................................................
00099 ///  Purpose:  Default Destructor.
00100 TDbiBinaryFile::~TDbiBinaryFile()
00101 {
00102 //
00103 //
00104 
00105 
00106   delete[] fArrayBuffer;
00107   fArrayBuffer = 0;
00108   this->Close();
00109   delete fFile;
00110   fFile = 0;
00111 
00112 }
00113 //.....................................................................
00114 ///  Purpose:  Close file.
00115 void TDbiBinaryFile::Close()
00116 {
00117 //
00118 //
00119 
00120 
00121   if ( fFile ) fFile->close();
00122 }
00123 
00124 //  Builtin data type I/O.
00125 //  **********************
00126 
00127 #define READ_BUILTIN(t)                                   \
00128                                                           \
00129 TDbiBinaryFile& TDbiBinaryFile::operator >> (t& v) {        \
00130   UInt_t numBytes = sizeof(v);                            \
00131   char* bytes = reinterpret_cast<char*>(&v);              \
00132   this->Read(bytes,numBytes);                             \
00133   return *this;                                           \
00134 }
00135 #define WRITE_BUILTIN(t)                                  \
00136                                                           \
00137 TDbiBinaryFile& TDbiBinaryFile::operator << (const t& v) {  \
00138   UInt_t numBytes = sizeof(v);                            \
00139   const char* bytes = reinterpret_cast<const char*>(&v);  \
00140   this->Write(bytes,numBytes);                            \
00141   return *this;                                           \
00142 }
00143 
00144 READ_BUILTIN(Bool_t)
00145 WRITE_BUILTIN(Bool_t)
00146 READ_BUILTIN(Int_t)
00147 WRITE_BUILTIN(Int_t)
00148 READ_BUILTIN(UInt_t)
00149 WRITE_BUILTIN(UInt_t)
00150 READ_BUILTIN(Double_t)
00151 WRITE_BUILTIN(Double_t)
00152 
00153 
00154 //  Simple Virtual object I/O
00155 //  *************************
00156 
00157 #define READ_SIMPLE(t)                                    \
00158                                                           \
00159 TDbiBinaryFile& TDbiBinaryFile::operator >> (t& v) {        \
00160   void* vt = GetVTptr(&v);                                \
00161   UInt_t numBytes = sizeof(v);                            \
00162   char* bytes = reinterpret_cast<char*>(&v);              \
00163   this->Read(bytes,numBytes);                             \
00164   SetVTptr(&v,vt);                                        \
00165   return *this;                                           \
00166 }
00167 #define WRITE_SIMPLE(t)                                   \
00168                                                           \
00169 TDbiBinaryFile& TDbiBinaryFile::operator << (const t& v) {  \
00170   UInt_t numBytes = sizeof(v);                            \
00171   const char* bytes = reinterpret_cast<const char*>(&v);  \
00172   this->Write(bytes,numBytes);                            \
00173   return *this;                                           \
00174 }
00175 
00176 READ_SIMPLE(TVldTimeStamp)
00177 WRITE_BUILTIN(TVldTimeStamp)
00178 
00179 
00180 //  String I/O.
00181 //  ***********
00182 
00183 //.....................................................................
00184 
00185 TDbiBinaryFile& TDbiBinaryFile::operator >> (string& str) {
00186 
00187   if ( this->CanRead() ) {
00188     getline(*fFile,str,'\0');
00189     this->CheckFileStatus();
00190   }
00191   return *this;
00192 }
00193 //.....................................................................
00194 
00195 TDbiBinaryFile& TDbiBinaryFile::operator << (const string& str) {
00196 
00197   UInt_t numBytes = str.size()+1;
00198   this->Write(str.c_str(),numBytes);
00199   return *this;
00200 }
00201 
00202 //.....................................................................
00203 
00204 TDbiBinaryFile& TDbiBinaryFile::operator >> (TVldRange& vr) {
00205 
00206   if ( this->CanRead() ) {
00207     Int_t        detectorMask;
00208     Int_t        simMask;
00209     TVldTimeStamp timeStart;
00210     TVldTimeStamp timeEnd;
00211     string str;
00212     (*this) >> detectorMask
00213             >> simMask
00214             >> timeStart
00215             >> timeEnd
00216             >> str;
00217     TString dataSource(str.c_str());
00218     TVldRange tmp(detectorMask,simMask,timeStart,timeEnd,dataSource);
00219     vr = tmp;
00220   }
00221   return *this;
00222 }
00223 //.....................................................................
00224 
00225 TDbiBinaryFile& TDbiBinaryFile::operator << (const TVldRange& vr) {
00226 
00227   if ( this->CanWrite() ) {
00228     string str(vr.GetDataSource().Data());
00229     (*this) << vr.GetDetectorMask()
00230             << vr.GetSimMask()
00231             << vr.GetTimeStart()
00232             << vr.GetTimeEnd()
00233             << str;
00234   }
00235   return *this;
00236 }
00237 
00238 //.....................................................................
00239 ///\verbatim
00240 /// Vector I/O.
00241 /// ***********
00242 ///
00243 ///
00244 ///  Purpose: Read a vector of objects inheriting from TDbiTableRow.
00245 ///
00246 ///   NB:     On entry, array must be empty.
00247 ///
00248 ///
00249 ///           The objects are written into a buffer that is a contiguous
00250 ///           area of memory that is allocated to receive it. After a
00251 ///           successful read the user must call ReleaseArrayBuffer to take
00252 ///           control over this buffer as it will be automatically release
00253 ///           when the next array input occurs otherwise.
00254 ///
00255 //  For the format of record see the operator <<.
00256 ///\endverbatim
00257 TDbiBinaryFile& TDbiBinaryFile::operator >> (vector<TDbiTableRow*>& arr) {
00258 
00259 
00260   if ( ! this->CanRead() ) return *this;
00261 
00262   if ( arr.size() ) {
00263        SK_DBI_Severe( "Attempting to read into non-empty array" << "  ");
00264     return *this;
00265   }
00266 
00267 // Check for start of array marker.
00268 
00269   UInt_t marker = 0;
00270   (*this) >> marker;
00271   if ( marker != StartMarker ) {
00272        SK_DBI_Severe( "Cannot find start of array marker" << "  ");
00273     this->Close();
00274     this->CheckFileStatus();
00275     return *this;
00276   }
00277 
00278 //  Get array size and deal with non-empty arrays.
00279 
00280   Int_t arrSize = 0;
00281   (*this) >> arrSize;
00282 
00283   if ( arrSize ) {
00284     Int_t objSize  = 0;
00285     string objName;
00286     (*this) >> objName >> objSize;
00287 
00288 //  Ensure that sizes look sensible and use ROOT to instatiate
00289 //  an example object so that we can get the address of the
00290 //  virtual table.
00291 
00292     TClass objClass(objName.c_str());
00293     Int_t objSizefromRoot = objClass.Size();
00294     void* obj = objClass.New();
00295     void* vt  = GetVTptr(obj);
00296 //  This only works if the address of the sub-class object is the same
00297 //  as the underlying base class, which should be true in this simple case.
00298     TDbiTableRow* tr = reinterpret_cast<TDbiTableRow*>(obj);
00299     delete tr;
00300 
00301     SK_DBI_Verbose(  "Restoring array of " << arrSize << " "
00302          << objName << " objects"
00303          << "  VTaddr " << std::ios::hex << vt << std::ios::dec 
00304          << " object size "  << objSize << "(from file) "
00305          << objSizefromRoot << "(from ROOT)"
00306          << "  ");
00307 
00308     if ( arrSize < 0 || objSize != objSizefromRoot ) {
00309          SK_DBI_Severe( "Illegal  array size ("<< arrSize
00310                             << ") or object size(" << objSize
00311                             << "," << objSizefromRoot << ")" << "  ");
00312       this->Close();
00313       this->CheckFileStatus();
00314       return *this;
00315     }
00316 
00317 //  Allocate buffer and load in array.
00318     delete[] fArrayBuffer;
00319     Int_t buffSize = arrSize*objSize;
00320     fArrayBuffer = new char[buffSize];
00321     this->Read(fArrayBuffer,buffSize);
00322 
00323 //  Fix up VT pointers and populate the vector.
00324 
00325     char* elem = fArrayBuffer;
00326     arr.reserve(arrSize);
00327     for (int row = 0; row < arrSize; ++row ) {
00328       SetVTptr(elem,vt);
00329       arr.push_back(reinterpret_cast<TDbiTableRow*>(elem));
00330       elem += objSize;
00331     }
00332 
00333   }
00334 
00335 //  Check for end of array marker.
00336 
00337   (*this) >> marker;
00338   if ( marker != EndMarker ) {
00339        SK_DBI_Severe( "Cannot find end of array marker" << "  ");
00340     this->Close();
00341     this->CheckFileStatus();
00342   }
00343 
00344   return *this;
00345 
00346 }
00347 
00348 ///.....................................................................
00349 ///\verbatim
00350 ///
00351 ///  Purpose: Write a vector of objects inheriting from TDbiTableRow.
00352 ///
00353 ///  Format of record:-
00354 ///
00355 ///  Int_t   StartMarker  Start of record marker = 0xaabbccdd
00356 ///  Int_t   arrSize      Size of vector
00357 ///
00358 ///  If size of vector > 0 this is folowed by:-
00359 ///
00360 ///  string  objName      Name of object
00361 ///  Int_t   objSize      Size of object
00362 ///  char*                The data arrSize*objSize bytes long
00363 ///
00364 ///  The record concludes:-
00365 ///
00366 ///  Int_t     EndMarker  End of record marker = 0xddbbccaa
00367 ///\endverbatim
00368 TDbiBinaryFile& TDbiBinaryFile::operator << (vector<TDbiTableRow*>& arr) {
00369 
00370 
00371   if ( ! this->CanWrite() ) return *this;
00372 
00373   UInt_t marker = StartMarker;
00374   (*this) << marker;
00375   Int_t arrSize = arr.size();
00376   (*this) << arrSize;
00377 
00378   if ( arrSize ) {
00379     TDbiTableRow* obj = arr[0];
00380     Int_t objSize  = obj->IsA()->Size();
00381     string objName = obj->ClassName();
00382     (*this) << objName << objSize;
00383     for (int row = 0; row < arrSize; ++row ) {
00384       obj = arr[row];
00385       const char* p = reinterpret_cast<const char*>(arr[row]);
00386       this->Write(p,objSize);
00387     }
00388 
00389   }
00390 
00391   marker = EndMarker;
00392   (*this) << marker;
00393 
00394   return *this;
00395 
00396 }
00397 
00398 // The functions that do the low-level I/O.
00399 // ****************************************
00400 
00401 //.....................................................................
00402 
00403 Bool_t TDbiBinaryFile::CanRead() {
00404 
00405   if ( ! fReading ) {
00406        SK_DBI_Severe( "Attempting to read from a write-only file" << "  ");
00407     return kFALSE;
00408   }
00409   return this->IsOK();
00410 
00411 }
00412 //.....................................................................
00413 
00414 Bool_t TDbiBinaryFile::CanWrite() {
00415 
00416   if ( fReading ) {
00417        SK_DBI_Severe( "Attempting to write to a read-only file" << "  ");
00418     return kFALSE;
00419   }
00420   return this->IsOK();
00421 
00422 }
00423 
00424 //.....................................................................
00425 
00426 void TDbiBinaryFile::CheckFileStatus() {
00427 
00428 //  If file was good but has just gone bad, report and close it.
00429 //  Delete it if writing.
00430 
00431   if (    fFile
00432        && ! fHasErrors
00433        && ( ! fFile->is_open() || ! fFile->good() ) ) {
00434        SK_DBI_Severe( "File not open or has gone bad,"
00435                            << " all further I/O will fail." << "  ");
00436     fHasErrors = kTRUE;
00437     this->Close();
00438 
00439     //Delete file if writing.
00440     if ( ! fReading ) {
00441          SK_DBI_Severe( "Erasing " << fFileName << "  ");
00442       gSystem->Unlink(fFileName.c_str());
00443     }
00444 
00445   }
00446 
00447 }
00448 
00449 //.....................................................................
00450 
00451 Bool_t TDbiBinaryFile::Read(char* bytes, UInt_t numBytes) {
00452 //
00453 //
00454 //  Purpose: Low-level I/O with error checking.
00455 //
00456 
00457   if ( ! this->CanRead() ) return kFALSE;
00458 
00459   fFile->read(bytes,numBytes);
00460   this->CheckFileStatus();
00461   return ! fHasErrors;
00462 }
00463 
00464 //.....................................................................
00465 
00466 Bool_t TDbiBinaryFile::Write(const char* bytes, UInt_t numBytes) {
00467 //
00468 //
00469 //  Purpose: Low-level I/O with error checking.
00470 //
00471 
00472   if ( ! this->CanWrite() ) return kFALSE;
00473 
00474   fFile->write(bytes,numBytes);
00475   this->CheckFileStatus();
00476   return ! fHasErrors;
00477 }
00478 
00479 

Generated on 11 Aug 2013 for SKDatabase by  doxygen 1.6.1