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_key 00005 #define inlib_rroot_key 00006 00007 #include "rbuf" 00008 #include "seek" 00009 #include "date" 00010 #include "ifile" 00011 00012 #ifdef INLIB_MEM 00013 #include "../mem" 00014 #endif 00015 00016 #include <map> 00017 #include <ostream> 00018 00019 //#include <zlib.h> 00020 00021 extern "C" { 00022 void csz__Init_Inflate(long,unsigned char*,long,unsigned char*); 00023 int csz__Inflate(); 00024 unsigned char* csz__obufptr(); 00025 } 00026 00027 namespace inlib { 00028 namespace rroot { 00029 00030 class key { 00031 static uint32 class_version() {return 2;} 00032 public: 00033 static uint32 std_string_record_size(const std::string& x) { 00034 // Returns size string will occupy on I/O buffer. 00035 if (x.size() > 254) 00036 return x.size()+sizeof(unsigned char)+sizeof(int); 00037 else 00038 return x.size()+sizeof(unsigned char); 00039 } 00040 00041 public: 00042 key(ifile& a_file) 00043 :m_file(a_file) 00044 ,m_buf_size(0) 00045 ,m_buffer(0) 00046 // Record : 00047 ,m_nbytes(0) 00048 ,m_version(class_version()) 00049 ,m_object_size(0) 00050 ,m_date(0) 00051 ,m_key_length(0) 00052 ,m_cycle(0) 00053 ,m_seek_key(0) 00054 ,m_seek_parent_dir(0) 00055 //,m_object_class 00056 //,m_object_name 00057 //,m_object_title 00058 { 00059 #ifdef INLIB_MEM 00060 mem::increment(s_class().c_str()); 00061 #endif 00062 m_key_length = record_size(m_version); 00063 //fDate.setDate(0); 00064 } 00065 00066 key(ifile& a_file,seek a_pos,uint32 a_nbytes) 00067 :m_file(a_file) 00068 ,m_buf_size(0) 00069 ,m_buffer(0) 00070 // Record : 00071 ,m_nbytes(a_nbytes) //key len + compressed object size 00072 ,m_version(class_version()) 00073 ,m_object_size(0) 00074 ,m_date(0) 00075 ,m_key_length(0) 00076 ,m_cycle(0) 00077 ,m_seek_key(a_pos) 00078 ,m_seek_parent_dir(0) 00079 //,m_object_class 00080 //,m_object_name 00081 //,m_object_title 00082 { 00083 #ifdef INLIB_MEM 00084 mem::increment(s_class().c_str()); 00085 #endif 00086 if(a_pos>START_BIG_FILE) m_version += 1000; 00087 m_buffer = new char[a_nbytes]; 00088 if(!m_buffer) { 00089 m_file.out() << "inlib::rroot::key::key(cpcstor) :" 00090 << " can't alloc " << a_nbytes << "." 00091 << std::endl; 00092 } else { 00093 m_buf_size = a_nbytes; 00094 } 00095 } 00096 virtual ~key(){ 00097 delete [] m_buffer; 00098 #ifdef INLIB_MEM 00099 mem::decrement(s_class().c_str()); 00100 #endif 00101 } 00102 protected: 00103 key(const key& a_from) 00104 :m_file(a_from.m_file) 00105 ,m_buf_size(0) 00106 ,m_buffer(0) 00107 ,m_nbytes(a_from.m_nbytes) 00108 ,m_version(a_from.m_version) 00109 ,m_object_size(a_from.m_object_size) 00110 ,m_date(a_from.m_date) 00111 ,m_key_length(a_from.m_key_length) 00112 ,m_cycle(a_from.m_cycle) 00113 ,m_seek_key(a_from.m_seek_key) 00114 ,m_seek_parent_dir(a_from.m_seek_parent_dir) 00115 ,m_object_class(a_from.m_object_class) 00116 ,m_object_name(a_from.m_object_name) 00117 ,m_object_title(a_from.m_object_title) 00118 { 00119 #ifdef INLIB_MEM 00120 mem::increment(s_class().c_str()); 00121 #endif 00122 if(a_from.m_buf_size && a_from.m_buffer) { 00123 m_buffer = new char[a_from.m_buf_size]; 00124 if(!m_buffer) { 00125 m_file.out() << "inlib::rroot::key::key(cpcstor) :" 00126 << " can't alloc " << a_from.m_buf_size << "." 00127 << std::endl; 00128 } else { 00129 m_buf_size = a_from.m_buf_size; 00130 ::memcpy(m_buffer,a_from.m_buffer,a_from.m_buf_size); 00131 } 00132 } 00133 } 00134 public: 00135 key& operator=(const key& a_from){ 00136 m_nbytes = a_from.m_nbytes; 00137 m_version = a_from.m_version; 00138 m_object_size = a_from.m_object_size; 00139 m_date = a_from.m_date; 00140 m_key_length = a_from.m_key_length; 00141 m_cycle = a_from.m_cycle; 00142 m_seek_key = a_from.m_seek_key; 00143 m_seek_parent_dir = a_from.m_seek_parent_dir; 00144 m_object_class = a_from.m_object_class; 00145 m_object_name = a_from.m_object_name; 00146 m_object_title = a_from.m_object_title; 00147 00148 delete [] m_buffer; 00149 m_buffer = 0; 00150 m_buf_size = 0; 00151 00152 if(a_from.m_buf_size && a_from.m_buffer) { 00153 m_buffer = new char[a_from.m_buf_size]; 00154 if(!m_buffer) { 00155 m_file.out() << "inlib::rroot::key::operator=() :" 00156 << " can't alloc " << a_from.m_buf_size << "." 00157 << std::endl; 00158 } else { 00159 m_buf_size = a_from.m_buf_size; 00160 ::memcpy(m_buffer,a_from.m_buffer,a_from.m_buf_size); 00161 } 00162 } 00163 00164 return *this; 00165 } 00166 00167 public: 00168 ifile& file() {return m_file;} 00169 00170 uint32 nbytes() const {return m_nbytes;} 00171 seek seek_key() const {return m_seek_key;} 00172 uint32 object_size() const {return m_object_size;} 00173 00174 const std::string& object_name() const {return m_object_name;} 00175 std::string object_name() {return m_object_name;} 00176 00177 const std::string& object_title() const {return m_object_title;} 00178 std::string object_title() {return m_object_title;} 00179 00180 const std::string& object_class() const {return m_object_class;} 00181 std::string object_class() {return m_object_class;} 00182 00183 bool read_file(){ 00184 // Read the key structure from the file. 00185 if(!m_file.set_pos(m_seek_key)) return false; 00186 if(!m_file.read_buffer(m_buffer,m_nbytes)) return false; 00187 if(m_file.verbose()) { 00188 m_file.out() << "inlib::rroot::key::read_file :" 00189 << " reading " << m_nbytes << " bytes" 00190 << " at position " << m_seek_key 00191 << "." 00192 << std::endl; 00193 } 00194 return true; 00195 } 00196 00197 char* buf() const {return m_buffer;} 00198 char* data_buffer() const {return m_buffer + m_key_length;} 00199 const char* eob() const {return m_buffer + m_buf_size;} 00200 uint32 buf_size() const {return m_buf_size;} 00201 uint32 key_length() const {return m_key_length;} 00202 00203 bool from_buffer(const char* aEOB,char*& a_pos) { 00204 rbuf rb(m_file.out(),m_file.byte_swap(),aEOB,a_pos); 00205 int nbytes; 00206 if(!rb.read(nbytes)) return false; 00207 /* 00208 if(m_nbytes) { 00209 if(nbytes!=int(m_nbytes)) { 00210 out << "inlib::rroot::key::from_buffer :" 00211 << " nbytes not consistent." 00212 << " read " << nbytes 00213 << ", expected " << m_nbytes 00214 << ". Continue with " << nbytes 00215 << std::endl; 00216 m_nbytes = nbytes; 00217 } 00218 } else { 00219 */ 00220 m_nbytes = nbytes; 00221 //} 00222 short version; 00223 if(!rb.read(version)) return false; 00224 m_version = version; 00225 {int v; 00226 if(!rb.read(v)) return false; 00227 m_object_size = v;} 00228 unsigned int date; 00229 if(!rb.read(date)) return false; 00230 //fDate.setDate(date); 00231 {short v; 00232 if(!rb.read(v)) return false; 00233 m_key_length = v;} 00234 {short v; 00235 if(!rb.read(v)) return false; 00236 m_cycle = v;} 00237 if(version>1000) { 00238 if(!rb.read(m_seek_key)) return false; 00239 if(!rb.read(m_seek_parent_dir)) return false; 00240 } else { 00241 {seek32 i; 00242 if(!rb.read(i)) return false; 00243 m_seek_key = i;} 00244 {seek32 i; 00245 if(!rb.read(i)) return false; 00246 m_seek_parent_dir = i;} 00247 } 00248 if(!rb.read(m_object_class)) return false; 00249 if(!rb.read(m_object_name)) return false; 00250 if(!rb.read(m_object_title)) return false; 00251 if(m_file.verbose()) { 00252 m_file.out() << "inlib::rroot::key::from_buffer :" 00253 << " nbytes : " << m_nbytes 00254 << ", object class : " << sout(m_object_class) 00255 << ", object name : " << sout(m_object_name) 00256 << ", object title : " << sout(m_object_title) 00257 << ", object size : " << m_object_size 00258 << "." 00259 << std::endl; 00260 } 00261 return true; 00262 } 00263 00264 char* get_object_buffer(uint32& a_size) { 00265 if(!m_key_length) { 00266 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00267 << " WARNING : m_key_length is zero." 00268 << std::endl; 00269 //delete [] m_buffer; 00270 //m_buffer = 0; 00271 //m_buf_size = 0; 00272 //a_size = 0; 00273 //return 0; 00274 } 00275 if(!m_nbytes) { 00276 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00277 << " m_nbytes is zero." 00278 << std::endl; 00279 delete [] m_buffer; 00280 m_buffer = 0; 00281 m_buf_size = 0; 00282 a_size = 0; 00283 return 0; 00284 } 00285 if(!m_object_size) { 00286 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00287 << " WARNING : m_object_size is zero." 00288 << std::endl; 00289 } 00290 00291 if(m_file.verbose()) { 00292 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00293 << " m_nbytes : " << m_nbytes 00294 << " m_key_length : " << m_key_length 00295 << " m_object_size : " << m_object_size << "." 00296 << " m_seek_key : " << m_seek_key << "." 00297 << std::endl; 00298 } 00299 00300 if(m_object_size <= (m_nbytes-m_key_length)) { 00301 delete [] m_buffer; 00302 m_buf_size = m_key_length+m_object_size; 00303 if(m_buf_size<m_nbytes) { 00304 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00305 << " WARNING : m_buf_size<m_nbytes." 00306 << " m_buf_size " << m_buf_size 00307 << " m_nbytes " << m_nbytes 00308 << ". Raise m_buf_size to " << m_nbytes << "." 00309 << std::endl; 00310 m_buf_size = m_nbytes; //for read_file() 00311 } 00312 m_buffer = new char[m_buf_size]; 00313 if(!m_buffer) { 00314 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00315 << " can't alloc " << m_buf_size 00316 << std::endl; 00317 m_buffer = 0; 00318 m_buf_size = 0; 00319 a_size = 0; 00320 return 0; 00321 } 00322 00323 if(!read_file()) { 00324 delete [] m_buffer; 00325 m_buffer = 0; 00326 m_buf_size = 0; 00327 a_size = 0; 00328 return 0; 00329 } 00330 00331 } else { 00332 // have to decompress. Need a second buffer. 00333 00334 uint32 decsiz = m_key_length+m_object_size; 00335 char* decbuf = new char[decsiz]; 00336 if(!decbuf) { 00337 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00338 << " can't alloc " << decsiz 00339 << std::endl; 00340 a_size = 0; 00341 return 0; 00342 } 00343 00344 delete [] m_buffer; 00345 m_buffer = new char[m_nbytes]; 00346 m_buf_size = m_nbytes; 00347 if(!read_file()) { 00348 delete [] decbuf; 00349 decbuf = 0; 00350 delete [] m_buffer; 00351 m_buffer = 0; 00352 m_buf_size = 0; 00353 a_size = 0; 00354 return 0; 00355 } 00356 00357 ::memcpy(decbuf,m_buffer,m_key_length); 00358 00359 // decompress : 00360 unsigned char* objbuf = (unsigned char*)(decbuf+m_key_length); 00361 unsigned char* bufcur = (unsigned char*)(m_buffer+m_key_length); 00362 int nout = 0; 00363 uint32 noutot = 0; 00364 while(true) { 00365 int nin = 00366 9 + ((int)bufcur[3] | ((int)bufcur[4] << 8) | ((int)bufcur[5] << 16)); 00367 int nbuf = 00368 (int)bufcur[6] | ((int)bufcur[7] << 8) | ((int)bufcur[8] << 16); 00369 if(!unzip(m_file.out(),nin,bufcur, nbuf,objbuf, nout)) break; 00370 if(!nout) break; 00371 noutot += nout; 00372 if(noutot >= m_object_size) break; 00373 bufcur += nin; 00374 objbuf += nout; 00375 } 00376 00377 delete [] m_buffer; 00378 m_buffer = 0; 00379 m_buf_size = 0; 00380 00381 if(!noutot) { 00382 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00383 << " nothing from decompression." 00384 << std::endl; 00385 delete [] decbuf; 00386 decbuf = 0; 00387 a_size = 0; 00388 return 0; 00389 } 00390 if(noutot!=m_object_size) { 00391 m_file.out() << "inlib::rroot::key::get_object_buffer :" 00392 << " decompression mismatch." 00393 << " noutot " << noutot 00394 << " m_object_size " << m_object_size 00395 << std::endl; 00396 delete [] decbuf; 00397 decbuf = 0; 00398 a_size = 0; 00399 return 0; 00400 } 00401 00402 m_buffer = decbuf; 00403 m_buf_size = decsiz; 00404 00405 } 00406 a_size = m_object_size; 00407 return m_buffer+m_key_length; 00408 } 00409 //NOTE : print is a Python keyword. 00410 void dump(std::ostream& a_out) const { 00411 a_out << "class : " << sout(m_object_class) 00412 << ", name : " << sout(m_object_name) 00413 << ", title : " << sout(m_object_title) 00414 << ", size : " << m_object_size 00415 << "." 00416 << std::endl; 00417 } 00418 00419 protected: 00420 static const uint32 START_BIG_FILE = 2000000000; 00421 protected: 00422 uint32 record_size(uint32 a_version) const { 00423 // Return the size in bytes of the key header structure. 00424 uint32 nbytes = sizeof(m_nbytes); 00425 nbytes += sizeof(short); //2 00426 nbytes += sizeof(m_object_size); 00427 nbytes += sizeof(date); 00428 nbytes += sizeof(m_key_length); 00429 nbytes += sizeof(m_cycle); //2+4*4=18 00430 if(a_version>1000) { 00431 nbytes += sizeof(seek); 00432 nbytes += sizeof(seek); //18+2*8=34 00433 } else { 00434 nbytes += sizeof(seek32); 00435 nbytes += sizeof(seek32); //18+2*4=26 00436 } 00437 nbytes += std_string_record_size(m_object_class); 00438 nbytes += std_string_record_size(m_object_name); 00439 nbytes += std_string_record_size(m_object_title); 00440 //::printf("debug : record_size %d\n",nbytes); 00441 return nbytes; 00442 } 00443 static std::string sout(const std::string& a_string) { 00444 return std::string("\"")+a_string+"\""; 00445 } 00446 00447 bool unzip(std::ostream& a_out, 00448 int a_srcsize,unsigned char* a_src, 00449 int a_tgtsize,unsigned char* a_tgt, 00450 int& a_irep) { 00451 00452 // Author: E.Chernyaev (IHEP/Protvino) 00453 // Input: scrsize - size of input buffer 00454 // src - input buffer 00455 // tgtsize - size of target buffer 00456 // 00457 // Output: tgt - target buffer (decompressed) 00458 // irep - size of decompressed data 00459 // 0 - if error 00460 00461 a_irep = 0; 00462 00463 // C H E C K H E A D E R 00464 const int HDRSIZE = 9; 00465 00466 if (a_srcsize < HDRSIZE) { 00467 a_out << "inlib::rroot::key::unzip : too small source" << std::endl; 00468 return false; 00469 } 00470 00471 unsigned char DEFLATE = 8; 00472 00473 if ((a_src[0] != 'C' && a_src[0] != 'Z') || 00474 (a_src[1] != 'S' && a_src[1] != 'L') || 00475 a_src[2] != DEFLATE) { 00476 a_out << "inlib::rroot::key::unzip : error in header" << std::endl; 00477 return false; 00478 } 00479 00480 long _ibufcnt = 00481 (long)a_src[3] | ((long)a_src[4] << 8) | ((long)a_src[5] << 16); 00482 long isize = 00483 (long)a_src[6] | ((long)a_src[7] << 8) | ((long)a_src[8] << 16); 00484 00485 if(a_tgtsize<isize) { 00486 a_out << "inlib::rroot::key::unzip : too small target." << std::endl; 00487 return false; 00488 } 00489 00490 if(_ibufcnt + HDRSIZE != a_srcsize) { 00491 a_out << "inlib::rroot::key::unzip :" 00492 << " discrepancy in source length." << std::endl; 00493 return false; 00494 } 00495 00496 // D E C O M P R E S S D A T A 00497 00498 if (a_src[0] == 'Z' && a_src[1] == 'L') { //compressed with zlib. 00499 ifile::unzip_func func; 00500 if(!m_file.unziper('Z',func)) { 00501 a_out << "inlib::rroot::key::unzip : " 00502 << " zlib unziper not found." << std::endl; 00503 return false; 00504 } 00505 00506 if(!func(a_out,a_srcsize,a_src + HDRSIZE,a_tgtsize,a_tgt,a_irep)) { 00507 a_out << "inlib::rroot::key::unzip : " 00508 << " unzip function failed." << std::endl; 00509 return false; 00510 } 00511 00512 } else if (a_src[0] == 'C' && a_src[1] == 'S') { 00513 //compressed with Chernyaev & Smirnov 00514 00515 csz__Init_Inflate(_ibufcnt,a_src + HDRSIZE,a_tgtsize,a_tgt); 00516 00517 if (csz__Inflate()) { 00518 a_out << "inlib::rroot::key::unzip :" 00519 << " error during decompression." << std::endl; 00520 return false; 00521 } 00522 00523 unsigned char* obufptr = csz__obufptr(); 00524 00525 // if (obufptr - a_tgt != isize) { 00526 // There are some rare cases when a few more bytes are required 00527 if (obufptr - a_tgt > a_tgtsize) { 00528 a_out << "inlib::rroot::key::_unzip :" 00529 << " discrepancy " << (int)(obufptr - a_tgt) 00530 << " with initial size: " << (int)isize 00531 << ", tgtsize= " << a_tgtsize 00532 << std::endl; 00533 a_irep = obufptr - a_tgt; 00534 //return false; 00535 } 00536 a_irep = isize; 00537 00538 //a_out << "inlib::rroot::key::unzip : CS : ok " 00539 // << a_irep << std::endl; 00540 00541 } else { 00542 a_out << "inlib::rroot::key::_unzip : unknown a_src[0,1]." 00543 << " [0] = " << a_src[0] << ", [1] = " << a_src[1] 00544 << std::endl; 00545 a_irep = 0; 00546 return false; 00547 } 00548 return true; 00549 } 00550 00551 static const std::string& s_class() { 00552 static const std::string s_v("inlib::rroot::key"); 00553 return s_v; 00554 } 00555 protected: 00556 ifile& m_file; 00557 uint32 m_buf_size; 00558 char* m_buffer; 00559 // Record (stored in file) : 00560 uint32 m_nbytes; //Number of bytes for the object on file 00561 uint32 m_version; //Key version identifier 00562 uint32 m_object_size; //Length of uncompressed object in bytes 00563 date m_date; //Date/Time of insertion in file 00564 uint16 m_key_length; //Number of bytes for the key itself 00565 uint16 m_cycle; //Cycle number 00566 seek m_seek_key; //Location of object on file 00567 seek m_seek_parent_dir; //Location of parent directory on file 00568 std::string m_object_class; //Object Class name. 00569 std::string m_object_name; //name of the object. 00570 std::string m_object_title; //title of the object. 00571 }; 00572 00573 }} 00574 00575 #endif 00576 00577 //doc : 00579 // // 00580 // The Key class includes functions to book space on a file, // 00581 // to create I/O buffers, to fill these buffers // 00582 // to compress/uncompress data buffers. // 00583 // // 00584 // Before saving (making persistent) an object on a file, a key must // 00585 // be created. The key structure contains all the information to // 00586 // uniquely identify a persistent object on a file. // 00587 // fNbytes = number of bytes for the compressed object+key // 00588 // version of the Key class // 00589 // fObjlen = Length of uncompressed object // 00590 // fDatime = Date/Time when the object was written // 00591 // fKeylen = number of bytes for the key structure // 00592 // fCycle = cycle number of the object // 00593 // fSeekKey = Address of the object on file (points to fNbytes) // 00594 // This is a redundant information used to cross-check // 00595 // the data base integrity. // 00596 // fSeekPdir = Pointer to the directory supporting this object // 00597 // fClassName = Object class name // 00598 // fName = name of the object // 00599 // fTitle = title of the object // 00600 // // 00601 // The Key class is used by ROOT to: // 00602 // - to write an object in the Current Directory // 00603 // - to write a new ntuple buffer // 00604 // //