Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

DbiBinaryFile.cxx

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

Generated on Mon Feb 15 11:06:34 2010 for loon by  doxygen 1.3.9.1