Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_wroot_directory 5 #define tools_wroot_directory 6 7 #include "idir" 8 9 #include "date" 10 #include "key" 11 #include "ifile" 12 #include "date" 13 #include "buffer" 14 #include "iobject" 15 16 #include "../strip" 17 #include "../vmanip" 18 #include "../forit" 19 20 #include <vector> 21 #include <list> 22 23 namespace tools { 24 namespace wroot { 25 26 class directory : public virtual idir { 27 static uint32 class_version() {return 1;} 28 public: 29 static const std::string& s_class() { 30 static const std::string s_v("tools::wroot::directory"); 31 return s_v; 32 } 33 public: //idir 34 virtual ifile& file() {return m_file;} 35 virtual seek seek_directory() const {return m_seek_directory;} 36 virtual void append_object(iobject* a_object) {m_objs.push_back(a_object);} //take ownership of a_object 37 public: 38 directory(ifile& a_file) 39 :m_file(a_file) 40 ,m_parent(0) 41 ,m_is_valid(false) 42 ,m_date_C(0) 43 ,m_date_M(0) 44 ,m_nbytes_keys(0) 45 ,m_nbytes_name(0) 46 ,m_seek_directory(0) 47 ,m_seek_parent(0) 48 ,m_seek_keys(0) 49 { 50 #ifdef TOOLS_MEM 51 mem::increment(s_class().c_str()); 52 #endif 53 } 54 directory(ifile& a_file,const std::string& a_name,const std::string& a_title) 55 :m_file(a_file) 56 ,m_parent(0) 57 ,m_is_valid(false) 58 ,m_name(a_name) 59 ,m_title(a_title) 60 ,m_nbytes_keys(0) 61 ,m_nbytes_name(0) 62 ,m_seek_directory(0) 63 ,m_seek_parent(0) 64 ,m_seek_keys(0) 65 { 66 #ifdef TOOLS_MEM 67 mem::increment(s_class().c_str()); 68 #endif 69 m_date_C = get_date(); 70 m_date_M = get_date(); 71 72 if(m_name.empty()) { 73 m_file.out() << "tools::wroot::directory::directory :" 74 << " directory name cannot be \"\"." 75 << std::endl; 76 return; //FIXME : throw 77 } 78 if(m_name.find('/')!=std::string::npos) { 79 m_file.out() << "tools::wroot::directory::directory :" 80 << " directory name " << sout(m_name) 81 << " cannot contain a slash." 82 << std::endl; 83 return; //FIXME : throw 84 } 85 if(m_title.empty()) m_title = m_name; 86 m_is_valid = true; 87 } 88 directory(ifile& a_file, 89 directory* a_parent, //assume a_parent not nul. 90 const std::string& a_name, 91 const std::string& a_title) 92 :m_file(a_file) 93 ,m_parent(a_parent) 94 ,m_is_valid(false) 95 ,m_name(a_name) 96 ,m_title(a_title) 97 ,m_nbytes_keys(0) 98 ,m_nbytes_name(0) 99 ,m_seek_directory(0) 100 ,m_seek_parent(0) 101 ,m_seek_keys(0) 102 { 103 #ifdef TOOLS_MEM 104 mem::increment(s_class().c_str()); 105 #endif 106 m_date_C = get_date(); 107 m_date_M = get_date(); 108 109 if(m_name.empty()) { 110 m_file.out() << "tools::wroot::directory::directory :" 111 << " directory name cannot be \"\"." 112 << std::endl; 113 return; //FIXME : throw 114 } 115 if(m_name.find('/')!=std::string::npos) { 116 m_file.out() << "tools::wroot::directory::directory :" 117 << " directory name " << sout(m_name) 118 << " cannot contain a slash." 119 << std::endl; 120 return; //FIXME : throw 121 } 122 123 if(m_title.empty()) m_title = m_name; 124 125 if(m_parent->find_key(m_name)) { 126 m_file.out() << "tools::wroot::directory::directory :" 127 << " directory " << sout(m_name) << " exists already." 128 << std::endl; 129 return; //FIXME : throw 130 } 131 132 m_seek_parent = m_parent->seek_directory(); 133 uint32 nbytes = record_size(); 134 135 wroot::key* key = new wroot::key(m_file.out(),m_file,m_parent->seek_directory(), 136 m_name,m_title,"TDirectory",nbytes); // It does a m_file.set_END(). 137 m_nbytes_name = key->key_length(); 138 m_seek_directory = key->seek_key(); //at EOF 139 if(!m_seek_directory) { 140 m_file.out() << "tools::wroot::directory::directory :" 141 << " bad key." 142 << std::endl; 143 delete key; 144 return; //FIXME : throw 145 } 146 {char* buffer = key->data_buffer(); 147 wbuf wb(m_file.out(),m_file.byte_swap(),key->eob(),buffer); 148 if(!to_buffer(wb)) { 149 m_file.out() << "tools::wroot::directory::directory :" 150 << " directory name " << sout(m_name) 151 << " cannot fill buffer." 152 << std::endl; 153 delete key; 154 return; //FIXME : throw 155 }} 156 uint16 cycle = m_parent->append_key(key); 157 key->set_cycle(cycle); 158 if(!key->write_self(m_file)) { 159 m_file.out() << "tools::wroot::directory::directory :" 160 << " key.write_self() failed." 161 << std::endl; 162 return; //FIXME : throw 163 } 164 uint32 n; 165 if(!key->write_file(m_file,n)) { 166 m_file.out() << "tools::wroot::directory::directory :" 167 << " directory name " << sout(m_name) 168 << " cannot write key to file." 169 << std::endl; 170 return; //FIXME : throw 171 } 172 173 m_is_valid = true; 174 } 175 virtual ~directory(){ 176 clear_dirs(); 177 clear_objs(); 178 clear_keys(); 179 #ifdef TOOLS_MEM 180 mem::decrement(s_class().c_str()); 181 #endif 182 } 183 protected: 184 directory(const directory& a_from) 185 :idir(a_from) 186 ,m_file(a_from.m_file) 187 ,m_parent(0) 188 ,m_is_valid(false){ 189 #ifdef TOOLS_MEM 190 mem::increment(s_class().c_str()); 191 #endif 192 } 193 directory& operator=(const directory &){ 194 m_is_valid = false; 195 return *this; 196 } 197 public: 198 bool is_valid() const {return m_is_valid;} 199 void set_seek_directory(seek a_seek) {m_seek_directory = a_seek;} 200 201 directory* mkdir(const std::string& a_name,const std::string& a_title = ""){ 202 // Create a sub-directory and return a pointer to the created directory. 203 // Note that the directory name cannot contain slashes. 204 if(a_name.empty()) { 205 m_file.out() << "tools::wroot::directory::mkdir :" 206 << " directory name cannot be \"\"." 207 << std::endl; 208 return 0; 209 } 210 if(a_name.find('/')!=std::string::npos) { 211 m_file.out() << "tools::wroot::directory::mkdir :" 212 << " " << sout(a_name) 213 << " cannot contain a slash." 214 << std::endl; 215 return 0; 216 } 217 directory* dir = new directory(m_file,this,a_name,a_title.empty()?a_name:a_title); 218 if(!dir->is_valid()) { 219 m_file.out() << "tools::wroot::directory::mkdir :" 220 << " directory badly created." 221 << std::endl; 222 delete dir; 223 return 0; 224 } 225 m_dirs.push_back(dir); 226 return dir; 227 } 228 229 //uint32 nbytes_name() const {return m_nbytes_name;} 230 void set_nbytes_name(uint32 a_n) {m_nbytes_name = a_n;} 231 232 uint32 record_size() const { 233 uint32 nbytes = sizeof(short); 234 nbytes += sizeof(date); //m_date_C.record_size(); 235 nbytes += sizeof(date); //m_date_M.record_size(); 236 nbytes += sizeof(m_nbytes_keys); 237 nbytes += sizeof(m_nbytes_name); 238 //ROOT version >= 40000: 239 nbytes += sizeof(seek); 240 nbytes += sizeof(seek); 241 nbytes += sizeof(seek); 242 return nbytes; 243 } 244 245 bool close() { 246 if(!save()) return false; 247 clear_dirs(); 248 clear_objs(); 249 clear_keys(); 250 return true; 251 } 252 253 bool to_buffer(wbuf& a_wb){ 254 // Decode input buffer. 255 // (Name, title) are stored in the (name, title) of the associated key. 256 short version = class_version(); 257 version += big_file_version_tag(); //GB : enforce writing on seek (and not seek32). 258 if(!a_wb.write(version)) return false; 259 if(!a_wb.write(m_date_C)) return false; 260 if(!a_wb.write(m_date_M)) return false; 261 if(!a_wb.write(m_nbytes_keys)) return false; 262 if(!a_wb.write(m_nbytes_name)) return false; 263 264 if(!a_wb.write(m_seek_directory)) return false; 265 if(!a_wb.write(m_seek_parent)) return false; 266 if(!a_wb.write(m_seek_keys)) return false; 267 268 if(m_file.verbose()) { 269 m_file.out() << "tools::wroot::key::to_buffer :" 270 << " nbytes keys : " << m_nbytes_keys 271 << ", pos keys : " << m_seek_keys 272 << std::endl; 273 } 274 return true; 275 } 276 277 bool write(uint32& a_nbytes){ 278 // Write all objects in memory to disk. 279 // Loop on all objects in memory (including subdirectories). 280 // A new key is created in the m_keys linked list for each object. 281 // For allowed options see TObject::Write(). 282 // The directory header info is rewritten on the directory header record 283 a_nbytes = 0; 284 if(m_file.verbose()) { 285 m_file.out() << "tools::wroot::directory::write :" 286 << " " << sout(m_name) 287 << " : " << m_dirs.size() 288 << " : " << m_objs.size() 289 << " objects." 290 << std::endl; 291 } 292 293 uint32 nbytes = 0; 294 295 {tools_vforcit(directory*,m_dirs,it) { 296 uint32 n; 297 if(!(*it)->write(n)) return false; 298 nbytes += n; 299 }} 300 301 {tools_vforit(iobject*,m_objs,it) { 302 uint32 n; 303 if(!write_object(*(*it),n)) { 304 m_file.out() << "tools::wroot::directory::write :" 305 << " for directory " << sout(m_name) 306 << ", write_object " << sout((*it)->name()) 307 << " failed." 308 << std::endl; 309 return false; 310 } 311 nbytes += n; 312 }} 313 314 if(!save_self()) { 315 m_file.out() << "tools::wroot::directory::write :" 316 << " for directory " << sout(m_name) 317 << ", save_self failed." 318 << std::endl; 319 return false; //it will write keys of objects. 320 } 321 322 a_nbytes = nbytes; 323 return true; 324 } 325 326 void clear_dirs() {safe_clear<directory>(m_dirs);} 327 void clear_objs() {safe_clear<iobject>(m_objs);} 328 329 const std::list<key*>& keys() const {return m_keys;} 330 //std::list<key*>& keys() {return m_keys;} 331 332 protected: 333 void clear_keys() { 334 std::list<key*>::iterator it; 335 for(it=m_keys.begin();it!=m_keys.end();) { 336 key* k = *it; 337 it = m_keys.erase(it); 338 delete k; 339 } 340 m_keys.clear(); 341 } 342 343 bool save(){ 344 if(!save_self()) return false; 345 tools_vforit(directory*,m_dirs,it) { 346 if(!(*it)->save()) return false; 347 } 348 return true; 349 } 350 351 bool save_self() { 352 // Save Directory keys and header : 353 // If the directory has been modified (fModified set), write the keys 354 // and the directory header. 355 //if (fModified || aForce) { 356 // if(!fFile.freeSegments().empty()) { 357 // if(!writeKeys()) return false; // Write keys record. 358 // if(!writeHeader()) return false; // Update directory record. 359 // } 360 //} 361 if(!write_keys()) return false; 362 if(!write_header()) return false; 363 return true; 364 } 365 366 key* find_key(const std::string& a_name) { 367 if(m_file.verbose()) { 368 m_file.out() << "tools::wroot::directory::find_key :" 369 << " " << sout(a_name) << " ..." 370 << std::endl; 371 } 372 tools_lforcit(key*,m_keys,it) { 373 if((*it)->object_name()==a_name) return *it; 374 } 375 376 return 0; 377 } 378 seek seek_keys() const {return m_seek_keys;} 379 380 uint16 append_key(key* a_key){ //take ownership of a_key 381 tools_lforit(key*,m_keys,it) { 382 if((*it)->object_name()==a_key->object_name()) { 383 m_keys.insert(it,a_key); //a_key will be before *it. 384 return ((*it)->cycle() + 1); 385 } 386 } 387 // Not found : 388 m_keys.push_back(a_key); 389 return 1; 390 } 391 392 bool write_keys(){ 393 // The list of keys (m_keys) is written as a single data record 394 // Delete the old keys structure if it exists 395 396 //if(fSeekKeys) { 397 // if(!fFile.makeFreeSegment 398 // (fSeekKeys, fSeekKeys + fNbytesKeys -1)) return false; 399 //} 400 401 // Write new keys record : 402 uint32 nkeys = uint32(m_keys.size()); 403 404 // Compute size of all keys 405 uint32 nbytes = sizeof(nkeys); 406 407 {tools_lforit(key*,m_keys,it) { 408 nbytes += (*it)->key_length(); 409 }} 410 411 key headerkey(m_file.out(),m_file,m_seek_directory,m_name,m_title,"TDirectory",nbytes); // m_file.set_END(). 412 if(!headerkey.seek_key()) return false; 413 414 {char* buffer = headerkey.data_buffer(); 415 wbuf wb(m_file.out(),m_file.byte_swap(),headerkey.eob(),buffer); 416 if(!wb.write(nkeys)) return false; 417 {tools_lforit(key*,m_keys,it) { 418 if(!((*it)->to_buffer(wb,m_file.verbose()))) return false; 419 }}} 420 421 m_seek_keys = headerkey.seek_key(); 422 m_nbytes_keys = headerkey.number_of_bytes(); 423 424 if(m_file.verbose()) { 425 m_file.out() << "tools::wroot::directory::write_keys :" 426 << " write header key" 427 << " " << sout(m_name) 428 << " " << sout(m_title) 429 << " (" << nkeys 430 << ", " << nbytes 431 << ", " << m_seek_keys 432 << ", " << m_nbytes_keys 433 << "):" 434 << std::endl; 435 } 436 437 headerkey.set_cycle(1); 438 if(!headerkey.write_self(m_file)) { 439 m_file.out() << "tools::wroot::directory::write_keys :" 440 << " key.write_self() failed." 441 << std::endl; 442 return false; 443 } 444 445 uint32 n; 446 return headerkey.write_file(m_file,n); 447 } 448 449 bool write_header(){ 450 // Overwrite the Directory header record. 451 uint32 nbytes = record_size(); 452 char* header = new char[nbytes]; 453 char* buffer = header; 454 m_date_M = get_date(); 455 wbuf wb(m_file.out(),m_file.byte_swap(),header+nbytes,buffer); 456 if(!to_buffer(wb)) { 457 delete [] header; 458 return false; 459 } 460 // do not overwrite the name/title part 461 seek pointer = m_seek_directory + m_nbytes_name; 462 //fModified = false; 463 if(!m_file.set_pos(pointer)) { 464 delete [] header; 465 return false; 466 } 467 if(!m_file.write_buffer(header,nbytes)) { 468 delete [] header; 469 return false; 470 } 471 if(!m_file.synchronize()) { 472 delete [] header; 473 return false; 474 } 475 delete [] header; 476 return true; 477 } 478 479 bool write_object(iobject& a_obj,uint32& a_nbytes){ 480 buffer bref(m_file.out(),m_file.byte_swap(),256*128); //32768 481 if(!a_obj.stream(bref)) { 482 m_file.out() << "tools::wroot::directory::write_object :" 483 << " cannot stream object of store class name " 484 << " " << sout(a_obj.store_class_name()) << "." 485 << std::endl; 486 a_nbytes = 0; 487 return false; 488 } 489 490 std::string name = a_obj.name(); 491 strip(name); 492 493 //first create the key to get key_length(); 494 495 wroot::key* key = new wroot::key(m_file.out(),m_file,m_seek_directory, 496 name, 497 a_obj.title(),a_obj.store_class_name(), 498 bref.length()); // It does a m_file.set_END(). 499 500 if(!key->seek_key()) { 501 delete key; 502 return false; 503 } 504 505 if(!bref.displace_mapped(key->key_length())) { //done before compression. 506 delete key; 507 return false; 508 } 509 510 char* kbuf = 0; 511 uint32 klen = 0; 512 bool kdelete = false; 513 m_file.compress_buffer(bref,kbuf,klen,kdelete); 514 515 ::memcpy(key->data_buffer(),kbuf,klen); 516 if(kdelete) delete [] kbuf; 517 518 {uint32 nkey = key->key_length()+klen; 519 m_file.set_END(key->seek_key()+nkey); 520 key->set_number_of_bytes(nkey);} 521 522 uint16 cycle = append_key(key); 523 key->set_cycle(cycle); 524 525 if(!key->write_self(m_file)) { 526 m_file.out() << "tools::wroot::directory::write_object :" 527 << " key.write_self() failed." 528 << std::endl; 529 return false; 530 } 531 532 //FIXME m_file.sumBuffer(key->object_size()); //uncompressed data size. 533 534 if(m_file.verbose()) { 535 m_file.out() << "tools::wroot::directory::_write_buffer :" 536 << " " << sout(a_obj.name()) << "." 537 << std::endl; 538 } 539 540 return key->write_file(m_file,a_nbytes); 541 } 542 543 protected: 544 ifile& m_file; 545 directory* m_parent; 546 bool m_is_valid; 547 std::string m_name; 548 std::string m_title; 549 std::vector<directory*> m_dirs; 550 std::vector<iobject*> m_objs; 551 std::list<key*> m_keys; 552 // Record (stored in file): 553 date m_date_C; //Date and time when directory is created 554 date m_date_M; //Date and time of last modification 555 uint32 m_nbytes_keys; //Number of bytes for the keys 556 uint32 m_nbytes_name; //Number of bytes in TNamed at creation time 557 seek m_seek_directory; //Location of directory on file 558 seek m_seek_parent; //Location of parent directory on file 559 seek m_seek_keys; //Location of Keys record on file 560 }; 561 562 }} 563 564 #endif