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