Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_wroot_file 5 #define tools_wroot_file 6 7 #include "ifile" 8 9 #include "directory" 10 11 #include "infos" 12 #include "free_seg" 13 14 #include "../platform" 15 16 #include "../path" 17 18 #include <map> 19 20 #include <fcntl.h> 21 #include <errno.h> 22 #include <sys/stat.h> 23 24 #if defined(_MSC_VER) || defined(__MINGW32__) 25 #include <direct.h> 26 #include <io.h> 27 #else 28 #include <unistd.h> 29 #endif 30 31 namespace tools { 32 namespace wroot { 33 34 class file : public virtual ifile { 35 file& get_me() {return *this;} //_MSC_VER : to avoid warning about the usage of "this" in the constructor. 36 static int not_open() {return -1;} 37 static uint32 kBegin() {return 64;} 38 public: 39 static const std::string& s_class() { 40 static const std::string s_v("tools::wroot::file"); 41 return s_v; 42 } 43 virtual const std::string& s_cls() const {return s_class();} 44 public: //ifile 45 virtual bool verbose() const {return m_verbose;} 46 virtual std::ostream& out() const {return m_out;} 47 48 virtual bool byte_swap() const {return is_little_endian();} 49 virtual bool set_pos(seek a_offset = 0,from a_from = begin){ 50 int whence = 0; 51 switch(a_from) { 52 case begin: 53 whence = SEEK_SET; 54 break; 55 case current: 56 whence = SEEK_CUR; 57 break; 58 case end: 59 whence = SEEK_END; 60 break; 61 } 62 63 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2) 64 if (::lseek64(m_file, a_offset, whence) < 0) { 65 #elif defined(_MSC_VER) || defined(__MINGW32__) 66 if (::_lseeki64(m_file, a_offset, whence) < 0) { 67 #else 68 if (::lseek(m_file, a_offset, whence) < 0) { 69 #endif 70 m_out << "tools::wroot::file::set_pos :" 71 << " cannot set position " << a_offset 72 << " in file " << sout(m_path) << "." 73 << std::endl; 74 return false; 75 } 76 return true; 77 } 78 79 virtual seek END() const {return m_END;} 80 virtual void set_END(seek a_end){ 81 m_END = a_end; 82 83 if(m_free_segs.empty()) { 84 m_out << "tools::wroot::file::set_END :" 85 << " free_seg list should not be empty here." 86 << std::endl; 87 } else { 88 free_seg* end_seg = m_free_segs.back(); 89 if(end_seg->last()!=START_BIG_FILE()) { 90 m_out << "tools::wroot::file::set_END :" 91 << " last free_seg is not the ending of file one." 92 << " free_seg list looks corrupted." 93 << std::endl; 94 } else { 95 m_free_segs.back()->set_first(m_END); 96 } 97 } 98 } 99 100 virtual bool write_buffer(const char* a_buffer,uint32 a_length) { 101 // Write a buffer to the file. This is the basic low level write operation. 102 #ifdef _MSC_VER 103 typedef int ssize_t; 104 #endif 105 ssize_t siz; 106 while ((siz = ::write(m_file,a_buffer,a_length)) < 0 && 107 error_number() == EINTR) reset_error_number(); 108 109 if(siz < 0) { 110 m_out << "tools::wroot::file::write_buffer :" 111 << " error writing to file " << sout(m_path) << "." 112 << std::endl; 113 return false; 114 } 115 if(siz!=(ssize_t)a_length) { 116 m_out << "tools::wroot::file::write_buffer :" 117 << "error writing all requested bytes to file " << sout(m_path) 118 << ", wrote " << long_out(siz) << " of " << a_length 119 << std::endl; 120 return false; 121 } 122 //m_bytes_write += siz; 123 return true; 124 } 125 126 virtual uint32 version() const { 127 // Return version id as an integer, i.e. "2.22/04" -> 22204. 128 static const uint32 ROOT_MAJOR_VERSION = 4; 129 static const uint32 ROOT_MINOR_VERSION = 0; 130 static const uint32 ROOT_PATCH_VERSION = 0; 131 return 132 10000 * ROOT_MAJOR_VERSION + 133 100 * ROOT_MINOR_VERSION + 134 ROOT_PATCH_VERSION; 135 } 136 137 virtual bool synchronize(){ 138 // Synchornize a file's in-core and on-disk states. 139 #ifdef _MSC_VER 140 if(::_commit(m_file)) { 141 m_out << "tools::wroot::file::synchronize :" 142 << " in _commit() for file " << sout(m_path) << "." 143 << std::endl; 144 return false; 145 } 146 #elif defined(__MINGW32__) 147 return true; 148 #else 149 if (::fsync(m_file) < 0) { 150 m_out << "tools::wroot::file::synchronize :" 151 << " error in fsync() for file " << sout(m_path) << "." 152 << std::endl; 153 return false; 154 } 155 #endif 156 return true; 157 } 158 159 virtual bool ziper(char a_key,compress_func& a_func) const { 160 std::map<char,compress_func>::const_iterator it = m_zipers.find(a_key); 161 if(it==m_zipers.end()) { 162 a_func = 0; 163 return false; 164 } 165 a_func = (*it).second; 166 return true; 167 } 168 virtual uint32 compression() const {return m_compress;} 169 virtual void compress_buffer(const buffer& a_buffer,char*& a_kbuf,uint32& a_klen,bool& a_kdel) { 170 //NOTE: if(kdelete) delete [] kbuf; 171 172 a_kbuf = 0; 173 a_klen = 0; 174 a_kdel = false; 175 176 uint32 nbytes = a_buffer.length(); 177 uint32 cxlevel = m_compress; 178 if(cxlevel && (nbytes>256)) { 179 compress_func func; 180 if(!ziper('Z',func)) { 181 //m_out << "tools::wroot::file::compress_buffer :" 182 // << " zlib ziper not found." 183 // << std::endl; 184 a_kbuf = (char*)a_buffer.buf(); 185 a_klen = a_buffer.length(); 186 a_kdel = false; 187 } else { 188 const uint32 kMAXBUF = 0xffffff; 189 const uint32 HDRSIZE = 9; 190 uint32 nbuffers = nbytes/kMAXBUF; 191 uint32 buf_out_size = kMAXBUF+HDRSIZE+kMAXBUF/2; 192 uint32 buflen = (nbuffers+1)*buf_out_size; 193 a_kbuf = new char[buflen]; 194 a_kdel = true; 195 char* src = (char*)a_buffer.buf(); 196 char* tgt = a_kbuf; 197 uint32 nzip = 0; 198 for(uint32 i=0;i<=nbuffers;i++) { 199 uint32 bufmax = ((i == nbuffers) ? nbytes - nzip : kMAXBUF); 200 uint32 nout; 201 if(!zip(m_out,func,cxlevel,bufmax,src,buf_out_size,tgt,nout)) { 202 delete [] a_kbuf; 203 a_kbuf = (char*)a_buffer.buf(); 204 a_klen = a_buffer.length(); 205 a_kdel = false; 206 return; 207 } 208 tgt += nout; //nout includes HDRSIZE 209 a_klen += nout; 210 src += kMAXBUF; 211 nzip += kMAXBUF; 212 } 213 if(a_klen>=a_buffer.length()) { 214 //NOTE: It is in the ROOT/IO specification (see ROOT/TKey.cxx/TKey::ReadObj() code) that some data compressions 215 // are detected at read time by checking that "fObjlen > fNbytes-fKeylen", that is to say that 216 // the overall output size (fNbytes-fKeylen) is stricly lower than the input size (fObjlen). 217 // By using the zlib-ng compression library, we saw that we may fall on cases where the overall 218 // output size (a_klen here at this point) may be equal to the input size (a_buffer.lengt()) which 219 // induces problem when reading back the data with ROOT. Then the upper test checks and protects against that. 220 delete [] a_kbuf; 221 a_kbuf = (char*)a_buffer.buf(); 222 a_klen = a_buffer.length(); 223 a_kdel = false; 224 } 225 } 226 } else { 227 a_kbuf = (char*)a_buffer.buf(); 228 a_klen = a_buffer.length(); 229 a_kdel = false; 230 } 231 } 232 public: 233 file(std::ostream& a_out,const std::string& a_path,bool a_verbose = false) 234 :m_out(a_out) 235 ,m_path(a_path) 236 ,m_verbose(a_verbose) 237 ,m_file(not_open()) 238 //,m_bytes_write(0) 239 ,m_root_directory(get_me(),nosuffix(a_path),m_title) 240 // begin of record : 241 ,m_version(0) 242 ,m_BEGIN(0) 243 ,m_END(0) 244 ,m_seek_free(0) 245 ,m_nbytes_free(0) 246 ,m_nbytes_name(0) 247 ,m_units(4) 248 ,m_compress(1) 249 ,m_seek_info(0) 250 ,m_nbytes_info(0) 251 { 252 #ifdef TOOLS_MEM 253 mem::increment(s_class().c_str()); 254 #endif 255 256 m_version = version(); 257 258 if(access_path(m_path,kFileExists)) unlink(m_path); 259 260 if(!m_root_directory.is_valid()) { 261 m_out << "tools::wroot::file::file :" 262 << " " << sout(m_path) << " root directory badly created." 263 << std::endl; 264 return; 265 } 266 267 m_file = _open(a_path.c_str(), 268 #if defined(_MSC_VER) || defined(__MINGW32__) 269 O_RDWR | O_CREAT | O_BINARY,S_IREAD | S_IWRITE 270 #else 271 O_RDWR | O_CREAT,0644 272 #endif 273 ); 274 if(m_file==not_open()) { 275 m_out << "tools::wroot::file::file :" 276 << " can't open " << sout(a_path) << "." 277 << std::endl; 278 return; 279 } 280 281 //initialize : 282 283 m_BEGIN = kBegin(); // First used word in file following the file header. 284 m_END = m_BEGIN; // Pointer to end of file. 285 286 m_free_segs.push_back(new free_seg(m_out,m_BEGIN,START_BIG_FILE())); 287 288 // Write Directory info : 289 uint32 namelen = 290 key::std_string_record_size(m_path) + 291 key::std_string_record_size(m_title); 292 uint32 nbytes = namelen + m_root_directory.record_size(); 293 294 //TUUID version 1: 295 nbytes += sizeof(unsigned int); 296 nbytes += 2*sizeof(unsigned short); 297 nbytes += 8*sizeof(unsigned char); 298 299 wroot::key key(m_out,*this,0,m_path,m_title,"TFile",nbytes); // It does a (*this).set_END(). 300 301 // m_nbytes_name = start point of directory info from key head. 302 m_nbytes_name = key.key_length() + namelen; 303 m_root_directory.set_nbytes_name(m_nbytes_name); 304 m_root_directory.set_seek_directory(key.seek_key()); //at EOF. 305 306 //the below write 45 bytes at BOF (Begin Of File). 307 if(!write_header()) { //need m_nbytes_name, m_END after key written. 308 m_out << "tools::wroot::file::file :" 309 << " can't write file header." 310 << std::endl; 311 return; 312 } 313 314 {char* pos = key.data_buffer(); 315 wbuf wb(m_out,byte_swap(),key.eob(),pos); 316 if(!wb.write(m_path)) return; 317 if(!wb.write(m_title)) return; 318 if(!m_root_directory.to_buffer(wb)) return; 319 //TUUID version 1: 320 if(!wb.write((unsigned int)0)) return; 321 if(!wb.write((unsigned short)0)) return; 322 if(!wb.write((unsigned short)0)) return; 323 {for(size_t count=0;count<8;count++) if(!wb.write((unsigned char)0)) return;}} 324 325 if(m_verbose) { 326 m_out << "tools::wroot::file::file :" 327 << " write key (" 328 << namelen 329 << ", " 330 << m_root_directory.record_size() 331 << ", " 332 << nbytes 333 << ", " 334 << m_nbytes_name 335 << ", " 336 << key.seek_key() 337 << ")." 338 << std::endl; 339 } 340 341 key.set_cycle(1); 342 if(!key.write_self(*this)) { 343 m_out << "tools::wroot::file::file :" 344 << " key.write_self() failed." 345 << std::endl; 346 return; 347 } 348 349 //the below write at kBegin + nbytes. 350 //64+52 351 uint32 n; 352 if(!key.write_file(*this,n)) { 353 m_out << "tools::wroot::file::file :" 354 << " can't write key in file." 355 << std::endl; 356 return; 357 } 358 //::printf("debug : file::file : write key : %d\n",n); 359 360 } 361 virtual ~file() { 362 close(); 363 #ifdef TOOLS_MEM 364 mem::decrement(s_class().c_str()); 365 #endif 366 } 367 protected: 368 file(const file& a_from) 369 :ifile(a_from) 370 ,m_out(a_from.m_out) 371 ,m_root_directory(get_me()) 372 { 373 #ifdef TOOLS_MEM 374 mem::increment(s_class().c_str()); 375 #endif 376 } 377 file& operator=(const file&){return *this;} 378 public: 379 const std::string& path() const {return m_path;} 380 381 void set_compression(uint32 a_level) { 382 // level = 0 objects written to this file will not be compressed. 383 // level = 1 minimal compression level but fast. 384 // .... 385 // level = 9 maximal compression level but slow. 386 m_compress = a_level; 387 if(m_compress>9) m_compress = 9; 388 } 389 390 bool is_open() const {return (m_file==not_open()?false:true);} 391 392 void close() { 393 if(m_file==not_open()) return; 394 m_root_directory.close(); 395 396 if(m_free_segs.size()) { 397 if(!write_free_segments()) { 398 m_out << "tools::wroot::file::close :" 399 << " can't write free segments." 400 << std::endl; 401 } 402 if(!write_header()) { // Now write file header 403 m_out << "tools::wroot::file::close :" 404 << " can't write file header." 405 << std::endl; 406 } 407 } 408 409 {std::list<free_seg*>::iterator it; 410 for(it=m_free_segs.begin(); 411 it!=m_free_segs.end(); 412 it = m_free_segs.erase(it)) { 413 delete (*it); 414 }} 415 416 ::close(m_file); 417 m_file = not_open(); 418 } 419 420 directory& dir() {return m_root_directory;} 421 const directory& dir() const {return m_root_directory;} 422 423 bool write(uint32& a_nbytes){ 424 // Write memory objects to this file : 425 // Loop on all objects in m_root_directory (including subdirectories). 426 // A new key is created in the directories m_keys linked list 427 // for each object. 428 // The list of keys is then saved on the file (via write_keys) 429 // as a single data record. 430 // The directory header info is rewritten on the directory header record. 431 // //The linked list of FREE segments is written. 432 // The file header is written (bytes 1->m_BEGIN). 433 a_nbytes = 0; 434 435 if(m_verbose) { 436 m_out << "tools::wroot::file::write :" 437 << " writing Name=" << sout(m_path) 438 << " Title=" << sout(m_title) << "." 439 << std::endl; 440 } 441 442 uint32 nbytes; 443 if(!m_root_directory.write(nbytes)) return false; // Write directory tree 444 445 if(!write_streamer_infos()) { 446 m_out << "tools::wroot::file::write :" 447 << " write_streamer_infos failed." 448 << std::endl; 449 return false; 450 } 451 452 if(!write_free_segments()) { 453 m_out << "tools::wroot::file::write :" 454 << " can't write free segments." 455 << std::endl; 456 return false; 457 } 458 459 if(!write_header()) { //write 45 bytes at BOF. 460 m_out << "tools::wroot::file::write :" 461 << " can't write file header." 462 << std::endl; 463 return false; 464 } 465 466 a_nbytes = nbytes; 467 return true; 468 } 469 470 bool add_ziper(char a_key,compress_func a_func){ 471 std::map<char,compress_func>::const_iterator it = m_zipers.find(a_key); 472 if(it!=m_zipers.end()) { 473 //(*it).second = a_func; //override ? 474 return false; 475 } else { 476 m_zipers[a_key] = a_func; 477 return true; 478 } 479 } 480 protected: 481 enum EAccessMode { 482 kFileExists = 0, 483 kExecutePermission = 1, 484 kWritePermission = 2, 485 kReadPermission = 4 486 }; 487 static bool access_path(const std::string& a_path,EAccessMode a_mode){ 488 // Returns true if one can access a file using the specified access mode. 489 // Mode is the same as for the WinNT access(2) function. 490 #ifdef _MSC_VER 491 return (::_access(a_path.c_str(),a_mode) == 0) ? true : false; 492 #else 493 return (::access(a_path.c_str(),a_mode) == 0) ? true : false; 494 #endif 495 } 496 static bool unlink(const std::string& a_path){ 497 // Unlink, i.e. remove, a file or directory. Returns true when succesfull, 498 // false in case of failure. 499 struct stat finfo; 500 if (::stat(a_path.c_str(),&finfo) < 0) return false; 501 #ifdef _MSC_VER 502 if (finfo.st_mode & S_IFDIR) 503 return (::_rmdir(a_path.c_str())==-1 ? false : true); 504 else 505 return (::unlink(a_path.c_str())==-1 ? false : true); 506 #else 507 if (S_ISDIR(finfo.st_mode)) 508 return (::rmdir(a_path.c_str())==-1 ? false : true); 509 else 510 return (::unlink(a_path.c_str())==-1 ? false : true); 511 #endif 512 } 513 514 static int _open(const char* a_name,int a_flags,unsigned int a_mode) { 515 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2) 516 return ::open64(a_name,a_flags,a_mode); 517 #else 518 return ::open(a_name,a_flags,a_mode); 519 #endif 520 } 521 bool write_header() { 522 const char root[] = "root"; 523 //char psave[kBegin()]; 524 char psave[128]; 525 const char* eob = psave + kBegin(); 526 char* pos = psave; 527 ::memcpy(pos,root,4); pos += 4; 528 uint32 vers = m_version; 529 if((m_END>START_BIG_FILE()) || 530 (m_seek_free>START_BIG_FILE()) || 531 (m_seek_info>START_BIG_FILE()) ){ 532 vers += 1000000; 533 m_units = 8; 534 } 535 wbuf wb(m_out,byte_swap(),eob,pos); 536 if(!wb.write(vers)) return false; 537 if(!wb.write((seek32)m_BEGIN)) return false; 538 if(vers>1000000) { 539 if(!wb.write(m_END)) return false; 540 if(!wb.write(m_seek_free)) return false; 541 } else { 542 if(!wb.write((seek32)m_END)) return false; 543 if(!wb.write((seek32)m_seek_free)) return false; 544 } 545 if(!wb.write(m_nbytes_free)) return false; 546 //int nfree = fFreeSegments.size(); 547 uint32 nfree = 0; //FIXME 548 if(!wb.write(nfree)) return false; 549 if(!wb.write(m_nbytes_name)) return false; 550 if(!wb.write(m_units)) return false; 551 if(!wb.write(m_compress)) return false; 552 if(vers>1000000) { 553 if(!wb.write(m_seek_info)) return false; 554 } else { 555 if(!wb.write((seek32)m_seek_info)) return false; 556 } 557 if(!wb.write(m_nbytes_info)) return false; 558 if(!set_pos()) return false; //BOF 559 uint32 nbytes = uint32(pos - psave); 560 //::printf("debug : write_header : %d\n",nbytes); 561 if(!write_buffer(psave,nbytes)) return false; 562 if(!synchronize()) return false; 563 return true; 564 } 565 566 bool write_streamer_infos() { 567 obj_list<streamer_info> sinfos; 568 fill_infos(sinfos,m_out); 569 570 if(sinfos.empty()) return false; 571 572 buffer bref(m_out,byte_swap(),256); 573 574 if(!sinfos.stream(bref)) { 575 m_out << "tools::wroot::file::write_streamer_infos :" 576 << " cannot stream obj_list<streamer_info>." 577 << std::endl; 578 return false; 579 } 580 uint32 nbytes = bref.length(); 581 582 wroot::key key(m_out,*this, 583 m_root_directory.seek_directory(), 584 "StreamerInfo","", 585 sinfos.store_cls(), 586 nbytes); // It does a (*this).set_END(). 587 if(!key.seek_key()) return false; 588 589 if(!bref.displace_mapped(key.key_length())) return false; 590 591 ::memcpy(key.data_buffer(),bref.buf(),nbytes); 592 593 //key.set_cycle(1); 594 if(!key.write_self(*this)) { 595 m_out << "tools::wroot::file::write_streamer_infos :" 596 << " key.write_self() failed." 597 << std::endl; 598 return false; 599 } 600 601 m_seek_info = key.seek_key(); 602 m_nbytes_info = key.number_of_bytes(); 603 //FIXME sumBuffer(key.objectSize()); 604 605 uint32 n; 606 if(!key.write_file(*this,n)) return false; 607 if(!n) return false; 608 609 return true; 610 } 611 612 bool make_free_seg(seek a_first,seek a_last) { 613 // Mark unused bytes on the file : 614 // The list of free segments is in the m_free_segs list 615 // When an object is deleted from the file, the freed space is added 616 // into the FREE linked list (m_free_segs). The FREE list consists 617 // of a chain of consecutive free segments on the file. At the same 618 // time, the first 4 bytes of the freed record on the file 619 // are overwritten by GAPSIZE where 620 // GAPSIZE = -(Number of bytes occupied by the record). 621 622 if(m_free_segs.empty()) { 623 m_out << "tools::wroot::file::make_free_seg :" 624 << " free_seg list should not be empty here." 625 << std::endl; 626 return false; 627 } 628 629 free_seg* newfree = add_free(m_free_segs,a_first,a_last); 630 if(!newfree) { 631 m_out << "tools::wroot::file::make_free_seg :" 632 << " add_free failed." 633 << std::endl; 634 return false; 635 } 636 637 seek nfirst = newfree->first(); 638 seek nlast = newfree->last(); 639 640 seek _nbytes = nlast-nfirst+1; 641 if(_nbytes>START_BIG_FILE()) _nbytes = START_BIG_FILE(); 642 int nbytes = -int(_nbytes); 643 644 int nb = sizeof(int); 645 646 char psave[128]; 647 const char* eob = psave + nb; 648 char* pos = psave; 649 650 wbuf wb(m_out,byte_swap(),eob,pos); 651 if(!wb.write(nbytes)) return false; 652 653 if(nlast == (m_END-1)) m_END = nfirst; 654 if(!set_pos(nfirst)) return false; 655 if(!write_buffer(psave,nb)) return false; 656 if(!synchronize()) return false; 657 return true; 658 } 659 660 bool write_free_segments(){ 661 // The linked list of FREE segments (fFree) is written as a single data record. 662 663 // Delete old record if it exists : 664 if(m_seek_free){ 665 if(!make_free_seg(m_seek_free, m_seek_free + m_nbytes_free -1)) { 666 m_out << "tools::wroot::file::write_free_segments :" 667 << " key.write_self() failed." 668 << std::endl; 669 return false; 670 } 671 } 672 673 //::printf("debug : write_free_segments : seg list :\n"); 674 675 uint32 nbytes = 0; 676 {tools_lforcit(free_seg*,m_free_segs,it) { 677 nbytes += (*it)->record_size(); 678 //::printf("debug : write_free_segments : %lu %lu\n", 679 // (*it)->first(),(*it)->last()); 680 }} 681 if(!nbytes) return true; 682 683 wroot::key key(m_out,*this, 684 m_root_directory.seek_directory(), 685 m_path,m_title,"TFile", 686 nbytes); // It does a (*this).set_END(). 687 if(!key.seek_key()) return false; 688 689 {char* pos = key.data_buffer(); 690 wbuf wb(m_out,byte_swap(),key.eob(),pos); 691 tools_lforcit(free_seg*,m_free_segs,it) { 692 if(!(*it)->fill_buffer(wb)) return false; 693 }} 694 695 //key.set_cycle(1); 696 if(!key.write_self(*this)) { 697 m_out << "tools::wroot::file::write_free_segments :" 698 << " key.write_self() failed." 699 << std::endl; 700 return false; 701 } 702 703 m_seek_free = key.seek_key(); 704 m_nbytes_free = key.number_of_bytes(); 705 if(m_verbose) { 706 m_out << "tools::wroot::file::write_free_segments :" 707 << " write key." << std::endl; 708 } 709 710 uint32 n; 711 if(!key.write_file(*this,n)) return false; 712 if(!n) return false; 713 714 return true; 715 } 716 717 static bool zip(std::ostream& a_out, 718 compress_func a_func, 719 int a_level, 720 uint32 a_srcsize,char* a_src, 721 uint32 a_tgtsize,char* a_tgt, 722 uint32& a_irep){ 723 724 // from Rio/Bits/R__zip using zlib. 725 726 const uint32 HDRSIZE = 9; 727 728 if(a_tgtsize<HDRSIZE) { 729 a_out << "tools::wroot::file::zip :" 730 << " target buffer too small." 731 << std::endl; 732 a_irep = 0; 733 return false; 734 } 735 if(a_srcsize>0xffffff) { 736 a_out << "tools::wroot::file::zip :" 737 << " source buffer too big." 738 << std::endl; 739 a_irep = 0; 740 return false; 741 } 742 743 uint32 out_size; 744 if(!a_func(a_out,a_level, 745 a_srcsize,a_src, 746 a_tgtsize,a_tgt+HDRSIZE, 747 out_size)) { 748 a_out << "tools::wroot::file::zip :" 749 << " zipper failed." 750 << std::endl; 751 a_irep = 0; 752 return false; 753 } 754 755 if((HDRSIZE+out_size)>a_tgtsize) { 756 a_out << "tools::wroot::file::zip :" 757 << " target buffer overflow." 758 << std::endl; 759 a_irep = 0; 760 return false; 761 } 762 763 // HEADER : 764 a_tgt[0] = 'Z'; // Signature ZLib 765 a_tgt[1] = 'L'; 766 a_tgt[2] = 8; //DEFLATE 767 768 a_tgt[3] = (char)(out_size & 0xff); 769 a_tgt[4] = (char)((out_size >> 8) & 0xff); 770 a_tgt[5] = (char)((out_size >> 16) & 0xff); 771 772 a_tgt[6] = (char)(a_srcsize & 0xff); 773 a_tgt[7] = (char)((a_srcsize >> 8) & 0xff); 774 a_tgt[8] = (char)((a_srcsize >> 16) & 0xff); 775 776 a_irep = HDRSIZE+out_size; 777 778 return true; 779 } 780 781 #if defined(__sun) && !defined(__linux__) && (__SUNPRO_CC > 0x420) 782 int error_number() {return ::errno;} 783 void reset_error_number() {::errno = 0;} 784 #else 785 int error_number() {return errno;} 786 void reset_error_number() {errno = 0;} 787 #endif 788 789 protected: 790 std::ostream& m_out; 791 std::string m_path; 792 bool m_verbose; 793 int m_file; 794 //uint64 m_bytes_write; //Number of bytes write in this file 795 std::string m_title; //must be before the below. 796 directory m_root_directory; 797 std::map<char,compress_func> m_zipers; 798 std::list<free_seg*> m_free_segs; //Free segments linked list table 799 // begin of record : 800 // "root" 801 uint32 m_version; //File format version 802 seek m_BEGIN; //First used byte in file 803 seek m_END; //Last used byte in file 804 seek m_seek_free; //Location on disk of free segments structure 805 uint32 m_nbytes_free; //Number of bytes for free segments structure 806 //int nfree 807 uint32 m_nbytes_name; //Number of bytes in TNamed at creation time 808 char m_units; //Number of bytes for file pointers 809 uint32 m_compress; //(=1 file is compressed, 0 otherwise) 810 seek m_seek_info; //Location on disk of StreamerInfo record 811 uint32 m_nbytes_info; //Number of bytes for StreamerInfo record 812 }; 813 814 815 }} 816 817 #endif 818 819 //doc 820 // 821 // A ROOT file is a suite of consecutive data records with the following 822 // format (see also the TKey class); 823 // TKey --------------------- 824 // byte 1->4 Nbytes = Length of compressed object (in bytes) 825 // 5->6 Version = TKey version identifier 826 // 7->10 ObjLen = Length of uncompressed object 827 // 11->14 Datime = Date and time when object was written to file 828 // 15->16 KeyLen = Length of the key structure (in bytes) 829 // 17->18 Cycle = Cycle of key 830 // 19->22 SeekKey = Pointer to record itself (consistency check) 831 // 23->26 SeekPdir = Pointer to directory header 832 // 27->27 lname = Number of bytes in the class name 833 // 28->.. ClassName = Object Class Name 834 // ..->.. lname = Number of bytes in the object name 835 // ..->.. Name = lName bytes with the name of the object 836 // ..->.. lTitle = Number of bytes in the object title 837 // ..->.. Title = Title of the object 838 // -----> DATA = Data bytes associated to the object 839 // 840 // The first data record starts at byte fBEGIN (currently set to kBegin) 841 // Bytes 1->kBegin contain the file description: 842 // byte 1->4 "root" = Root file identifier 843 // 5->8 fVersion = File format version 844 // 9->12 fBEGIN = Pointer to first data record 845 // 13->16 fEND = Pointer to first free word at the EOF 846 // 17->20 fSeekFree = Pointer to FREE data record 847 // 21->24 fNbytesFree = Number of bytes in FREE data record 848 // 25->28 nfree = Number of free data records 849 // 29->32 fNbytesName = Number of bytes in TNamed at creation time 850 // 33->33 fUnits = Number of bytes for file pointers 851 // 34->37 fCompress = Zip compression level 852 //