Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights 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 : 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 41 return s_v; 42 } 43 virtual const std::string& s_cls() const {re 44 public: //ifile 45 virtual bool verbose() const {return m_verbo 46 virtual std::ostream& out() const {return m_ 47 48 virtual bool byte_swap() const {return is_li 49 virtual bool set_pos(seek a_offset = 0,from 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) && 64 if (::lseek64(m_file, a_offset, whence) < 65 #elif defined(_MSC_VER) || defined(__MINGW32__ 66 if (::_lseeki64(m_file, a_offset, whence) 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_of 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 e 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 en 92 << " free_seg list looks corrupt 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_buff 101 // Write a buffer to the file. This is the 102 #ifdef _MSC_VER 103 typedef int ssize_t; 104 #endif 105 ssize_t siz; 106 while ((siz = ::write(m_file,a_buffer,a_le 107 error_number() == EINTR) reset_err 108 109 if(siz < 0) { 110 m_out << "tools::wroot::file::write_buff 111 << " error writing to file " << so 112 << std::endl; 113 return false; 114 } 115 if(siz!=(ssize_t)a_length) { 116 m_out << "tools::wroot::file::write_buff 117 << "error writing all requested byt 118 << ", wrote " << long_out(siz) << " 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. " 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-dis 139 #ifdef _MSC_VER 140 if(::_commit(m_file)) { 141 m_out << "tools::wroot::file::synchroniz 142 << " in _commit() for file " << so 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::synchroniz 151 << " error in fsync() for file " < 152 << std::endl; 153 return false; 154 } 155 #endif 156 return true; 157 } 158 159 virtual bool ziper(char a_key,compress_func& 160 std::map<char,compress_func>::const_iterat 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 169 virtual void compress_buffer(const buffer& a 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::compre 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+ 192 uint32 buflen = (nbuffers+1)*buf_out_s 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) ? n 200 uint32 nout; 201 if(!zip(m_out,func,cxlevel,bufmax,sr 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 specifi 215 // are detected at read time by 216 // the overall output size (fNb 217 // By using the zlib-ng compres 218 // output size (a_klen here at 219 // induces problem when reading 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& 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), 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 259 260 if(!m_root_directory.is_valid()) { 261 m_out << "tools::wroot::file::file :" 262 << " " << sout(m_path) << " root d 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_CREA 270 #else 271 O_RDWR | O_CREA 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 284 m_END = m_BEGIN; // Pointer to end of fi 285 286 m_free_segs.push_back(new free_seg(m_out,m 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 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_titl 300 301 // m_nbytes_name = start point of director 302 m_nbytes_name = key.key_length() + namelen 303 m_root_directory.set_nbytes_name(m_nbytes_ 304 m_root_directory.set_seek_directory(key.se 305 306 //the below write 45 bytes at BOF (Begin O 307 if(!write_header()) { //need m_nbytes_name 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 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 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_pa 380 381 void set_compression(uint32 a_level) { 382 // level = 0 objects written to this file 383 // level = 1 minimal compression level but 384 // .... 385 // level = 9 maximal compression level but 386 m_compress = a_level; 387 if(m_compress>9) m_compress = 9; 388 } 389 390 bool is_open() const {return (m_file==not_op 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 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_ 422 423 bool write(uint32& a_nbytes){ 424 // Write memory objects to this file : 425 // Loop on all objects in m_root_director 426 // A new key is created in the directorie 427 // for each object. 428 // The list of keys is then saved on the 429 // as a single data record. 430 // The directory header info is rewritten 431 // //The linked list of FREE segments is 432 // The file header is written (bytes 1->m 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 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 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_fu 471 std::map<char,compress_func>::const_iterat 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 488 // Returns true if one can access a file u 489 // Mode is the same as for the WinNT acces 490 #ifdef _MSC_VER 491 return (::_access(a_path.c_str(),a_mode) = 492 #else 493 return (::access(a_path.c_str(),a_mode) == 494 #endif 495 } 496 static bool unlink(const std::string& a_path 497 // Unlink, i.e. remove, a file or director 498 // false in case of failure. 499 struct stat finfo; 500 if (::stat(a_path.c_str(),&finfo) < 0) ret 501 #ifdef _MSC_VER 502 if (finfo.st_mode & S_IFDIR) 503 return (::_rmdir(a_path.c_str())==-1 ? f 504 else 505 return (::unlink(a_path.c_str())==-1 ? f 506 #else 507 if (S_ISDIR(finfo.st_mode)) 508 return (::rmdir(a_path.c_str())==-1 ? fa 509 else 510 return (::unlink(a_path.c_str())==-1 ? f 511 #endif 512 } 513 514 static int _open(const char* a_name,int a_fl 515 #if defined(__linux__) && (__GLIBC__ == 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 fals 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 fals 543 if(!wb.write((seek32)m_seek_free)) retur 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)) retur 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",n 561 if(!write_buffer(psave,nbytes)) return fal 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_stre 576 << " cannot stream obj_list<stream 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_direc 584 "StreamerInfo","", 585 sinfos.store_cls(), 586 nbytes); // It does a (*thi 587 if(!key.seek_key()) return false; 588 589 if(!bref.displace_mapped(key.key_length()) 590 591 ::memcpy(key.data_buffer(),bref.buf(),nbyt 592 593 //key.set_cycle(1); 594 if(!key.write_self(*this)) { 595 m_out << "tools::wroot::file::write_stre 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_ 615 // When an object is deleted from the fil 616 // into the FREE linked list (m_free_segs 617 // of a chain of consecutive free segmen 618 // time, the first 4 bytes of the freed r 619 // are overwritten by GAPSIZE where 620 // GAPSIZE = -(Number of bytes occupied 621 622 if(m_free_segs.empty()) { 623 m_out << "tools::wroot::file::make_free_ 624 << " free_seg list should not be e 625 << std::endl; 626 return false; 627 } 628 629 free_seg* newfree = add_free(m_free_segs,a 630 if(!newfree) { 631 m_out << "tools::wroot::file::make_free_ 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 = STA 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 (fFre 662 663 // Delete old record if it exists : 664 if(m_seek_free){ 665 if(!make_free_seg(m_seek_free, m_seek_fr 666 m_out << "tools::wroot::file::write_fr 667 << " key.write_self() failed." 668 << std::endl; 669 return false; 670 } 671 } 672 673 //::printf("debug : write_free_segments : 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 679 // (*it)->first(),(*it)->last()) 680 }} 681 if(!nbytes) return true; 682 683 wroot::key key(m_out,*this, 684 m_root_directory.seek_direc 685 m_path,m_title,"TFile", 686 nbytes); // It does a (*thi 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 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 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__) && ( 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 wr 795 std::string m_title; //must be before the be 796 directory m_root_directory; 797 std::map<char,compress_func> m_zipers; 798 std::list<free_seg*> m_free_segs; //Free seg 799 // begin of record : 800 // "root" 801 uint32 m_version; //File format versio 802 seek m_BEGIN; //First used byte in 803 seek m_END; //Last used byte in 804 seek m_seek_free; //Location on disk o 805 uint32 m_nbytes_free; //Number of bytes fo 806 //int nfree 807 uint32 m_nbytes_name; //Number of bytes in 808 char m_units; //Number of bytes fo 809 uint32 m_compress; //(=1 file is compre 810 seek m_seek_info; //Location on disk o 811 uint32 m_nbytes_info; //Number of bytes fo 812 }; 813 814 815 }} 816 817 #endif 818 819 //doc 820 // 821 // A ROOT file is a suite of consecutive data 822 // format (see also the TKey class); 823 // TKey --------------------- 824 // byte 1->4 Nbytes = Length of compr 825 // 5->6 Version = TKey version id 826 // 7->10 ObjLen = Length of uncom 827 // 11->14 Datime = Date and time w 828 // 15->16 KeyLen = Length of the k 829 // 17->18 Cycle = Cycle of key 830 // 19->22 SeekKey = Pointer to reco 831 // 23->26 SeekPdir = Pointer to dire 832 // 27->27 lname = Number of bytes 833 // 28->.. ClassName = Object Class Na 834 // ..->.. lname = Number of bytes 835 // ..->.. Name = lName bytes wit 836 // ..->.. lTitle = Number of bytes 837 // ..->.. Title = Title of the ob 838 // -----> DATA = Data bytes asso 839 // 840 // The first data record starts at byte fBEGI 841 // Bytes 1->kBegin contain the file descripti 842 // byte 1->4 "root" = Root file i 843 // 5->8 fVersion = File format 844 // 9->12 fBEGIN = Pointer to 845 // 13->16 fEND = Pointer to 846 // 17->20 fSeekFree = Pointer to 847 // 21->24 fNbytesFree = Number of b 848 // 25->28 nfree = Number of f 849 // 29->32 fNbytesName = Number of b 850 // 33->33 fUnits = Number of b 851 // 34->37 fCompress = Zip compres 852 //