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