Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_rroot_buffer 5 #define tools_rroot_buffer 6 7 #include "rbuf" 8 #include "ifac" 9 #include "iro" 10 #include "../sout" 11 #include "../mapmanip" 12 #ifdef TOOLS_MEM 13 #include "../mem" 14 #endif 15 16 #include <string> 17 #include <vector> 18 #include <ostream> 19 #include <utility> 20 21 // in TOOLS_STL, we don't have (yet) a performant map. 22 23 #ifdef tools_stl_vector 24 #define TOOLS_RROOT_OBJ_MAP_HASH_TABLE 25 //#define TOOLS_RROOT_OBJ_MAP_OMAP 26 #else 27 #define TOOLS_RROOT_OBJ_MAP_STD_MAP 28 #endif 29 30 #ifdef TOOLS_RROOT_OBJ_MAP_STD_MAP 31 #include <map> 32 #endif 33 #ifdef TOOLS_RROOT_OBJ_MAP_OMAP 34 #include "../omap" 35 #endif 36 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 37 #include "../hash_table" 38 #include "../hash" 39 #endif 40 41 namespace tools { 42 namespace rroot { 43 44 class buffer : public rbuf { 45 typedef rbuf parent; 46 47 static const std::string& s_class() { 48 static const std::string s_v("tools::rroot::buffer"); 49 return s_v; 50 } 51 52 #ifdef TOOLS_RROOT_OBJ_MAP_STD_MAP 53 typedef std::map<uint32,iro*> obj_map; 54 #endif 55 #ifdef TOOLS_RROOT_OBJ_MAP_OMAP 56 typedef omap<uint32,iro*> obj_map; 57 #endif 58 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 59 class obj_map : public hash_table<uint32,iro*> { 60 typedef hash_table<uint32,iro*> parent; 61 protected: 62 virtual unsigned int hash(const uint32& a_key) { 63 return hash(&a_key,sizeof(uint32)); 64 } 65 virtual bool cmp(const uint32& a_key1,const uint32& a_key2) { 66 return a_key1==a_key2?true:false; 67 } 68 public: 69 obj_map():parent(){} 70 virtual ~obj_map(){} 71 private: 72 obj_map(const obj_map& a_from):parent(a_from){} 73 obj_map& operator=(const obj_map& a_from){ 74 parent::operator=(a_from); 75 return *this; 76 } 77 }; 78 #endif 79 80 public: 81 buffer(std::ostream& a_out,bool a_byte_swap,uint32 a_size,char* a_buffer,uint32 a_klen,bool a_verbose) 82 :parent(a_out,a_byte_swap,a_buffer+a_size,m_pos) 83 ,m_byte_swap(a_byte_swap) 84 ,m_verbose(a_verbose) 85 //,m_verbose(true) 86 ,m_size(a_size) //expect a not zero size. 87 ,m_buffer(a_buffer) //don't get ownership. 88 ,m_pos(a_buffer) 89 ,m_klen(a_klen) //to compute refs (used in read_class, read_object) 90 //,m_map_objs(false) 91 ,m_map_objs(true) 92 { 93 #ifdef TOOLS_MEM 94 mem::increment(s_class().c_str()); 95 #endif 96 } 97 virtual ~buffer(){ 98 m_objs.clear(); 99 #ifdef TOOLS_MEM 100 mem::decrement(s_class().c_str()); 101 #endif 102 } 103 protected: 104 buffer(const buffer& a_from) 105 :parent(a_from.m_out,a_from.m_byte_swap,0,m_pos) 106 ,m_byte_swap(a_from.m_byte_swap) 107 ,m_map_objs(a_from.m_map_objs) 108 { 109 #ifdef TOOLS_MEM 110 mem::increment(s_class().c_str()); 111 #endif 112 } 113 buffer& operator=(const buffer&){return *this;} 114 public: 115 bool byte_swap() const {return m_byte_swap;} 116 bool verbose() const {return m_verbose;} 117 118 void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;} 119 120 //char* buffer() const {return m_buffer;} 121 uint32 length() const {return uint32(m_pos-m_buffer);} 122 uint32 size() const {return m_size;} 123 124 void set_map_objs(bool a_value) {m_map_objs = a_value;} 125 bool map_objs() const {return m_map_objs;} 126 protected: 127 // on first_int : 128 static uint32 kNullTag() {return 0;} 129 static uint32 kByteCountMask() {return 0x40000000;} 130 // on tag : 131 static uint32 kNewClassTag() {return 0xFFFFFFFF;} 132 static uint32 kClassMask() {return 0x80000000; } 133 static uint32 kMapOffset() {return 2;} 134 static short kByteCountVMask() {return 0x4000;} 135 136 bool read_class_tag(std::string& a_class) { 137 a_class.clear(); 138 139 uint32 tag; 140 if(!parent::read(tag)) return false; 141 142 if(tag==kNewClassTag()) { 143 char _s[80]; 144 if(!read_string(_s, 80)) { 145 m_out << "tools::rroot::read_class_tag :" 146 << " read string." << std::endl; 147 return false; 148 } 149 //m_out << "tools::rroot::read_class_tag :" 150 // << " tag kNewClassTag" 151 // << " class " << _s 152 // << std::endl; 153 a_class = _s; 154 return true; 155 156 } else if(tag & kClassMask()) { 157 //m_out << "tools::rroot::read_class_tag :" 158 // << " tag & kClassMask" 159 // << " ref " << (uint32)(tag & ~kClassMask) 160 // << " recurse..." 161 // << std::endl; 162 163 unsigned int cl_offset = (tag & ~kClassMask()); 164 cl_offset -= kMapOffset(); 165 cl_offset -= m_klen; 166 char* old_pos = m_pos; 167 m_pos = m_buffer + cl_offset; 168 //std::string scls; 169 //uint32 ref; 170 if(!read_class_tag(a_class)) return false; 171 m_pos = old_pos; 172 173 return true; 174 175 } else { 176 177 std::ios::fmtflags old_flags = m_out.flags(); 178 m_out << "tools::rroot::read_class_tag :" 179 << " tag unknown case ! " 180 << tag << " hex " << std::hex << tag 181 << std::endl; 182 m_out.flags(old_flags); 183 184 return false; 185 } 186 } 187 188 bool read_class(std::string& a_class,uint32& a_bcnt,bool& a_is_ref){ 189 //m_verbose = true; 190 a_class.clear(); 191 a_bcnt = 0; 192 a_is_ref = false; 193 194 //uint32 fVersion = 0; //Buffer format version 195 196 // read byte count and/or tag (older files don't have byte count) 197 uint32 first_int = 0; 198 if(!parent::read(first_int)) return false; 199 200 if(m_verbose) { 201 std::ios::fmtflags old_flags = m_out.flags(); 202 m_out << "tools::rroot::read_class :" 203 << " first_int " << std::hex << first_int 204 << std::endl; 205 m_out.flags(old_flags); 206 } 207 208 if(first_int==kNullTag()) { //GB 209 if(m_verbose) { 210 m_out << "tools::rroot::read_class :" 211 << " first_int is kNullTag." 212 << std::endl; 213 } 214 a_bcnt = 0; 215 return true; 216 217 //} else if(first_int==kNewClassTag()) { // class desc follows. 218 } else if(first_int & kByteCountMask()) { 219 // at write : 220 // skip int to store bcnt. 221 // + write class 222 // if(!write((clIdx | Rio_kClassMask))) return false; 223 // or 224 // if(!write(Rio_kNewClassTag)) return false; 225 // + write object 226 // + set byte cnt (cnt|kByteCountMask()) at skipped int. 227 228 if(m_verbose) { 229 m_out << "tools::rroot::read_class :" 230 << " first_int & kByteCountMask." 231 << std::endl; 232 } 233 234 uint32 bef_tag = uint32(m_pos-m_buffer); 235 //fVersion = 1; 236 237 std::string scls; 238 if(!read_class_tag(scls)) return false; 239 if(scls.empty()) { 240 m_out << "tools::rroot::buffer::read_class :" 241 << " read_class_tag did not find a class name." 242 << std::endl; 243 return false; 244 } 245 246 a_class = std::move(scls); 247 a_bcnt = (first_int & ~kByteCountMask()); 248 249 if(m_verbose) { 250 m_out << "tools::rroot::read_class :" 251 << " kNewClassTag : read class name " << sout(a_class) 252 << " a_bcnt " << a_bcnt 253 << " bef_tag " << bef_tag 254 << "." << std::endl; 255 } 256 257 return true; 258 259 } else { 260 if(m_verbose) { 261 std::ios::fmtflags old_flags = m_out.flags(); 262 m_out << "tools::rroot::read_class :" 263 << " first_int " << std::hex << first_int 264 << ". first_int is position toward object." 265 << std::endl; 266 m_out.flags(old_flags); 267 } 268 a_bcnt = first_int; //pos toward object. 269 a_is_ref = true; 270 a_class.clear(); 271 return true; 272 } 273 274 return false; 275 } 276 public: 277 void remove_in_map(iro* a_obj) { 278 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 279 m_out << "tools::rroot::remove_in_map : dummy." << std::endl; 280 #else 281 find_and_remove_value(m_objs,a_obj); 282 #endif 283 } 284 bool read_object(ifac& a_fac,const ifac::args& a_args,iro*& a_obj,bool& a_created){ 285 a_obj = 0; 286 a_created = false; 287 288 //m_out << "debug : tools::rroot::buffer::read_object : begin :" << std::endl; 289 290 // before reading object save start position 291 uint32 startpos = (uint32)(m_pos-m_buffer); 292 293 uint32 bcnt; 294 std::string sclass; 295 bool is_ref; 296 if(!read_class(sclass,bcnt,is_ref)) { 297 m_out << "tools::rroot::buffer::read_object :" 298 << " can't read class." << std::endl; 299 return false; 300 } 301 //::printf("debug : %d\n",length()-startpos); 302 303 if(m_verbose) { 304 m_out << "tools::rroot::buffer::read_object :" 305 << " class " << sout(sclass) << ", is_ref " << is_ref 306 << ", bcnt " << bcnt 307 << std::endl; 308 } 309 310 if(is_ref) { //bcnt is the position toward an object or an object ref. 311 //m_out << "debug : tools::rroot::buffer::read_object : is_ref : bcnt " << bcnt << std::endl; 312 313 unsigned int obj_offset = bcnt; 314 obj_offset -= kMapOffset(); 315 obj_offset -= m_klen; 316 317 if(!m_map_objs) { 318 m_out << "tools::rroot::buffer::read_object : warning :" 319 << " class " << sout(sclass) << ", is_ref but map objs is not enabled on this buffer." 320 << std::endl; 321 } 322 323 if(m_map_objs) { 324 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 325 if(m_objs.find(obj_offset,a_obj)) { 326 //m_out << "debug : tools::rroot::buffer::read_object : found object in map." << bcnt << std::endl; 327 return true; 328 } 329 #else 330 obj_map::const_iterator it = m_objs.find(obj_offset); 331 if(it!=m_objs.end()) { 332 a_obj = (*it).second; 333 //::printf("debug : find : %d %lu\n",obj_offset,a_obj); 334 //stay at current m_pos ? 335 return true; 336 } 337 #endif 338 } 339 340 {char* old_pos = m_pos; 341 342 m_pos = m_buffer + obj_offset; 343 344 uint32 first_int; 345 if(!parent::read(first_int)) { 346 m_out << "tools::rroot::buffer::read_object : parent::read(first_int) failed." << std::endl; 347 return false; 348 } 349 if(first_int & kByteCountMask()) { 350 std::string scls; 351 if(!read_class_tag(scls)) { 352 m_out << "tools::rroot::buffer::read_object : read_class_tag() failed." << std::endl; 353 return false; 354 } 355 if(scls.empty()) { 356 m_out << "tools::rroot::buffer::read_object :" 357 << " read_class_tag did not find a class name." 358 << std::endl; 359 return false; 360 } 361 362 //m_out << "tools::rroot::buffer::read_object :" 363 // << " is_ref : class " << sout(scls) 364 // << std::endl; 365 366 iro* obj = a_fac.create(scls,a_args); 367 if(!obj) { 368 m_out << "tools::rroot::buffer::read_object : is_ref : creation of object" 369 << " of class " << sout(sclass) << " failed." << std::endl; 370 return false; 371 } 372 373 if(m_map_objs) { 374 //must be done before stream() 375 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 376 if(!m_objs.insert(obj_offset,obj)) { 377 m_out << "tools::rroot::buffer::read_object :" 378 << " map insert failed." 379 << std::endl; 380 } 381 #else 382 m_objs[obj_offset] = obj; 383 #endif 384 } 385 386 if(!obj->stream(*this)) { 387 m_out << "tools::rroot::buffer::read_object :" 388 << " is_ref : streamed failed for class " << sout(scls) 389 << std::endl; 390 //restore a good buffer position : 391 //m_pos = m_buffer+startpos+sizeof(unsigned int); 392 delete obj; 393 return false; 394 } 395 396 //m_out << "tools::rroot::buffer::read_object :" 397 // << " is_ref : streamed ok for class " << sout(scls) 398 // << std::endl; 399 400 a_obj = obj; 401 a_created = true; 402 403 } else { 404 m_out << "tools::rroot::buffer::read_object :" 405 << " is_ref : zzz" 406 << std::endl; 407 } 408 409 m_pos = old_pos;} 410 411 // in principle at this point m_pos should be 412 // m_buffer+startpos+sizeof(unsigned int) 413 // but enforce it anyway : 414 m_pos = m_buffer+startpos+sizeof(unsigned int); 415 //check_byte_count(startpos,0,sclass) would always be ok. 416 417 //a_obj = ??? 418 419 } else { 420 if(sclass.empty()) { 421 //m_out << "debug : tools::rroot::buffer::read_object : found empty class name." << std::endl; 422 423 m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 424 425 } else { 426 //m_out << "debug : tools::rroot::buffer::read_object : not a ref, create object." << std::endl; 427 428 // Being not a ref, it must NOT be in the map. 429 // We gain a lot by not doing the below find. 430 /* 431 if(m_map_objs) { 432 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 433 if(m_objs.find(startpos,a_obj)) return true; 434 #else 435 obj_map::const_iterator it = m_objs.find(startpos); 436 if(it!=m_objs.end()) { 437 a_obj = (*it).second; 438 ::printf("debug : find xxx : %d %lu\n",startpos,a_obj); 439 //stay at current m_pos ? 440 return true; 441 } 442 #endif 443 } 444 */ 445 446 iro* obj = a_fac.create(sclass,a_args); 447 if(!obj) { 448 m_out << "tools::rroot::buffer::read_object : creation of object" 449 << " of class " << sout(sclass) << " failed." << std::endl; 450 return false; 451 } 452 //m_out << "debug : tools::rroot::buffer::read_object : object created." << std::endl; 453 454 if(m_map_objs) { 455 //must be done before stream() 456 #ifdef TOOLS_RROOT_OBJ_MAP_HASH_TABLE 457 if(!m_objs.insert(startpos,obj)) { 458 m_out << "tools::rroot::buffer::read_object :" 459 << " map insert failed." 460 << std::endl; 461 } 462 #else 463 m_objs[startpos] = obj; 464 #endif 465 } 466 467 //::printf("debug : map : %d %lu\n",startpos,obj); 468 469 //NOTE : if class ref, "up there"-startpos = 8. 470 if(!obj->stream(*this)) { 471 m_out << "tools::rroot::buffer::read_object : object.stream() failed" 472 << " for object of class " << sout(sclass) << "." << std::endl; 473 //restore a good buffer position : 474 //m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 475 delete obj; 476 return false; 477 } 478 479 //NOTE : if obj stream ok, the below line is not needed. 480 //m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 481 482 if(!check_byte_count(startpos,bcnt,sclass)) { 483 m_out << "tools::rroot::buffer::read_object :" 484 << " check_byte_count failed " 485 << "for object of class " 486 << sout(sclass) << "." << std::endl; 487 delete obj; 488 return false; 489 } 490 491 a_obj = obj; 492 a_created = true; 493 } 494 495 } 496 497 if(m_verbose) { 498 m_out << "tools::rroot::buffer::read_object : end." << std::endl; 499 } 500 501 return true; 502 } 503 public: 504 bool read_version(short& a_version){ 505 // Read class version from I/O buffer. 506 // Is read a short or three shorts. 507 a_version = 0; 508 short version = 0; 509 // not interested in byte count 510 if(!parent::read(version)) return false; 511 512 // if this is a byte count, then skip next short and read version 513 if(version & kByteCountVMask()) { 514 if(!parent::read(version)) return false; 515 if(!parent::read(version)) return false; 516 } 517 518 a_version = version; 519 return true; 520 } 521 522 bool read_version(short& a_version,uint32& a_start_pos,uint32& a_byte_count){ 523 // Read class version from I/O buffer. 524 // Is read one or three shorts. 525 a_version = 0; 526 a_start_pos = 0; 527 a_byte_count = 0; 528 529 short version = 0; 530 531 // before reading object save start position 532 uint32 startpos = (uint32)(m_pos-m_buffer); 533 534 // read byte count (older files don't have byte count) 535 // byte count is packed in two individual shorts, this to be 536 // backward compatible with old files that have at this location 537 // only a single short (i.e. the version) 538 union { 539 unsigned int cnt; 540 short vers[2]; 541 } v; 542 543 if(m_byte_swap) { 544 if(!parent::read(v.vers[1])) return false; 545 if(!parent::read(v.vers[0])) return false; 546 } else { 547 if(!parent::read(v.vers[0])) return false; 548 if(!parent::read(v.vers[1])) return false; 549 } 550 551 // no bytecount, backup and read version 552 uint32 bcnt = 0; 553 if(v.cnt & kByteCountMask()) { 554 bcnt = (v.cnt & ~kByteCountMask()); 555 } else { 556 m_pos -= sizeof(unsigned int); 557 } 558 if(!parent::read(version)) return false; 559 //printf("Reading version=%d at pos=%d, bytecount=%d\n", 560 //version,*startpos,*bcnt); 561 562 a_version = version; 563 a_start_pos = startpos; 564 a_byte_count = bcnt; 565 566 return true; 567 } 568 569 bool check_byte_count(uint32 a_start_pos,uint32 a_byte_count,const std::string& a_store_cls){ 570 if(!a_byte_count) return true; 571 572 size_t len = a_start_pos + a_byte_count + sizeof(unsigned int); 573 574 size_t diff = size_t(m_pos-m_buffer); 575 576 if(diff==len) return true; 577 578 if(diff<len) { 579 m_out << "tools::rroot::buffer::check_byte_count :" 580 << " object of class " << sout(a_store_cls) 581 << " read too few bytes (" 582 << long_out(long(len-diff)) << " missing)." 583 << std::endl; 584 } 585 if(diff>len) { 586 m_out << "tools::rroot::buffer::check_byte_count :" 587 << " object of class " << sout(a_store_cls) 588 << " read too many bytes (" 589 << long_out(long(diff-len)) << " in excess)." << std::endl; 590 } 591 592 m_out << "tools::rroot::buffer::check_byte_count :" 593 << " " << sout(a_store_cls) 594 << " streamer not in sync with data on file, fix streamer." 595 << std::endl; 596 597 m_pos = m_buffer+len; 598 599 return false; 600 } 601 protected: 602 bool read_string(char* a_string,uint32 a_max) { 603 // Read string from I/O buffer. String is read till 0 character is 604 // found or till max-1 characters are read (i.e. string s has max 605 // bytes allocated). 606 int nr = 0; 607 while (nr < int(a_max-1)) { 608 char ch; 609 if(!parent::read(ch)) return false; 610 // stop when 0 read 611 if(ch == 0) break; 612 a_string[nr++] = ch; 613 } 614 a_string[nr] = 0; 615 return true; 616 } 617 protected: 618 // buffer objects cannot be copied or assigned 619 //void checkCount(unsigned int); 620 //unsigned int checkObject(unsigned int,const IClass*,bool = false); 621 protected: 622 bool m_byte_swap; 623 bool m_verbose; 624 uint32 m_size; 625 char* m_buffer; 626 char* m_pos; 627 uint32 m_klen; //GB 628 bool m_map_objs; 629 obj_map m_objs; 630 }; 631 632 inline bool dummy_TXxx_pointer_stream(buffer& a_buffer,ifac& a_fac) { 633 ifac::args args; 634 iro* obj; 635 bool created; 636 bool status = a_buffer.read_object(a_fac,args,obj,created); 637 if(obj) { 638 if(created) { 639 if(a_buffer.map_objs()) a_buffer.remove_in_map(obj); 640 delete obj; 641 } 642 } 643 return status; 644 } 645 646 template <class T> 647 inline bool pointer_stream(buffer& a_buffer, 648 ifac& a_fac,ifac::args& a_args, 649 const std::string& a_T_class, 650 T*& a_obj,bool& a_created){ 651 iro* obj; 652 if(!a_buffer.read_object(a_fac,a_args,obj,a_created)) { 653 a_buffer.out() << "tools::rroot::pointer_stream : read_object failed." << std::endl; 654 a_obj = 0; 655 a_created = false; 656 return false; 657 } 658 if(!obj) { 659 a_obj = 0; 660 a_created = false; 661 } else { 662 a_obj = (T*)obj->cast(a_T_class); 663 if(!a_obj) { 664 a_buffer.out() << "tools::rroot::pointer_stream : " 665 << " tools::cast to " << a_T_class << " failed." 666 << ". Object is a " << obj->s_cls() << "." 667 << std::endl; 668 if(a_created) delete obj; 669 a_created = false; 670 return false; 671 } 672 } 673 return true; 674 } 675 676 template <class T> 677 inline bool pointer_stream(buffer& a_buffer, 678 ifac& a_fac,ifac::args& a_args, 679 cid a_T_class, 680 T*& a_obj,bool& a_created){ 681 iro* obj; 682 if(!a_buffer.read_object(a_fac,a_args,obj,a_created)) { 683 a_buffer.out() << "tools::rroot::pointer_stream : read_object failed." << std::endl; 684 a_obj = 0; 685 a_created = false; 686 return false; 687 } 688 if(!obj) { 689 a_obj = 0; 690 a_created = false; 691 } else { 692 a_obj = (T*)obj->cast(a_T_class); 693 if(!a_obj) { 694 a_buffer.out() << "tools::rroot::pointer_stream : " 695 << " tools::cast to " << a_T_class << " failed." 696 << ". Object is a " << obj->s_cls() << "." 697 << std::endl; 698 if(a_created) delete obj; 699 a_created = false; 700 return false; 701 } 702 } 703 return true; 704 } 705 706 template <class T> 707 inline bool pointer_stream(buffer& a_buffer,ifac& a_fac,ifac::args& a_args,T*& a_obj,bool& a_created){ 708 //return pointer_stream(a_buffer,a_fac,a_args,T::s_class(),a_obj,a_created); 709 return pointer_stream(a_buffer,a_fac,a_args,T::id_class(),a_obj,a_created); 710 } 711 712 template <class T> 713 inline bool fixed_array_stream(buffer& a_buffer,int a_n,T*& a_v){ 714 delete [] a_v; 715 a_v = 0; 716 char is_array; 717 if(!a_buffer.read(is_array)) return false; 718 if(!is_array) return true; 719 if(!a_n) return true; 720 a_v = new T[a_n]; 721 if(!a_buffer.read_fast_array<T>(a_v,a_n)) { 722 delete [] a_v; 723 a_v = 0; 724 return false; 725 } 726 return true; 727 } 728 729 }} 730 731 #endif