Warning, /include/Geant4/tools/wroot/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_wroot_file
0005 #define tools_wroot_file
0006
0007 #include "ifile"
0008
0009 #include "directory"
0010
0011 #include "infos"
0012 #include "free_seg"
0013
0014 #include "../platform"
0015
0016 #include "../path"
0017
0018 #include <map>
0019
0020 #include <fcntl.h>
0021 #include <errno.h>
0022 #include <sys/stat.h>
0023
0024 #if defined(_MSC_VER) || defined(__MINGW32__)
0025 #include <direct.h>
0026 #include <io.h>
0027 #else
0028 #include <unistd.h>
0029 #endif
0030
0031 namespace tools {
0032 namespace wroot {
0033
0034 class file : public virtual ifile {
0035 file& get_me() {return *this;} //_MSC_VER : to avoid warning about the usage of "this" in the constructor.
0036 static int not_open() {return -1;}
0037 static uint32 kBegin() {return 64;}
0038 public:
0039 static const std::string& s_class() {
0040 static const std::string s_v("tools::wroot::file");
0041 return s_v;
0042 }
0043 virtual const std::string& s_cls() const {return s_class();}
0044 public: //ifile
0045 virtual bool verbose() const {return m_verbose;}
0046 virtual std::ostream& out() const {return m_out;}
0047
0048 virtual bool byte_swap() const {return is_little_endian();}
0049 virtual bool set_pos(seek a_offset = 0,from a_from = begin){
0050 int whence = 0;
0051 switch(a_from) {
0052 case begin:
0053 whence = SEEK_SET;
0054 break;
0055 case current:
0056 whence = SEEK_CUR;
0057 break;
0058 case end:
0059 whence = SEEK_END;
0060 break;
0061 }
0062
0063 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
0064 if (::lseek64(m_file, a_offset, whence) < 0) {
0065 #elif defined(_MSC_VER) || defined(__MINGW32__)
0066 if (::_lseeki64(m_file, a_offset, whence) < 0) {
0067 #else
0068 if (::lseek(m_file, a_offset, whence) < 0) {
0069 #endif
0070 m_out << "tools::wroot::file::set_pos :"
0071 << " cannot set position " << a_offset
0072 << " in file " << sout(m_path) << "."
0073 << std::endl;
0074 return false;
0075 }
0076 return true;
0077 }
0078
0079 virtual seek END() const {return m_END;}
0080 virtual void set_END(seek a_end){
0081 m_END = a_end;
0082
0083 if(m_free_segs.empty()) {
0084 m_out << "tools::wroot::file::set_END :"
0085 << " free_seg list should not be empty here."
0086 << std::endl;
0087 } else {
0088 free_seg* end_seg = m_free_segs.back();
0089 if(end_seg->last()!=START_BIG_FILE()) {
0090 m_out << "tools::wroot::file::set_END :"
0091 << " last free_seg is not the ending of file one."
0092 << " free_seg list looks corrupted."
0093 << std::endl;
0094 } else {
0095 m_free_segs.back()->set_first(m_END);
0096 }
0097 }
0098 }
0099
0100 virtual bool write_buffer(const char* a_buffer,uint32 a_length) {
0101 // Write a buffer to the file. This is the basic low level write operation.
0102 #ifdef _MSC_VER
0103 typedef int ssize_t;
0104 #endif
0105 ssize_t siz;
0106 while ((siz = ::write(m_file,a_buffer,a_length)) < 0 &&
0107 error_number() == EINTR) reset_error_number();
0108
0109 if(siz < 0) {
0110 m_out << "tools::wroot::file::write_buffer :"
0111 << " error writing to file " << sout(m_path) << "."
0112 << std::endl;
0113 return false;
0114 }
0115 if(siz!=(ssize_t)a_length) {
0116 m_out << "tools::wroot::file::write_buffer :"
0117 << "error writing all requested bytes to file " << sout(m_path)
0118 << ", wrote " << long_out(siz) << " of " << a_length
0119 << std::endl;
0120 return false;
0121 }
0122 //m_bytes_write += siz;
0123 return true;
0124 }
0125
0126 virtual uint32 version() const {
0127 // Return version id as an integer, i.e. "2.22/04" -> 22204.
0128 static const uint32 ROOT_MAJOR_VERSION = 4;
0129 static const uint32 ROOT_MINOR_VERSION = 0;
0130 static const uint32 ROOT_PATCH_VERSION = 0;
0131 return
0132 10000 * ROOT_MAJOR_VERSION +
0133 100 * ROOT_MINOR_VERSION +
0134 ROOT_PATCH_VERSION;
0135 }
0136
0137 virtual bool synchronize(){
0138 // Synchornize a file's in-core and on-disk states.
0139 #ifdef _MSC_VER
0140 if(::_commit(m_file)) {
0141 m_out << "tools::wroot::file::synchronize :"
0142 << " in _commit() for file " << sout(m_path) << "."
0143 << std::endl;
0144 return false;
0145 }
0146 #elif defined(__MINGW32__)
0147 return true;
0148 #else
0149 if (::fsync(m_file) < 0) {
0150 m_out << "tools::wroot::file::synchronize :"
0151 << " error in fsync() for file " << sout(m_path) << "."
0152 << std::endl;
0153 return false;
0154 }
0155 #endif
0156 return true;
0157 }
0158
0159 virtual bool ziper(char a_key,compress_func& a_func) const {
0160 std::map<char,compress_func>::const_iterator it = m_zipers.find(a_key);
0161 if(it==m_zipers.end()) {
0162 a_func = 0;
0163 return false;
0164 }
0165 a_func = (*it).second;
0166 return true;
0167 }
0168 virtual uint32 compression() const {return m_compress;}
0169 virtual void compress_buffer(const buffer& a_buffer,char*& a_kbuf,uint32& a_klen,bool& a_kdel) {
0170 //NOTE: if(kdelete) delete [] kbuf;
0171
0172 a_kbuf = 0;
0173 a_klen = 0;
0174 a_kdel = false;
0175
0176 uint32 nbytes = a_buffer.length();
0177 uint32 cxlevel = m_compress;
0178 if(cxlevel && (nbytes>256)) {
0179 compress_func func;
0180 if(!ziper('Z',func)) {
0181 //m_out << "tools::wroot::file::compress_buffer :"
0182 // << " zlib ziper not found."
0183 // << std::endl;
0184 a_kbuf = (char*)a_buffer.buf();
0185 a_klen = a_buffer.length();
0186 a_kdel = false;
0187 } else {
0188 const uint32 kMAXBUF = 0xffffff;
0189 const uint32 HDRSIZE = 9;
0190 uint32 nbuffers = nbytes/kMAXBUF;
0191 uint32 buf_out_size = kMAXBUF+HDRSIZE+kMAXBUF/2;
0192 uint32 buflen = (nbuffers+1)*buf_out_size;
0193 a_kbuf = new char[buflen];
0194 a_kdel = true;
0195 char* src = (char*)a_buffer.buf();
0196 char* tgt = a_kbuf;
0197 uint32 nzip = 0;
0198 for(uint32 i=0;i<=nbuffers;i++) {
0199 uint32 bufmax = ((i == nbuffers) ? nbytes - nzip : kMAXBUF);
0200 uint32 nout;
0201 if(!zip(m_out,func,cxlevel,bufmax,src,buf_out_size,tgt,nout)) {
0202 delete [] a_kbuf;
0203 a_kbuf = (char*)a_buffer.buf();
0204 a_klen = a_buffer.length();
0205 a_kdel = false;
0206 return;
0207 }
0208 tgt += nout; //nout includes HDRSIZE
0209 a_klen += nout;
0210 src += kMAXBUF;
0211 nzip += kMAXBUF;
0212 }
0213 if(a_klen>=a_buffer.length()) {
0214 //NOTE: It is in the ROOT/IO specification (see ROOT/TKey.cxx/TKey::ReadObj() code) that some data compressions
0215 // are detected at read time by checking that "fObjlen > fNbytes-fKeylen", that is to say that
0216 // the overall output size (fNbytes-fKeylen) is stricly lower than the input size (fObjlen).
0217 // By using the zlib-ng compression library, we saw that we may fall on cases where the overall
0218 // output size (a_klen here at this point) may be equal to the input size (a_buffer.lengt()) which
0219 // induces problem when reading back the data with ROOT. Then the upper test checks and protects against that.
0220 delete [] a_kbuf;
0221 a_kbuf = (char*)a_buffer.buf();
0222 a_klen = a_buffer.length();
0223 a_kdel = false;
0224 }
0225 }
0226 } else {
0227 a_kbuf = (char*)a_buffer.buf();
0228 a_klen = a_buffer.length();
0229 a_kdel = false;
0230 }
0231 }
0232 public:
0233 file(std::ostream& a_out,const std::string& a_path,bool a_verbose = false)
0234 :m_out(a_out)
0235 ,m_path(a_path)
0236 ,m_verbose(a_verbose)
0237 ,m_file(not_open())
0238 //,m_bytes_write(0)
0239 ,m_root_directory(get_me(),nosuffix(a_path),m_title)
0240 // begin of record :
0241 ,m_version(0)
0242 ,m_BEGIN(0)
0243 ,m_END(0)
0244 ,m_seek_free(0)
0245 ,m_nbytes_free(0)
0246 ,m_nbytes_name(0)
0247 ,m_units(4)
0248 ,m_compress(1)
0249 ,m_seek_info(0)
0250 ,m_nbytes_info(0)
0251 {
0252 #ifdef TOOLS_MEM
0253 mem::increment(s_class().c_str());
0254 #endif
0255
0256 m_version = version();
0257
0258 if(access_path(m_path,kFileExists)) unlink(m_path);
0259
0260 if(!m_root_directory.is_valid()) {
0261 m_out << "tools::wroot::file::file :"
0262 << " " << sout(m_path) << " root directory badly created."
0263 << std::endl;
0264 return;
0265 }
0266
0267 m_file = _open(a_path.c_str(),
0268 #if defined(_MSC_VER) || defined(__MINGW32__)
0269 O_RDWR | O_CREAT | O_BINARY,S_IREAD | S_IWRITE
0270 #else
0271 O_RDWR | O_CREAT,0644
0272 #endif
0273 );
0274 if(m_file==not_open()) {
0275 m_out << "tools::wroot::file::file :"
0276 << " can't open " << sout(a_path) << "."
0277 << std::endl;
0278 return;
0279 }
0280
0281 //initialize :
0282
0283 m_BEGIN = kBegin(); // First used word in file following the file header.
0284 m_END = m_BEGIN; // Pointer to end of file.
0285
0286 m_free_segs.push_back(new free_seg(m_out,m_BEGIN,START_BIG_FILE()));
0287
0288 // Write Directory info :
0289 uint32 namelen =
0290 key::std_string_record_size(m_path) +
0291 key::std_string_record_size(m_title);
0292 uint32 nbytes = namelen + m_root_directory.record_size();
0293
0294 //TUUID version 1:
0295 nbytes += sizeof(unsigned int);
0296 nbytes += 2*sizeof(unsigned short);
0297 nbytes += 8*sizeof(unsigned char);
0298
0299 wroot::key key(m_out,*this,0,m_path,m_title,"TFile",nbytes); // It does a (*this).set_END().
0300
0301 // m_nbytes_name = start point of directory info from key head.
0302 m_nbytes_name = key.key_length() + namelen;
0303 m_root_directory.set_nbytes_name(m_nbytes_name);
0304 m_root_directory.set_seek_directory(key.seek_key()); //at EOF.
0305
0306 //the below write 45 bytes at BOF (Begin Of File).
0307 if(!write_header()) { //need m_nbytes_name, m_END after key written.
0308 m_out << "tools::wroot::file::file :"
0309 << " can't write file header."
0310 << std::endl;
0311 return;
0312 }
0313
0314 {char* pos = key.data_buffer();
0315 wbuf wb(m_out,byte_swap(),key.eob(),pos);
0316 if(!wb.write(m_path)) return;
0317 if(!wb.write(m_title)) return;
0318 if(!m_root_directory.to_buffer(wb)) return;
0319 //TUUID version 1:
0320 if(!wb.write((unsigned int)0)) return;
0321 if(!wb.write((unsigned short)0)) return;
0322 if(!wb.write((unsigned short)0)) return;
0323 {for(size_t count=0;count<8;count++) if(!wb.write((unsigned char)0)) return;}}
0324
0325 if(m_verbose) {
0326 m_out << "tools::wroot::file::file :"
0327 << " write key ("
0328 << namelen
0329 << ", "
0330 << m_root_directory.record_size()
0331 << ", "
0332 << nbytes
0333 << ", "
0334 << m_nbytes_name
0335 << ", "
0336 << key.seek_key()
0337 << ")."
0338 << std::endl;
0339 }
0340
0341 key.set_cycle(1);
0342 if(!key.write_self(*this)) {
0343 m_out << "tools::wroot::file::file :"
0344 << " key.write_self() failed."
0345 << std::endl;
0346 return;
0347 }
0348
0349 //the below write at kBegin + nbytes.
0350 //64+52
0351 uint32 n;
0352 if(!key.write_file(*this,n)) {
0353 m_out << "tools::wroot::file::file :"
0354 << " can't write key in file."
0355 << std::endl;
0356 return;
0357 }
0358 //::printf("debug : file::file : write key : %d\n",n);
0359
0360 }
0361 virtual ~file() {
0362 close();
0363 #ifdef TOOLS_MEM
0364 mem::decrement(s_class().c_str());
0365 #endif
0366 }
0367 protected:
0368 file(const file& a_from)
0369 :ifile(a_from)
0370 ,m_out(a_from.m_out)
0371 ,m_root_directory(get_me())
0372 {
0373 #ifdef TOOLS_MEM
0374 mem::increment(s_class().c_str());
0375 #endif
0376 }
0377 file& operator=(const file&){return *this;}
0378 public:
0379 const std::string& path() const {return m_path;}
0380
0381 void set_compression(uint32 a_level) {
0382 // level = 0 objects written to this file will not be compressed.
0383 // level = 1 minimal compression level but fast.
0384 // ....
0385 // level = 9 maximal compression level but slow.
0386 m_compress = a_level;
0387 if(m_compress>9) m_compress = 9;
0388 }
0389
0390 bool is_open() const {return (m_file==not_open()?false:true);}
0391
0392 void close() {
0393 if(m_file==not_open()) return;
0394 m_root_directory.close();
0395
0396 if(m_free_segs.size()) {
0397 if(!write_free_segments()) {
0398 m_out << "tools::wroot::file::close :"
0399 << " can't write free segments."
0400 << std::endl;
0401 }
0402 if(!write_header()) { // Now write file header
0403 m_out << "tools::wroot::file::close :"
0404 << " can't write file header."
0405 << std::endl;
0406 }
0407 }
0408
0409 {std::list<free_seg*>::iterator it;
0410 for(it=m_free_segs.begin();
0411 it!=m_free_segs.end();
0412 it = m_free_segs.erase(it)) {
0413 delete (*it);
0414 }}
0415
0416 ::close(m_file);
0417 m_file = not_open();
0418 }
0419
0420 directory& dir() {return m_root_directory;}
0421 const directory& dir() const {return m_root_directory;}
0422
0423 bool write(uint32& a_nbytes){
0424 // Write memory objects to this file :
0425 // Loop on all objects in m_root_directory (including subdirectories).
0426 // A new key is created in the directories m_keys linked list
0427 // for each object.
0428 // The list of keys is then saved on the file (via write_keys)
0429 // as a single data record.
0430 // The directory header info is rewritten on the directory header record.
0431 // //The linked list of FREE segments is written.
0432 // The file header is written (bytes 1->m_BEGIN).
0433 a_nbytes = 0;
0434
0435 if(m_verbose) {
0436 m_out << "tools::wroot::file::write :"
0437 << " writing Name=" << sout(m_path)
0438 << " Title=" << sout(m_title) << "."
0439 << std::endl;
0440 }
0441
0442 uint32 nbytes;
0443 if(!m_root_directory.write(nbytes)) return false; // Write directory tree
0444
0445 if(!write_streamer_infos()) {
0446 m_out << "tools::wroot::file::write :"
0447 << " write_streamer_infos failed."
0448 << std::endl;
0449 return false;
0450 }
0451
0452 if(!write_free_segments()) {
0453 m_out << "tools::wroot::file::write :"
0454 << " can't write free segments."
0455 << std::endl;
0456 return false;
0457 }
0458
0459 if(!write_header()) { //write 45 bytes at BOF.
0460 m_out << "tools::wroot::file::write :"
0461 << " can't write file header."
0462 << std::endl;
0463 return false;
0464 }
0465
0466 a_nbytes = nbytes;
0467 return true;
0468 }
0469
0470 bool add_ziper(char a_key,compress_func a_func){
0471 std::map<char,compress_func>::const_iterator it = m_zipers.find(a_key);
0472 if(it!=m_zipers.end()) {
0473 //(*it).second = a_func; //override ?
0474 return false;
0475 } else {
0476 m_zipers[a_key] = a_func;
0477 return true;
0478 }
0479 }
0480 protected:
0481 enum EAccessMode {
0482 kFileExists = 0,
0483 kExecutePermission = 1,
0484 kWritePermission = 2,
0485 kReadPermission = 4
0486 };
0487 static bool access_path(const std::string& a_path,EAccessMode a_mode){
0488 // Returns true if one can access a file using the specified access mode.
0489 // Mode is the same as for the WinNT access(2) function.
0490 #ifdef _MSC_VER
0491 return (::_access(a_path.c_str(),a_mode) == 0) ? true : false;
0492 #else
0493 return (::access(a_path.c_str(),a_mode) == 0) ? true : false;
0494 #endif
0495 }
0496 static bool unlink(const std::string& a_path){
0497 // Unlink, i.e. remove, a file or directory. Returns true when succesfull,
0498 // false in case of failure.
0499 struct stat finfo;
0500 if (::stat(a_path.c_str(),&finfo) < 0) return false;
0501 #ifdef _MSC_VER
0502 if (finfo.st_mode & S_IFDIR)
0503 return (::_rmdir(a_path.c_str())==-1 ? false : true);
0504 else
0505 return (::unlink(a_path.c_str())==-1 ? false : true);
0506 #else
0507 if (S_ISDIR(finfo.st_mode))
0508 return (::rmdir(a_path.c_str())==-1 ? false : true);
0509 else
0510 return (::unlink(a_path.c_str())==-1 ? false : true);
0511 #endif
0512 }
0513
0514 static int _open(const char* a_name,int a_flags,unsigned int a_mode) {
0515 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
0516 return ::open64(a_name,a_flags,a_mode);
0517 #else
0518 return ::open(a_name,a_flags,a_mode);
0519 #endif
0520 }
0521 bool write_header() {
0522 const char root[] = "root";
0523 //char psave[kBegin()];
0524 char psave[128];
0525 const char* eob = psave + kBegin();
0526 char* pos = psave;
0527 ::memcpy(pos,root,4); pos += 4;
0528 uint32 vers = m_version;
0529 if((m_END>START_BIG_FILE()) ||
0530 (m_seek_free>START_BIG_FILE()) ||
0531 (m_seek_info>START_BIG_FILE()) ){
0532 vers += 1000000;
0533 m_units = 8;
0534 }
0535 wbuf wb(m_out,byte_swap(),eob,pos);
0536 if(!wb.write(vers)) return false;
0537 if(!wb.write((seek32)m_BEGIN)) return false;
0538 if(vers>1000000) {
0539 if(!wb.write(m_END)) return false;
0540 if(!wb.write(m_seek_free)) return false;
0541 } else {
0542 if(!wb.write((seek32)m_END)) return false;
0543 if(!wb.write((seek32)m_seek_free)) return false;
0544 }
0545 if(!wb.write(m_nbytes_free)) return false;
0546 //int nfree = fFreeSegments.size();
0547 uint32 nfree = 0; //FIXME
0548 if(!wb.write(nfree)) return false;
0549 if(!wb.write(m_nbytes_name)) return false;
0550 if(!wb.write(m_units)) return false;
0551 if(!wb.write(m_compress)) return false;
0552 if(vers>1000000) {
0553 if(!wb.write(m_seek_info)) return false;
0554 } else {
0555 if(!wb.write((seek32)m_seek_info)) return false;
0556 }
0557 if(!wb.write(m_nbytes_info)) return false;
0558 if(!set_pos()) return false; //BOF
0559 uint32 nbytes = uint32(pos - psave);
0560 //::printf("debug : write_header : %d\n",nbytes);
0561 if(!write_buffer(psave,nbytes)) return false;
0562 if(!synchronize()) return false;
0563 return true;
0564 }
0565
0566 bool write_streamer_infos() {
0567 obj_list<streamer_info> sinfos;
0568 fill_infos(sinfos,m_out);
0569
0570 if(sinfos.empty()) return false;
0571
0572 buffer bref(m_out,byte_swap(),256);
0573
0574 if(!sinfos.stream(bref)) {
0575 m_out << "tools::wroot::file::write_streamer_infos :"
0576 << " cannot stream obj_list<streamer_info>."
0577 << std::endl;
0578 return false;
0579 }
0580 uint32 nbytes = bref.length();
0581
0582 wroot::key key(m_out,*this,
0583 m_root_directory.seek_directory(),
0584 "StreamerInfo","",
0585 sinfos.store_cls(),
0586 nbytes); // It does a (*this).set_END().
0587 if(!key.seek_key()) return false;
0588
0589 if(!bref.displace_mapped(key.key_length())) return false;
0590
0591 ::memcpy(key.data_buffer(),bref.buf(),nbytes);
0592
0593 //key.set_cycle(1);
0594 if(!key.write_self(*this)) {
0595 m_out << "tools::wroot::file::write_streamer_infos :"
0596 << " key.write_self() failed."
0597 << std::endl;
0598 return false;
0599 }
0600
0601 m_seek_info = key.seek_key();
0602 m_nbytes_info = key.number_of_bytes();
0603 //FIXME sumBuffer(key.objectSize());
0604
0605 uint32 n;
0606 if(!key.write_file(*this,n)) return false;
0607 if(!n) return false;
0608
0609 return true;
0610 }
0611
0612 bool make_free_seg(seek a_first,seek a_last) {
0613 // Mark unused bytes on the file :
0614 // The list of free segments is in the m_free_segs list
0615 // When an object is deleted from the file, the freed space is added
0616 // into the FREE linked list (m_free_segs). The FREE list consists
0617 // of a chain of consecutive free segments on the file. At the same
0618 // time, the first 4 bytes of the freed record on the file
0619 // are overwritten by GAPSIZE where
0620 // GAPSIZE = -(Number of bytes occupied by the record).
0621
0622 if(m_free_segs.empty()) {
0623 m_out << "tools::wroot::file::make_free_seg :"
0624 << " free_seg list should not be empty here."
0625 << std::endl;
0626 return false;
0627 }
0628
0629 free_seg* newfree = add_free(m_free_segs,a_first,a_last);
0630 if(!newfree) {
0631 m_out << "tools::wroot::file::make_free_seg :"
0632 << " add_free failed."
0633 << std::endl;
0634 return false;
0635 }
0636
0637 seek nfirst = newfree->first();
0638 seek nlast = newfree->last();
0639
0640 seek _nbytes = nlast-nfirst+1;
0641 if(_nbytes>START_BIG_FILE()) _nbytes = START_BIG_FILE();
0642 int nbytes = -int(_nbytes);
0643
0644 int nb = sizeof(int);
0645
0646 char psave[128];
0647 const char* eob = psave + nb;
0648 char* pos = psave;
0649
0650 wbuf wb(m_out,byte_swap(),eob,pos);
0651 if(!wb.write(nbytes)) return false;
0652
0653 if(nlast == (m_END-1)) m_END = nfirst;
0654 if(!set_pos(nfirst)) return false;
0655 if(!write_buffer(psave,nb)) return false;
0656 if(!synchronize()) return false;
0657 return true;
0658 }
0659
0660 bool write_free_segments(){
0661 // The linked list of FREE segments (fFree) is written as a single data record.
0662
0663 // Delete old record if it exists :
0664 if(m_seek_free){
0665 if(!make_free_seg(m_seek_free, m_seek_free + m_nbytes_free -1)) {
0666 m_out << "tools::wroot::file::write_free_segments :"
0667 << " key.write_self() failed."
0668 << std::endl;
0669 return false;
0670 }
0671 }
0672
0673 //::printf("debug : write_free_segments : seg list :\n");
0674
0675 uint32 nbytes = 0;
0676 {tools_lforcit(free_seg*,m_free_segs,it) {
0677 nbytes += (*it)->record_size();
0678 //::printf("debug : write_free_segments : %lu %lu\n",
0679 // (*it)->first(),(*it)->last());
0680 }}
0681 if(!nbytes) return true;
0682
0683 wroot::key key(m_out,*this,
0684 m_root_directory.seek_directory(),
0685 m_path,m_title,"TFile",
0686 nbytes); // It does a (*this).set_END().
0687 if(!key.seek_key()) return false;
0688
0689 {char* pos = key.data_buffer();
0690 wbuf wb(m_out,byte_swap(),key.eob(),pos);
0691 tools_lforcit(free_seg*,m_free_segs,it) {
0692 if(!(*it)->fill_buffer(wb)) return false;
0693 }}
0694
0695 //key.set_cycle(1);
0696 if(!key.write_self(*this)) {
0697 m_out << "tools::wroot::file::write_free_segments :"
0698 << " key.write_self() failed."
0699 << std::endl;
0700 return false;
0701 }
0702
0703 m_seek_free = key.seek_key();
0704 m_nbytes_free = key.number_of_bytes();
0705 if(m_verbose) {
0706 m_out << "tools::wroot::file::write_free_segments :"
0707 << " write key." << std::endl;
0708 }
0709
0710 uint32 n;
0711 if(!key.write_file(*this,n)) return false;
0712 if(!n) return false;
0713
0714 return true;
0715 }
0716
0717 static bool zip(std::ostream& a_out,
0718 compress_func a_func,
0719 int a_level,
0720 uint32 a_srcsize,char* a_src,
0721 uint32 a_tgtsize,char* a_tgt,
0722 uint32& a_irep){
0723
0724 // from Rio/Bits/R__zip using zlib.
0725
0726 const uint32 HDRSIZE = 9;
0727
0728 if(a_tgtsize<HDRSIZE) {
0729 a_out << "tools::wroot::file::zip :"
0730 << " target buffer too small."
0731 << std::endl;
0732 a_irep = 0;
0733 return false;
0734 }
0735 if(a_srcsize>0xffffff) {
0736 a_out << "tools::wroot::file::zip :"
0737 << " source buffer too big."
0738 << std::endl;
0739 a_irep = 0;
0740 return false;
0741 }
0742
0743 uint32 out_size;
0744 if(!a_func(a_out,a_level,
0745 a_srcsize,a_src,
0746 a_tgtsize,a_tgt+HDRSIZE,
0747 out_size)) {
0748 a_out << "tools::wroot::file::zip :"
0749 << " zipper failed."
0750 << std::endl;
0751 a_irep = 0;
0752 return false;
0753 }
0754
0755 if((HDRSIZE+out_size)>a_tgtsize) {
0756 a_out << "tools::wroot::file::zip :"
0757 << " target buffer overflow."
0758 << std::endl;
0759 a_irep = 0;
0760 return false;
0761 }
0762
0763 // HEADER :
0764 a_tgt[0] = 'Z'; // Signature ZLib
0765 a_tgt[1] = 'L';
0766 a_tgt[2] = 8; //DEFLATE
0767
0768 a_tgt[3] = (char)(out_size & 0xff);
0769 a_tgt[4] = (char)((out_size >> 8) & 0xff);
0770 a_tgt[5] = (char)((out_size >> 16) & 0xff);
0771
0772 a_tgt[6] = (char)(a_srcsize & 0xff);
0773 a_tgt[7] = (char)((a_srcsize >> 8) & 0xff);
0774 a_tgt[8] = (char)((a_srcsize >> 16) & 0xff);
0775
0776 a_irep = HDRSIZE+out_size;
0777
0778 return true;
0779 }
0780
0781 #if defined(__sun) && !defined(__linux__) && (__SUNPRO_CC > 0x420)
0782 int error_number() {return ::errno;}
0783 void reset_error_number() {::errno = 0;}
0784 #else
0785 int error_number() {return errno;}
0786 void reset_error_number() {errno = 0;}
0787 #endif
0788
0789 protected:
0790 std::ostream& m_out;
0791 std::string m_path;
0792 bool m_verbose;
0793 int m_file;
0794 //uint64 m_bytes_write; //Number of bytes write in this file
0795 std::string m_title; //must be before the below.
0796 directory m_root_directory;
0797 std::map<char,compress_func> m_zipers;
0798 std::list<free_seg*> m_free_segs; //Free segments linked list table
0799 // begin of record :
0800 // "root"
0801 uint32 m_version; //File format version
0802 seek m_BEGIN; //First used byte in file
0803 seek m_END; //Last used byte in file
0804 seek m_seek_free; //Location on disk of free segments structure
0805 uint32 m_nbytes_free; //Number of bytes for free segments structure
0806 //int nfree
0807 uint32 m_nbytes_name; //Number of bytes in TNamed at creation time
0808 char m_units; //Number of bytes for file pointers
0809 uint32 m_compress; //(=1 file is compressed, 0 otherwise)
0810 seek m_seek_info; //Location on disk of StreamerInfo record
0811 uint32 m_nbytes_info; //Number of bytes for StreamerInfo record
0812 };
0813
0814
0815 }}
0816
0817 #endif
0818
0819 //doc
0820 //
0821 // A ROOT file is a suite of consecutive data records with the following
0822 // format (see also the TKey class);
0823 // TKey ---------------------
0824 // byte 1->4 Nbytes = Length of compressed object (in bytes)
0825 // 5->6 Version = TKey version identifier
0826 // 7->10 ObjLen = Length of uncompressed object
0827 // 11->14 Datime = Date and time when object was written to file
0828 // 15->16 KeyLen = Length of the key structure (in bytes)
0829 // 17->18 Cycle = Cycle of key
0830 // 19->22 SeekKey = Pointer to record itself (consistency check)
0831 // 23->26 SeekPdir = Pointer to directory header
0832 // 27->27 lname = Number of bytes in the class name
0833 // 28->.. ClassName = Object Class Name
0834 // ..->.. lname = Number of bytes in the object name
0835 // ..->.. Name = lName bytes with the name of the object
0836 // ..->.. lTitle = Number of bytes in the object title
0837 // ..->.. Title = Title of the object
0838 // -----> DATA = Data bytes associated to the object
0839 //
0840 // The first data record starts at byte fBEGIN (currently set to kBegin)
0841 // Bytes 1->kBegin contain the file description:
0842 // byte 1->4 "root" = Root file identifier
0843 // 5->8 fVersion = File format version
0844 // 9->12 fBEGIN = Pointer to first data record
0845 // 13->16 fEND = Pointer to first free word at the EOF
0846 // 17->20 fSeekFree = Pointer to FREE data record
0847 // 21->24 fNbytesFree = Number of bytes in FREE data record
0848 // 25->28 nfree = Number of free data records
0849 // 29->32 fNbytesName = Number of bytes in TNamed at creation time
0850 // 33->33 fUnits = Number of bytes for file pointers
0851 // 34->37 fCompress = Zip compression level
0852 //