Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
939 lines
21 KiB
C++
939 lines
21 KiB
C++
//===========================================================================//
|
|
// File: memstrm.cpp //
|
|
// Project: MUNGA Brick: Resource Manager //
|
|
// Contents: Implementation Details of resource management //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "StuffHeaders.hpp"
|
|
|
|
//#############################################################################
|
|
//########################## MemoryStream ###############################
|
|
//#############################################################################
|
|
|
|
MemoryStream::ClassData*
|
|
MemoryStream::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MemoryStream::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
MemoryStreamClassID,
|
|
"Stuff::MemoryStream",
|
|
RegisteredClass::DefaultData
|
|
);
|
|
Check_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MemoryStream::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream::MemoryStream(
|
|
void *stream_start,
|
|
DWORD stream_size,
|
|
DWORD initial_offset
|
|
):
|
|
RegisteredClass(DefaultData)
|
|
{
|
|
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(
|
|
ClassData *class_data,
|
|
void *stream_start,
|
|
DWORD stream_size,
|
|
DWORD initial_offset
|
|
):
|
|
RegisteredClass(class_data)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
streamStart = static_cast<BYTE*>(stream_start);
|
|
highWaterByte = streamStart;
|
|
streamSize = stream_size;
|
|
Verify(initial_offset <= stream_size);
|
|
currentPosition = streamStart + initial_offset;
|
|
currentBit = 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
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
|
|
|
|
Mem_Copy(ptr, GetPointer(), number_of_bytes, number_of_bytes);
|
|
AdvancePointer(number_of_bytes);
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
MemoryStream::ReadChar()
|
|
{
|
|
Check_Object(this);
|
|
DWORD bytes_remaining = GetBytesRemaining();
|
|
if (bytes_remaining > 0)
|
|
{
|
|
BYTE byte;
|
|
ReadBytes(&byte, 1);
|
|
return byte;
|
|
}
|
|
return End_Of_Stream;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MemoryStream::ReadLine(
|
|
char *buffer,
|
|
int max_number_of_bytes,
|
|
char continuator
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(buffer);
|
|
Verify(max_number_of_bytes > 0);
|
|
|
|
//
|
|
// while the character is not end of file &&
|
|
// there is room left in the buffer,
|
|
// copy the character into the buffer
|
|
//
|
|
int c = ReadChar();
|
|
if (c == End_Of_Stream)
|
|
return false;
|
|
|
|
char *p = buffer;
|
|
int i = 0;
|
|
|
|
Check_Object(FileStreamManager::Instance);
|
|
const char *eol = "\r\n";
|
|
DWORD eol_length = strlen(eol);
|
|
|
|
while (c != End_Of_Stream && i < max_number_of_bytes)
|
|
{
|
|
Check_Pointer(p);
|
|
Verify(i < max_number_of_bytes);
|
|
p[i] = (char)c;
|
|
|
|
//
|
|
// If we have met the end of line condition, break
|
|
//
|
|
switch (eol_length)
|
|
{
|
|
case 1:
|
|
if (p[i] == *eol)
|
|
{
|
|
c = End_Of_Stream;
|
|
}
|
|
else
|
|
{
|
|
++i;
|
|
c = ReadChar();
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (p[i] == eol[1] && i > 0 && p[i-1] == eol[0])
|
|
{
|
|
i -= 1;
|
|
c = End_Of_Stream;
|
|
}
|
|
else
|
|
{
|
|
++i;
|
|
c = ReadChar();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
STOP(("Unhandled eol style"));
|
|
}
|
|
}
|
|
if (i < max_number_of_bytes)
|
|
{
|
|
p[i] = '\0';
|
|
return true;
|
|
}
|
|
|
|
Warn(i >= max_number_of_bytes);
|
|
Verify(i == max_number_of_bytes);
|
|
p[i-1] = '\0';
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MString
|
|
MemoryStream::ReadString(
|
|
DWORD size_of_buffer,
|
|
char continuator
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Verify(size_of_buffer > 0);
|
|
|
|
static char buffer[1024];
|
|
Verify(size_of_buffer < sizeof(buffer));
|
|
|
|
MString temp_string;
|
|
if (ReadLine(buffer, size_of_buffer, continuator))
|
|
{
|
|
temp_string = buffer;
|
|
}
|
|
return temp_string;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
MemoryStream::ReadSwappedBytes(
|
|
void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(ptr);
|
|
Verify(number_of_bytes > 0);
|
|
Verify(GetBytesRemaining() >= number_of_bytes);
|
|
|
|
BYTE *buffer = new BYTE[number_of_bytes];
|
|
Check_Pointer(buffer);
|
|
ReadBytes(buffer, number_of_bytes);
|
|
for (DWORD i=0; i<number_of_bytes; ++i)
|
|
{
|
|
static_cast<BYTE*>(ptr)[i] = buffer[number_of_bytes-1 - i];
|
|
}
|
|
Check_Pointer(buffer);
|
|
delete[] buffer;
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MemoryStream::WriteLine(char *buffer)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(buffer);
|
|
|
|
WriteBytes(buffer, strlen(buffer));
|
|
WriteBytes("\r\n", 2);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
MemoryStream::WriteBytes(
|
|
const void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(ptr);
|
|
Verify(number_of_bytes > 0);
|
|
|
|
Mem_Copy(GetPointer(), ptr, number_of_bytes, GetBytesRemaining());
|
|
AdvancePointer(number_of_bytes);
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
MemoryStream::WriteSwappedBytes(
|
|
const void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(ptr);
|
|
Verify(number_of_bytes > 0);
|
|
Verify(GetBytesRemaining() >= number_of_bytes);
|
|
|
|
BYTE *buffer = new BYTE[number_of_bytes];
|
|
Check_Pointer(buffer);
|
|
for (DWORD i=0; i<number_of_bytes; ++i)
|
|
{
|
|
buffer[number_of_bytes-1 - i] = static_cast<const BYTE*>(ptr)[i];
|
|
}
|
|
WriteBytes(buffer, number_of_bytes);
|
|
Check_Pointer(buffer);
|
|
delete[] buffer;
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
MemoryStreamIO::Write(
|
|
MemoryStream *stream,
|
|
const MemoryStream *input_stream
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
Check_Object(input_stream);
|
|
|
|
return
|
|
stream->WriteBytes(
|
|
input_stream->GetPointer(),
|
|
input_stream->GetBytesRemaining()
|
|
);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Bit packing methods...
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
#if 0
|
|
|
|
// quick reference for the boneheads...
|
|
|
|
// >> shift right
|
|
// << shift left
|
|
// ~ complement
|
|
// ^ exclusive or - 1 if either but not both bits are 1
|
|
// | and - 1 if either bit is one
|
|
// & or - 1 if both bits are one
|
|
|
|
// 0000|1111 << 4 = 1111|0000
|
|
// 1111|0000 >> 2 = 0011|1100
|
|
// ~1111|0000 = 0000|1111
|
|
|
|
//
|
|
// 0000|1111
|
|
// ^ 1010|1010
|
|
//---------------
|
|
// 1010|0101
|
|
|
|
//
|
|
// 0000|0101
|
|
// | 1100|1100
|
|
//---------------
|
|
// 1100|1101
|
|
|
|
//
|
|
// 0000|0101
|
|
// & 1100|1100
|
|
//---------------
|
|
// 0000|0100
|
|
|
|
|
|
|
|
// set a number to a specific value
|
|
|
|
|
|
|
|
// bitmasks
|
|
|
|
//0x01 // 0000|0001
|
|
//0x03 // 0000|0011
|
|
//0x07 // 0000|0111
|
|
//0x0f // 0000|1111
|
|
//0x1f // 0001|1111
|
|
//0x3f // 0011|1111
|
|
//0x7f // 0111|1111
|
|
//0xff // 1111|1111
|
|
|
|
// inverted bitmasks
|
|
|
|
//0x80 // 1000|0000
|
|
//0xc0 // 1100|0000
|
|
//0xe0 // 1110|0000
|
|
//0xf0 // 1111|0000
|
|
//0xf8 // 1111|1000
|
|
//0xfc // 1111|1100
|
|
//0xfe // 1111|1110
|
|
//0xff // 1111|1111
|
|
|
|
|
|
|
|
Verify(bit_count > 0);
|
|
Verify(bit_count < 32);
|
|
|
|
unsigned int bit_count = 0;
|
|
bit_count = 0x1 << i;
|
|
|
|
SPEW(("jerryeds", "%u %u", i,bit_count));
|
|
|
|
#endif
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
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 = Cast_Pointer(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;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
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 = Cast_Pointer(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::ReadBitsToScaledInt(int &number, int min, int max, DWORD number_of_bits)
|
|
{
|
|
|
|
DWORD buffer = 0x0;
|
|
|
|
ReadUnsafeBits(&buffer, number_of_bits);
|
|
|
|
number = Scaled_Int_From_Bits(buffer, min, max, number_of_bits);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
MemoryStream&
|
|
MemoryStream::WriteScaledIntToBits(const int &number, int min, int max, DWORD number_of_bits)
|
|
{
|
|
Check_Object(this);
|
|
|
|
DWORD buffer;
|
|
|
|
buffer = Scaled_Int_To_Bits(number, min, max, number_of_bits);
|
|
|
|
WriteBits(&buffer, number_of_bits);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
MemoryStream&
|
|
MemoryStream::ReadBitsToScaledFloat(float &number, float min, float max, DWORD number_of_bits)
|
|
{
|
|
Check_Object(this);
|
|
|
|
DWORD buffer = 0x0;
|
|
|
|
ReadBits(&buffer, number_of_bits);
|
|
|
|
number = Scaled_Float_From_Bits(buffer, min, max, number_of_bits);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
MemoryStream&
|
|
MemoryStream::WriteScaledFloatToBits(const float &number, float min, float max, DWORD number_of_bits)
|
|
{
|
|
Check_Object(this);
|
|
|
|
DWORD buffer;
|
|
|
|
buffer = Scaled_Float_To_Bits(number, min, max, number_of_bits);
|
|
|
|
WriteBits(&buffer, number_of_bits);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MemoryStream::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
Verify(DWORD(currentPosition - streamStart) <= streamSize);
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### DynamicMemoryStream ############################
|
|
//#############################################################################
|
|
|
|
//
|
|
// calculate the allocation size for stream
|
|
//
|
|
static inline DWORD
|
|
Calculate_Buffer_Size(DWORD needed)
|
|
{
|
|
return (needed+0x80)&~0x7F;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DynamicMemoryStream::DynamicMemoryStream(DWORD stream_size):
|
|
MemoryStream(NULL, stream_size)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
bufferSize = Calculate_Buffer_Size(stream_size);
|
|
streamStart = new BYTE[bufferSize];
|
|
highWaterByte = streamStart;
|
|
Check_Pointer(streamStart);
|
|
|
|
currentPosition = streamStart;
|
|
streamSize = stream_size;
|
|
ownsStream = true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DynamicMemoryStream::DynamicMemoryStream(const DynamicMemoryStream &otherStream):
|
|
MemoryStream(NULL, otherStream.GetSize())
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(&otherStream);
|
|
|
|
bufferSize = otherStream.bufferSize;
|
|
streamStart = new BYTE[bufferSize];
|
|
highWaterByte = streamStart;
|
|
Check_Pointer(streamStart);
|
|
|
|
streamSize = otherStream.GetSize();
|
|
Mem_Copy(streamStart, otherStream.streamStart, streamSize, bufferSize);
|
|
currentPosition = streamStart + otherStream.GetBytesUsed();
|
|
ownsStream = true;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DynamicMemoryStream::DynamicMemoryStream(
|
|
void *stream_start,
|
|
DWORD stream_size,
|
|
DWORD initial_offset
|
|
):
|
|
MemoryStream(stream_start, stream_size, initial_offset)
|
|
{
|
|
Check_Pointer(this);
|
|
ownsStream = false;
|
|
bufferSize = stream_size;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DynamicMemoryStream::~DynamicMemoryStream()
|
|
{
|
|
Check_Object(this);
|
|
if (ownsStream)
|
|
{
|
|
Check_Pointer(streamStart);
|
|
delete[] streamStart;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
DynamicMemoryStream::AllocateBytes(DWORD count)
|
|
{
|
|
Check_Object(this);
|
|
|
|
DWORD current_offset = currentPosition - streamStart;
|
|
DWORD new_stream_size = current_offset + count;
|
|
if (ownsStream && bufferSize - current_offset < count)
|
|
{
|
|
bufferSize = Calculate_Buffer_Size(new_stream_size);
|
|
BYTE *new_stream_start = new BYTE[bufferSize];
|
|
Check_Pointer(new_stream_start);
|
|
|
|
Mem_Copy(new_stream_start, streamStart, streamSize, bufferSize);
|
|
Check_Pointer(streamStart);
|
|
delete[] streamStart;
|
|
streamStart = new_stream_start;
|
|
streamSize = new_stream_size;
|
|
currentPosition = streamStart + current_offset;
|
|
highWaterByte = currentPosition;
|
|
}
|
|
else if (new_stream_size > streamSize)
|
|
streamSize = new_stream_size;
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
DynamicMemoryStream::WriteBytes(
|
|
const void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(ptr);
|
|
Verify(number_of_bytes > 0);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If we own the stream, and we don't have enough memory to accept the
|
|
// write, copy the buffer and make a new stream that is bigger
|
|
//--------------------------------------------------------------------
|
|
//
|
|
AllocateBytes(number_of_bytes);
|
|
Mem_Copy(
|
|
GetPointer(),
|
|
ptr,
|
|
number_of_bytes,
|
|
MemoryStream::GetBytesRemaining()
|
|
);
|
|
AdvancePointer(number_of_bytes);
|
|
|
|
bufferSize = Max(bufferSize, GetBytesUsed());
|
|
return *this;
|
|
}
|
|
|