inlib
1.2.0
|
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 */