inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/rroot/buffer
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines