inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/wroot/file
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_wroot_file
00005 #define inlib_wroot_file
00006 
00007 // inheritance :
00008 #include "ifile"
00009 
00010 #include "directory"
00011 
00012 #include "infos"
00013 
00014 #include "../platform"
00015 
00016 #include "../path"
00017         
00018 #include <map>
00019 
00020 #include <fcntl.h>
00021 #include <errno.h>
00022 #include <sys/stat.h>
00023 
00024 #if defined(WIN32) && !defined(__GNUC__)
00025 #include <direct.h>
00026 #define ssize_t int
00027 #include <io.h>
00028 // disable the warning about the usage of "this" in the constructor.
00029 #pragma warning(disable:4355)
00030 #endif
00031 
00032 namespace inlib {
00033 namespace wroot {
00034 
00035 class file : public virtual ifile {
00036   static const std::string& s_class() {
00037     static const std::string s_v("inlib::wroot::file");
00038     return s_v;
00039   }
00040   static int not_open() {return -1;}
00041   static uint32 kBegin() {return 64;}
00042   static uint32 START_BIG_FILE() {return 2000000000;}
00043 public: //ifile
00044   virtual bool verbose() const {return m_verbose;}
00045   virtual std::ostream& out() {return m_out;}
00046 
00047   virtual bool byte_swap() const {return is_little_endian();}
00048   virtual bool set_pos(seek a_offset = 0,from a_from = begin){
00049     int whence = 0;
00050     switch(a_from) {
00051     case begin:
00052       whence = SEEK_SET;
00053       break;
00054     case current:
00055       whence = SEEK_CUR;
00056       break;
00057     case end:
00058       whence = SEEK_END;
00059       break;
00060     }
00061 
00062 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
00063     if (::lseek64(m_file, a_offset, whence) < 0) {
00064 #elif defined(WIN32)
00065     if (::_lseeki64(m_file, a_offset, whence) < 0) {
00066 #else
00067     if (::lseek(m_file, a_offset, whence) < 0) {
00068 #endif
00069       m_out << "inlib::wroot::file::set_pos :"
00070             << " cannot set position " << a_offset 
00071             << " in file " << sout(m_path) << "."
00072             << std::endl;
00073       return false;
00074     }
00075     return true;
00076   }
00077 
00078   virtual seek END() const {return m_END;}
00079   virtual void set_END(seek a_end){m_END = a_end;}
00080 
00081   virtual bool write_buffer(const char* a_buffer,uint32 a_length) {
00082     // Write a buffer to the file. This is the basic low level write operation.
00083     ssize_t siz;
00084     while ((siz = ::write(m_file,a_buffer,a_length)) < 0 && 
00085             error_number() == EINTR) reset_error_number();
00086 
00087     if(siz < 0) {
00088       m_out << "inlib::wroot::file::write_buffer :"
00089             << " error writing to file " << sout(m_path) << "."
00090             << std::endl;
00091       return false;
00092     }
00093     if(siz!=(ssize_t)a_length) {
00094       m_out << "inlib::wroot::file::write_buffer :"
00095            << "error writing all requested bytes to file " << sout(m_path)
00096            << ", wrote " << long2s(siz) << " of " << a_length
00097            << std::endl;
00098       return false;
00099     }
00100     //m_bytes_write  += siz;
00101     return true;
00102   }
00103 
00104   virtual uint32 version() const {
00105     // Return version id as an integer, i.e. "2.22/04" -> 22204.
00106     static const uint32 ROOT_MAJOR_VERSION = 4;
00107     static const uint32 ROOT_MINOR_VERSION = 0;
00108     static const uint32 ROOT_PATCH_VERSION = 0;
00109     return 
00110       10000 * ROOT_MAJOR_VERSION + 
00111       100 * ROOT_MINOR_VERSION + 
00112       ROOT_PATCH_VERSION;
00113   }
00114 
00115   virtual bool synchronize(){
00116     // Synchornize a file's in-core and on-disk states.
00117 #ifdef WIN32
00118     return true;
00119 #else
00120     if (::fsync(m_file) < 0) {
00121       m_out << "inlib::wroot::file::synchronize :"
00122             << " error flushing file " << sout(m_path) << "."
00123             << std::endl;
00124       return false;
00125     } 
00126     return true;
00127 #endif
00128   }
00129 
00130   virtual bool ziper(char a_key,zip_func& a_func) const {
00131     std::map<char,zip_func>::const_iterator it = m_zipers.find(a_key);
00132     if(it==m_zipers.end()) {
00133       a_func = 0;
00134       return false;
00135     }
00136     a_func = (*it).second;
00137     return true;
00138   }
00139   virtual uint32 compression() const {return m_compress;}
00140   virtual void compress_buffer(const buffer& a_buffer,
00141                                     char*& a_kbuf,uint32& a_klen,bool& a_kdel){
00142     //NOTE : if(kdelete) delete [] kbuf;
00143 
00144     a_kbuf = 0;
00145     a_klen = 0;
00146     a_kdel = false;
00147 
00148     uint32 nbytes = a_buffer.length();
00149     uint32 cxlevel = m_compress;
00150     if(cxlevel && (nbytes>256)) {
00151       ifile::zip_func func;
00152       if(!ziper('Z',func)) {
00153         //m_out << "inlib::wroot::directory::write_object :" 
00154         //      << " zlib ziper not found."
00155         //      << std::endl;
00156         a_kbuf = (char*)a_buffer.buf();
00157         a_klen = a_buffer.length();
00158         a_kdel = false;
00159       } else {
00160         const uint32 kMAXBUF = 0xffffff;
00161         const uint32 HDRSIZE = 9;
00162         uint32 nbuffers = nbytes/kMAXBUF;
00163         uint32 buflen = nbytes+HDRSIZE*(nbuffers+1); 
00164         a_kbuf = new char[buflen];
00165         a_kdel = true;
00166         char* src = (char*)a_buffer.buf();
00167         char* tgt = a_kbuf;
00168         uint32 nzip = 0;
00169         for(uint32 i=0;i<=nbuffers;i++) {
00170           uint32 bufmax = ((i == nbuffers) ? nbytes - nzip : kMAXBUF);
00171           uint32 nout;
00172           if(!zip(m_out,func,cxlevel,bufmax,src,bufmax,tgt,nout)) {
00173             delete [] a_kbuf;
00174             a_kbuf = (char*)a_buffer.buf();
00175             a_klen = a_buffer.length();
00176             a_kdel = false;
00177             break;
00178           }
00179           tgt += nout; //nout includes HDRSIZE
00180           a_klen += nout;
00181           src += kMAXBUF;
00182           nzip += kMAXBUF;
00183         }    
00184         //::printf("debug : compress : end : %u %u\n",nbytes,klen);
00185       }
00186     } else {
00187       a_kbuf = (char*)a_buffer.buf();
00188       a_klen = a_buffer.length();
00189       a_kdel = false;
00190     }
00191   }
00192 public:
00193   file(std::ostream& a_out,
00194               const std::string& a_path,
00195               bool a_verbose = false)
00196   :m_out(a_out)
00197   ,m_path(a_path)
00198   ,m_verbose(a_verbose)
00199   ,m_file(not_open())
00200   //,m_bytes_write(0)
00201   ,m_root_directory(*this,nosuffix(a_path),m_title)
00202   // begin of record :
00203   ,m_version(0)
00204   ,m_BEGIN(0)
00205   ,m_END(0)
00206   ,m_seek_free(0)
00207   ,m_nbytes_free(0)
00208   ,m_nbytes_name(0)
00209   ,m_units(4)
00210   ,m_compress(1)
00211   ,m_seek_info(0)
00212   ,m_nbytes_info(0)
00213   {
00214 #ifdef INLIB_MEM
00215     mem::increment(s_class().c_str());
00216 #endif
00217 
00218     m_version = version();
00219 
00220     if(access_path(m_path,kFileExists)) unlink(m_path);
00221 
00222     if(!m_root_directory.is_valid()) {
00223       m_out << "inlib::wroot::file::file :"
00224             << " " << sout(m_path) << " root directory badly created."
00225             << std::endl;
00226       return;
00227     }
00228 
00229     m_file = _open(a_path.c_str(),
00230 #ifdef WIN32
00231                                O_RDWR | O_CREAT | O_BINARY,S_IREAD | S_IWRITE
00232 #else
00233                                O_RDWR | O_CREAT,0644
00234 #endif
00235     );
00236     if(m_file==not_open()) {
00237       m_out << "inlib::wroot::file::file :"
00238             << " can't open " << sout(a_path) << "."
00239             << std::endl;
00240       return;
00241     }
00242 
00243     //initialize :
00244     m_BEGIN = kBegin();  // First used word in file following the file header.
00245     m_END = m_BEGIN;   // Pointer to end of file.
00246 
00247     // Write Directory info :
00248     uint32 namelen = 
00249       key::std_string_record_size(m_path) + 
00250       key::std_string_record_size(m_title);
00251     uint32 nbytes = namelen + m_root_directory.record_size();
00252     wroot::key key(*this,0,m_path,m_title,"TFile",nbytes); //set m_END.
00253 
00254     // m_nbytes_name = start point of directory info from key head.
00255     m_nbytes_name = key.key_length() + namelen; 
00256     m_root_directory.set_nbytes_name(m_nbytes_name);
00257     m_root_directory.set_seek_directory(key.seek_key()); //at EOF.
00258 
00259     //the below write 45 bytes at BOF (Begin Of File).
00260     if(!write_header()) { //need m_nbytes_name, m_END after key written.
00261       m_out << "inlib::wroot::file::file :"
00262             << " can't write file header."
00263             << std::endl;
00264       return;
00265     }
00266 
00267    {char* pos = key.data_buffer();
00268     wbuf wb(m_out,byte_swap(),key.eob(),pos);
00269     if(!wb.write(m_path)) return;
00270     if(!wb.write(m_title)) return;
00271     if(!m_root_directory.to_buffer(wb)) return;}
00272 
00273     if(m_verbose) {
00274       m_out << "inlib::wroot::file::file :"
00275             << " write key ("
00276             << namelen 
00277             << ", " 
00278             << m_root_directory.record_size()
00279             << ", " 
00280             << nbytes
00281             << ", "
00282             << m_nbytes_name
00283             << ", "
00284             << key.seek_key() 
00285             << ")."
00286             << std::endl;
00287     }
00288 
00289     key.set_cycle(1);
00290     if(!key.write_self()) {
00291       m_out << "inlib::wroot::file::file :"
00292             << " key.write_self() failed."
00293             << std::endl;
00294       return;
00295     }
00296 
00297     //the below write at kBegin + nbytes.
00298     //64+52
00299     uint32 n;
00300     if(!key.write_file(n)) {
00301       m_out << "inlib::wroot::file::file :"
00302             << " can't write key in file."
00303             << std::endl;
00304       return;
00305     }
00306     //::printf("debug : file::file : write key : %d\n",n);
00307 
00308   }
00309   virtual ~file() {
00310     close();
00311 #ifdef INLIB_MEM
00312     mem::decrement(s_class().c_str());
00313 #endif
00314   }
00315 protected:
00316   file(const file& a_from)
00317   :ifile(a_from)
00318   ,m_out(a_from.m_out)
00319   ,m_root_directory(*this)
00320   { 
00321 #ifdef INLIB_MEM
00322     mem::increment(s_class().c_str());
00323 #endif
00324   }
00325   file& operator=(const file&){return *this;}
00326 public:
00327   void set_compression(uint32 a_level) {
00328     // level = 0 objects written to this file will not be compressed.
00329     // level = 1 minimal compression level but fast.
00330     // ....
00331     // level = 9 maximal compression level but slow.
00332     m_compress = a_level;
00333     if(m_compress>9) m_compress = 9;
00334   }
00335 
00336   void close() {
00337     if(m_file==not_open()) return;
00338     m_root_directory.close();
00339     ::close(m_file);
00340     m_file = not_open();
00341   }
00342 
00343   directory& dir() {return m_root_directory;}
00344   const directory& dir() const {return m_root_directory;}
00345 
00346   bool write(uint32& a_nbytes){
00347     // Write memory objects to this file :
00348     //  Loop on all objects in m_root_directory (including subdirectories).
00349     //  A new key is created in the directories m_keys linked list
00350     //  for each object.
00351     //  The list of keys is then saved on the file (via write_keys)
00352     //  as a single data record.
00353     //  The directory header info is rewritten on the directory header record.
00354     //  //The linked list of FREE segments is written.
00355     //  The file header is written (bytes 1->m_BEGIN).
00356     a_nbytes = 0;
00357 
00358     if(m_verbose) {
00359       m_out << "inlib::wroot::file::write :"
00360             << " writing Name=" << sout(m_path)
00361             << " Title=" << sout(m_title) << "."
00362             << std::endl;
00363     }
00364 
00365     uint32 nbytes;
00366     if(!m_root_directory.write(nbytes)) return false; // Write directory tree
00367 
00368     if(!write_streamer_infos()) {
00369       m_out << "inlib::wroot::file::write :"
00370             << " write_streamer_infos failed."
00371             << std::endl;
00372       return false;
00373     }
00374 
00375     //if(!writeFreeSegments()) return false; // Write free segments.
00376 
00377     if(!write_header()) { //write 45 bytes at BOF.
00378       m_out << "inlib::wroot::file::write :"
00379             << " can't write file header."
00380             << std::endl;
00381       return false;
00382     }
00383 
00384     a_nbytes = nbytes;
00385     return true;
00386   }
00387 
00388   bool add_ziper(char a_key,zip_func a_func){
00389     std::map<char,zip_func>::iterator it = m_zipers.find(a_key);
00390     if(it!=m_zipers.end()) {
00391       //(*it).second = a_func; //override ?
00392       return false;
00393     } else {
00394       m_zipers[a_key] = a_func;
00395       return true;
00396     }
00397   }
00398 protected:
00399   enum EAccessMode {
00400     kFileExists        = 0,
00401     kExecutePermission = 1,
00402     kWritePermission   = 2,
00403     kReadPermission    = 4
00404   };
00405   static bool access_path(const std::string& a_path,EAccessMode a_mode){
00406     // Returns true if one can access a file using the specified access mode.
00407     // Mode is the same as for the WinNT access(2) function.
00408 #ifdef WIN32
00409     return (::_access(a_path.c_str(),a_mode) == 0) ? true : false;
00410 #else
00411     return (::access(a_path.c_str(),a_mode) == 0) ? true : false;
00412 #endif
00413   }
00414   static bool unlink(const std::string& a_path){
00415     // Unlink, i.e. remove, a file or directory. Returns true when succesfull,
00416     // false in case of failure.
00417     struct stat finfo;
00418     if (::stat(a_path.c_str(),&finfo) < 0) return false;
00419 #ifdef WIN32 
00420     if (finfo.st_mode & S_IFDIR)
00421       return (::_rmdir(a_path.c_str())==-1 ? false : true);
00422     else
00423       return (::unlink(a_path.c_str())==-1 ? false : true);
00424 #else
00425     if (S_ISDIR(finfo.st_mode))
00426       return (::rmdir(a_path.c_str())==-1 ? false : true);
00427     else
00428       return (::unlink(a_path.c_str())==-1 ? false : true);
00429 #endif
00430   }
00431 
00432   static int _open(const char* a_name,int a_flags,unsigned int a_mode) {
00433 #if defined(__linux__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
00434      return ::open64(a_name,a_flags,a_mode);
00435 #else
00436      return ::open(a_name,a_flags,a_mode);
00437 #endif
00438   }
00439   static std::string sout(const std::string& a_string) {
00440     return std::string("\"")+a_string+"\"";
00441   }
00442   bool write_header() {
00443     const char root[] = "root";
00444     //char psave[kBegin()];
00445     char psave[128];
00446     const char* eob = psave + kBegin();
00447     char* pos = psave;
00448     ::memcpy(pos,root,4); pos += 4;
00449     uint32 version = m_version;
00450     if((m_END>START_BIG_FILE())        ||
00451        (m_seek_free>START_BIG_FILE())  ||
00452        (m_seek_info>START_BIG_FILE())  ){
00453       version += 1000000;
00454       m_units = 8;
00455     }
00456     wbuf wb(m_out,byte_swap(),eob,pos);
00457     if(!wb.write(version)) return false;
00458     if(!wb.write((seek32)m_BEGIN)) return false;
00459     if(version>1000000) {
00460       if(!wb.write(m_END)) return false;
00461       if(!wb.write(m_seek_free)) return false;
00462     } else {
00463       if(!wb.write((seek32)m_END)) return false;
00464       if(!wb.write((seek32)m_seek_free)) return false;
00465     }
00466     if(!wb.write(m_nbytes_free)) return false;
00467     //int nfree  = fFreeSegments.size();
00468     uint32 nfree  = 0; //FIXME
00469     if(!wb.write(nfree)) return false;
00470     if(!wb.write(m_nbytes_name)) return false;
00471     if(!wb.write(m_units)) return false;
00472     if(!wb.write(m_compress)) return false;
00473     if(version>1000000) {
00474       if(!wb.write(m_seek_info)) return false;
00475     } else {
00476       if(!wb.write((seek32)m_seek_info)) return false;
00477     }
00478     if(!wb.write(m_nbytes_info)) return false;
00479     if(!set_pos()) return false; //BOF
00480     uint32 nbytes = pos - psave;
00481     //::printf("debug : write_header : %d\n",nbytes);
00482     if(!write_buffer(psave,nbytes)) return false;
00483     if(!synchronize()) return false;
00484     return true;
00485   }
00486 
00487   bool write_streamer_infos() {
00488     List<StreamerInfo> sinfos;
00489     fill_infos(sinfos,m_out);
00490 
00491     if(sinfos.empty()) return false;
00492 
00493     buffer bref(m_out,byte_swap(),256);
00494 
00495     if(!sinfos.stream(bref)) {
00496       m_out << "inlib::wroot::file::write_streamer_infos :" 
00497             << " cannot stream List<StreamerInfo>."
00498             << std::endl;
00499       return false;
00500     }
00501     uint32 nbytes = bref.length();
00502 
00503     wroot::key key(*this,
00504                    m_root_directory.seek_directory(),
00505                    "StreamerInfo","",
00506                    sinfos.store_cls(),
00507                    nbytes); //set m_END
00508     if(!key.seek_key()) return false;
00509 
00510     if(!bref.displace_mapped(key.key_length())) return false;
00511 
00512     ::memcpy(key.data_buffer(),bref.buf(),nbytes);
00513 
00514     //key.set_cycle(1);
00515     if(!key.write_self()) {
00516       m_out << "inlib::wroot::file::write_streamer_infos :" 
00517             << " key.write_self() failed."
00518             << std::endl;
00519       return false;
00520     }
00521 
00522     m_seek_info = key.seek_key();
00523     m_nbytes_info = key.number_of_bytes();
00524     //FIXME sumBuffer(key.objectSize());
00525 
00526 
00527     uint32 n;
00528     if(!key.write_file(n)) return false;
00529     if(!n) return false;
00530 
00531     return true;
00532   }
00533 
00534   static bool zip(std::ostream& a_out,
00535                          ifile::zip_func a_func,
00536                          int a_level,
00537                          uint32 a_srcsize,char* a_src,
00538                          uint32 a_tgtsize,char* a_tgt,
00539                          uint32& a_irep){
00540 
00541     // from Rio/Bits/R__zip using zlib.
00542 
00543     const uint32 HDRSIZE = 9;
00544 
00545     if(a_tgtsize<HDRSIZE) {
00546       a_out << "inlib::rroot::directory::zip :"
00547             << " target buffer too small."
00548             << std::endl;
00549       a_irep = 0; 
00550       return false;
00551     }
00552     if(a_srcsize>0xffffff) {
00553       a_out << "inlib::rroot::directory::zip :"
00554             << " source buffer too big."
00555             << std::endl;
00556       a_irep = 0; 
00557       return false;
00558     }
00559 
00560     uint32 out_size;
00561     if(!a_func(a_out,a_level,
00562                a_srcsize,a_src,
00563                a_tgtsize,a_tgt+HDRSIZE,
00564                out_size)) {
00565       a_out << "inlib::rroot::directory::zip :"
00566             << " zipper failed."
00567             << std::endl;
00568       a_irep = 0; 
00569       return false;
00570     }
00571     if((HDRSIZE+out_size)>a_tgtsize) {
00572       a_out << "inlib::rroot::directory::zip :"
00573             << " target buffer overflow."
00574             << std::endl;
00575       a_irep = 0; 
00576       return false;
00577     }
00578 
00579     // HEADER :
00580     a_tgt[0] = 'Z'; // Signature ZLib
00581     a_tgt[1] = 'L';
00582     a_tgt[2] = 8; //DEFLATE
00583  
00584     a_tgt[3] = (char)(out_size & 0xff);
00585     a_tgt[4] = (char)((out_size >> 8) & 0xff);
00586     a_tgt[5] = (char)((out_size >> 16) & 0xff);
00587  
00588     a_tgt[6] = (char)(a_srcsize & 0xff);
00589     a_tgt[7] = (char)((a_srcsize >> 8) & 0xff);
00590     a_tgt[8] = (char)((a_srcsize >> 16) & 0xff);
00591 
00592     a_irep = HDRSIZE+out_size;
00593 
00594     return true;
00595   }
00596 
00597 #if defined(__sun) && !defined(__linux__) && (__SUNPRO_CC > 0x420)
00598   int error_number() {return ::errno;}
00599   void reset_error_number() {::errno = 0;}
00600 #else
00601   int error_number() {return errno;}
00602   void reset_error_number() {errno = 0;}
00603 #endif
00604 
00605 protected:
00606   std::ostream& m_out;
00607   std::string m_path;
00608   bool m_verbose;
00609   int m_file;
00610   //uint64 m_bytes_write; //Number of bytes write in this file
00611   std::string m_title; //must be before the below.
00612   directory m_root_directory;
00613   std::map<char,zip_func> m_zipers;
00614   // begin of record :
00615   // "root"
00616   uint32 m_version;       //File format version
00617   seek m_BEGIN;           //First used byte in file
00618   seek m_END;             //Last used byte in file
00619   seek m_seek_free;       //Location on disk of free segments structure
00620   uint32 m_nbytes_free;   //Number of bytes for free segments structure
00621   //int nfree
00622   uint32 m_nbytes_name;   //Number of bytes in TNamed at creation time
00623   char m_units;           //Number of bytes for file pointers
00624   uint32 m_compress;      //(=1 file is compressed, 0 otherwise)
00625   seek m_seek_info;       //Location on disk of StreamerInfo record
00626   uint32 m_nbytes_info;   //Number of bytes for StreamerInfo record
00627 };
00628 
00629 
00630 }}
00631 
00632 #endif
00633 
00634 //doc
00635 //
00636 //  A ROOT file is a suite of consecutive data records with the following
00637 //    format (see also the TKey class);
00638 // TKey ---------------------
00639 //      byte 1->4  Nbytes    = Length of compressed object (in bytes)
00640 //           5->6  Version   = TKey version identifier
00641 //           7->10 ObjLen    = Length of uncompressed object
00642 //          11->14 Datime    = Date and time when object was written to file
00643 //          15->16 KeyLen    = Length of the key structure (in bytes)
00644 //          17->18 Cycle     = Cycle of key
00645 //          19->22 SeekKey   = Pointer to record itself (consistency check)
00646 //          23->26 SeekPdir  = Pointer to directory header
00647 //          27->27 lname     = Number of bytes in the class name
00648 //          28->.. ClassName = Object Class Name
00649 //          ..->.. lname     = Number of bytes in the object name
00650 //          ..->.. Name      = lName bytes with the name of the object
00651 //          ..->.. lTitle    = Number of bytes in the object title
00652 //          ..->.. Title     = Title of the object
00653 //          -----> DATA      = Data bytes associated to the object
00654 //
00655 //  The first data record starts at byte fBEGIN (currently set to kBegin)
00656 //  Bytes 1->kBegin contain the file description:
00657 //       byte  1->4  "root"      = Root file identifier
00658 //             5->8  fVersion    = File format version
00659 //             9->12 fBEGIN      = Pointer to first data record
00660 //            13->16 fEND        = Pointer to first free word at the EOF
00661 //            17->20 fSeekFree   = Pointer to FREE data record
00662 //            21->24 fNbytesFree = Number of bytes in FREE data record
00663 //            25->28 nfree       = Number of free data records
00664 //            29->32 fNbytesName = Number of bytes in TNamed at creation time
00665 //            33->33 fUnits      = Number of bytes for file pointers
00666 //            34->37 fCompress   = Zip compression level
00667 //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines