Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/rroot/file is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef tools_rroot_file
0005 #define tools_rroot_file
0006 
0007 #include "ifile"
0008 
0009 #include "directory"
0010 
0011 #include "../platform"
0012 
0013 #include "obj_list"
0014 #include "info"
0015 #include "streamer_fac"
0016 
0017 #include <string>
0018 #include <fcntl.h>
0019 #include <errno.h>
0020 
0021 #if defined(_MSC_VER) || defined(__MINGW32__)
0022 #include <io.h>
0023 #include <sys/stat.h>
0024 #else
0025 #include <unistd.h>
0026 #endif
0027 
0028 namespace tools {
0029 namespace rroot {
0030 //doc
0031 //
0032 //  A ROOT file is a suite of consecutive data records with the following
0033 //    format (see also the TKey class);
0034 // TKey ---------------------
0035 //      byte 1->4  Nbytes    = Length of compressed object (in bytes)
0036 //           5->6  Version   = TKey version identifier
0037 //           7->10 ObjLen    = Length of uncompressed object
0038 //          11->14 Datime    = Date and time when object was written to file
0039 //          15->16 KeyLen    = Length of the key structure (in bytes)
0040 //          17->18 Cycle     = Cycle of key
0041 //          19->22 SeekKey   = Pointer to record itself (consistency check)
0042 //          23->26 SeekPdir  = Pointer to directory header
0043 //          27->27 lname     = Number of bytes in the class name
0044 //          28->.. ClassName = Object Class Name
0045 //          ..->.. lname     = Number of bytes in the object name
0046 //          ..->.. Name      = lName bytes with the name of the object
0047 //          ..->.. lTitle    = Number of bytes in the object title
0048 //          ..->.. Title     = Title of the object
0049 //          -----> DATA      = Data bytes associated to the object
0050 //
0051 //  The first data record starts at byte fBEGIN (currently set to kBegin)
0052 //  Bytes 1->kBegin contain the file description:
0053 //       byte  1->4  "root"      = Root file identifier
0054 //             5->8  fVersion    = File format version
0055 //             9->12 fBEGIN      = Pointer to first data record
0056 //            13->16 fEND        = Pointer to first free word at the EOF
0057 //            17->20 fSeekFree   = Pointer to FREE data record
0058 //            21->24 fNbytesFree = Number of bytes in FREE data record
0059 //            25->28 nfree       = Number of free data records
0060 //            29->32 fNbytesName = Number of bytes in TNamed at creation time
0061 //            33->33 fUnits      = Number of bytes for file pointers
0062 //            34->37 fCompress   = Zip compression level
0063 //
0064 class file : public virtual ifile {
0065   file& get_me() {return *this;} //_MSC_VER : to avoid warning about the usage of "this" in the constructor.
0066   static int not_open() {return -1;}
0067 public:
0068   static const std::string& s_class() {
0069     static const std::string s_v("tools::rroot::file");
0070     return s_v;
0071   }
0072   virtual const std::string& s_cls() const {return s_class();}
0073 public: //ifile
0074   virtual const std::string& path() const {return m_path;}
0075 
0076   virtual bool verbose() const {return m_verbose;}
0077   virtual std::ostream& out() const {return m_out;}
0078 
0079   virtual bool byte_swap() const {return is_little_endian();}
0080   virtual bool set_pos(seek a_offset = 0,from a_from = begin){
0081     int whence = 0;
0082     switch(a_from) {
0083     case begin:
0084       whence = SEEK_SET;
0085       break;
0086     case current:
0087       whence = SEEK_CUR;
0088       break;
0089     case end:
0090       whence = SEEK_END;
0091       break;
0092     }
0093 
0094 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
0095     if (::lseek64(m_file, a_offset, whence) < 0) {
0096 #elif defined(_MSC_VER) || defined(__MINGW32__)
0097     if (::_lseeki64(m_file, a_offset, whence) < 0) {
0098 #else
0099     if (::lseek(m_file, a_offset, whence) < 0) {
0100 #endif
0101       m_out << "tools::rroot::file::set_pos :"
0102             << " cannot set position " << a_offset
0103             << " in file " << sout(m_path) << "."
0104             << std::endl;
0105       return false;
0106     }
0107     return true;
0108   }
0109   virtual bool read_buffer(char* a_buffer,uint32 a_length) {
0110     // Read a buffer from the file.
0111     // This is the basic low level read operation.
0112 #ifdef _MSC_VER
0113     typedef int ssize_t;
0114 #endif
0115     ssize_t siz;
0116     while ((siz = ::read(m_file,a_buffer,a_length)) < 0 &&
0117            error_number() == EINTR) reset_error_number();
0118     if (siz < 0) {
0119       m_out << "tools::rroot::file::read_buffer :"
0120             << " error reading from file " << sout(m_path) << "."
0121             << std::endl;
0122       return false;
0123     }
0124     if (siz != ssize_t(a_length)) {
0125       m_out << "tools::rroot::file::read_buffer :"
0126             << " error reading all requested bytes from file "
0127             << sout(m_path) << ", got " << long_out(siz)
0128             << " of " << a_length
0129             << std::endl;
0130       return false;
0131     }
0132     m_bytes_read += siz;
0133     return true;
0134   }
0135   virtual bool unziper(char a_key,decompress_func& a_func) const {
0136     std::map<char,decompress_func>::const_iterator it = m_unzipers.find(a_key);
0137     if(it==m_unzipers.end()) {
0138       a_func = 0;
0139       return false;
0140     }
0141     a_func = (*it).second;
0142     return true;
0143   }
0144 
0145   virtual key& sinfos_key() {return m_streamer_infos_key;}
0146 
0147 public:
0148   file(std::ostream& a_out,const std::string& a_path,bool a_verbose = false)
0149   :m_out(a_out)
0150   ,m_path(a_path)
0151   ,m_verbose(a_verbose)
0152   ,m_file(not_open())
0153   ,m_bytes_read(0)
0154   ,m_root_directory(get_me())
0155   ,m_streamer_infos_key(a_out)
0156   ,m_streamer_fac(a_out)
0157   ,m_streamer_infos(m_streamer_fac)
0158   // begin of record :
0159   ,m_version(0)
0160   ,m_BEGIN(0)
0161   ,m_END(0)
0162   ,m_seek_free(0)
0163   ,m_seek_info(0)
0164   ,m_nbytes_free(0)
0165   ,m_nbytes_info(0)
0166   ,m_nbytes_name(0)
0167   {
0168     m_file = _open(a_path.c_str(),
0169 #if defined(_MSC_VER) || defined(__MINGW32__)
0170                                O_RDONLY | O_BINARY,S_IREAD | S_IWRITE
0171 #else
0172                                O_RDONLY,0644
0173 #endif
0174     );
0175     if(m_file==not_open()) {
0176       m_out << "tools::rroot::file::file :"
0177             << " can't open " << sout(a_path) << "."
0178             << std::endl;
0179       return;
0180     }
0181     initialize();
0182   }
0183   virtual ~file() {
0184     close();
0185   }
0186 protected:
0187   file(const file& a_from)
0188   :ifile(a_from)
0189   ,m_out(a_from.m_out)
0190   ,m_root_directory(get_me())
0191   ,m_streamer_infos_key(a_from.m_out)
0192   ,m_streamer_fac(a_from.m_out)
0193   ,m_streamer_infos(m_streamer_fac)
0194   {
0195   }
0196   file& operator=(const file&){return *this;}
0197 public:
0198   uint32 version() const {return m_version;}
0199 
0200   bool is_open() const {
0201     return (m_file==not_open()?false:true);
0202   }
0203 
0204   void close() {
0205     if(m_file!=not_open()) ::close(m_file);
0206     m_file = not_open();
0207     m_root_directory.clear_keys();
0208   }
0209 
0210   directory& dir() {return m_root_directory;}
0211   const directory& dir() const {return m_root_directory;}
0212 
0213   bool add_unziper(char a_key,decompress_func a_func){
0214     std::map<char,decompress_func>::const_iterator it = m_unzipers.find(a_key);
0215     if(it!=m_unzipers.end()) {
0216       //(*it).second = a_func; //override ?
0217       return false;
0218     } else {
0219       m_unzipers[a_key] = a_func;
0220       return true;
0221     }
0222   }
0223 
0224   bool dump_streamer_infos() {
0225     // read_streamer_infos_data() done here (and not in initialize) since it may need to have unziper declared.
0226     if(m_streamer_infos.empty()) {if(!read_streamer_infos_data()) return false;}
0227     tools_vforcit(iro*,m_streamer_infos,it) {
0228       streamer_info* info = safe_cast<iro,streamer_info>(*(*it));
0229       if(!info) return false;
0230       info->out(m_out);
0231     }
0232     return true;
0233   }
0234   streamer_info* find_streamer_info(const std::string& a_class) {
0235     // read_streamer_infos_data() done here (and not in initialize) since it may need to have unziper declared.
0236     if(m_streamer_infos.empty()) {if(!read_streamer_infos_data()) return 0;}
0237     tools_vforcit(iro*,m_streamer_infos,it) {
0238       streamer_info* info = safe_cast<iro,streamer_info>(*(*it));
0239       if(info) {
0240         if(info->name()==a_class) return info;
0241       }
0242     }
0243     return 0;
0244   }
0245 
0246 protected:
0247   static int _open(const char* a_name,int a_flags,uint32 a_mode) {
0248 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
0249      return ::open64(a_name,a_flags,a_mode);
0250 #else
0251      return ::open(a_name,a_flags,a_mode);
0252 #endif
0253   }
0254   static std::string sout(const std::string& a_string) {return "\""+a_string+"\"";}
0255   bool initialize() {
0256     if(!read_header()) {
0257       m_out << "tools::rroot::file::initialize :"
0258             << " can't read header."
0259             << std::endl;
0260       return false;
0261     }
0262 
0263     // Read Directory info :
0264     uint32 nbytes = m_nbytes_name + m_root_directory.record_size(m_version);
0265     char* header = new char[nbytes];
0266     char* buffer = header;
0267     if(!set_pos(m_BEGIN)) {
0268       m_out << "tools::rroot::file::initialize :"
0269             << " can't set position."
0270             << std::endl;
0271       delete [] header;
0272       return false;
0273     }
0274     if(!read_buffer(buffer,nbytes)) {
0275       m_out << "tools::rroot::file::initialize :"
0276             << " can't read buffer."
0277             << std::endl;
0278       delete [] header;
0279       return false;
0280     }
0281     buffer = header+m_nbytes_name;
0282     const char* eob = header+nbytes;
0283     if(!m_root_directory.from_buffer(eob,buffer)) {
0284       m_out << "tools::rroot::file::initialize :"
0285             << " can't read buffer (2)."
0286             << std::endl;
0287       delete [] header;
0288       return false;
0289     }
0290     uint32 nk =          //size of Key
0291       sizeof(int) +      //Key::fNumberOfBytes
0292       sizeof(short) +    //Key::fVersion
0293       2*sizeof(int) +    //Key::fObjectSize, Date
0294       2*sizeof(short) +  //Key::fKeyLength,fCycle
0295       2*sizeof(seek32);  //Key::fSeekKey,fSeekParentDirectory
0296                         //WARNING : the upper is seek32 since at begin of file.
0297     buffer = header+nk;
0298     std::string cname;
0299     rbuf rb(m_out,byte_swap(),eob,buffer);
0300     // Should be "TFile".
0301     if(!rb.read(cname)) {
0302       m_out << "tools::rroot::file::initialize :"
0303             << " can't read buffer (3)."
0304             << std::endl;
0305       delete [] header;
0306       return false;
0307     }
0308     if(cname!="TFile") {
0309       m_out << "tools::rroot::file::initialize : TFile expected." << std::endl;
0310       delete [] header;
0311       return false;
0312     }
0313     if(m_verbose) {
0314       m_out << "tools::rroot::file::initialize :"
0315             << " " << sout("TFile") << " found."
0316             << std::endl;
0317     }
0318     if(!rb.read(cname)) {
0319       m_out << "tools::rroot::file::initialize :"
0320             << " can't read buffer (4)."
0321             << std::endl;
0322       delete [] header;
0323       return false;
0324     }
0325     if(m_verbose) {
0326       m_out << "tools::rroot::file::initialize :"
0327             << " found file name " << sout(cname)
0328             << std::endl;
0329     }
0330     if(!rb.read(m_title)) {
0331       m_out << "tools::rroot::file::initialize :"
0332             << " can't read buffer (5)."
0333             << std::endl;
0334       delete [] header;
0335       return false;
0336     }
0337     delete [] header;
0338     if(m_verbose) {
0339       m_out << "tools::rroot::file::initialize :"
0340             << " found title " << sout(m_title)
0341             << std::endl;
0342     }
0343     uint32 dirNbytesName = m_root_directory.nbytes_name();
0344     if (dirNbytesName < 10 || dirNbytesName > 1000) {
0345       m_out << "tools::rroot::file::initialize :"
0346             << " can't read directory info."
0347             << std::endl;
0348       return false;
0349     }
0350     // Read keys of the top directory :
0351     if(m_root_directory.seek_keys() > m_BEGIN) {
0352       uint32 n;
0353       if(!m_root_directory.read_keys(n)) {
0354         m_out << "tools::rroot::file::initialize :"
0355               << " can't read keys."
0356               << std::endl;
0357         return false;
0358       }
0359     } else {
0360       m_out << "tools::rroot::file::initialize :"
0361             << " file " << sout(m_path)
0362             << " probably not closed."
0363             << std::endl;
0364       return false;
0365     }
0366 
0367     // Create StreamerInfo index
0368     if(m_seek_info > m_BEGIN) {
0369       if(!read_streamer_infos_key()) {
0370         m_out << "tools::rroot::file::initialize :"
0371               << " read_streamer_infos_key() failed."
0372               << std::endl;
0373         return false;
0374       }
0375     } else {
0376       m_out << "tools::rroot::file::initialize :"
0377             << " file " << sout(m_path)
0378             << " probably not closed."
0379             << std::endl;
0380       return false;
0381     }
0382 
0383     return true;
0384   }
0385   bool read_header() {
0386     static const uint32 kBegin = 64;
0387     char header[kBegin];
0388     if(!set_pos()) return false;
0389     if(!read_buffer(header,kBegin)) return false;
0390     // make sure this is a root file
0391     if(::strncmp(header, "root", 4)) {
0392       m_out << "tools::rroot::file::read_header :"
0393             << " " << sout(m_path) << " not a file at the CERN-ROOT format."
0394             << std::endl;
0395       return false;
0396     }
0397     if(m_verbose) {
0398       m_out << "tools::rroot::file::read_header :"
0399             << " file signature is " << sout("root")
0400             << std::endl;
0401     }
0402     char* buffer = header + 4;    // skip the "root" file identifier
0403     const char* eob = header + kBegin;
0404     rbuf rb(m_out,byte_swap(),eob,buffer);
0405    {int v;
0406     if(!rb.read(v)) return false;
0407     m_version = v;}
0408    {seek32 i;
0409     if(!rb.read(i)) return false;
0410     m_BEGIN = i;}
0411     if(m_version>1000000) {
0412       if(!rb.read(m_END)) return false;
0413       if(!rb.read(m_seek_free)) return false;
0414     } else {
0415      {seek32 i;
0416       if(!rb.read(i)) return false;
0417       m_END = i;}
0418      {seek32 i;
0419       if(!rb.read(i)) return false;
0420       m_seek_free = i;}
0421     }
0422     if(m_verbose) {
0423       m_out << "tools::rroot::file::read_header :"
0424             << " begin " << m_BEGIN
0425             << " end " << m_END
0426             << std::endl;
0427     }
0428    {int v;
0429     if(!rb.read(v)) return false;
0430     m_nbytes_free = v;}
0431     int nfree = 0;
0432     if(!rb.read(nfree)) return false;
0433    {int v;
0434     if(!rb.read(v)) return false;
0435     m_nbytes_name = v;}
0436    {char fUnits;
0437     if(!rb.read(fUnits)) return false;}
0438    {int fCompress;
0439     if(!rb.read(fCompress)) return false;}
0440     if(m_version>1000000) {
0441       if(!rb.read(m_seek_info)) return false;
0442     } else {
0443      {seek32 i;
0444       if(!rb.read(i)) return false;
0445       m_seek_info = i;}
0446     }
0447     if(!rb.read(m_nbytes_info)) return false;
0448     return true;
0449   }
0450 
0451   bool read_streamer_infos_key() {
0452     // Read the list of StreamerInfo from this file
0453     // The key with name holding the list of TStreamerInfo objects is read.
0454     // The corresponding TClass objects are updated.
0455     if(m_seek_info<=0) return false;
0456     if(m_seek_info>=m_END) return false;
0457     if(!set_pos(m_seek_info)) return false;
0458     char* buffer = new char[m_nbytes_info+1];
0459     if(!read_buffer(buffer,m_nbytes_info)) {delete [] buffer;return false;}
0460     char* buf = buffer;
0461     if(!m_streamer_infos_key.from_buffer(byte_swap(),buffer+m_nbytes_info,buf,m_verbose)) {
0462       delete [] buffer;
0463       return false;
0464     }
0465     delete [] buffer;
0466     return true;
0467   }
0468 
0469   bool read_streamer_infos_data() {
0470     key& k = m_streamer_infos_key;
0471     if(k.object_class()!="TList") {
0472       m_out << "tools::rroot::file::read_streamer_infos_data : key not a TList." << std::endl;
0473       return false;
0474     }
0475     unsigned int sz;
0476     char* buf = k.get_object_buffer(*this,sz); //we don't have ownership of buf.
0477     if(!buf) {
0478       m_out << "tools::rroot::file::read_streamer_infos :"
0479           << " can't get data buffer of " << k.object_name() << "."
0480           << std::endl;
0481       return false;
0482     }
0483     buffer b(m_out,byte_swap(),sz,buf,k.key_length(),false);
0484     return m_streamer_infos.stream(b);
0485   }
0486 
0487 #if defined(__sun) && !defined(__linux__) && (__SUNPRO_CC > 0x420)
0488   int error_number() {return ::errno;}
0489   void reset_error_number() {::errno = 0;}
0490 #else
0491   int error_number() {return errno;}
0492   void reset_error_number() {errno = 0;}
0493 #endif
0494 
0495 protected:
0496   std::ostream& m_out;
0497   std::string m_path;
0498   bool m_verbose;
0499   int m_file;
0500   uint64 m_bytes_read; //Number of bytes read from this file
0501   directory m_root_directory;
0502   key m_streamer_infos_key;
0503   streamer_fac m_streamer_fac;
0504   obj_list m_streamer_infos;
0505   std::map<char,decompress_func> m_unzipers;
0506   std::string m_title;
0507   // begin of record :
0508   uint32 m_version;       //File format version
0509   seek m_BEGIN;           //First used byte in file
0510   seek m_END;             //Last used byte in file
0511   seek m_seek_free;       //Location on disk of free segments structure
0512   seek m_seek_info;       //Location on disk of StreamerInfo record
0513   uint32 m_nbytes_free;   //Number of bytes for free segments structure
0514   uint32 m_nbytes_info;   //Number of bytes for StreamerInfo record
0515   uint32 m_nbytes_name;   //Number of bytes in TNamed at creation time
0516 };
0517 
0518 
0519 }}
0520 
0521 #endif
0522 
0523