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_rroot_buffer 00005 #define inlib_rroot_buffer 00006 00007 #include "rbuf" 00008 #include "ifac" 00009 #include "iro" 00010 #include "../tos" 00011 #ifdef INLIB_MEM 00012 #include "../mem" 00013 #endif 00014 00015 #include <string> 00016 #include <vector> 00017 #include <ostream> 00018 00019 namespace inlib { 00020 namespace rroot { 00021 00022 class buffer : public rbuf { 00023 static const std::string& s_class() { 00024 static const std::string s_v("inlib::rroot::buffer"); 00025 return s_v; 00026 } 00027 public: 00028 buffer(std::ostream& a_out,bool a_byte_swap, 00029 uint32 a_size,char* a_buffer,uint32 a_klen,bool a_verbose) 00030 : rbuf(a_out,a_byte_swap,a_buffer+a_size,m_pos) 00031 ,m_byte_swap(a_byte_swap) 00032 ,m_verbose(a_verbose) 00033 ,m_size(a_size) //expect a not zero size. 00034 ,m_buffer(a_buffer) //don't get ownership. 00035 ,m_pos(a_buffer) 00036 ,m_klen(a_klen) //to compute refs (used in read_class, read_object) 00037 { 00038 #ifdef INLIB_MEM 00039 mem::increment(s_class().c_str()); 00040 #endif 00041 } 00042 virtual ~buffer(){ 00043 #ifdef INLIB_MEM 00044 mem::decrement(s_class().c_str()); 00045 #endif 00046 } 00047 protected: 00048 buffer(const buffer& a_from) 00049 : rbuf(a_from.m_out,a_from.m_byte_swap,0,m_pos) 00050 ,m_byte_swap(a_from.m_byte_swap) 00051 { 00052 #ifdef INLIB_MEM 00053 mem::increment(s_class().c_str()); 00054 #endif 00055 } 00056 buffer& operator=(const buffer&){return *this;} 00057 public: 00058 void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;} 00059 00060 //char* buffer() const {return m_buffer;} 00061 uint32 length() const {return m_pos-m_buffer;} 00062 uint32 size() const {return m_size;} 00063 00064 protected: 00065 // on first_int : 00066 static uint32 kNullTag() {return 0;} 00067 static uint32 kByteCountMask() {return 0x40000000;} 00068 // on tag : 00069 static uint32 kNewClassTag() {return 0xFFFFFFFF;} 00070 static uint32 kClassMask() {return 0x80000000; } 00071 static uint32 kMapOffset() {return 2;} 00072 static short kByteCountVMask() {return 0x4000;} 00073 00074 bool read_class_tag(std::string& a_class) { 00075 a_class.clear(); 00076 00077 uint32 tag; 00078 if(!rbuf::read(tag)) return false; 00079 //m_out << "tag " << tag << " " << tosx(tag) << std::endl; 00080 00081 if(tag==kNewClassTag()) { 00082 char s[80]; 00083 if(!read_string(s, 80)) { 00084 m_out << "inlib::rroot::read_class_tag :" 00085 << " read string." << std::endl; 00086 return false; 00087 } 00088 //m_out << "inlib::rroot::read_class_tag :" 00089 // << " tag kNewClassTag" 00090 // << " class " << s 00091 // << std::endl; 00092 a_class = s; 00093 return true; 00094 00095 } else if(tag & kClassMask()) { 00096 //m_out << "inlib::rroot::read_class_tag :" 00097 // << " tag & kClassMask" 00098 // << " ref " << (uint32)(tag & ~kClassMask) 00099 // << " recurse..." 00100 // << std::endl; 00101 00102 unsigned int cl_offset = (tag & ~kClassMask()); 00103 cl_offset -= kMapOffset(); 00104 cl_offset -= m_klen; 00105 char* old_pos = m_pos; 00106 m_pos = m_buffer + cl_offset; 00107 //std::string scls; 00108 //uint32 ref; 00109 if(!read_class_tag(a_class)) return false; 00110 m_pos = old_pos; 00111 00112 return true; 00113 00114 } else { 00115 m_out << "inlib::rroot::read_class_tag :" 00116 << " tag unknown case ! " << tosx(tag) 00117 << std::endl; 00118 return false; 00119 } 00120 } 00121 00122 bool read_class(std::string& a_class,uint32& a_bcnt,bool& a_is_ref){ 00123 //m_verbose = true; 00124 a_class.clear(); 00125 a_bcnt = 0; 00126 a_is_ref = false; 00127 00128 uint32 fVersion = 0; //Buffer format version 00129 00130 // read byte count and/or tag (older files don't have byte count) 00131 uint32 first_int = 0; 00132 if(!rbuf::read(first_int)) return false; 00133 00134 if(m_verbose) { 00135 m_out << "inlib::rroot::read_class :" 00136 << " first_int " << tosx(first_int) 00137 << std::endl; 00138 } 00139 00140 if(first_int==kNullTag()) { //GB 00141 if(m_verbose) { 00142 m_out << "inlib::rroot::read_class :" 00143 << " first_int is kNullTag." 00144 << std::endl; 00145 } 00146 a_bcnt = 0; 00147 return true; 00148 00149 //} else if(first_int==kNewClassTag()) { // class desc follows. 00150 } else if(first_int & kByteCountMask()) { 00151 // at write : 00152 // skip int to store bcnt. 00153 // + write class 00154 // if(!write((clIdx | Rio_kClassMask))) return false; 00155 // or 00156 // if(!write(Rio_kNewClassTag)) return false; 00157 // + write object 00158 // + set byte cnt (cnt|kByteCountMask()) at skipped int. 00159 00160 if(m_verbose) { 00161 m_out << "inlib::rroot::read_class :" 00162 << " first_int & kByteCountMask." 00163 << std::endl; 00164 } 00165 00166 uint32 bef_tag = m_pos-m_buffer; 00167 fVersion = 1; 00168 00169 std::string scls; 00170 if(!read_class_tag(scls)) return false; 00171 if(scls.empty()) { 00172 m_out << "inlib::rroot::buffer::read_class :" 00173 << " read_class_tag did not find a class name." 00174 << std::endl; 00175 return false; 00176 } 00177 00178 a_class = scls; 00179 a_bcnt = (first_int & ~kByteCountMask()); 00180 00181 if(m_verbose) { 00182 m_out << "inlib::rroot::read_class :" 00183 << " kNewClassTag : read class name " << sout(a_class) 00184 << " a_bcnt " << a_bcnt 00185 << " bef_tag " << bef_tag 00186 << "." << std::endl; 00187 } 00188 00189 return true; 00190 00191 } else { 00192 if(m_verbose) { 00193 m_out << "inlib::rroot::read_class :" 00194 << " first_int " << tosx(first_int) 00195 << ". first_int is position toward object." 00196 << std::endl; 00197 } 00198 a_bcnt = first_int; //pos toward object. 00199 a_is_ref = true; 00200 a_class.clear(); 00201 return true; 00202 } 00203 00204 return false; 00205 } 00206 public: 00207 bool read_object(ifac& a_fac,const ifac::args& a_args,iro*& a_obj){ 00208 a_obj = 0; 00209 00210 // before reading object save start position 00211 uint32 startpos = (uint32)(m_pos-m_buffer); 00212 00213 uint32 bcnt; 00214 std::string sclass; 00215 bool is_ref; 00216 if(!read_class(sclass,bcnt,is_ref)) { 00217 m_out << "inlib::rroot::buffer::read_object :" 00218 << " can't read class." << std::endl; 00219 return false; 00220 } 00221 //::printf("debug : %d\n",length()-startpos); 00222 00223 if(m_verbose) { 00224 m_out << "inlib::rroot::buffer::read_object :" 00225 << " class " << sout(sclass) 00226 << " bcnt " << bcnt 00227 << std::endl; 00228 } 00229 00230 if(is_ref) { 00231 //bcnt is the position toward an object or an object ref. 00232 //m_out << "inlib::rroot::buffer::read_object :" 00233 // << " is_ref " << bcnt 00234 // << std::endl; 00235 00236 {char* old_pos = m_pos; 00237 00238 unsigned int obj_offset = bcnt; 00239 obj_offset -= kMapOffset(); 00240 obj_offset -= m_klen; 00241 m_pos = m_buffer + obj_offset; 00242 00243 uint32 first_int; 00244 if(!rbuf::read(first_int)) return false; 00245 if(first_int & kByteCountMask()) { 00246 std::string scls; 00247 if(!read_class_tag(scls)) return false; 00248 if(scls.empty()) { 00249 m_out << "inlib::rroot::buffer::read_object :" 00250 << " read_class_tag did not find a class name." 00251 << std::endl; 00252 } 00253 } else { 00254 m_out << "inlib::rroot::buffer::read_object :" 00255 << " zzz" 00256 << std::endl; 00257 } 00258 00259 m_pos = old_pos;} 00260 00261 // in principle at this point m_pos should be 00262 // m_buffer+startpos+sizeof(unsigned int) 00263 // but enforce it anyway : 00264 m_pos = m_buffer+startpos+sizeof(unsigned int); 00265 //check_byte_count(startpos,0,sclass) would always be ok. 00266 00267 //a_obj = ??? 00268 00269 } else { 00270 if(sclass.empty()) { 00271 //m_out << "inlib::rroot::buffer::read_object :" 00272 // << " found empty class name." 00273 // << std::endl; 00274 00275 m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 00276 00277 } else { 00278 00279 iro* obj = a_fac.create(sclass,a_args); 00280 if(!obj) return false; 00281 //NOTE : if class ref, "up there"-startpos = 8. 00282 if(!obj->stream(*this)) { 00283 //restore a good buffer position : 00284 m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 00285 delete obj; 00286 return false; 00287 } 00288 00289 //NOTE : if obj stream ok, the below line is not needed. 00290 //m_pos = m_buffer+startpos+bcnt+sizeof(unsigned int); 00291 00292 if(!check_byte_count(startpos,bcnt,sclass)) { 00293 m_out << "inlib::rroot::buffer::read_object :" 00294 << " check_byte_count failed " 00295 << "for object of class " 00296 << sout(sclass) << "." << std::endl; 00297 delete obj; 00298 return false; 00299 } 00300 a_obj = obj; 00301 } 00302 00303 } 00304 00305 if(m_verbose) { 00306 m_out << "inlib::rroot::buffer::read_object :" 00307 << " end : " 00308 << std::endl; 00309 } 00310 00311 return true; 00312 } 00313 public: 00314 bool read_version(short& a_version){ 00315 // Read class version from I/O buffer. 00316 // Is read a short or three shorts. 00317 a_version = 0; 00318 short version = 0; 00319 // not interested in byte count 00320 if(!rbuf::read(version)) return false; 00321 00322 // if this is a byte count, then skip next short and read version 00323 if(version & kByteCountVMask()) { 00324 if(!rbuf::read(version)) return false; 00325 if(!rbuf::read(version)) return false; 00326 } 00327 00328 a_version = version; 00329 return true; 00330 } 00331 00332 bool read_version(short& a_version, 00333 uint32& a_start_pos, 00334 uint32& a_byte_count){ 00335 // Read class version from I/O buffer. 00336 // Is read one or three shorts. 00337 a_version = 0; 00338 a_start_pos = 0; 00339 a_byte_count = 0; 00340 00341 short version = 0; 00342 00343 // before reading object save start position 00344 uint32 startpos = (uint32)(m_pos-m_buffer); 00345 00346 // read byte count (older files don't have byte count) 00347 // byte count is packed in two individual shorts, this to be 00348 // backward compatible with old files that have at this location 00349 // only a single short (i.e. the version) 00350 union { 00351 unsigned int cnt; 00352 short vers[2]; 00353 } v; 00354 00355 if(m_byte_swap) { 00356 if(!rbuf::read(v.vers[1])) return false; 00357 if(!rbuf::read(v.vers[0])) return false; 00358 } else { 00359 if(!rbuf::read(v.vers[0])) return false; 00360 if(!rbuf::read(v.vers[1])) return false; 00361 } 00362 00363 // no bytecount, backup and read version 00364 uint32 bcnt = 0; 00365 if(v.cnt & kByteCountMask()) { 00366 bcnt = (v.cnt & ~kByteCountMask()); 00367 } else { 00368 m_pos -= sizeof(unsigned int); 00369 } 00370 if(!rbuf::read(version)) return false; 00371 //printf("Reading version=%d at pos=%d, bytecount=%d\n", 00372 //version,*startpos,*bcnt); 00373 00374 a_version = version; 00375 a_start_pos = startpos; 00376 a_byte_count = bcnt; 00377 00378 return true; 00379 } 00380 00381 bool check_byte_count(uint32 a_start_pos, 00382 uint32 a_byte_count, 00383 const std::string& a_store_cls){ 00384 if(!a_byte_count) return true; 00385 00386 unsigned long len = a_start_pos + a_byte_count + sizeof(unsigned int); 00387 00388 unsigned long diff = m_pos-m_buffer; 00389 00390 if(diff==len) return true; 00391 00392 if(diff<len) { 00393 m_out << "inlib::rroot::buffer::check_byte_count :" 00394 << " object of class " << sout(a_store_cls) 00395 << " read too few bytes (" 00396 << long2s(len-diff) << " missing)." 00397 << std::endl; 00398 } 00399 if(diff>len) { 00400 m_out << "inlib::rroot::buffer::check_byte_count :" 00401 << " object of class " << sout(a_store_cls) 00402 << " read too many bytes (" 00403 << long2s(diff-len) << " in excess)." << std::endl; 00404 } 00405 00406 m_out << "inlib::rroot::buffer::check_byte_count :" 00407 << " " << sout(a_store_cls) 00408 << " streamer not in sync with data on file, fix streamer." 00409 << std::endl; 00410 00411 m_pos = m_buffer+len; 00412 00413 return false; 00414 } 00415 protected: 00416 bool read_string(char* a_string,uint32 a_max) { 00417 // Read string from I/O buffer. String is read till 0 character is 00418 // found or till max-1 characters are read (i.e. string s has max 00419 // bytes allocated). 00420 int nr = 0; 00421 while (nr < int(a_max-1)) { 00422 char ch; 00423 if(!rbuf::read(ch)) return false; 00424 // stop when 0 read 00425 if(ch == 0) break; 00426 a_string[nr++] = ch; 00427 } 00428 a_string[nr] = 0; 00429 return true; 00430 } 00431 protected: 00432 // buffer objects cannot be copied or assigned 00433 //void checkCount(unsigned int); 00434 //unsigned int checkObject(unsigned int,const IClass*,bool = false); 00435 static std::string sout(const std::string& a_string) { 00436 return std::string("\"")+a_string+"\""; 00437 } 00438 protected: 00439 bool m_byte_swap; 00440 bool m_verbose; 00441 uint32 m_size; 00442 char* m_buffer; 00443 char* m_pos; 00444 uint32 m_klen; //GB 00445 }; 00446 00447 }} 00448 00449 #endif