// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_rroot_basket #define tools_rroot_basket #include "iro" #include "key" #include "../scast" #include "buffer" #include "cids" namespace tools { namespace rroot { class basket : public virtual iro, public key { typedef key parent; static uint32 kDisplacementMask() {return 0xFF000000;} public: static const std::string& s_class() { static const std::string s_v("tools::rroot::basket"); return s_v; } public: //iro virtual void* cast(const std::string& a_class) const { if(void* p = cmp_cast(this,a_class)) return p; return 0; } virtual const std::string& s_cls() const {return s_class();} public: static cid id_class() {return basket_cid();} virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } public: virtual iro* copy() const {return new basket(*this);} virtual bool stream(buffer& a_buffer) { _clear(); uint32 startpos = a_buffer.length(); if(!parent::from_buffer(a_buffer.byte_swap(),a_buffer.eob(),a_buffer.pos(),a_buffer.verbose())) return false; uint32 fBufferSize; short v; if(!a_buffer.read_version(v)) return false; if(!a_buffer.read(fBufferSize)) return false; if(!a_buffer.read(m_nev_buf_size)) return false; if(!a_buffer.read(m_nev)) return false; if(!a_buffer.read(m_last)) return false; char flag; if(!a_buffer.read(flag)) return false; if(m_last>fBufferSize) fBufferSize = m_last; uint16 basket_key_length = a_buffer.length()-startpos; if(basket_key_length!=m_key_length) { m_key_length = basket_key_length; } if(!m_object_size) { m_object_size = m_nbytes-m_key_length; } if(!flag) return true; //fHeaderOnly //G.Barrand : add the below test. if( (flag!=1) &&(flag!=2) && (flag!=11)&&(flag!=12) && (flag!=41)&&(flag!=42) && (flag!=51)&&(flag!=52) ) { m_out << "tools::rroot::basket::stream :" << " bad flag " << (int)flag << std::endl; return false; } if((flag%10)!=2) { //due to the upper "G.Barrand if", flag is here in {1,11,41,51} if(!m_nev_buf_size) { m_out << "tools::rroot::basket::stream :" << " m_nev_buf_size is zero." << std::endl; return false; } if(m_nev>m_nev_buf_size) { m_out << "tools::rroot::basket::stream :" << " m_nev>m_nev_buf_size !" << " m_nev " << m_nev << " m_nev_buf_size " << m_nev_buf_size << std::endl; return false; } m_entry_offset = new int[m_nev_buf_size]; if(m_nev) { uint32 n; if(!a_buffer.read_array(m_nev_buf_size,m_entry_offset,n)) { _clear(); return false; } if((n!=m_nev)&&(n!=(m_nev+1))) { m_out << "tools::rroot::basket::stream :" << " m_entry_offset read len mismatch." << " n " << n << " m_nev " << m_nev << std::endl; _clear(); return false; } } if(flag>40) { m_displacement = new int[m_nev_buf_size]; uint32 n; if(!a_buffer.read_array(m_nev_buf_size,m_displacement,n)) { _clear(); return false; } if((n!=m_nev)&&(n!=(m_nev+1))) { m_out << "tools::rroot::basket::stream :" << " m_displacement read len mismatch." << " n " << n << " m_nev " << m_nev << std::endl; _clear(); return false; } } } else { //m_nev_buf_size is the size in bytes of one entry. } if((flag==1)||(flag>10)) { delete [] m_buffer; m_buffer = 0; m_buf_size = 0; if(fBufferSize) { char* _buf = new char[fBufferSize]; if(!_buf) { m_out << "tools::rroot::basket::stream :" << " can't alloc " << fBufferSize << std::endl; _clear(); return false; } if(v>1) { if(!a_buffer.read_fast_array(_buf,m_last)) { _clear(); delete [] _buf; return false; } } else { uint32 n; if(!a_buffer.read_array(fBufferSize,_buf,n)) { _clear(); delete [] _buf; return false; } } m_buffer = _buf; m_buf_size = fBufferSize; } } return true; } public: basket(std::ostream& a_out) :parent(a_out) ,m_nev_buf_size(0) ,m_nev(0) ,m_last(0) ,m_entry_offset(0) ,m_displacement(0) { } basket(std::ostream& a_out,seek a_pos,uint32 a_nbytes) :parent(a_out,a_pos,a_nbytes) ,m_nev_buf_size(0) ,m_nev(0) ,m_last(0) ,m_entry_offset(0) ,m_displacement(0) { } virtual ~basket(){ _clear(); } public: basket(const basket& a_from) :iro(a_from) ,parent(a_from) ,m_nev_buf_size(a_from.m_nev_buf_size) ,m_nev(a_from.m_nev) ,m_last(a_from.m_last) ,m_entry_offset(0) ,m_displacement(0) { if(a_from.m_nev && a_from.m_entry_offset) { m_entry_offset = new int[a_from.m_nev]; if(!m_entry_offset) { m_out << "tools::rroot::basket::basket(cpcstor) :" << " can't alloc " << a_from.m_nev << "." << std::endl; } else { uint32 len = a_from.m_nev*sizeof(int); ::memcpy(m_entry_offset,a_from.m_entry_offset,len); } } if(a_from.m_nev && a_from.m_displacement) { m_displacement = new int[a_from.m_nev]; if(!m_displacement) { m_out << "tools::rroot::basket::basket(cpcstor) :" << " can't alloc " << a_from.m_nev << "." << std::endl; } else { uint32 len = a_from.m_nev*sizeof(int); ::memcpy(m_displacement,a_from.m_displacement,len); } } } basket& operator=(const basket& a_from){ parent::operator=(a_from); if(&a_from==this) return *this; m_nev_buf_size = a_from.m_nev_buf_size; m_nev = a_from.m_nev; m_last = a_from.m_last; delete [] m_entry_offset; m_entry_offset = 0; delete [] m_displacement; m_displacement = 0; if(a_from.m_nev && a_from.m_entry_offset) { m_entry_offset = new int[a_from.m_nev]; if(!m_entry_offset) { m_out << "tools::rroot::basket::operator=() :" << " can't alloc " << a_from.m_nev << "." << std::endl; } else { uint32 len = a_from.m_nev*sizeof(int); ::memcpy(m_entry_offset,a_from.m_entry_offset,len); } } if(a_from.m_nev && a_from.m_displacement) { m_displacement = new int[a_from.m_nev]; if(!m_displacement) { m_out << "tools::rroot::basket::operator=() :" << " can't alloc " << a_from.m_nev << "." << std::endl; } else { uint32 len = a_from.m_nev*sizeof(int); ::memcpy(m_displacement,a_from.m_displacement,len); } } return *this; } public: int* entry_offset() {return m_entry_offset;} int* displacement() {return m_displacement;} uint32 nev_buf_size() const {return m_nev_buf_size;} uint32 nev() const {return m_nev;} uint32 last() const {return m_last;} bool read_offset_tables(bool a_byte_swap) { if(!m_buffer) return false; if(!m_last) return false; delete [] m_entry_offset; m_entry_offset = 0; buffer _buffer(m_out,a_byte_swap,m_buf_size,m_buffer,0,false); _buffer.set_offset(m_last); {uint32 n; if(!_buffer.read_array(0,m_entry_offset,n)) { m_out << "tools::rroot::basket::read_offset_tables :" << " read_array failed." << std::endl; return false; } if((n!=m_nev)&&(n!=(m_nev+1))) { m_out << "tools::rroot::basket::read_offset_tables :" << " m_entry_offset read len mismatch." << " n " << n << " m_nev " << m_nev << std::endl; return false; }} delete [] m_displacement; m_displacement = 0; if(_buffer.length()!=_buffer.size()) { // There is more data in the buffer! It is the diplacement // array. uint32 n; if(!_buffer.read_array(0,m_displacement,n)) { m_out << "tools::rroot::basket::read_offset_tables :" << " readArray(2) failed." << std::endl; return false; } if((n!=m_nev)&&(n!=(m_nev+1))) { m_out << "tools::rroot::basket::read_offset_tables :" << " m_displacement read len mismatch." << " n " << n << " m_nev " << m_nev << std::endl; return false; } } return true; } protected: void _clear(){ delete [] m_entry_offset; delete [] m_displacement; m_entry_offset = 0; m_displacement = 0; } protected: //Named uint32 m_nev_buf_size; //Length in Int_t of m_entry_offset uint32 m_nev; //Number of entries in basket uint32 m_last; //Pointer to last used byte in basket int* m_entry_offset; //[m_nev] Offset of entries in fBuffer(TKey) int* m_displacement; //![m_nev] Displacement of entries in fBuffer(TKey) }; }} #endif