Bit stream class (C++)
Posted: Thu Aug 30, 2007 8:12 pm
I made this a while back to manipulate data at the bit level. I also included dependency function/classes
I have a challenge for someone though, get the overloaders to actually work.
Archived topic from AOV, old topic ID:1203, old post ID:7633
Code: Select all
/*
Dumps a string in hex, then normal underneeth, for easy ascii-hex compare
*Some code courtesy of hexdump.
*/
void HexDump(string str)
{
int strsize=str.size();
const int cols=26;
int pos=0;
cout<<flush<<endl;
while(pos<strsize)
{
for(int i=pos;i<pos+cols;i++)
{
if(i>=strsize)break;
cout<<flush<< setw(2) << setfill ( '0' )<< hex <<(unsigned int)(unsigned char)str[i]<<" ";
}
cout<<"
";
for(int i=pos;i<pos+cols;i++)
{
if(i>=strsize)break;
if((int)str[i] < 32 || 126 < (int)str[i])cout<<". ";
else cout<< str[i]<<" ";
}
pos+=cols;
if(pos<strsize)cout<<"
";
}
cout<<dec;
}
//safer substring (wont crash when out of range)
string safesubstr(string source,int start,int end)
{
if(start>source.size())return "";
if((source.size()+end)>source.size())
end=source.size()-start;
return source.substr(start,end);
}
//turns int to string
string Int2Str(int sourceint)
{
char destinationchar[50];
sprintf(destinationchar,"%d",sourceint);
return destinationchar;
}
//turns string to int
int Str2Int(string sourcestr)
{
return atoi(sourcestr.c_str());
}
//turns str to bool
bool Str2Bool(string source)
{
if(source.size()<1)return false;
if(tolower(source[0])=='y' || tolower(source[0])=='t' || tolower(source[0])=='1')return true;
return false;
}
/***************************
ARRAY LIST
****************************/
template<class T>
class RSarraylist
{
private:
T *Item; //This list stores items of type double
int size; //The current size of the list, must be updated
//in the Add, Insert and Delete methods
int maxsize; //The declared size of the array for this list,
//set in the constructors
public:
RSarraylist(int); //Creates a list of size provided by parameter
bool isEmpty(); //Returns true if the list is empty (no values )
bool isFull(); //Returns true is the list is full
int Size(); //Returns the number of elements in the list
int MaxSize(); //Returns the maximum size of the list
void clearList(); //Removes all items from the list, but does not
//destroy the list
int findItem(T); //Find a match for the item parameter and
//return the postion, -1 if not found
T Retrieve(int); //Returns the item at the specified position,
//if it exists
bool Add(T); //Adds an item to the end of the list,
//if there is room
bool Insert(T, int); //Inserts an item at the specified
//postion. Existing items are moved accordingly
bool Delete(int); //Deletes an item from the specified position
void displayList(); //outputs all elements of the list to the screen
void Grow(int); //increases size of the array by specified amount
};
template<class T>
RSarraylist<T>::RSarraylist(int pmaxsize=100)
{
size=0;
maxsize=pmaxsize;
Item = new T[pmaxsize+1];
}
template<class T>
bool RSarraylist<T>::isEmpty()
{
if(size<=0)return true;
return false;
}
template<class T>
bool RSarraylist<T>::isFull()
{
if(size>=maxsize)return true;
return false;
}
template<class T>
int RSarraylist<T>::Size() { return size; }
template<class T>
int RSarraylist<T>::MaxSize() { return maxsize; }
template<class T>
void RSarraylist<T>::clearList()
{
size=0;
}
template<class T>
int RSarraylist<T>::findItem(T tofind)
{
for(int i=0;i<maxsize;i++)
{
if(Item[i]==tofind)return i;
}
return -1;
}
template<class T>
T RSarraylist<T>::Retrieve(int pos)
{
if(pos>=size)pos=size-1;
return Item[pos];
}
template<class T>
bool RSarraylist<T>::Add(T toadd)
{
if(size>=maxsize)Grow(maxsize > 100 ? 1000 : maxsize); //by default, double the size if its too small for another element but no more then 1000 elements
Item[size]=toadd;
size++;
return true;
}
template<class T>
bool RSarraylist<T>::Insert(T toinsert, int insertat)
{
if(size>=maxsize)Grow(maxsize > 100 ? 1000 : maxsize); //by default, double the size if its too small for another element but no more then 1000 elements
if(insertat < 0 || insertat > (maxsize-1))return false;
for(int i=maxsize;i>=insertat;i--)
{
Item[i+1]=Item[i];
}
Item[insertat]=toinsert;
size++;
return true;
}
template<class T>
bool RSarraylist<T>::Delete(int deleteat)
{
if(deleteat>=maxsize || deleteat<0)return false;
for(int i=deleteat;i<maxsize;i++)
{
Item[i]=Item[i+1];
}
size--;
return true;
}
template<class T>
void RSarraylist<T>::displayList()
{
cout<<"
Contents "<<size<<"/"<<maxsize;
if(isFull())cout<<" [full]";
else if(isEmpty())cout<<" [empty]";
cout<<" : "<<endl;
for(int i=0;i<size;i++)
{
cout<<i<<": "<<Item[i]<<endl;
}
cout<<endl;
}
template<class T>
void RSarraylist<T>::Grow(int addsize=1)
{
T * temp = new T[maxsize];
for(int i=0;i<maxsize;i++)temp[i]=Item[i];
delete[] Item;
maxsize+=addsize;
Item = new T[maxsize];
for(int i=0;i<maxsize;i++)Item[i]=temp[i];
}
/*+++++++++++++++++++++++
Bit Stream Class
++++++++++++++++++++++++*/
class RSbitstream
{
private:
RSarraylist <bool>stream;
public:
RSbitstream(int);
string ToStr();
void Display();
void Hexdump();
void Clear();
int Size();
int MaxSize();
//add data
void WriteBit(bool);
void WriteVarInt(unsigned int,int);
void WriteInt8(unsigned int);
void WriteInt16(unsigned int);
void WriteInt24(unsigned int);
void WriteInt32(unsigned int);
void WriteString(string);
void WriteBitstream(RSbitstream);
//get data
bool ReadBit(int);
unsigned long int ReadVarInt(int,int);
unsigned long int ReadInt8(int);
unsigned long int ReadInt16(int);
unsigned long int ReadInt24(int);
unsigned long int ReadInt32(int);
string ReadString(int,int);
//overloaders
void operator+(RSbitstream);
RSbitstream & operator=(RSbitstream&);
RSbitstream & operator+=(RSbitstream&);
RSbitstream & operator=(string);
RSbitstream & operator+=(string);
};
RSbitstream::RSbitstream(int initsize=1024)
{
stream.Grow(initsize);
}
string RSbitstream::ToStr()
{
string temp;
bool byte[8] = {0,0,0,0,0,0,0,0}; //used to store 8 bit chunks
unsigned int ibyte; //used to construct a byte as a number
for(int i=0;i<=(stream.Size()-8);i+=8)
{
ibyte=0;
//I could use the ReadInt8() function but this way has less overhead and we know its only 8 bit ints coming through
//get one byte
byte[0]=stream.Retrieve(i);
byte[1]=stream.Retrieve(i+1);
byte[2]=stream.Retrieve(i+2);
byte[3]=stream.Retrieve(i+3);
byte[4]=stream.Retrieve(i+4);
byte[5]=stream.Retrieve(i+5);
byte[6]=stream.Retrieve(i+6);
byte[7]=stream.Retrieve(i+7);
//yes I go backwards, this is intentional
if(byte[0])ibyte |=128;
if(byte[1])ibyte |=64;
if(byte[2])ibyte |=32;
if(byte[3])ibyte |=16;
if(byte[4])ibyte |=8;
if(byte[5])ibyte |=4;
if(byte[6])ibyte |=2;
if(byte[7])ibyte |=1;
temp.append(1,(unsigned char)ibyte);
}
return temp;
}
void RSbitstream::Hexdump()
{
HexDump(ToStr());
}
void RSbitstream::Display()
{
cout<<"Stream size: "<<stream.Size()<<"/"<<stream.MaxSize()<<endl;
int pos8=0;
for(int i=0;i<stream.Size();i++)
{
cout<<stream.Retrieve(i);
if(pos8==7)cout<<" ";
if(pos8>=7)pos8=0;
else pos8++;
}
cout<<endl;
}
void RSbitstream::Clear()
{
stream.clearList();
}
int RSbitstream::Size()
{
return stream.Size();
}
int RSbitstream::MaxSize()
{
return stream.MaxSize();
}
//writers:
//--------
void RSbitstream::WriteBit(bool tw)
{
stream.Add(tw>0 ? true : false);
}
//writes a int based on specified lenght (bits)
void RSbitstream::WriteVarInt(unsigned int tw,int bits)
{
if(bits>32)bits=32;
if(bits<1)bits=1;
unsigned long int orer=1;
for(int i=1;i<bits;i++)
{
orer*=2;
}
//make sure tw is not past its capacity
tw = (tw>((orer*2)-1)) ? ((orer*2)-1) : tw;
for(int i=0;i<bits;i++)
{
stream.Add(((orer & tw)==orer) ? true : false);
orer/=2;
}
}
void RSbitstream::WriteInt8(unsigned int tw)
{
WriteVarInt(tw,8);
}
void RSbitstream::WriteInt16(unsigned int tw)
{
WriteVarInt(tw,16);
}
void RSbitstream::WriteInt24(unsigned int tw)
{
WriteVarInt(tw,24);
}
void RSbitstream::WriteInt32(unsigned int tw)
{
WriteVarInt(tw,32);
}
void RSbitstream::WriteString(string tw)
{
for(int i=0;i<tw.size();i++)
{
WriteInt8((unsigned int)(unsigned char)tw[i]);
}
}
void RSbitstream::WriteBitstream(RSbitstream tw)
{
for(int i=0;i<tw.Size();i++)WriteBit(tw.ReadBit(i));
}
//readers
//--------
bool RSbitstream::ReadBit(int pos)
{
return stream.Retrieve(pos);
}
/*position: bit to start after
bits: how many bits to take to combine into a numerical value
ex:
pos: 3 bits: 8
101[01010101]010
*/
unsigned long int RSbitstream::ReadVarInt(int pos,int bits)
{
if(bits>32)bits=32; //probably bad idea to go higher
if(bits<1)bits=1; //make sure we take at least one (though this would be rather pointless)
unsigned long int tmp=0;
unsigned long int orer=1;
for(int i=1;i<bits;i++)
{
orer*=2;
}
for(int i=0;i<bits;i++)
{
if(stream.Retrieve(pos+i))tmp |=orer;
orer/=2;
}
return tmp;
}
unsigned long int RSbitstream::ReadInt8(int pos)
{
ReadVarInt(pos,8);
}
unsigned long int RSbitstream::ReadInt16(int pos)
{
ReadVarInt(pos,16);
}
unsigned long int RSbitstream::ReadInt24(int pos)
{
ReadVarInt(pos,24);
}
unsigned long int RSbitstream::ReadInt32(int pos)
{
ReadVarInt(pos,32);
}
string RSbitstream::ReadString(int pos,int chars)
{
string toreturn="";
for(int i=0;i<chars;i++)
{
int bitpos=pos+(i*8);
if(bitpos>=Size())break;
toreturn.append(1,(unsigned int)(unsigned char)ReadInt8(bitpos));
}
return toreturn;
}
//overloaders
void RSbitstream::operator+(RSbitstream val)
{
WriteBitstream(val);
}
RSbitstream& RSbitstream::operator=(RSbitstream& tw)
{
if (this == &tw) return *this; //make sure we're not assigning ourselves to ourselves
Clear();
WriteBitstream(tw);
return *this;
}
RSbitstream& RSbitstream::operator+=(RSbitstream& tw)
{
WriteBitstream(tw);
return *this;
}
RSbitstream& RSbitstream::operator=(string tw)
{
Clear();
WriteString(tw);
return *this;
}
RSbitstream& RSbitstream::operator+=(string tw)
{
WriteString(tw);
return *this;
}
I have a challenge for someone though, get the overloaders to actually work.
Archived topic from AOV, old topic ID:1203, old post ID:7633