inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/rroot/file
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_rroot_file
00005 #define inlib_rroot_file
00006 
00007 //inheritance :
00008 #include "ifile"
00009 
00010 #include "directory"
00011 
00012 #include "../platform"
00013 
00014 #include <string>
00015 #include <fcntl.h>
00016 #include <errno.h>
00017 
00018 #ifdef WIN32
00019 #define ssize_t int
00020 #include <io.h>
00021 #include <sys/stat.h>
00022 // disable the warning about the usage of "this" in the constructor.
00023 #pragma warning(disable:4355)
00024 #endif
00025 
00026 namespace inlib {
00027 namespace rroot {
00028 
00029 class file : public virtual ifile {
00030   static int not_open() {return -1;}
00031 public: //ifile
00032   virtual bool verbose() const {return m_verbose;}
00033   virtual std::ostream& out() {return m_out;}
00034 
00035   virtual bool byte_swap() const {return is_little_endian();}
00036   virtual bool set_pos(seek a_offset = 0,from a_from = begin){
00037     int whence = 0;
00038     switch(a_from) {
00039     case begin:
00040       whence = SEEK_SET;
00041       break;
00042     case current:
00043       whence = SEEK_CUR;
00044       break;
00045     case end:
00046       whence = SEEK_END;
00047       break;
00048     }
00049 
00050 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
00051     if (::lseek64(m_file, a_offset, whence) < 0) {
00052 #elif defined(WIN32)
00053     if (::_lseeki64(m_file, a_offset, whence) < 0) {
00054 #else
00055     if (::lseek(m_file, a_offset, whence) < 0) {
00056 #endif
00057       m_out << "inlib::rroot::file::set_pos :"
00058             << " cannot set position " << a_offset 
00059             << " in file " << sout(m_path) << "."
00060             << std::endl;
00061       return false;
00062     }
00063     return true;
00064   }
00065   virtual bool read_buffer(char* a_buffer,uint32 a_length) {
00066     // Read a buffer from the file.
00067     // This is the basic low level read operation.
00068     ssize_t siz;
00069     while ((siz = ::read(m_file,a_buffer,a_length)) < 0 && 
00070            error_number() == EINTR) reset_error_number();
00071     if (siz < 0) {
00072       m_out << "inlib::rroot::file::read_buffer :"
00073             << " error reading from file " << sout(m_path) << "."
00074             << std::endl;
00075       return false;
00076     }
00077     if (siz != ssize_t(a_length)) {
00078       m_out << "inlib::rroot::file::read_buffer :"
00079             << " error reading all requested bytes from file " 
00080             << sout(m_path) << ", got " << long2s(siz)
00081             << " of " << a_length
00082             << std::endl;
00083       return false;
00084     }
00085     m_bytes_read += siz;
00086     return true;
00087   }
00088   virtual bool unziper(char a_key,unzip_func& a_func){
00089     std::map<char,unzip_func>::iterator it = m_unzipers.find(a_key);
00090     if(it==m_unzipers.end()) {
00091       a_func = 0;
00092       return false;
00093     }
00094     a_func = (*it).second;
00095     return true;
00096   }
00097 
00098 public:
00099   file(std::ostream& a_out,
00100               const std::string& a_path,
00101               bool a_verbose = false)
00102   :m_out(a_out)
00103   ,m_path(a_path)
00104   ,m_verbose(a_verbose)
00105   ,m_file(not_open())
00106   ,m_bytes_read(0)
00107   ,m_root_directory(*this)
00108   // begin of record :
00109   ,m_version(0)
00110   ,m_BEGIN(0)
00111   ,m_END(0)
00112   ,m_seek_free(0)
00113   ,m_nbytes_free(0)
00114   ,m_nbytes_name(0)
00115   {
00116 #ifdef INLIB_MEM
00117     mem::increment(s_class().c_str());
00118 #endif
00119 
00120     m_file = _open(a_path.c_str(),
00121 #ifdef WIN32
00122                                O_RDONLY | O_BINARY,S_IREAD | S_IWRITE
00123 #else
00124                                O_RDONLY,0644
00125 #endif
00126     );
00127     if(m_file==not_open()) {
00128       m_out << "inlib::rroot::file::file :"
00129             << " can't open " << sout(a_path) << "."
00130             << std::endl;
00131       return;
00132     }
00133     initialize();
00134   }
00135   virtual ~file() {
00136     close();
00137 #ifdef INLIB_MEM
00138     mem::decrement(s_class().c_str());
00139 #endif
00140   }
00141 protected:
00142   file(const file& a_from)
00143   : ifile(a_from)
00144   ,m_out(a_from.m_out)
00145   ,m_root_directory(*this)
00146   { 
00147 #ifdef INLIB_MEM
00148     mem::increment(s_class().c_str());
00149 #endif
00150   }
00151   file& operator=(const file&){return *this;}
00152 public:
00153   uint32 version() const {return m_version;}
00154 
00155   void close() {
00156     if(m_file!=not_open()) ::close(m_file);
00157     m_file = not_open();
00158     m_root_directory.clear_keys();
00159   }
00160 
00161   directory& dir() {return m_root_directory;}
00162   const directory& dir() const {return m_root_directory;}
00163 
00164   bool add_unziper(char a_key,unzip_func a_func){
00165     std::map<char,unzip_func>::iterator it = m_unzipers.find(a_key);
00166     if(it!=m_unzipers.end()) {
00167       //(*it).second = a_func; //override ?
00168       return false;
00169     } else {
00170       m_unzipers[a_key] = a_func;
00171       return true;
00172     }
00173   }
00174 
00175 protected:
00176   static int _open(const char* a_name,int a_flags,uint32 a_mode) {
00177 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
00178      return ::open64(a_name,a_flags,a_mode);
00179 #else
00180      return ::open(a_name,a_flags,a_mode);
00181 #endif
00182   }
00183   static std::string sout(const std::string& a_string) {
00184     return std::string("\"")+a_string+"\"";
00185   }
00186   bool initialize() {
00187     if(!read_header()) {
00188       m_out << "inlib::rroot::file::initialize :"
00189             << " can't read header."
00190             << std::endl;
00191       return false;
00192     }
00193 /*
00194     fRootDirectory->setSeekDirectory(fBEGIN);
00195     // Read Free segments structure if file is writable :
00196     if (fWritable) {
00197       if (fSeekFree > fBEGIN) {
00198         if(!readFreeSegments()) {
00199           m_out << "inlib::rroot::file::initialize : Cannot read free segments." 
00200                << std::endl;
00201           return false;
00202         }
00203       } else {
00204         m_out << "inlib::rroot::file::initialize : file \"" << fName 
00205              << "\" probably not closed, cannot read free segments" << std::endl;
00206       }
00207     }
00208 */
00209     // Read Directory info :
00210     uint32 nbytes = m_nbytes_name + m_root_directory.record_size(m_version);
00211     char* header = new char[nbytes];
00212     char* buffer = header;
00213     if(!set_pos(m_BEGIN)) {
00214       m_out << "inlib::rroot::file::initialize :"
00215             << " can't set position."
00216             << std::endl;
00217       delete [] header;
00218       return false;
00219     }
00220     if(!read_buffer(buffer,nbytes)) {
00221       m_out << "inlib::rroot::file::initialize :"
00222             << " can't read buffer."
00223             << std::endl;
00224       delete [] header;
00225       return false;
00226     }
00227     buffer = header+m_nbytes_name;
00228     const char* eob = header+nbytes;
00229     if(!m_root_directory.from_buffer(eob,buffer)) {
00230       m_out << "inlib::rroot::file::initialize :"
00231             << " can't read buffer (2)."
00232             << std::endl;
00233       delete [] header;
00234       return false;
00235     }
00236     uint32 nk =          //size of Key
00237       sizeof(int) +      //Key::fNumberOfBytes
00238       sizeof(short) +    //Key::fVersion
00239       2*sizeof(int) +    //Key::fObjectSize, Date
00240       2*sizeof(short) +  //Key::fKeyLength,fCycle
00241       2*sizeof(seek32);  //Key::fSeekKey,fSeekParentDirectory
00242                         //WARNING : the upper is seek32 since at begin of file.
00243     buffer = header+nk;
00244     std::string cname;
00245     rbuf rb(m_out,byte_swap(),eob,buffer);
00246     // Should be "TFile".
00247     if(!rb.read(cname)) {
00248       m_out << "inlib::rroot::file::initialize :"
00249             << " can't read buffer (3)."
00250             << std::endl;
00251       delete [] header;
00252       return false;
00253     }
00254     if(cname!="TFile") {
00255       m_out << "inlib::rroot::file::initialize : TFile expected." << std::endl;
00256       delete [] header;
00257       return false;
00258     }
00259     if(m_verbose) {
00260       m_out << "inlib::rroot::file::initialize :"
00261             << " " << sout("TFile") << " found."
00262             << std::endl;
00263     }
00264     if(!rb.read(cname)) {
00265       m_out << "inlib::rroot::file::initialize :"
00266             << " can't read buffer (4)."
00267             << std::endl;
00268       delete [] header;
00269       return false;
00270     }
00271     if(m_verbose) {
00272       m_out << "inlib::rroot::file::initialize :"
00273             << " found file name " << sout(cname)
00274             << std::endl;
00275     }
00276     if(!rb.read(m_title)) {
00277       m_out << "inlib::rroot::file::initialize :"
00278             << " can't read buffer (5)."
00279             << std::endl;
00280       delete [] header;
00281       return false;
00282     }
00283     delete [] header;
00284     if(m_verbose) {
00285       m_out << "inlib::rroot::file::initialize :"
00286             << " found title " << sout(m_title)
00287             << std::endl;
00288     }
00289     uint32 dirNbytesName = m_root_directory.nbytes_name();
00290     if (dirNbytesName < 10 || dirNbytesName > 1000) {
00291       m_out << "inlib::rroot::file::initialize :"
00292             << " can't read directory info."
00293             << std::endl;
00294       return false;
00295     }
00296     // Read keys of the top directory :
00297     if(m_root_directory.seek_keys() > m_BEGIN) {
00298       uint32 n;
00299       if(!m_root_directory.read_keys(n)) {
00300         m_out << "inlib::rroot::file::initialize :"
00301               << " can't read keys."
00302               << std::endl;
00303         return false;
00304       }
00305     } else {
00306       m_out << "inlib::rroot::file::initialize :"
00307             << " file " << sout(m_path)
00308             << " probably not closed."
00309             << std::endl;
00310       return false;
00311     }
00312     return true;
00313   }
00314   bool read_header() {
00315     static const uint32 kBegin = 64;
00316     char header[kBegin];
00317     if(!set_pos()) return false;
00318     if(!read_buffer(header,kBegin)) return false;
00319     // make sure this is a root file
00320     if(::strncmp(header, "root", 4)) {
00321       m_out << "inlib::rroot::file::read_header :"
00322             << " " << sout(m_path) << " not a ROOT file."
00323             << std::endl;
00324       return false;
00325     }
00326     if(m_verbose) {
00327       m_out << "inlib::rroot::file::read_header :"
00328             << " file signature is " << sout("root")
00329             << std::endl;
00330     }
00331     char* buffer = header + 4;    // skip the "root" file identifier
00332     const char* eob = header + kBegin;
00333     rbuf rb(m_out,byte_swap(),eob,buffer);
00334    {int v;
00335     if(!rb.read(v)) return false;
00336     m_version = v;}
00337    {seek32 i;
00338     if(!rb.read(i)) return false;
00339     m_BEGIN = i;}
00340     if(m_version>1000000) {
00341       if(!rb.read(m_END)) return false;
00342       if(!rb.read(m_seek_free)) return false;
00343     } else {
00344      {seek32 i;
00345       if(!rb.read(i)) return false;
00346       m_END = i;}
00347      {seek32 i;
00348       if(!rb.read(i)) return false;
00349       m_seek_free = i;}
00350     }
00351     if(m_verbose) {
00352       m_out << "inlib::rroot::file::read_header :"
00353             << " begin " << m_BEGIN
00354             << " end " << m_END
00355             << std::endl;
00356     }
00357    {int v;
00358     if(!rb.read(v)) return false;
00359     m_nbytes_free = v;}
00360     int nfree = 0;
00361     if(!rb.read(nfree)) return false;
00362    {int v;
00363     if(!rb.read(v)) return false;
00364     m_nbytes_name = v;}
00365     //m_out << "debug : 1002 " << m_nbytes_name << std::endl;
00366 /*
00367     if(!rb.read(fUnits )) return false;
00368     if(!rb.read(fCompress)) return false;
00369     if(fVersion>1000000) {
00370       if(!rb.read(fSeekInfo)) return false;
00371     } else {
00372      {Seek32 i;
00373       if(!rb.read(i)) return false;
00374       fSeekInfo = i;}
00375     }
00376     if(!rb.read(fNbytesInfo)) return false;
00377 */
00378     return true;
00379   }
00380 
00381   static const std::string& s_class() {
00382     static const std::string s_v("inlib::rroot::file");
00383     return s_v;
00384   }
00385 
00386 #if defined(__sun) && !defined(__linux__) && (__SUNPRO_CC > 0x420)
00387   int error_number() {return ::errno;}
00388   void reset_error_number() {::errno = 0;}
00389 #else
00390   int error_number() {return errno;}
00391   void reset_error_number() {errno = 0;}
00392 #endif
00393 
00394 protected:
00395   std::ostream& m_out;
00396   std::string m_path;
00397   bool m_verbose;
00398   int m_file;
00399   inlib::uint64 m_bytes_read; //Number of bytes read from this file
00400   directory m_root_directory;
00401   std::map<char,unzip_func> m_unzipers;
00402   std::string m_title;
00403   // begin of record :
00404   uint32 m_version;          //File format version
00405   seek m_BEGIN;           //First used byte in file
00406   seek m_END;             //Last used byte in file
00407   seek m_seek_free;       //Location on disk of free segments structure
00408   uint32 m_nbytes_free;      //Number of bytes for free segments structure
00409   //int nfree
00410   uint32 m_nbytes_name;      //Number of bytes in TNamed at creation time
00411 };
00412 
00413 
00414 }}
00415 
00416 #endif
00417 
00418 //doc
00419 //
00420 //  A ROOT file is a suite of consecutive data records with the following
00421 //    format (see also the TKey class);
00422 // TKey ---------------------
00423 //      byte 1->4  Nbytes    = Length of compressed object (in bytes)
00424 //           5->6  Version   = TKey version identifier
00425 //           7->10 ObjLen    = Length of uncompressed object
00426 //          11->14 Datime    = Date and time when object was written to file
00427 //          15->16 KeyLen    = Length of the key structure (in bytes)
00428 //          17->18 Cycle     = Cycle of key
00429 //          19->22 SeekKey   = Pointer to record itself (consistency check)
00430 //          23->26 SeekPdir  = Pointer to directory header
00431 //          27->27 lname     = Number of bytes in the class name
00432 //          28->.. ClassName = Object Class Name
00433 //          ..->.. lname     = Number of bytes in the object name
00434 //          ..->.. Name      = lName bytes with the name of the object
00435 //          ..->.. lTitle    = Number of bytes in the object title
00436 //          ..->.. Title     = Title of the object
00437 //          -----> DATA      = Data bytes associated to the object
00438 //
00439 //  The first data record starts at byte fBEGIN (currently set to kBegin)
00440 //  Bytes 1->kBegin contain the file description:
00441 //       byte  1->4  "root"      = Root file identifier
00442 //             5->8  fVersion    = File format version
00443 //             9->12 fBEGIN      = Pointer to first data record
00444 //            13->16 fEND        = Pointer to first free word at the EOF
00445 //            17->20 fSeekFree   = Pointer to FREE data record
00446 //            21->24 fNbytesFree = Number of bytes in FREE data record
00447 //            25->28 nfree       = Number of free data records
00448 //            29->32 fNbytesName = Number of bytes in TNamed at creation time
00449 //            33->33 fUnits      = Number of bytes for file pointers
00450 //            34->37 fCompress   = Zip compression level
00451 //
00452 
00453 /*
00454 void TFile::ReadStreamerInfo()
00455 {
00456 // Read the list of StreamerInfo from this file
00457 // The key with name holding the list of TStreamerInfo objects is read.
00458 // The corresponding TClass objects are updated.
00459 
00460    TList *list = 0;
00461    if (fSeekInfo > 0 && fSeekInfo < fEND) {
00462       TKey *key = new TKey();
00463       char *buffer = new char[fNbytesInfo+1];
00464       char *buf    = buffer;
00465       Seek(fSeekInfo);
00466       ReadBuffer(buf,fNbytesInfo);
00467       key->ReadBuffer(buf);
00468       TFile *filesave = gFile;
00469       gFile = this; // used in ReadObj
00470       list = (TList*)key->ReadObj();
00471       if (!list) {
00472          gDirectory->GetListOfKeys()->Remove(key);
00473          MakeZombie();
00474       }
00475       gFile = filesave;
00476       delete [] buffer;
00477       delete key;
00478    } else {
00479       list = (TList*)Get("StreamerInfo"); //for versions 2.26 (never released)
00480    }
00481 
00482    if (list == 0) return;
00483    if (gDebug > 0) Info("ReadStreamerInfo", "called for file %s",GetName());
00484 
00485    // loop on all TStreamerInfo classes
00486    TStreamerInfo *info;
00487    TIter next(list);
00488    while ((info = (TStreamerInfo*)next())) {
00489       if (info->IsA() != TStreamerInfo::Class()) {
00490          Warning("ReadStreamerInfo","%s: not a TStreamerInfo object", GetName());
00491          continue;
00492       }
00493       info->BuildCheck();
00494       Int_t uid = info->GetNumber();
00495       Int_t asize = fClassIndex->GetSize();
00496       if (uid >= asize && uid <100000) fClassIndex->Set(2*asize);
00497       if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1;
00498       else {
00499          printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid);
00500       }
00501       if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid);
00502    }
00503    fClassIndex->fArray[0] = 0;
00504    list->Clear();  //this will delete all TStreamerInfo objects with kCanDelete bit set
00505    delete list;
00506 }
00507 
00508 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines