inlib
1.2.0
|
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