////////////////////////////////////////////////////////////////////////////
//
// Bit input and output classes
// (c)2003 Jeremy Collake and Bitsum Technologies
// jeremy@bitsum.com
//
// This code may not be used without the permission of Bitsum Technologies.
// To use this code in your application, please email us at support@bitsum.com
// and we will be happy to grant you a free license.
//
//////////////////////////////////////////////////////////////////////////////

#include "bitio.h"
#include <excpt.h>

bitout::bitout(PSTREAM plStream) 
{
	pStream=plStream;
	cByte=0;
	nBitCount=1;		// must be initialized to 1
}

bitout::~bitout()
{
	// in case stream is deallocated before 
	// destructor is called, we must catch exception.
	__try 
	{
		Flush();
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{				
	}
}

void bitout::EmitBit(BIT bBit) 
{	
	cByte<<=1;
	cByte|=(unsigned int)bBit;
	nBitCount<<=1;
	if(!nBitCount)
	{			
		*pStream=cByte;
		pStream++;			
		nBitCount=1;
	}
}

void bitout::EmitByte(BYTE ctByte)
{
	for(unsigned int nI=0;nI<8;nI++)
	{
		EmitBit((bool)(ctByte>>7));
		ctByte<<=1;
	}
}

void bitout::EmitBits(DWORD ctByte, DWORD nBits)
{
	ctByte<<=(31-nBits+1);
	for(unsigned int nI=0;nI<nBits;nI++)
	{
		EmitBit((bool)(ctByte>>31));
		ctByte<<=1;
	}
}

void bitout::Flush()
{
	while(nBitCount!=1)
	{
		EmitBit(false);		
	}		
}

PSTREAM bitout::ptr()
{
	return pStream;
}

// the following save and restore the current
// stream position. Please note that this 
// mechanism only allows for one push, obviously.
// Since more are not needed, a more complex
// structure will hinder performance. Implement
// typical stack if more are needed at any
// point.
void bitout::push()
{
	pushed_nBitCount=nBitCount;
	pushed_cByte=cByte;
	pushed_pStream=pStream;
}

void bitout::pop()
{
	nBitCount=pushed_nBitCount;
	cByte=pushed_cByte;
	pStream=pushed_pStream;
}

// emit word w to the stream
void bitout::EmitWord(WORD w)
{
	for(unsigned int nI=0;nI<16;nI++)
	{
		EmitBit((bool)(w>>15));
		w<<=1;
	}
}
void bitout::EmitDword(DWORD dw)
{
	for(unsigned int nI=0;nI<32;nI++)
	{
		EmitBit((bool)(dw>>31));
		dw<<=1;
	}
}


bitin::bitin(PSTREAM plStream) 
{
	pStream=plStream;
	cByte=0;
	nBitCount=0;
}

BIT bitin::GetBit()
{	
	nBitCount>>=1;	
	if(!nBitCount)
	{			
		cByte=*pStream;
		pStream++;				
		nBitCount=0x80;
	}
	return cByte&nBitCount?true:false;
}

BYTE bitin::GetByte() 
{
	BYTE cR=0;
	for(unsigned int nI=0;nI<8;nI++)
	{
		cR|=GetBit()<<(7-nI);
	}
	return cR;
}	

WORD bitin::GetWord()
{
	WORD w=0;
	for(unsigned int nI=0;nI<16;nI++)
	{
		w|=GetBit()<<(15-nI);
	}
	return w;
}

DWORD bitin::GetDword()
{
	DWORD dw=0;
	for(unsigned int nI=0;nI<32;nI++)
	{
		dw|=GetBit()<<(31-nI);
	}
	return dw;
}

DWORD bitin::GetBits(DWORD dwBits)
{
	DWORD dwR=0;
	for(unsigned int nI=0;nI<dwBits;nI++)
	{
		dwR|=GetBit()<<((dwBits-1)-nI);
	}
	return dwR;
}