Bit stream class (C++)

Anything regarding UO or Age of Valor
Locked
User avatar
Red Squirrel
Posts: 29209
Joined: Wed Dec 18, 2002 12:14 am
Location: Northern Ontario
Contact:

Bit stream class (C++)

Post by Red Squirrel »

I made this a while back to manipulate data at the bit level. I also included dependency function/classes

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. :P

Archived topic from AOV, old topic ID:1203, old post ID:7633
Honk if you love Jesus, text if you want to meet Him!
Locked