inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/wroot/directory
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_directory
00005 #define inlib_wroot_directory
00006 
00007 #include "idir"
00008 
00009 #include "date"
00010 #include "key"
00011 #include "ifile"
00012 #include "date"
00013 #include "buffer"
00014 #include "iobject"
00015 
00016 #include "../strip"
00017 #include "../vmanip"
00018 
00019 #include <vector>
00020 #include <list>
00021 
00022 namespace inlib {
00023 namespace wroot {
00024 
00025 class directory : public virtual idir {
00026   static uint32 class_version() {return 1;}
00027 public:
00028   static const std::string& s_class() {
00029     static const std::string s_v("inlib::wroot::directory");
00030     return s_v;
00031   }
00032 public: //idir
00033   virtual ifile& file() {return m_file;}
00034   virtual seek seek_directory() const {return m_seek_directory;}
00035   virtual void append_object(iobject* a_object) {
00036     //take ownership of a_object
00037     m_objs.push_back(a_object);
00038   }
00039 public:
00040   directory(ifile& a_file)
00041   :m_file(a_file)  
00042   ,m_parent(0)
00043   ,m_is_valid(false)
00044   ,m_date_C(0)
00045   ,m_date_M(0)
00046   ,m_nbytes_keys(0)
00047   ,m_nbytes_name(0)
00048   ,m_seek_directory(0)
00049   ,m_seek_parent(0)
00050   ,m_seek_keys(0)
00051   {
00052 #ifdef INLIB_MEM
00053     mem::increment(s_class().c_str());
00054 #endif
00055   }
00056   directory(ifile& a_file,
00057             const std::string& a_name,
00058             const std::string& a_title)
00059   :m_file(a_file)  
00060   ,m_parent(0)
00061   ,m_is_valid(false)
00062   ,m_name(a_name)
00063   ,m_title(a_title)
00064   ,m_nbytes_keys(0)
00065   ,m_nbytes_name(0)
00066   ,m_seek_directory(0)
00067   ,m_seek_parent(0)
00068   ,m_seek_keys(0)
00069   {
00070 #ifdef INLIB_MEM
00071     mem::increment(s_class().c_str());
00072 #endif
00073     m_date_C = get_date();
00074     m_date_M = get_date();
00075 
00076     if(m_name.empty()) {
00077       m_file.out() << "inlib::wroot::directory::directory :"
00078                    << " directory name cannot be \"\"."
00079                    << std::endl;
00080       return; //FIXME : throw
00081     }
00082     if(m_name.find('/')!=std::string::npos) {
00083       m_file.out() << "inlib::wroot::directory::directory :"
00084                    << " directory name " << sout(m_name)
00085                    << " cannot contain a slash."
00086                    << std::endl;
00087       return; //FIXME : throw
00088     }
00089     if(m_title.empty()) m_title = m_name;
00090     m_is_valid = true;
00091   }
00092   directory(ifile& a_file,
00093             directory* a_parent, //assume a_parent not nul.
00094             const std::string& a_name,
00095             const std::string& a_title)
00096   :m_file(a_file)  
00097   ,m_parent(a_parent)
00098   ,m_is_valid(false)
00099   ,m_name(a_name)
00100   ,m_title(a_title)
00101   ,m_nbytes_keys(0)
00102   ,m_nbytes_name(0)
00103   ,m_seek_directory(0)
00104   ,m_seek_parent(0)
00105   ,m_seek_keys(0)
00106   {
00107 #ifdef INLIB_MEM
00108     mem::increment(s_class().c_str());
00109 #endif
00110     m_date_C = get_date();
00111     m_date_M = get_date();
00112 
00113     if(m_name.empty()) {
00114       m_file.out() << "inlib::wroot::directory::directory :"
00115                    << " directory name cannot be \"\"."
00116                    << std::endl;
00117       return; //FIXME : throw
00118     }
00119     if(m_name.find('/')!=std::string::npos) {
00120       m_file.out() << "inlib::wroot::directory::directory :"
00121                    << " directory name " << sout(m_name)
00122                    << " cannot contain a slash."
00123                    << std::endl; 
00124       return; //FIXME : throw
00125     }
00126 
00127     if(m_title.empty()) m_title = m_name;
00128 
00129     if(m_parent->find_key(m_name)) {
00130       m_file.out() << "inlib::wroot::directory::directory :"
00131                    << " directory " << sout(m_name) << " exists already."
00132                    << std::endl;
00133       return; //FIXME : throw
00134     }
00135 
00136     m_seek_parent = m_parent->seek_directory();
00137     uint32 nbytes = record_size();
00138 
00139     wroot::key* key = 
00140       new wroot::key(m_file,m_parent->seek_directory(),
00141                      m_name,m_title,"TDirectory",nbytes); //set m_END
00142     m_nbytes_name = key->key_length();
00143     m_seek_directory = key->seek_key(); //at EOF
00144     if(!m_seek_directory) {
00145       m_file.out() << "inlib::wroot::directory::directory :"
00146                    << " bad key."
00147                    << std::endl;
00148       delete key;
00149       return; //FIXME : throw
00150     }
00151    {char* buffer = key->data_buffer();
00152     wbuf wb(m_file.out(),m_file.byte_swap(),key->eob(),buffer);
00153     if(!to_buffer(wb)) {
00154       m_file.out() << "inlib::wroot::directory::directory :"
00155                    << " directory name " << sout(m_name)
00156                    << " cannot fill buffer."
00157                    << std::endl;
00158       delete key;
00159       return; //FIXME : throw
00160     }}
00161     uint16 cycle = m_parent->append_key(key);
00162     key->set_cycle(cycle);
00163     if(!key->write_self()) {
00164       m_file.out() << "inlib::wroot::directory::directory :"
00165                    << " key.write_self() failed."
00166                    << std::endl;
00167       return; //FIXME : throw
00168     }  
00169     uint32 n;
00170     if(!key->write_file(n)) {
00171       m_file.out() << "inlib::wroot::directory::directory :"
00172                    << " directory name " << sout(m_name)
00173                    << " cannot write key to file."
00174                    << std::endl;
00175       return; //FIXME : throw
00176     }  
00177 
00178     m_is_valid = true;
00179   }
00180   virtual ~directory(){
00181     clear_dirs();
00182     clear_objs();
00183     clear_keys();
00184 #ifdef INLIB_MEM
00185     mem::decrement(s_class().c_str());
00186 #endif
00187   }
00188 protected:
00189   directory(const directory& a_from)
00190   :idir(a_from)
00191   ,m_file(a_from.m_file)
00192   ,m_parent(0)
00193   ,m_is_valid(false){
00194 #ifdef INLIB_MEM
00195     mem::increment(s_class().c_str());
00196 #endif
00197   }
00198   directory& operator=(const directory &){
00199     m_is_valid = false;
00200     return *this;
00201   }
00202 public:
00203   bool is_valid() const {return m_is_valid;}
00204   void set_seek_directory(seek a_seek) {m_seek_directory = a_seek;}
00205 
00206   directory* mkdir(const std::string& a_name,
00207                           const std::string& a_title = ""){
00208     // Create a sub-directory and return a pointer to the created directory.
00209     // Note that the directory name cannot contain slashes.
00210     if(a_name.empty()) {
00211       m_file.out() << "inlib::wroot::directory::mkdir :" 
00212                    << " directory name cannot be \"\"." 
00213                    << std::endl;
00214       return 0;
00215     }
00216     if(a_name.find('/')!=std::string::npos) {
00217       m_file.out() << "inlib::wroot::directory::mkdir :" 
00218                    << " " << sout(a_name)
00219                    << " cannot contain a slash."
00220                    << std::endl;
00221       return 0;
00222     }
00223     directory* dir = 
00224       new directory(m_file,this,a_name,a_title.empty()?a_name:a_title);
00225     if(!dir->is_valid()) {
00226       m_file.out() << "inlib::wroot::directory::mkdir :" 
00227                    << " directory badly created."
00228                    << std::endl;
00229       delete dir;
00230       return 0;
00231     }
00232     m_dirs.push_back(dir);
00233     return dir;
00234   }
00235 
00236   //uint32 nbytes_name() const {return m_nbytes_name;}
00237   void set_nbytes_name(uint32 a_n) {m_nbytes_name = a_n;}
00238 
00239   uint32 record_size() const {
00240     uint32 nbytes = sizeof(short);
00241     nbytes += sizeof(date); //m_date_C.record_size();
00242     nbytes += sizeof(date); //m_date_M.record_size();
00243     nbytes += sizeof(m_nbytes_keys);
00244     nbytes += sizeof(m_nbytes_name);
00245     //ROOT version >= 40000:
00246     nbytes += sizeof(seek);
00247     nbytes += sizeof(seek);
00248     nbytes += sizeof(seek);
00249     return nbytes;
00250   }
00251 
00252   bool close() {
00253     if(!save()) return false;
00254     clear_dirs();
00255     clear_objs();
00256     clear_keys();
00257     return true;
00258   }
00259 
00260   bool to_buffer(wbuf& a_wb){
00261     // Decode input buffer.
00262     // (Name, title) are stored in the (name, title) of the associated key.
00263     short version = class_version();
00264     version += 1000; //GB : enforce writing on seek (and not seek32).
00265     if(!a_wb.write(version)) return false;
00266     if(!a_wb.write(m_date_C)) return false;
00267     if(!a_wb.write(m_date_M)) return false;
00268     if(!a_wb.write(m_nbytes_keys)) return false;
00269     if(!a_wb.write(m_nbytes_name)) return false;
00270 
00271     if(!a_wb.write(m_seek_directory)) return false;
00272     if(!a_wb.write(m_seek_parent)) return false;
00273     if(!a_wb.write(m_seek_keys)) return false;
00274 
00275     if(m_file.verbose()) {
00276       m_file.out() << "inlib::wroot::key::to_buffer :"
00277           << " nbytes keys : " << m_nbytes_keys 
00278           << ", pos keys : " << m_seek_keys 
00279           << std::endl;
00280     }
00281     return true;
00282   }
00283 
00284   bool write(uint32& a_nbytes){
00285     // Write all objects in memory to disk.
00286     // Loop on all objects in memory (including subdirectories).
00287     // A new key is created in the m_keys linked list for each object.
00288     // For allowed options see TObject::Write().
00289     // The directory header info is rewritten on the directory header record
00290     a_nbytes = 0;
00291     if(m_file.verbose()) {
00292       m_file.out() << "inlib::wroot::directory::write :"
00293                    << " " << sout(m_name)
00294                    << " : " << long2s(m_dirs.size())
00295                    << " : " << long2s(m_objs.size())
00296                    << " objects."
00297                    << std::endl;
00298     }
00299 
00300     uint32 nbytes = 0;
00301 
00302    {std::vector<directory*>::iterator it;
00303     for(it=m_dirs.begin();it!=m_dirs.end();++it) {
00304       uint32 n;
00305       if(!(*it)->write(n)) return false;
00306       nbytes += n;
00307     }}
00308 
00309    {std::vector<iobject*>::iterator it;
00310     for(it=m_objs.begin();it!=m_objs.end();++it) {
00311       uint32 n;
00312       if(!write_object(*(*it),n)) {
00313         m_file.out() << "inlib::wroot::directory::write :"
00314                      << " for directory " << sout(m_name)
00315                      << ", write_object " << sout((*it)->name())
00316                      << " failed."
00317                      << std::endl;
00318         return false;
00319       }
00320       nbytes += n;
00321     }}
00322 
00323     if(!save_self()) {
00324       m_file.out() << "inlib::wroot::directory::write :"
00325                    << " for directory " << sout(m_name)
00326                    << ", save_self failed."
00327                    << std::endl;
00328       return false; //it will write keys of objects.
00329     }
00330   
00331     a_nbytes = nbytes;
00332     return true;
00333   }
00334 protected:
00335   void clear_keys() {
00336     std::list<key*>::iterator it;
00337     for(it=m_keys.begin();it!=m_keys.end();) {
00338       key* k = *it;
00339       it = m_keys.erase(it);
00340       delete k;
00341     }
00342     m_keys.clear();
00343   }
00344 
00345   bool save(){
00346     if(!save_self()) return false;
00347    {std::vector<directory*>::iterator it;
00348     for(it=m_dirs.begin();it!=m_dirs.end();++it) {
00349       if(!(*it)->save()) return false;
00350     }}
00351     return true;
00352   }
00353 
00354   bool save_self() {
00355     // Save Directory keys and header :
00356     //  If the directory has been modified (fModified set), write the keys
00357     //  and the directory header.
00358     //if (fModified || aForce) {
00359     //  if(!fFile.freeSegments().empty()) {
00360     //    if(!writeKeys()) return false; // Write keys record.
00361     //    if(!writeHeader()) return false; // Update directory record.
00362     //  }
00363     //}
00364     if(!write_keys()) return false;
00365     if(!write_header()) return false;
00366     return true;
00367   }
00368 
00369   //const std::list<key*>& keys() const {return m_keys;}
00370   //std::list<key*>& keys() {return m_keys;}
00371 
00372   key* find_key(const std::string& a_name) {
00373     if(m_file.verbose()) {
00374       m_file.out() << "inlib::wroot::directory::find_key :" 
00375                    << " " << sout(a_name) << " ..."
00376                    << std::endl;
00377     }
00378     std::list<key*>::const_iterator it;
00379     for(it=m_keys.begin();it!=m_keys.end();++it) {
00380       if((*it)->object_name()==a_name) return *it;
00381     }
00382 
00383     return 0;
00384   }
00385   seek seek_keys() const {return m_seek_keys;}
00386 
00387   void clear_dirs() {clear<directory>(m_dirs);}
00388   void clear_objs() {clear<iobject>(m_objs);}
00389 
00390   uint16 append_key(key* a_key){ //take ownership of a_key
00391     std::list<key*>::iterator itk;
00392     for(itk=m_keys.begin();itk!=m_keys.end();++itk) {
00393       if((*itk)->object_name()==a_key->object_name()) {
00394         m_keys.insert(itk,a_key); //a_key will be before *itk.
00395         return ((*itk)->cycle() + 1);
00396       }
00397     }
00398     // Not found :
00399     m_keys.push_back(a_key);
00400     return 1;
00401   }
00402 
00403   bool write_keys(){
00404     // The list of keys (m_keys) is written as a single data record
00405     // Delete the old keys structure if it exists
00406 
00407     //if(fSeekKeys) {
00408     //  if(!fFile.makeFreeSegment
00409     //     (fSeekKeys, fSeekKeys + fNbytesKeys -1)) return false;
00410     //}
00411 
00412     // Write new keys record :
00413     uint32 nkeys  = m_keys.size();
00414 
00415     // Compute size of all keys
00416     uint32 nbytes = sizeof(nkeys);
00417 
00418    {std::list<key*>::iterator it;
00419     for(it=m_keys.begin();it!=m_keys.end();++it) {
00420       nbytes += (*it)->key_length();
00421     }}
00422 
00423     key headerkey(m_file,m_seek_directory,
00424                   m_name,m_title,"TDirectory",nbytes);
00425     if(!headerkey.seek_key()) return false;
00426 
00427    {char* buffer = headerkey.data_buffer();
00428     wbuf wb(m_file.out(),m_file.byte_swap(),headerkey.eob(),buffer);
00429     if(!wb.write(nkeys)) return false;
00430    {std::list<key*>::iterator it;
00431     for(it=m_keys.begin();it!=m_keys.end();++it) {
00432       if(!((*it)->to_buffer(wb))) return false;
00433     }}}
00434   
00435     m_seek_keys = headerkey.seek_key();
00436     m_nbytes_keys = headerkey.number_of_bytes();
00437 
00438     if(m_file.verbose()) {
00439       m_file.out() << "inlib::wroot::directory::write_keys :" 
00440                    << " write header key"
00441                    << " " << sout(m_name)
00442                    << " " << sout(m_title)
00443                    << " (" << nkeys
00444                    << ", " << nbytes
00445                    << ", " << m_seek_keys
00446                    << ", " << m_nbytes_keys
00447                    << "):"
00448                    << std::endl;
00449     }
00450 
00451     headerkey.set_cycle(1);
00452     if(!headerkey.write_self()) {
00453       m_file.out() << "inlib::wroot::directory::write_keys :" 
00454                    << " key.write_self() failed."
00455                    << std::endl;
00456       return false;
00457     }  
00458 
00459     uint32 n;
00460     return headerkey.write_file(n);
00461   }
00462 
00463   bool write_header(){
00464     // Overwrite the Directory header record.
00465     uint32 nbytes = record_size();
00466     char* header = new char[nbytes];
00467     char* buffer = header;
00468     m_date_M = get_date();
00469     wbuf wb(m_file.out(),m_file.byte_swap(),header+nbytes,buffer);
00470     if(!to_buffer(wb)) {
00471       delete [] header;
00472       return false;
00473     }
00474     // do not overwrite the name/title part
00475     seek pointer = m_seek_directory + m_nbytes_name; 
00476     //fModified = false;
00477     if(!m_file.set_pos(pointer)) {
00478       delete [] header;
00479       return false;
00480     }
00481     if(!m_file.write_buffer(header,nbytes)) {
00482       delete [] header;
00483       return false;
00484     }
00485     if(!m_file.synchronize()) {
00486       delete [] header;
00487       return false;
00488     }
00489     delete [] header;
00490     return true;
00491   }
00492 
00493   bool write_object(iobject& a_obj,uint32& a_nbytes){
00494     buffer bref(m_file.out(),m_file.byte_swap(),256*128); //32768
00495     if(!a_obj.stream(bref)) {
00496       m_file.out() << "inlib::wroot::directory::write_object :" 
00497                    << " cannot stream object of store class name "
00498                    << " " << sout(a_obj.store_class_name()) << "." 
00499                    << std::endl;
00500       a_nbytes = 0;
00501       return false;
00502     }
00503 
00504     std::string name = a_obj.name();
00505     strip(name);
00506 
00507     //first create the key to get key_length();
00508 
00509     wroot::key* key = new wroot::key(m_file,m_seek_directory,
00510                                      name,
00511                                      a_obj.title(),a_obj.store_class_name(),
00512                                      bref.length()); //set m_END
00513 
00514     if(!key->seek_key()) {
00515       delete key;
00516       return false;
00517     }
00518 
00519     if(!bref.displace_mapped(key->key_length())) { //done before compression.
00520       delete key;
00521       return false;
00522     }
00523 
00524     char* kbuf = 0;
00525     uint32 klen = 0;
00526     bool kdelete = false;
00527     m_file.compress_buffer(bref,kbuf,klen,kdelete);
00528 
00529     ::memcpy(key->data_buffer(),kbuf,klen);
00530     if(kdelete) delete [] kbuf;
00531 
00532    {uint32 nkey = key->key_length()+klen;
00533     m_file.set_END(key->seek_key()+nkey);
00534     key->set_number_of_bytes(nkey);}
00535 
00536     uint16 cycle = append_key(key);
00537     key->set_cycle(cycle);
00538     
00539     if(!key->write_self()) {
00540       m_file.out() << "inlib::wroot::directory::write_object :" 
00541                    << " key.write_self() failed."
00542                    << std::endl;
00543       return false;
00544     }  
00545 
00546     //FIXME m_file.sumBuffer(key->object_size()); //uncompressed data size.
00547   
00548     if(m_file.verbose()) {
00549       m_file.out() << "inlib::wroot::directory::_write_buffer :" 
00550                    << " " << sout(a_obj.name()) << "."
00551                    << std::endl;
00552     }
00553     
00554     return key->write_file(a_nbytes);
00555   }
00556 
00557 protected:
00558   static std::string sout(const std::string& a_string) {
00559     return std::string("\"")+a_string+"\"";
00560   }
00561 protected:
00562   ifile& m_file;
00563   directory* m_parent;
00564   bool m_is_valid;
00565   std::string m_name;
00566   std::string m_title;
00567   std::vector<directory*> m_dirs;
00568   std::vector<iobject*> m_objs;
00569   std::list<key*> m_keys;
00570   // Record (stored in file):
00571   date m_date_C;           //Date and time when directory is created
00572   date m_date_M;           //Date and time of last modification
00573   uint32 m_nbytes_keys;    //Number of bytes for the keys
00574   uint32 m_nbytes_name;    //Number of bytes in TNamed at creation time
00575   seek m_seek_directory;   //Location of directory on file
00576   seek m_seek_parent;      //Location of parent directory on file
00577   seek m_seek_keys;        //Location of Keys record on file
00578 };
00579 
00580 }}
00581 
00582 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines