#ifndef _BITMASK_HPP #define _BITMASK_HPP /*! \file bitrange.hpp \brief Definition of the ::bitrange_t class */ //--------------------------------------------------------------------------- /// This class manages the offset and size of a value that occupies /// a number of contiguous bits within some container - generally a byte array. /// A special state - empty range (both offset and size are zeroes) - determines /// the value as all bits of the container. class bitrange_t { public: /// Constructor explicit bitrange_t(uint16 bit_ofs = 0, uint16 size_in_bits = 0); /// Initialize offset and size to given values inline void init(uint16 bit_ofs, uint16 size_in_bits); /// Make the bitrange empty inline void reset(); /// Is the bitrange empty? inline bool empty() const; /// Get offset of 1st bit inline uint bitoff() const; /// Get size of the value in bits inline uint bitsize() const; /// Size of the value in bytes inline uint bytesize() const; /// Convert to mask of 64 bits inline uint64 mask64() const; /// Does have common bits with another bitrange? inline bool has_common(const bitrange_t &r) const; /// Apply mask to a bitrange /// \param subrange range *inside* the main bitrange to keep /// After this operation the main bitrange will be truncated /// to have only the bits that are specified by subrange. /// Example: [off=8,nbits=4], subrange[off=1,nbits=2] => [off=9,nbits=2] /// \return success inline bool apply_mask(const bitrange_t &subrange); /// Intersect two ranges inline void intersect(const bitrange_t &r); /// Create union of 2 ranges including the hole between them inline void create_union(const bitrange_t &r); /// Subtract a bitrange inline bool sub(const bitrange_t &r); /// Shift range down (left) inline void shift_down(uint cnt); /// Shift range up (right) inline void shift_up(uint cnt); /// Initialize bitrange_t with offset/size defined by given mask template inline void assign_max_nonzero(T mask); /// \name Extract /// Extract a value from 'src' according to the bitrange /// \param dst vector the extracted value will be stored to /// \param src source buffer /// \param src_size size of source buffer /// \param is_mf is Msb First? (TRUE-big endian, FALSE-little endian) //@{ inline bool extract( bytevec_t *dst, const void *src, size_t src_size, bool is_mf) const; inline bool extract( void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf) const; //@} /// \name Inject /// Inject a value into 'dst' according to the bitrange /// \param dst a buffer the value will be injected into /// \param dst_size size of buffer /// \param src source value /// \param is_mf is Msb First? (TRUE-big endian, FALSE-little endian) //@{ inline bool inject( void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf) const; inline bool inject( void *dst, size_t dst_size, const bytevec_t &src, bool is_mf) const; //@} DECLARE_COMPARISONS(bitrange_t); private: uint16 offset; ///< offset of 1st bit starting with the lowest bit uint16 nbits; ///< size of the value in bits }; //--------------------------------------------------------------------------- inline bitrange_t::bitrange_t(uint16 bit_ofs, uint16 size_in_bits) : offset(bit_ofs), nbits(size_in_bits) { } //--------------------------------------------------------------------------- inline void bitrange_t::init(uint16 bit_ofs, uint16 size_in_bits) { offset = bit_ofs; nbits = size_in_bits; } //--------------------------------------------------------------------------- inline void bitrange_t::reset() { init(0, 0); } //--------------------------------------------------------------------------- inline bool bitrange_t::empty() const { return nbits == 0; } //--------------------------------------------------------------------------- inline uint bitrange_t::bitoff() const { return offset; } //--------------------------------------------------------------------------- inline uint bitrange_t::bitsize() const { return nbits; } //--------------------------------------------------------------------------- inline uint bitrange_t::bytesize() const { return (nbits + 8-1) / 8; } //-------------------------------------------------------------------------- inline uint64 bitrange_t::mask64() const { return empty() ? 0 : (left_shift(uint64(1), nbits)-1) << offset; } //-------------------------------------------------------------------------- inline bool bitrange_t::apply_mask(const bitrange_t &submask) { if ( submask.bitoff() + submask.bitsize() > bitsize() ) return false; init(bitoff() + submask.bitoff(), submask.bitsize()); return true; } //-------------------------------------------------------------------------- inline void bitrange_t::intersect(const bitrange_t &r) { uint16 e1 = offset + nbits; uint16 e2 = r.offset + r.nbits; uint16 e = qmin(e1, e2); uint16 s = qmax(offset, r.offset); if ( s > e ) { s = 0; e = 0; } init(s, e-s); } //-------------------------------------------------------------------------- inline bool bitrange_t::has_common(const bitrange_t &r) const { return interval::overlap(offset, nbits, r.offset, r.nbits); } //-------------------------------------------------------------------------- inline void bitrange_t::create_union(const bitrange_t &r) { uint16 e1 = offset + nbits; uint16 e2 = r.offset + r.nbits; uint16 e = qmax(e1, e2); uint16 s = qmin(offset, r.offset); init(s, e-s); } //-------------------------------------------------------------------------- inline bool bitrange_t::sub(const bitrange_t &r) { // r is in the middle of our bitrange, cannot handle this case // because it would require 2 bitranges :/ uint16 end = offset + nbits; uint16 rend = r.offset + r.nbits; if ( r.offset > offset && rend < end ) return false; if ( r.offset <= offset ) { if ( rend > end ) { reset(); } else if ( rend > offset ) { offset = rend; nbits = end - offset; } } else if ( r.offset < end ) { nbits = r.offset - offset; } return true; } //-------------------------------------------------------------------------- inline int bitrange_t::compare(const bitrange_t &r) const { if ( offset != r.offset ) return offset < r.offset ? -1 : 1; if ( nbits != r.nbits ) return nbits < r.nbits ? -1 : 1; return 0; } //-------------------------------------------------------------------------- inline void bitrange_t::shift_down(uint cnt) { if ( cnt > offset ) { cnt -= offset; offset = 0; if ( cnt > nbits ) nbits = 0; else nbits -= cnt; } else { offset -= cnt; } } //-------------------------------------------------------------------------- inline void bitrange_t::shift_up(uint cnt) { offset += cnt; } //-------------------------------------------------------------------------- template inline void bitrange_t::assign_max_nonzero(T mask) { if ( mask == T(0) ) { reset(); return; } int i = 0; T bit = T(1); for ( i=0; i < sizeof(T)*8; ++i, bit <<= 1 ) if ( (mask & bit) != 0 ) break; offset = i; i = sizeof(T)*8 - 1; bit = left_shift(T(1), i); while ( i >= offset ) { if ( (mask & bit) != 0 ) break; --i; bit >>= 1; } nbits = i - offset + 1; } //-------------------------------------------------------------------------- #ifndef SWIG /// \name Helper functions /// Should not be called directly! //@{ idaman bool ida_export bitrange_t_extract_using_bitrange(const bitrange_t *bm, void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf); idaman bool ida_export bitrange_t_inject_using_bitrange(const bitrange_t *bm, void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf); //@} #else #endif // SWIG //-------------------------------------------------------------------------- inline bool bitrange_t::extract( void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf) const { return bitrange_t_extract_using_bitrange(this, dst, dst_size, src, src_size, is_mf); } //-------------------------------------------------------------------------- inline bool bitrange_t::extract( bytevec_t *dst, const void *src, size_t src_size, bool is_mf) const { size_t dst_size = empty() ? src_size : bytesize(); dst->resize(dst_size); return bitrange_t_extract_using_bitrange(this, dst->begin(), dst_size, src, src_size, is_mf); } //-------------------------------------------------------------------------- inline bool bitrange_t::inject( void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf) const { return bitrange_t_inject_using_bitrange(this, dst, dst_size, src, src_size, is_mf); } //-------------------------------------------------------------------------- inline bool bitrange_t::inject( void *dst, size_t dst_size, const bytevec_t &src, bool is_mf) const { return bitrange_t_inject_using_bitrange(this, dst, dst_size, src.begin(), src.size(), is_mf); } #endif // define _BITMASK_HPP