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