/* * Copyright 2011, 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef _BYTEVECTOR_H_ #define _BYTEVECTOR_H_ #include #include #include "MemoryLeak.h" #include "BitVector.h" #include "ScalarTypes.h" #include "Logger.h" // Originally based on BitVector, based on Vector // ByteVector is like a Vector but for objects of type... guess what? // ByteVector also has an efficient append facility. // A ByteVector consists of packed memory that is byte-aligned on the left side // and bit-aligned on the right side. Both the left and right side can be moved // back and forth within the constraints of the originally allocated memory. // See: trimLeft, trimRight, growLeft, and the many append functions. // The basic strategy is that ByteVectors are always allocated initially // such that size() is the full allocated size, so if you want to use the append // feature you must call setAppendP() (or conceivably trimRight) to set the location // where you want to start appending. // Exceeding the edges of the allocated memory area throws ByteVectorError // There are two classes defined here: // o ByteVector points to a memory area that it manages. // All segments derived from a ByteVector share the same memory using refcnts. // When the last segment is deleted, the memory is freed. // o ByteVectorTemp is identical but does not 'own' the memory, rather it points into // an area of memory that it does not manage. It allows you to use the rather extensive // set of ByteVector manipulation functions on some other memory, or derive a segment // using segmentTemp when you know for sure that the derived segment is temporary and // will not outlive the original ByteVector. // It is unwise to expand the left or right side of a ByteVectorTemp because there is // no protection for exceeding the bounds of the memory area, however those functions // are not currently over-ridden in ByteVectorTemp to remove them, but they should be eliminated. // ByteVector is the base class and can refer to either ByteVectors that own memory, // or ByteVectorTemps that do not. // I started inheriting from Vector but we could only reuse a few lines of code // from there so it is not worth the trouble. It would be better to push // the appending ability down into Vector. But appending creates a different // concept of size() than Vector which would be a major change. // To avoid confusion with Vector type functions resize() is not defined in ByteVector. #define NEW_SEGMENT_SEMANTICS 1 #define BYTEVECTOR_REFCNT 1 // ByteVectors now use reference counting #define BVASSERT(expr) {if (!(expr)) throw ByteVectorError();} class ByteVectorError {}; typedef uint8_t ByteType; void sethtonl(ByteType *cp,unsigned value); void sethtons(ByteType *cp,unsigned value); uint16_t getntohs(ByteType *cp); uint32_t getntohl(ByteType *cp); class ItemWithSize { virtual size_t sizeBits() const =0; virtual size_t sizeBytes() const =0; }; class ByteVectorTemp; class Dorky {}; // Used to force use of a particular constructor. class ByteVector //: public Vector : public ItemWithSize { ByteType* mData; ///< allocated data block, if any ByteType* mStart; ///< start of useful data, always >=mData and <=mAllocEnd unsigned mSizeBits; ///< size of useful data in bits. ByteType *mAllocEnd; ///< end of allocated data + 1. //unsigned mBitInd; unsigned bitind() { return mSizeBits % 8; } #if BYTEVECTOR_REFCNT // The first mDataOffset bytes of mData is a short reference count of the number // of ByteVectors pointing at it. static const int mDataOffset = sizeof(short); int setRefCnt(int val) { return ((short*)mData)[0] = val; } int decRefCnt() { return setRefCnt(((short*)mData)[0] - 1); } void incRefCnt() { setRefCnt(((short*)mData)[0] + 1); } #endif void init(size_t newSize); /** set size and allocated size to that specified */ void initstr(const char *wdata, unsigned wlen) { init(wlen); setAppendP(0); append(wdata,wlen); } void initstr(const char *wdata) { initstr(wdata,strlen(wdata)); } void dup(const ByteVector& other); // Constructor: A ByteVector that does not own any memory, but is just a segment // of some other memory. This constructor is private. // The public way to do this is to use segmentTemp or create a ByteVectorTemp. protected: ByteVector(Dorky,ByteType*wstart,ByteType*wend) : mData(0), mStart(wstart), mSizeBits(8*(wend-wstart)), mAllocEnd(wend) {} //: mData(0), mStart(wstart), mEnd(wend), mAllocEnd(wend), mBitInd(0) {} public: void clear(); // Release the memory used by this ByteVector. // clone semantics are weird: copies data from other to self. void clone(const ByteVector& other); /** Copy data from another vector. */ #if BYTEVECTOR_REFCNT int getRefCnt() { return mData ? ((short*)mData)[0] : 0; } #endif const ByteType* begin() const { return mStart; } ByteType*begin() { return mStart; } // This is the allocSize from mStart, not from mData. size_t allocSize() const { return mAllocEnd - mStart; } //size_t sizeBytes() const { return mEnd - mStart + !!mBitInd; } // size in bytes size_t sizeBytes() const { return (mSizeBits+7)/8; } // size in bytes size_t size() const { return sizeBytes(); } // size in bytes //size_t sizeBits() const { return size() * 8 + mBitInd; } // size in bits size_t sizeBits() const { return mSizeBits; } // size in bits size_t sizeRemaining() const { // Remaining full bytes for appends return (mAllocEnd - mStart) - sizeBytes(); //int result = mAllocEnd - mEnd - !!mBitInd; //return result >= 0 ? (size_t) result : 0; } void resetSize() { mSizeBits = 8*allocSize(); } // Set the Write Position for appends. This is equivalent to setting size(). void setAppendP(size_t bytep, unsigned bitp=0) { BVASSERT(bytep + !!bitp <= allocSize()); mSizeBits = bytep*8 + bitp; //mEnd=mStart+bytep; mBitInd=bitp; } void setSizeBits(size_t bits) { BVASSERT((bits+7)/8 <= allocSize()); mSizeBits = bits; //mEnd=mStart+(bits/8); mBitInd=bits%8; } // Concat unimplemented. //ByteVector(const ByteVector& source1, const ByteVector source2); /** Constructor: An empty Vector of a given size. */ ByteVector(size_t wSize=0) { RN_MEMCHKNEW(ByteVector); init(wSize); } // Constructor: A ByteVector whose contents is from a string with optional length specified. // A copy of the string is malloced into the ByteVector. // ByteType is "unsigned char" so we need both signed and unsigned versions to passify C++. ByteVector(const ByteType *wdata,int wlen) { RN_MEMCHKNEW(ByteVector) initstr((const char*)wdata,wlen); } ByteVector(const ByteType *wdata) { RN_MEMCHKNEW(ByteVector) initstr((const char*)wdata); } ByteVector(const char *wdata,int wlen) { RN_MEMCHKNEW(ByteVector) initstr(wdata,wlen); } ByteVector(const char *wdata) { RN_MEMCHKNEW(ByteVector) initstr(wdata); } // Constructor: A ByteVector which is a duplicate of some other. // They both 'own' the memory using refcounts. // The const is tricky - other is modified despite the 'const', because only the ByteVector itself is 'const', // the memory it points to is not. // See also: alias. ByteVector(ByteVector& other) : mData(0) { RN_MEMCHKNEW(ByteVector) dup(other); } ByteVector(const ByteVector&other) : mData(0) { RN_MEMCHKNEW(ByteVector) dup(other); } ByteVector(const BitVector &other) { RN_MEMCHKNEW(ByteVector) init((other.size()+7)/8); setAppendP(0); append(other); } virtual ~ByteVector() { RN_MEMCHKDEL(ByteVector) clear(); } // Make a duplicate of the vector where both point into shared memory, and increment the refcnt. // Use clone if you want a completely distinct copy. void operator=(ByteVector& other) { dup(other); } // The BitVector class implements this with a clone(). // However, this gets called if a hidden intermediary variable is required // to implement the assignment, for example: x = segment(...); // In this case it is safer for the class to call clone to be safe, // however, that is probably never what is wanted by the calling code, // so I am leaving it out of here. Only use this type of assignment if the // other does not own the memory. // Update: With refcnts, these issues evaporate, and the two forms // of assignment are identical. void operator=(const ByteVector& other) { #if BYTEVECTOR_REFCNT dup(other); #else BVASSERT(other.mData == NULL); // Dont use assignment in this case. set(other); #endif } static int compare(const ByteVector &bv1, const ByteVector &bv2); bool eql(const ByteVector &other) const; bool operator==(const ByteVector &other) const { return eql(other); } bool operator!=(const ByteVector &other) const { return !eql(other); } // This is here so you put ByteVectors in a map, which needs operator< defined. bool operator<(const ByteVector &other) const { return compare(*this,other)<0; } bool operator>(const ByteVector &other) const { return compare(*this,other)>0; } bool operator<=(const ByteVector &other) const { return compare(*this,other)<=0; } bool operator>=(const ByteVector &other) const { return compare(*this,other)>=0; } /**@name Functions identical to Vector: */ // Return a segment of a ByteVector that shares the same memory as the original. // The const is tricky - the original ByteVector itself is not modified, but the memory it points to is. ByteVector segment(size_t start, size_t span) const; // For the const version, since we are not allowed to modify the original // to change the refcnt, we have to either return a segment that does not own memory, // or a completely new piece of memory. So I am using a different name so that // it is obvious that the memory ownership is being stripped off the ByteVector. const ByteVectorTemp segmentTemp(size_t start, size_t span) const; // Copy other to this starting at start. // The 'this' ByteVector must be allocated large enough to hold other. void setSegment(size_t start, ByteVector&other); bool isOwner() { return !!mData; } // Do we own any memory ourselves? // Trim specified number of bytes from left or right in place. // growLeft is the opposite: move the mStart backward by amt, throw error if no room. // New space is uninitialized. // These are for byte-aligned only, so we assert bit index is 0. void trimLeft(unsigned amt); void trimRight(unsigned amt); ByteType *growLeft(unsigned amt); void growRight(unsigned amt); void fill(ByteType byte, size_t start, size_t span); void fill(ByteType byte, size_t start) { fill(byte,start,size()-start); } void fill(ByteType byte) { fill(byte,0,size()); } void appendFill(ByteType byte, size_t span); // Zero out the rest of the ByteVector: void appendZero() { if (bitind()) appendField(0,8-bitind()); // 0 fill partial byte. appendFill(0,allocSize() - size()); // 0 fill remaining bytes. } // Copy part of this ByteVector to a segment of another. // The specified span must not exceed our size, and it must fit in the target ByteVector. void copyToSegment(ByteVector& other, size_t start, size_t span) const; /** Copy all of this Vector to a segment of another Vector. */ void copyToSegment(ByteVector& other, size_t start=0) const; // pat 2-2012: I am modifying this to use the refcnts, so to get // a segment with an incremented refcnt, use: alias().segment(...) //ByteVector alias() { return segment(0,size()); } ByteVector head(size_t span) const { return segment(0,span); } //const ByteVector headTemp(size_t span) const { return segmentTemp(0,span); } ByteVector tail(size_t start) const { return segment(start,size()-start); } //const ByteVector tailTemp(size_t start) const { return segmentTemp(start,size()-start); } // GSM04.60 10.0b.3.1: Note that fields in RLC blocks use network order, // meaning most significant byte first (cause they started on Sun workstations.) // It is faster to use htons, etc, than unpacking these ourselves. // Note that this family of functions all assume byte-aligned fields. // See setField/appendField for bit-aligned fields. unsigned grow(unsigned amt); unsigned growBits(unsigned amt); void setByte(size_t ind, ByteType byte) { BVASSERT(ind < size()); mStart[ind] = byte; } void setUInt16(size_t writeIndex,unsigned value); // 2 byte value void setUInt32(size_t writeIndex, unsigned value); // 4 byte value void appendByte(unsigned value) { BVASSERT(bitind()==0); setByte(grow(1),value); } void appendUInt16(unsigned value) { BVASSERT(bitind()==0); setUInt16(grow(2),value); } void appendUInt32(unsigned value) { BVASSERT(bitind()==0); setUInt32(grow(4),value); } ByteType getByte(size_t ind) const { BVASSERT(ind < size()); return mStart[ind]; } ByteType getNibble(size_t ind,int hi) const { ByteType val = getByte(ind); return hi ? (val>>4) : val & 0xf; } unsigned getUInt16(size_t readIndex) const; // 2 byte value unsigned getUInt32(size_t readIndex) const; // 4 byte value ByteType readByte(size_t &rp) { return getByte(rp++); } unsigned readUInt16(size_t &rp); unsigned readUInt32(size_t &rp); unsigned readLI(size_t &rp); // GSM8.16 1 or 2 octet length indicator. void append(const ByteVector&other); void append(const BitVector&other); void append(const ByteType*bytes, unsigned len); void append(const char*bytes, unsigned len) { append((const ByteType*)bytes,len); } void appendLI(unsigned len); // GSM8.16 1 or 2 octet length indicator. void append(const ByteVector*other) { append(*other); } void append(const BitVector*other) { append(*other); } // Set from another ByteVector. // The other is typically a segment which does not own the memory, ie: // v1.set(v2.segment()) The other is not a reference because // the result of segment() is not a variable to which // the reference operator can be applied. // This is not really needed any more because the refcnts take care of these cases. void set(ByteVector other) // That's right. No ampersand. { #if BYTEVECTOR_REFCNT // Its ok, everything will work. dup(other); #else BVASSERT(other.mData == NULL); // Dont use set() in this case. clear(); mStart=other.mStart; mEnd=other.mEnd; mAllocEnd = other.mAllocEnd; mBitInd = other.mBitInd; #endif } // Bit aligned operations. // The "2" suffix versions specify both byte and bit index in the range 0..7. // The "R1" suffix versions are identical to the "2" suffix versions, // but with start bit numbered from 1 like this: 8 | 7 | ... | 1 // This is just a convenience because all the specs number the bits this weird way. // The no suffix versions take a bit pos ranging from 0 to 8*size()-1 // Get a bit from the specified byte, numbered like this: 0 | 1 | ... | 7 bool getBit2(size_t byteIndex, unsigned bitIndex) const; // Get a bit in same bit order, but with start bit numbered from 1 like this: 8 | 7 | ... | 1 // Many GSM L3 specs specify numbering this way. bool getBitR1(size_t byteIndex, unsigned bitIndex) const { return getBit2(byteIndex,8-bitIndex); } bool getBit(unsigned bitPos) const { return getBit2(bitPos/8,bitPos%8); } void setBit2(size_t byteIndex, unsigned bitIndex, unsigned val); void setBit(unsigned bitPos, unsigned val) { setBit2(bitPos/8,bitPos%8,val); } // Set/get fields giving both byte and bit index. void setField2(size_t byteIndex, size_t bitIndex, uint64_t value,unsigned lengthBits); uint64_t getField2(size_t byteIndex, size_t bitIndex, unsigned lengthBits) const; uint64_t getFieldR1(size_t byteIndex, size_t bitIndex, unsigned length) const { return getField2(byteIndex,8-bitIndex,length); } // Set/get bit field giving bit position treating the entire ByteVector as a string of bits. void setField(size_t bitPos, uint64_t value, unsigned lengthBits) { setField2(bitPos/8,bitPos%8,value,lengthBits); } uint64_t getField(size_t bitPos, unsigned lengthBits) const { // aka peekField return getField2(bitPos/8,bitPos%8,lengthBits); } // Identical to getField, but add lengthBits to readIndex. uint64_t readField(size_t& readIndex, unsigned lengthBits) const { uint64_t result = getField(readIndex,lengthBits); readIndex += lengthBits; return result; } void appendField(uint64_t value,unsigned lengthBits); // This works for Field<> data types. void appendField(ItemWithValueAndWidth &item) { appendField(item.getValue(),item.getWidth()); } std::string str() const; std::string hexstr() const; }; class ByteVectorTemp : public ByteVector { public: ByteVectorTemp(ByteType*wstart,ByteType*wend) : ByteVector(Dorky(),wstart,wend) {} ByteVectorTemp(size_t) { assert(0); } // Constructor: A ByteVector whose contents is from a string with optional length specified. // These cannot be const because the ByteVectorTemp points into the original memory // and has methods to modify it. // ByteType is "unsigned char" so we need both signed and unsigned versions to passify C++. // All the explicit casts are required. This is so brain dead. ByteVectorTemp(ByteType *wdata,int wlen) : ByteVector(Dorky(),wdata,wdata+wlen) {} ByteVectorTemp(ByteType *wdata) : ByteVector(Dorky(),wdata,wdata+strlen((char*)wdata)) {} ByteVectorTemp(char *wdata,int wlen) : ByteVector(Dorky(),(ByteType*)wdata,(ByteType*)wdata+wlen) {} ByteVectorTemp(char *wdata) : ByteVector(Dorky(),(ByteType*)wdata,(ByteType*)wdata+strlen((char*)wdata)) {} ByteVectorTemp(ByteVector& other) : ByteVector(Dorky(),other.begin(),other.begin()+other.size()) {} ByteVectorTemp(BitVector &) { assert(0); } }; // Warning: C++ prefers an operator<< that is const to one that is not. std::ostream& operator<<(std::ostream&os, const ByteVector&vec); #endif