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