ReplicatorID ReplicatorID::Null;
char AssetsDirectory1[MAX_PATH];
HWND hWindow;

MemoryStream::MemoryStream(
	void *stream_start,
	DWORD stream_size,
	DWORD initial_offset
)
{
	Check_Pointer(this);

	streamStart = static_cast<BYTE*>(stream_start);
	highWaterByte = streamStart;
	streamSize = stream_size;
	Verify(initial_offset <= stream_size);
	currentPosition = streamStart + initial_offset;
	currentBit = Empty_Bit_Buffer;
}

MemoryStream::~MemoryStream()
{
}

MemoryStream&
	MemoryStream::ReadBytes(
		void *ptr,
		DWORD number_of_bytes
	)
{
	Check_Object(this);
	Check_Pointer(ptr);
	Verify(number_of_bytes > 0);
	#if defined(_ARMOR)
		DWORD remaining = GetBytesRemaining();
		Verify(remaining >= number_of_bytes);
	#endif

	memcpy(ptr, GetPointer(), number_of_bytes);
	AdvancePointer(number_of_bytes);
	return *this;
}

MemoryStream&
	MemoryStream::WriteBytes(
		const void *ptr,
		DWORD number_of_bytes
	)
{
	Check_Object(this);
	Check_Pointer(ptr);
	Verify(number_of_bytes > 0);

	memcpy(GetPointer(), ptr, number_of_bytes);
	AdvancePointer(number_of_bytes);
	return *this;
}


void
	MemoryStream::WriteByteAlign()
{
	if (currentBit == 0 || currentBit == Empty_Bit_Buffer)
	{
		return;
	}
	Check_Object(this);
	//SPEW(("jerryeds", "WRITE : %x", workingBitBuffer));
	WriteBytes(&workingBitBuffer, 1);
	workingBitBuffer = 0x00;
	currentBit = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MemoryStream::ReadByteAlign()
{

	

	if (currentBit == Empty_Bit_Buffer)
	{
		return;
	}
	Check_Object(this);
	
	// we just read this byte but didn't read any bits..
	// so unread it. 
	if (currentBit == 0)
	{
		RewindPointer(1);
	}
	
	// this will trigger the next read...
	currentBit = Empty_Bit_Buffer;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MemoryStream&
	MemoryStream::ReadBit(bool &bit_value)
{
	Check_Object(this);

	int result = 0;
	
	if (currentBit == Empty_Bit_Buffer)
	{
		ReadBytes(&workingBitBuffer, 1);
		//SPEW(("jerryeds", "READ : %x", workingBitBuffer));
		currentBit = 0;
	}	


	Verify(currentBit >= 0);
	Verify(currentBit <  8);

	result = (0x01 & (workingBitBuffer >> currentBit));
	bit_value = (result)?true:false;

	currentBit++;
	if (currentBit > 7)
	{

		if (GetBytesRemaining())
		{
			ReadBytes(&workingBitBuffer, 1);
			//SPEW(("jerryeds", "READ : %x", workingBitBuffer));
			currentBit = 0;
		}
		else
		{
			currentBit = Empty_Bit_Buffer;
		}
	}

	return *this;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
 
MemoryStream&
	MemoryStream::WriteBit(const bool &bit_value)
{
	Check_Object(this);

	int int_bit_value = (bit_value)?1:0;
	
	if (currentBit == Empty_Bit_Buffer)
	{
		currentBit = 0;
		workingBitBuffer = 0x0;
	}

	Verify(currentBit >= 0);
	Verify(currentBit <  8);

	workingBitBuffer |= (int_bit_value << currentBit);
	
	
	currentBit++;
	if (currentBit > 7)
	{
		WriteBytes(&workingBitBuffer, 1);
		//SPEW(("jerryeds", "WRITE : %x", workingBitBuffer));
		workingBitBuffer = 0x00;
		currentBit = 0;
	}
	


	return *this;
}

Adept::AdeptNetMissionParameters::AdeptNetMissionParameters()
{
	ResetParameters();
}

void Adept::AdeptNetMissionParameters::ResetParameters(void)
{
	m_runDedicated = 0;
	m_closedGame = 0;
	m_playerLimit = 16;

	m_visibility = 0;

}


void Adept::AdeptNetMissionParameters::SaveParameters(DynamicMemoryStream *stream)
{
	stream->WriteBits(&m_runDedicated, 1);
	stream->WriteBits(&m_closedGame, 1);
	stream->WriteBits(&m_playerLimit, 8);			// 256
	stream->WriteBits(&m_visibility,3);//5
}

void Adept::AdeptNetMissionParameters::LoadParameters(MemoryStream *stream)
{
	stream->ReadBits(&m_runDedicated, 1);
	stream->ReadBits(&m_closedGame, 1);
	stream->ReadBits(&m_playerLimit, 8);// 256
	stream->ReadBits(&m_visibility,3);//5
}

NetMissionParameters::TeamParameters::TeamParameters()
{
	ResetParameters(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void NetMissionParameters::TeamParameters::ResetParameters(int index)
{
	m_maxPlayersOnTeam = 16;
	m_minimumTonnage = 0;
	m_maximumTonnage = 100;
	m_maximumTotalTonnage = 1600;
	m_currentTotalTonnage = 0;
	m_skin = (int)'0';
	m_skin += index;
	m_alignment = index;

	m_allowedMech[0] = 0xffffffff;
	m_allowedBeam[0] = 0xfffffffd;
	m_allowedMissile[0] = 0xff3bffff;
	m_allowedProjectile[0] = 0xffffdfff;
	m_allowedSubsystem[0] = 0xffffffff;
	m_allowedMech[1] = 0xffffffff;
	m_allowedBeam[1] = 0xffffffff;
	m_allowedMissile[1] = 0xffffffff;
	m_allowedProjectile[1] = 0xffffffff;
	m_allowedSubsystem[1] = 0xffffffff;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void NetMissionParameters::TeamParameters::SaveParameters(DynamicMemoryStream *stream)
{

	stream->WriteBits(&m_maxPlayersOnTeam,7);
	stream->WriteBits(&m_minimumTonnage,8);
	stream->WriteBits(&m_maximumTonnage,8);
	stream->WriteBits(&m_maximumTotalTonnage,16);
	stream->WriteBits(&m_currentTotalTonnage,8*sizeof(Scalar));
	stream->WriteBits(&m_skin,8);
	stream->WriteBits(&m_alignment,4);


	stream->WriteBits(&m_allowedMech[0],32);
	stream->WriteBits(&m_allowedBeam[0],32);
	stream->WriteBits(&m_allowedMissile[0],32);
	stream->WriteBits(&m_allowedProjectile[0],32);
	stream->WriteBits(&m_allowedSubsystem[0],32);
	stream->WriteBits(&m_allowedMech[1],32);
	stream->WriteBits(&m_allowedBeam[1],32);
	stream->WriteBits(&m_allowedMissile[1],32);
	stream->WriteBits(&m_allowedProjectile[1],32);
	stream->WriteBits(&m_allowedSubsystem[1],32);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


void NetMissionParameters::TeamParameters::LoadParameters(MemoryStream *stream)
{

	stream->ReadBits(&m_maxPlayersOnTeam,7);
	stream->ReadBits(&m_minimumTonnage,8);
	stream->ReadBits(&m_maximumTonnage,8);
	stream->ReadBits(&m_maximumTotalTonnage,16);
	stream->ReadBits(&m_currentTotalTonnage,8*sizeof(Scalar));
	stream->ReadBits(&m_skin,8);
	stream->ReadBits(&m_alignment,4);

	stream->ReadBits(&m_allowedMech[0],32);
	stream->ReadBits(&m_allowedBeam[0],32);
	stream->ReadBits(&m_allowedMissile[0],32);
	stream->ReadBits(&m_allowedProjectile[0],32);
	stream->ReadBits(&m_allowedSubsystem[0],32);
	stream->ReadBits(&m_allowedMech[1],32);
	stream->ReadBits(&m_allowedBeam[1],32);
	stream->ReadBits(&m_allowedMissile[1],32);
	stream->ReadBits(&m_allowedProjectile[1],32);
	stream->ReadBits(&m_allowedSubsystem[1],32);
}

NetMissionParameters::MWNetMissionParameters::MWNetMissionParameters()
{
	m_mapID = 0;
	m_mapName[0] = '\0';
	m_scenarioName[0] = '\0';
	m_scenarioPath[0] = '\0';
	m_serverName[0] = '\0';
	m_serverIP[0] = '\0';
	m_scriptName[0] = '\0';
	m_scenarioText[0] = '\0';
	m_mapClientCRC = 0;

	ResetParameters();
}

void NetMissionParameters::MWNetMissionParameters::ResetParameters(void)
{
	AdeptNetMissionParameters::ResetParameters();

	m_joinInProgress = 1;
	m_joinInProgressCutOff = false;
	m_joinInProgressCutOffTime = 0;

	m_heatOn = true;
	m_killLimit = false;
	m_killLimitNumber = 0;
	m_respawnLimit = false;
	m_respawnLimitNumber = 0;
	m_forceRespawn = true;
	m_splashOn = false;
	m_weaponjamOn = false;
	m_ammobayfireOn = false;
// MSL 5.05 Advance Mode
	m_advancemodeOn = false;
// MSL 5.06 Armor Mode
	m_armormodeOn = false;
	m_splashPercentage = 100;
	m_unlimitedAmmo = false;
	m_friendlyFirePercentage = 100;
	m_allowZoom = true;
	m_allow3rdPerson = true;
	m_allowAutoAim = true;
	m_allowDeadToChat = false;
	m_invulnerableDrop = false;
	m_isNight = false;
	

	
	m_weather = false;
	m_radarMode = 0;

	m_reportStats = true;
	m_serverConnection = MWApplication::LAN;
	m_serverBandwidth = MWApplication::c_10_Mbps;
	


	m_onlyStockMech = false;
	m_minimumTonnage = 0;
	m_maximumTonnage = 100;

	m_allowedMech[0] = 0xffffffff;
	m_allowedBeam[0] = 0xfffffffd;
	m_allowedMissile[0] = 0xff3bffff;
	m_allowedProjectile[0] = 0xffffdfff;
	m_allowedSubsystem[0] = 0xffffffff;
	m_allowedMech[1] = 0xffffffff;
	m_allowedBeam[1] = 0xffffffff;
	m_allowedMissile[1] = 0xffffffff;
	m_allowedProjectile[1] = 0xffffffff;
	m_allowedSubsystem[1] = 0xffffffff;

	m_gameLength = 10;
	m_serverRecycle = 0;
	m_recycleDelay = 60;
	m_playMissionReview = 0;

	m_ruleType = CustomAttrition; //StockAttrition;
	m_deadMechCantSee = false;
	m_deadMechCantSeeOtherTeam = false;

	m_teamAllowed = false;
	m_teamCount = 8;
	m_allowdecaltransfer = false;
	m_useMapCycle = false;
	m_pureMapCycle = false;


	for (int i = 0; i < 8; ++i)
	{
		m_teamParams[i].ResetParameters(i);
	}

	m_maxPlayers = 0;
	m_maxBots = 0;

	strcpy(m_serverCPU, "cpu");
	//SPEW(("jerryeds", "RESET TIME : %d", m_gameLength));
}

void NetMissionParameters::MWNetMissionParameters::SaveParameters(DynamicMemoryStream *stream)
{
	AdeptNetMissionParameters::SaveParameters(stream);

	stream->WriteBits(&m_joinInProgress, 1);
	stream->WriteBits(&m_joinInProgressCutOff, 1);
	stream->WriteBits(&m_joinInProgressCutOffTime, 8); // minutes 256
	stream->WriteBits(&m_heatOn, 1);
	stream->WriteBits(&m_killLimit, 1);
	stream->WriteBits(&m_killLimitNumber, 8); //256
	stream->WriteBits(&m_respawnLimit, 1);
	stream->WriteBits(&m_respawnLimitNumber, 8); //256
	stream->WriteBits(&m_forceRespawn, 1);
	stream->WriteBits(&m_splashOn, 1);
	stream->WriteBits(&m_weaponjamOn, 1);
	stream->WriteBits(&m_ammobayfireOn, 1);
// MSL 5.05 Advance Mode
	stream->WriteBits(&m_advancemodeOn, 1);
// MSL 5.06 Armor Mode
	stream->WriteBits(&m_armormodeOn, 1);
	stream->WriteBits(&m_splashPercentage, 8); //256
	stream->WriteBits(&m_unlimitedAmmo, 1);
	stream->WriteBits(&m_friendlyFirePercentage, 8); //256
	stream->WriteBits(&m_allowZoom, 1);
	stream->WriteBits(&m_allow3rdPerson, 1);
	stream->WriteBits(&m_allowAutoAim, 1);
	stream->WriteBits(&m_allowDeadToChat, 1);
	stream->WriteBits(&m_invulnerableDrop, 1);
	stream->WriteBits(&m_onlyStockMech,1);
	stream->WriteBits(&m_minimumTonnage,8);
	stream->WriteBits(&m_maximumTonnage,8);
	stream->WriteBits(&m_allowedMech[0],32);
	stream->WriteBits(&m_allowedBeam[0],32);
	stream->WriteBits(&m_allowedMissile[0],32);
	stream->WriteBits(&m_allowedProjectile[0],32);
	stream->WriteBits(&m_allowedSubsystem[0],32);
	stream->WriteBits(&m_allowedMech[1],32);
	stream->WriteBits(&m_allowedBeam[1],32);
	stream->WriteBits(&m_allowedMissile[1],32);
	stream->WriteBits(&m_allowedProjectile[1],32);
	stream->WriteBits(&m_allowedSubsystem[1],32);
	stream->WriteBits(&m_gameLength, 8); // 256 minutes
	stream->WriteBits(&m_serverRecycle, 1);
	stream->WriteBits(&m_recycleDelay, 16); //65535 seconds
	stream->WriteBits(&m_playMissionReview, 1);
	stream->WriteBits(&m_isNight, 1);
	
	stream->WriteBits(&m_weather,1);
	stream->WriteBits(&m_radarMode,2);
	stream->WriteBits(&m_reportStats,1);
	stream->WriteBits(&m_serverConnection,5);//32
	stream->WriteBits(&m_serverBandwidth,5);//32
	stream->WriteBits(&m_ruleType, 5);//32
	stream->WriteBits(&m_deadMechCantSee,1);
	stream->WriteBits(&m_deadMechCantSeeOtherTeam,1);
	stream->WriteBits(&m_teamAllowed,1);
	stream->WriteBits(&m_teamCount, 4);
	stream->WriteBits(&m_allowdecaltransfer,1);
	stream->WriteBits(&m_useMapCycle,1);
	stream->WriteBits(&m_pureMapCycle,1);


	stream->WriteBits(&m_maxPlayers, 5); // 16 players maximum
	stream->WriteBits(&m_maxBots, 5); // 16 players maximum
	stream->WriteBits(&m_mapID, 16); // 65535 maps available
	stream->WriteBits(&m_mapClientCRC, 64);


	for (int i = 0; i < 8; ++i)
	{
		m_teamParams[i].SaveParameters(stream);
	}



	stream->WriteByteAlign();

	int map_length = strlen(&m_mapName[0]);
	stream->WriteBytes(&map_length, 1);
	if (map_length > 0)
		stream->WriteBytes(&m_mapName[0], map_length);
		
	int scn_length = strlen(&m_scenarioName[0]);
	stream->WriteBytes(&scn_length, 1);
	if (scn_length > 0)
		stream->WriteBytes(&m_scenarioName[0], scn_length);
	
	int scp_length = strlen(&m_scenarioPath[0]);
	stream->WriteBytes(&scp_length, 1);
	if (scp_length > 0)
		stream->WriteBytes(&m_scenarioPath[0], scp_length);

	int srn_length = strlen(&m_serverName[0]);
	stream->WriteBytes(&srn_length, 1);
	if (srn_length > 0)
		stream->WriteBytes(&m_serverName[0], srn_length);

	int sip_length = strlen(&m_serverIP[0]);
	stream->WriteBytes(&sip_length, 1);
	if (sip_length > 0)
		stream->WriteBytes(&m_serverIP[0], sip_length);

	int cpu_length = strlen(&m_serverCPU[0]);
	stream->WriteBytes(&cpu_length, 1);
	if (cpu_length > 0)
		stream->WriteBytes(&m_serverCPU[0], cpu_length);

	int scriptname_length = strlen(&m_scriptName[0]);
	stream->WriteBytes(&scriptname_length,1);
	if (scriptname_length > 0)
		stream->WriteBytes(&m_scriptName[0],scriptname_length);	

	int scenariotext_length = strlen(&m_scenarioText[0]); //_mbstrlen(&m_scenarioText[0]);
	++scenariotext_length;
	stream->WriteBytes(&scenariotext_length,4);
	if (scenariotext_length > 0)
		stream->WriteBytes(&m_scenarioText[0],scenariotext_length);	
}

void NetMissionParameters::MWNetMissionParameters::LoadParameters(MemoryStream *stream)
{
	AdeptNetMissionParameters::LoadParameters(stream);

	stream->ReadBits(&m_joinInProgress, 1);
	stream->ReadBits(&m_joinInProgressCutOff, 1);
	stream->ReadBits(&m_joinInProgressCutOffTime, 8); // minutes 256
	stream->ReadBits(&m_heatOn, 1);
	stream->ReadBits(&m_killLimit, 1);
	stream->ReadBits(&m_killLimitNumber, 8); //256
	stream->ReadBits(&m_respawnLimit, 1);
	stream->ReadBits(&m_respawnLimitNumber, 8); //256
	stream->ReadBits(&m_forceRespawn, 1);
	stream->ReadBits(&m_splashOn, 1);
	stream->ReadBits(&m_weaponjamOn, 1);
	stream->ReadBits(&m_ammobayfireOn, 1);
// MSL 5.05 Advance Mode
	stream->ReadBits(&m_advancemodeOn, 1);
// MSL 5.06 Armor Mode
	stream->ReadBits(&m_armormodeOn, 1);
	stream->ReadBits(&m_splashPercentage, 8); //256
	stream->ReadBits(&m_unlimitedAmmo, 1);
	stream->ReadBits(&m_friendlyFirePercentage, 8); //256
	stream->ReadBits(&m_allowZoom, 1);
	stream->ReadBits(&m_allow3rdPerson, 1);
	stream->ReadBits(&m_allowAutoAim, 1);
	stream->ReadBits(&m_allowDeadToChat, 1);
	stream->ReadBits(&m_invulnerableDrop, 1);
	stream->ReadBits(&m_onlyStockMech,1);
	stream->ReadBits(&m_minimumTonnage,8);
	stream->ReadBits(&m_maximumTonnage,8);
	stream->ReadBits(&m_allowedMech[0],32);
	stream->ReadBits(&m_allowedBeam[0],32);
	stream->ReadBits(&m_allowedMissile[0],32);
	stream->ReadBits(&m_allowedProjectile[0],32);
	stream->ReadBits(&m_allowedSubsystem[0],32);
	stream->ReadBits(&m_allowedMech[1],32);
	stream->ReadBits(&m_allowedBeam[1],32);
	stream->ReadBits(&m_allowedMissile[1],32);
	stream->ReadBits(&m_allowedProjectile[1],32);
	stream->ReadBits(&m_allowedSubsystem[1],32);
	stream->ReadBits(&m_gameLength, 8); // 256 minutes
	stream->ReadBits(&m_serverRecycle, 1);
	stream->ReadBits(&m_recycleDelay, 16); //65535 seconds
	stream->ReadBits(&m_playMissionReview, 1);
	stream->ReadBits(&m_isNight, 1);
	
	stream->ReadBits(&m_weather,1);
	stream->ReadBits(&m_radarMode,2);
	stream->ReadBits(&m_reportStats,1);
	stream->ReadBits(&m_serverConnection,5);//32
	stream->ReadBits(&m_serverBandwidth,5);//32
	stream->ReadBits(&m_ruleType, 5);//32
	stream->ReadBits(&m_deadMechCantSee,1);
	stream->ReadBits(&m_deadMechCantSeeOtherTeam,1);
	stream->ReadBits(&m_teamAllowed,1);
	stream->ReadBits(&m_teamCount, 4);
	stream->ReadBits(&m_allowdecaltransfer,1);
	stream->ReadBits(&m_useMapCycle,1);
	stream->ReadBits(&m_pureMapCycle,1);

	stream->ReadBits(&m_maxPlayers, 5); // 16 players max
	stream->ReadBits(&m_maxBots, 5); // 16 players max
	stream->ReadBits(&m_mapID, 16); // 65535 maps available
	stream->ReadBits(&m_mapClientCRC, 64);

	
	for (int i = 0; i < 8; ++i)
	{
		m_teamParams[i].LoadParameters(stream);
	}

	stream->ReadByteAlign();

	int map_length = 0;
	stream->ReadBytes(&map_length, 1);
	if (map_length > 0)
		stream->ReadBytes(&m_mapName[0], map_length);
	m_mapName[map_length] = '\0';
	
	int scn_length = 0;
	stream->ReadBytes(&scn_length, 1);
	if (scn_length > 0)
		stream->ReadBytes(&m_scenarioName[0], scn_length);
	m_scenarioName[scn_length] = '\0';
	
	int scp_length = 0;
	stream->ReadBytes(&scp_length, 1);
	if (scp_length > 0)
		stream->ReadBytes(&m_scenarioPath[0], scp_length);
	m_scenarioPath[scp_length] = '\0';

	int srn_length = 0;
	stream->ReadBytes(&srn_length, 1);
	if (srn_length > 0)
		stream->ReadBytes(&m_serverName[0], srn_length);
	m_serverName[srn_length] = '\0';

	int sip_length = 0;
	stream->ReadBytes(&sip_length, 1);
	if (sip_length > 0)
		stream->ReadBytes(&m_serverIP[0], sip_length);
	m_serverIP[sip_length] = '\0';

	int cpu_length = 0;
	stream->ReadBytes(&cpu_length, 1);
	if (cpu_length > 0)
		stream->ReadBytes(&m_serverCPU[0], cpu_length);
	m_serverCPU[cpu_length] = '\0';

	int scriptname_length = 0;
	stream->ReadBytes(&scriptname_length,1);
	if (scriptname_length > 0)
		stream->ReadBytes(&m_scriptName[0],scriptname_length);

	int scenariotext_length = 0;
	stream->ReadBytes(&scenariotext_length,4);
	if (scenariotext_length > 0)
		stream->ReadBytes(&m_scenarioText[0],scenariotext_length);
}

MemoryStream&
	MemoryStream::WriteBits(
		const void *ptr, 
		DWORD number_of_bits
	)
{
	Check_Object(this);
	Check_Pointer(ptr);


	if (currentBit == Empty_Bit_Buffer)
	{
		workingBitBuffer = 0x00;
		currentBit = 0;
	}
	
	Verify(currentBit >= 0);
	Verify(currentBit < 8);


	

	int total_number_of_bytes = (int)(number_of_bits/8.0f);
	int total_remainder_bits = number_of_bits  - (total_number_of_bytes*8);

	if ( total_remainder_bits != 0)
	{
		total_number_of_bytes += 1;
	}

	
	const BYTE *source_array = (const BYTE *)ptr;
	int source_byte_counter = 0;
	
	int bits_remaining = number_of_bits;

	while (bits_remaining > 0)
	{
	
		
		// if we are writing the full byte
		const BYTE *source = &source_array[source_byte_counter];
	
		int total_bits_to_be_written = 8;
		Max_Clamp(total_bits_to_be_written, bits_remaining);
		
		int bits_in_first_destination_byte = total_bits_to_be_written;
		Max_Clamp(bits_in_first_destination_byte, 8-currentBit);


		
		// make sure our destination is empty
		workingBitBuffer &= (0xff >> (8-currentBit));
		// move the source data to the correct bit location
		BYTE new_source = (BYTE)(*source << currentBit);
		// put the adjusted source into the destination
		workingBitBuffer |= new_source;



		currentBit += bits_in_first_destination_byte;


		if (currentBit == 8)
		{
			int bits_in_second_destination_byte = total_bits_to_be_written - bits_in_first_destination_byte;

			//SPEW(("jerryeds", "WRITE : %x", workingBitBuffer));
			WriteBytes(&workingBitBuffer, 1);
			++source_byte_counter;
			workingBitBuffer = 0x00;
			currentBit = 0;

			if (bits_in_second_destination_byte)
			{
				// remove bits we have already used
				workingBitBuffer = (BYTE)(*source >> bits_in_first_destination_byte);
				currentBit = bits_in_second_destination_byte;
			}

		}


		bits_remaining -= total_bits_to_be_written;
	
	}

	Verify(currentBit >= 0);
	Verify(currentBit < 8);


	return *this;
}


MemoryStream&
	MemoryStream::ReadUnsafeBits(
		void *ptr, 
		DWORD number_of_bits
	)
{
	Check_Object(this);
	Check_Pointer(ptr);

	if (currentBit == Empty_Bit_Buffer)
	{
		ReadBytes(&workingBitBuffer, 1);
		//SPEW(("jerryeds", "READ : %x", workingBitBuffer));
		currentBit = 0;
	}

	Verify(currentBit >= 0);
	Verify(currentBit < 8);

	int total_number_of_bytes = (int)(number_of_bits/8.0f);
	int total_remainder_bits = number_of_bits - (total_number_of_bytes*8);

	if ( total_remainder_bits != 0)
	{
		total_number_of_bytes += 1;
	}

	BYTE *dest_array = (BYTE *)ptr;
	int dest_byte_counter = 0;

	int bits_remaining = number_of_bits;

	while (bits_remaining > 0)
	{
		BYTE *dest = &dest_array[dest_byte_counter];
		// empy out destination
		*dest = 0x00;


		int total_bits_to_be_read = 8;
		Max_Clamp(total_bits_to_be_read, bits_remaining);
		
		int bits_in_first_source_byte = total_bits_to_be_read;
		Max_Clamp(bits_in_first_source_byte, 8-currentBit);

		// make a mask of bits to be used
		int bit_mask = 0xff >> (8-bits_in_first_source_byte);

		// shift past the used bits in the buffer
		*dest = (BYTE)(workingBitBuffer >> currentBit);
		
		// remove any bits from the next set that tagged along
		*dest &= bit_mask;
		

		currentBit += bits_in_first_source_byte;


		if (currentBit == 8)
		{
			int bits_in_second_source_byte = total_bits_to_be_read - bits_in_first_source_byte;

			if (GetBytesRemaining())
			{
				ReadBytes(&workingBitBuffer, 1);
				//SPEW(("jerryeds", "READ : %x", workingBitBuffer));
			}

			++dest_byte_counter;
			currentBit = 0;

			if (bits_in_second_source_byte)
			{
				// make a bitmask of the used bits
				bit_mask = 0xff >> (8-bits_in_second_source_byte);
				// mask the used bits out of the buffer and then shift the buffer to the correct 
				// bit location.  Then combine it with the destination
				*dest |= ((workingBitBuffer & bit_mask) << bits_in_first_source_byte);


				currentBit = bits_in_second_source_byte;
			}
		}


		bits_remaining -= total_bits_to_be_read;


	}

	Verify(currentBit >= 0);
	Verify(currentBit < 8);


	return *this;
}

