Warning, /include/Geant4/tools/rroot/buffer is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_rroot_buffer
0005 #define tools_rroot_buffer
0006
0007 #include "rbuf"
0008 #include "ifac"
0009 #include "iro"
0010 #include "../sout"
0011 #include "../mapmanip"
0012
0013 #include <string>
0014 #include <vector>
0015 #include <ostream>
0016 #include <utility>
0017 #include <map>
0018
0019 namespace tools {
0020 namespace rroot {
0021
0022 class buffer : public rbuf {
0023 typedef rbuf parent;
0024
0025 static const std::string& s_class() {
0026 static const std::string s_v("tools::rroot::buffer");
0027 return s_v;
0028 }
0029
0030 typedef std::map<uint32,iro*> obj_map;
0031
0032 public:
0033 buffer(std::ostream& a_out,bool a_byte_swap,uint32 a_size,char* a_buffer,uint32 a_klen,bool a_verbose)
0034 :parent(a_out,a_byte_swap,a_buffer+a_size,m_pos)
0035 ,m_byte_swap(a_byte_swap)
0036 ,m_verbose(a_verbose)
0037 ,m_size(a_size) //expect a not zero size.
0038 ,m_buffer(a_buffer) //don't get ownership.
0039 ,m_pos(a_buffer)
0040 ,m_klen(a_klen) //to compute refs (used in read_class, read_object)
0041 ,m_map_objs(true)
0042 {
0043 }
0044 virtual ~buffer(){
0045 m_objs.clear();
0046 }
0047 protected:
0048 buffer(const buffer& a_from)
0049 :parent(a_from.m_out,a_from.m_byte_swap,0,m_pos)
0050 ,m_byte_swap(a_from.m_byte_swap)
0051 ,m_map_objs(a_from.m_map_objs)
0052 {
0053 }
0054 buffer& operator=(const buffer&){return *this;}
0055 public:
0056 bool byte_swap() const {return m_byte_swap;}
0057 bool verbose() const {return m_verbose;}
0058
0059 void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;}
0060
0061 uint32 length() const {return uint32(m_pos-m_buffer);}
0062 uint32 size() const {return m_size;}
0063
0064 void set_map_objs(bool a_value) {m_map_objs = a_value;}
0065 bool map_objs() const {return m_map_objs;}
0066 protected:
0067 // on first_int :
0068 static uint32 kNullTag() {return 0;}
0069 static uint32 kByteCountMask() {return 0x40000000;}
0070 // on tag :
0071 static uint32 kNewClassTag() {return 0xFFFFFFFF;}
0072 static uint32 kClassMask() {return 0x80000000; }
0073 static uint32 kMapOffset() {return 2;}
0074 static short kByteCountVMask() {return 0x4000;}
0075
0076 bool read_class_tag(std::string& a_class) {
0077 a_class.clear();
0078
0079 uint32 tag;
0080 if(!parent::read(tag)) return false;
0081
0082 if(tag==kNewClassTag()) {
0083 char _s[80];
0084 if(!read_string(_s, 80)) {
0085 m_out << "tools::rroot::read_class_tag :"
0086 << " read string." << std::endl;
0087 return false;
0088 }
0089 a_class = _s;
0090 return true;
0091
0092 } else if(tag & kClassMask()) {
0093 unsigned int cl_offset = (tag & ~kClassMask());
0094 cl_offset -= kMapOffset();
0095 cl_offset -= m_klen;
0096 char* old_pos = m_pos;
0097 m_pos = m_buffer + cl_offset;
0098 if(!read_class_tag(a_class)) return false;
0099 m_pos = old_pos;
0100
0101 return true;
0102
0103 } else {
0104
0105 std::ios::fmtflags old_flags = m_out.flags();
0106 m_out << "tools::rroot::read_class_tag :"
0107 << " tag unknown case ! "
0108 << tag << " hex " << std::hex << tag
0109 << std::endl;
0110 m_out.flags(old_flags);
0111
0112 return false;
0113 }
0114 }
0115
0116 bool read_class(std::string& a_class,uint32& a_bcnt,bool& a_is_ref){
0117 a_class.clear();
0118 a_bcnt = 0;
0119 a_is_ref = false;
0120
0121 // read byte count and/or tag (older files don't have byte count)
0122 uint32 first_int = 0;
0123 if(!parent::read(first_int)) return false;
0124
0125 if(m_verbose) {
0126 std::ios::fmtflags old_flags = m_out.flags();
0127 m_out << "tools::rroot::read_class :"
0128 << " first_int " << std::hex << first_int
0129 << std::endl;
0130 m_out.flags(old_flags);
0131 }
0132
0133 if(first_int==kNullTag()) { //GB
0134 if(m_verbose) {
0135 m_out << "tools::rroot::read_class :"
0136 << " first_int is kNullTag."
0137 << std::endl;
0138 }
0139 a_bcnt = 0;
0140 return true;
0141
0142 } else if(first_int & kByteCountMask()) {
0143 // at write :
0144 // skip int to store bcnt.
0145 // + write class
0146 // if(!write((clIdx | Rio_kClassMask))) return false;
0147 // or
0148 // if(!write(Rio_kNewClassTag)) return false;
0149 // + write object
0150 // + set byte cnt (cnt|kByteCountMask()) at skipped int.
0151
0152 if(m_verbose) {
0153 m_out << "tools::rroot::read_class :"
0154 << " first_int & kByteCountMask."
0155 << std::endl;
0156 }
0157
0158 uint32 bef_tag = uint32(m_pos-m_buffer);
0159 //fVersion = 1;
0160
0161 std::string scls;
0162 if(!read_class_tag(scls)) return false;
0163 if(scls.empty()) {
0164 m_out << "tools::rroot::buffer::read_class :"
0165 << " read_class_tag did not find a class name."
0166 << std::endl;
0167 return false;
0168 }
0169
0170 a_class = std::move(scls);
0171 a_bcnt = (first_int & ~kByteCountMask());
0172
0173 if(m_verbose) {
0174 m_out << "tools::rroot::read_class :"
0175 << " kNewClassTag : read class name " << sout(a_class)
0176 << " a_bcnt " << a_bcnt
0177 << " bef_tag " << bef_tag
0178 << "." << std::endl;
0179 }
0180
0181 return true;
0182
0183 } else {
0184 if(m_verbose) {
0185 std::ios::fmtflags old_flags = m_out.flags();
0186 m_out << "tools::rroot::read_class :"
0187 << " first_int " << std::hex << first_int
0188 << ". first_int is position toward object."
0189 << std::endl;
0190 m_out.flags(old_flags);
0191 }
0192 a_bcnt = first_int; //pos toward object.
0193 a_is_ref = true;
0194 a_class.clear();
0195 return true;
0196 }
0197
0198 return false;
0199 }
0200 public:
0201 void remove_in_map(iro* a_obj) {
0202 find_and_remove_value(m_objs,a_obj);
0203 }
0204 bool read_object(ifac& a_fac,const ifac::args& a_args,iro*& a_obj,bool& a_created){
0205 a_obj = 0;
0206 a_created = false;
0207
0208 // before reading object save start position
0209 uint32 startpos = (uint32)(m_pos-m_buffer);
0210
0211 uint32 bcnt;
0212 std::string sclass;
0213 bool is_ref;
0214 if(!read_class(sclass,bcnt,is_ref)) {
0215 m_out << "tools::rroot::buffer::read_object :"
0216 << " can't read class." << std::endl;
0217 return false;
0218 }
0219
0220 if(m_verbose) {
0221 m_out << "tools::rroot::buffer::read_object :"
0222 << " class " << sout(sclass) << ", is_ref " << is_ref
0223 << ", bcnt " << bcnt
0224 << std::endl;
0225 }
0226
0227 if(is_ref) { //bcnt is the position toward an object or an object ref.
0228 unsigned int obj_offset = bcnt;
0229 obj_offset -= kMapOffset();
0230 obj_offset -= m_klen;
0231
0232 if(!m_map_objs) {
0233 m_out << "tools::rroot::buffer::read_object : warning :"
0234 << " class " << sout(sclass) << ", is_ref but map objs is not enabled on this buffer."
0235 << std::endl;
0236 }
0237
0238 if(m_map_objs) {
0239 obj_map::const_iterator it = m_objs.find(obj_offset);
0240 if(it!=m_objs.end()) {
0241 a_obj = (*it).second;
0242 return true;
0243 }
0244 }
0245
0246 {char* old_pos = m_pos;
0247
0248 m_pos = m_buffer + obj_offset;
0249
0250 uint32 first_int;
0251 if(!parent::read(first_int)) {
0252 m_out << "tools::rroot::buffer::read_object : parent::read(first_int) failed." << std::endl;
0253 return false;
0254 }
0255 if(first_int & kByteCountMask()) {
0256 std::string scls;
0257 if(!read_class_tag(scls)) {
0258 m_out << "tools::rroot::buffer::read_object : read_class_tag() failed." << std::endl;
0259 return false;
0260 }
0261 if(scls.empty()) {
0262 m_out << "tools::rroot::buffer::read_object :"
0263 << " read_class_tag did not find a class name."
0264 << std::endl;
0265 return false;
0266 }
0267
0268 iro* obj = a_fac.create(scls,a_args);
0269 if(!obj) {
0270 m_out << "tools::rroot::buffer::read_object : is_ref : creation of object"
0271 << " of class " << sout(sclass) << " failed." << std::endl;
0272 return false;
0273 }
0274
0275 if(m_map_objs) {
0276 //must be done before stream()
0277 m_objs[obj_offset] = obj;
0278 }
0279
0280 if(!obj->stream(*this)) {
0281 m_out << "tools::rroot::buffer::read_object :"
0282 << " is_ref : streamed failed for class " << sout(scls)
0283 << std::endl;
0284 //restore a good buffer position :
0285 //m_pos = m_buffer+startpos+sizeof(unsigned int);
0286 delete obj;
0287 return false;
0288 }
0289
0290 a_obj = obj;
0291 a_created = true;
0292
0293 } else {
0294 m_out << "tools::rroot::buffer::read_object :"
0295 << " is_ref : zzz"
0296 << std::endl;
0297 }
0298
0299 m_pos = old_pos;}
0300
0301 // in principle at this point m_pos should be
0302 // m_buffer+startpos+sizeof(unsigned int)
0303 // but enforce it anyway :
0304 m_pos = m_buffer+startpos+sizeof(unsigned int);
0305 //check_byte_count(startpos,0,sclass) would always be ok.
0306
0307 } else {
0308 if(sclass.empty()) {
0309
0310 m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int);
0311
0312 } else {
0313 iro* obj = a_fac.create(sclass,a_args);
0314 if(!obj) {
0315 m_out << "tools::rroot::buffer::read_object : creation of object"
0316 << " of class " << sout(sclass) << " failed." << std::endl;
0317 return false;
0318 }
0319
0320 if(m_map_objs) {
0321 //must be done before stream()
0322 m_objs[startpos] = obj;
0323 }
0324
0325 //NOTE : if class ref, "up there"-startpos = 8.
0326 if(!obj->stream(*this)) {
0327 m_out << "tools::rroot::buffer::read_object : object.stream() failed"
0328 << " for object of class " << sout(sclass) << "." << std::endl;
0329 //restore a good buffer position :
0330 //m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int);
0331 delete obj;
0332 return false;
0333 }
0334
0335 //NOTE : if obj stream ok, the below line is not needed.
0336 //m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int);
0337
0338 if(!check_byte_count(startpos,bcnt,sclass)) {
0339 m_out << "tools::rroot::buffer::read_object :"
0340 << " check_byte_count failed "
0341 << "for object of class "
0342 << sout(sclass) << "." << std::endl;
0343 delete obj;
0344 return false;
0345 }
0346
0347 a_obj = obj;
0348 a_created = true;
0349 }
0350
0351 }
0352
0353 if(m_verbose) {
0354 m_out << "tools::rroot::buffer::read_object : end." << std::endl;
0355 }
0356
0357 return true;
0358 }
0359 public:
0360 bool read_version(short& a_version){
0361 // Read class version from I/O buffer.
0362 // Is read a short or three shorts.
0363 a_version = 0;
0364 short version = 0;
0365 // not interested in byte count
0366 if(!parent::read(version)) return false;
0367
0368 // if this is a byte count, then skip next short and read version
0369 if(version & kByteCountVMask()) {
0370 if(!parent::read(version)) return false;
0371 if(!parent::read(version)) return false;
0372 }
0373
0374 a_version = version;
0375 return true;
0376 }
0377
0378 bool read_version(short& a_version,uint32& a_start_pos,uint32& a_byte_count){
0379 // Read class version from I/O buffer.
0380 // Is read one or three shorts.
0381 a_version = 0;
0382 a_start_pos = 0;
0383 a_byte_count = 0;
0384
0385 short version = 0;
0386
0387 // before reading object save start position
0388 uint32 startpos = (uint32)(m_pos-m_buffer);
0389
0390 // read byte count (older files don't have byte count)
0391 // byte count is packed in two individual shorts, this to be
0392 // backward compatible with old files that have at this location
0393 // only a single short (i.e. the version)
0394 union {
0395 unsigned int cnt;
0396 short vers[2];
0397 } v;
0398
0399 if(m_byte_swap) {
0400 if(!parent::read(v.vers[1])) return false;
0401 if(!parent::read(v.vers[0])) return false;
0402 } else {
0403 if(!parent::read(v.vers[0])) return false;
0404 if(!parent::read(v.vers[1])) return false;
0405 }
0406
0407 // no bytecount, backup and read version
0408 uint32 bcnt = 0;
0409 if(v.cnt & kByteCountMask()) {
0410 bcnt = (v.cnt & ~kByteCountMask());
0411 } else {
0412 m_pos -= sizeof(unsigned int);
0413 }
0414 if(!parent::read(version)) return false;
0415
0416 a_version = version;
0417 a_start_pos = startpos;
0418 a_byte_count = bcnt;
0419
0420 return true;
0421 }
0422
0423 bool check_byte_count(uint32 a_start_pos,uint32 a_byte_count,const std::string& a_store_cls){
0424 if(!a_byte_count) return true;
0425
0426 size_t len = a_start_pos + a_byte_count + sizeof(unsigned int);
0427
0428 size_t diff = size_t(m_pos-m_buffer);
0429
0430 if(diff==len) return true;
0431
0432 if(diff<len) {
0433 m_out << "tools::rroot::buffer::check_byte_count :"
0434 << " object of class " << sout(a_store_cls)
0435 << " read too few bytes ("
0436 << long_out(long(len-diff)) << " missing)."
0437 << std::endl;
0438 }
0439 if(diff>len) {
0440 m_out << "tools::rroot::buffer::check_byte_count :"
0441 << " object of class " << sout(a_store_cls)
0442 << " read too many bytes ("
0443 << long_out(long(diff-len)) << " in excess)." << std::endl;
0444 }
0445
0446 m_out << "tools::rroot::buffer::check_byte_count :"
0447 << " " << sout(a_store_cls)
0448 << " streamer not in sync with data on file, fix streamer."
0449 << std::endl;
0450
0451 m_pos = m_buffer+len;
0452
0453 return false;
0454 }
0455 protected:
0456 bool read_string(char* a_string,uint32 a_max) {
0457 // Read string from I/O buffer. String is read till 0 character is
0458 // found or till max-1 characters are read (i.e. string s has max
0459 // bytes allocated).
0460 int nr = 0;
0461 while (nr < int(a_max-1)) {
0462 char ch;
0463 if(!parent::read(ch)) return false;
0464 // stop when 0 read
0465 if(ch == 0) break;
0466 a_string[nr++] = ch;
0467 }
0468 a_string[nr] = 0;
0469 return true;
0470 }
0471 protected:
0472 bool m_byte_swap;
0473 bool m_verbose;
0474 uint32 m_size;
0475 char* m_buffer;
0476 char* m_pos;
0477 uint32 m_klen; //GB
0478 bool m_map_objs;
0479 obj_map m_objs;
0480 };
0481
0482 inline bool dummy_TXxx_pointer_stream(buffer& a_buffer,ifac& a_fac) {
0483 ifac::args args;
0484 iro* obj;
0485 bool created;
0486 bool status = a_buffer.read_object(a_fac,args,obj,created);
0487 if(obj) {
0488 if(created) {
0489 if(a_buffer.map_objs()) a_buffer.remove_in_map(obj);
0490 delete obj;
0491 }
0492 }
0493 return status;
0494 }
0495
0496 template <class T>
0497 inline bool pointer_stream(buffer& a_buffer,
0498 ifac& a_fac,ifac::args& a_args,
0499 const std::string& a_T_class,
0500 T*& a_obj,bool& a_created){
0501 iro* obj;
0502 if(!a_buffer.read_object(a_fac,a_args,obj,a_created)) {
0503 a_buffer.out() << "tools::rroot::pointer_stream : read_object failed." << std::endl;
0504 a_obj = 0;
0505 a_created = false;
0506 return false;
0507 }
0508 if(!obj) {
0509 a_obj = 0;
0510 a_created = false;
0511 } else {
0512 a_obj = (T*)obj->cast(a_T_class);
0513 if(!a_obj) {
0514 a_buffer.out() << "tools::rroot::pointer_stream : "
0515 << " tools::cast to " << a_T_class << " failed."
0516 << ". Object is a " << obj->s_cls() << "."
0517 << std::endl;
0518 if(a_created) delete obj;
0519 a_created = false;
0520 return false;
0521 }
0522 }
0523 return true;
0524 }
0525
0526 template <class T>
0527 inline bool pointer_stream(buffer& a_buffer,
0528 ifac& a_fac,ifac::args& a_args,
0529 cid a_T_class,
0530 T*& a_obj,bool& a_created){
0531 iro* obj;
0532 if(!a_buffer.read_object(a_fac,a_args,obj,a_created)) {
0533 a_buffer.out() << "tools::rroot::pointer_stream : read_object failed." << std::endl;
0534 a_obj = 0;
0535 a_created = false;
0536 return false;
0537 }
0538 if(!obj) {
0539 a_obj = 0;
0540 a_created = false;
0541 } else {
0542 a_obj = (T*)obj->cast(a_T_class);
0543 if(!a_obj) {
0544 a_buffer.out() << "tools::rroot::pointer_stream : "
0545 << " tools::cast to " << a_T_class << " failed."
0546 << ". Object is a " << obj->s_cls() << "."
0547 << std::endl;
0548 if(a_created) delete obj;
0549 a_created = false;
0550 return false;
0551 }
0552 }
0553 return true;
0554 }
0555
0556 template <class T>
0557 inline bool pointer_stream(buffer& a_buffer,ifac& a_fac,ifac::args& a_args,T*& a_obj,bool& a_created){
0558 //return pointer_stream(a_buffer,a_fac,a_args,T::s_class(),a_obj,a_created);
0559 return pointer_stream(a_buffer,a_fac,a_args,T::id_class(),a_obj,a_created);
0560 }
0561
0562 template <class T>
0563 inline bool fixed_array_stream(buffer& a_buffer,int a_n,T*& a_v){
0564 delete [] a_v;
0565 a_v = 0;
0566 char is_array;
0567 if(!a_buffer.read(is_array)) return false;
0568 if(!is_array) return true;
0569 if(!a_n) return true;
0570 a_v = new T[a_n];
0571 if(!a_buffer.read_fast_array<T>(a_v,a_n)) {
0572 delete [] a_v;
0573 a_v = 0;
0574 return false;
0575 }
0576 return true;
0577 }
0578
0579 }}
0580
0581 #endif