Back to home page

EIC code displayed by LXR

 
 

    


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 //