forked from evilsocket/openbts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ByteVector.h
381 lines (329 loc) · 17.6 KB
/
ByteVector.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/*
* 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 <stdint.h>
#include <arpa/inet.h>
#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<ByteType>
: 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