SA-MP/raknet/BitStream_NoTemplate.h
RD42 bcdbedc0be Revert RakNet source files back to the original v2.518 state
* Add RakNet source files to the VS project
2024-08-16 23:33:48 +08:00

713 lines
23 KiB
C++

/// \depreciated
#if defined(_MSC_VER) && _MSC_VER < 1299 // VC6 doesn't support template specialization
#ifndef __BITSTREAM_H
#define __BITSTREAM_H
#ifdef _WIN32
#if defined (_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define HAS_INT64
#endif
#else
#include <stdint.h>
#define HAS_INT64
#endif
// Arbitrary size, just picking something likely to be larger than most packets
#define BITSTREAM_STACK_ALLOCATION_SIZE 256
/** \note If you want the default network byte stream to be
in Network Byte Order (Big Endian) then #define __BITSTREAM_BIG_END
otherwise the default is 'Little Endian'. If your CPU has the same
Byte Order as your network stream, you can cut out some overheads
using #define __BITSTREAM_NATIVE_END --- if this is defined,
the __BITSTREAM_BIG_END flag becomes ineffective.
*/
#include "NetworkTypes.h"
namespace RakNet
{
/**
* This macro transforms a bit in byte
* @param x Transform a bit to a byte
*/
#define BITS_TO_BYTES(x) (((x)+7)>>3)
#define BYTES_TO_BITS(x) (x<<3)
/**
* @brief Packets encoding and decoding facilities
*
* Helper class to encode and decode packets.
*
*/
class BitStream
{
public:
/**
* Default Constructor
*/
BitStream();
/**
* Preallocate some memory for the construction of the packet
* @param initialBytesToAllocate the amount of byte to pre-allocate.
*/
BitStream( int initialBytesToAllocate );
/**
* Initialize the BitStream object using data from the network.
* Set _copyData to true if you want to make an internal copy of
* the data you are passing. You can then Write and do all other
* operations Set it to false if you want to just use a pointer to
* the data you are passing, in order to save memory and speed.
* You should only then do read operations.
* @param _data An array of bytes.
* @param lengthInBytes Size of the @em _data.
* @param _copyData Does a copy of the input data.
*/
BitStream( char* _data, unsigned int lengthInBytes, bool _copyData );
/**
* Destructor
*/
~BitStream();
/**
* Reset the bitstream for reuse
*/
void Reset( void );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const bool input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const unsigned char input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const char input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const unsigned short input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const short input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const unsigned int input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const int input );
#if defined ( __APPLE__ ) || defined (__APPLE_CC__ )||defined ( _WIN32 )
// These are only provided for MS Windows and
// Mac OSX (G4 processor) convenience and are
// equivalent to the (int) versions.
// The use of 'long' for any network data is
// a fault since it will not be portable to 64-bit CPUs.
void Write( const unsigned long input );
void Write( const long input );
#endif
#ifdef HAS_INT64
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const uint64_t input );
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const int64_t input );
#endif
/**
* Write the native types to the end of the buffer
* without any compression mecanism.
* @param input The data
*/
void Write( const float input );
/**
* Write the native types to the end of the buffer
* without any compression mechanism.
* @param input The data
*/
void Write( const double input );
/**
* Write an array or casted stream. It is supposed to
* be raw data. It is also not possible to deal with endian problem
* @param input a byte buffer
* @param numberOfBytes the size of the byte buffer
*/
void Write( const char* input, const int numberOfBytes );
void Write( const NetworkID networkId );
/**
* Copy from another bitstream
* @bitStream the bitstream to copy from
*/
void Write( const BitStream *bitStream );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const unsigned char input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const char input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const unsigned short input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const short input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const unsigned int input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const int input );
#if defined ( __APPLE__ ) || defined ( __APPLE_CC__ ) || defined ( _WIN32 )
// These are only provided for MS Windows and
// Mac OSX (G4 processor) convenience and are
// equivalent to the (int) versions.
// The use of 'long' for any network data is
// a fault since it will not be portable to 64-bit CPUs.
void WriteCompressed( const unsigned long input );
void WriteCompressed( const long input );
#endif
#ifdef HAS_INT64
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const uint64_t input );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const int64_t input );
#endif
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const float input );
/**
* Write a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12 bytes. Will further compress y or z axis aligned vectors.
* Accurate to 1/32767.5.
* @param x x
* @param y y
* @param z z
*/
void WriteNormVector( float x, float y, float z );
/**
* Write a vector, using 10 bytes instead of 12.
* Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
* @param x x
* @param y y
* @param z z
*/
void WriteVector( float x, float y, float z );
/**
* Write a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
* @param w w
* @param x x
* @param y y
* @param z z
*/
void WriteNormQuat( float w, float x, float y, float z);
/**
* Write an orthogonal matrix by creating a quaternion, and writing 3 components of the quaternion in 2 bytes each
* for 6 bytes instead of 36
*/
void WriteOrthMatrix(
float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22 );
/**
* Write the native types with simple compression.
* Best used with negatives and positives close to 0
* @param input The data.
*/
void WriteCompressed( const double input );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( bool &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( unsigned char &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( char &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( unsigned short &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( short &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( unsigned int &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( int &output );
#if defined ( __APPLE__ ) || defined ( __APPLE_CC__ ) || defined ( _WIN32 )
// These are only provided for MS Windows and
// Mac OSX (G4 processor) convenience and are
// equivalent to the (int) versions.
// The use of 'long' for any network data is
// a fault since it will not be portable to 64-bit CPUs.
bool Read( unsigned long &output );
bool Read( long &output );
#endif
#ifdef HAS_INT64
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( uint64_t &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( int64_t &output );
#endif
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( float &output );
/**
* Read the native types from the front of the buffer
* @param output The readed value.
* @return true on success false otherwise. The result of a reading
* can only be wrong in the case we reach the end of the BitStream
* with some missing bits.
*/
bool Read( double &output );
/**
* Read an array or casted stream of byte. The array
* is raw data. There is no automatic conversion on
* big endian arch
* @param output The result byte array. It should be larger than @em numberOfBytes.
* @param numberOfBytes The number of byte to read
* @return true on success false if there is some missing bytes.
*/
bool Read( char* output, const int numberOfBytes );
bool Read( NetworkID &output);
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( unsigned char & output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( char &output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( unsigned short &output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( short &output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( unsigned int &output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( int &output );
#if defined ( __APPLE__ ) || defined ( __APPLE_CC__ )|| defined ( _WIN32 )
// These are only provided for MS Windows and
// Mac OSX (G4 processor) convenience and are
// equivalent to the (int) versions.
// The use of 'long' for any network data is
// a fault since it will not be portable to 64-bit CPUs.
bool ReadCompressed( unsigned long &output );
bool ReadCompressed( long &output );
#endif
#ifdef HAS_INT64
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( uint64_t &output );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( int64_t &output );
#endif
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( float &output );
/**
* Read a normalized 3D vector, using (at most) 4 bytes + 3 bits instead of 12 bytes. Will further compress y or z axis aligned vectors.
* Accurate to 1/32767.5.
* @param x x
* @param y y
* @param z z
*/
bool ReadNormVector( float &x, float &y, float &z );
/**
* Read 3 floats, using 10 bytes, where those floats comprise a vector
* Loses accuracy to about 3/10ths and only saves 2 bytes, so only use if accuracy is not important.
* @param x x
* @param y y
* @param z z
*/
bool ReadVector( float &x, float &y, float &z );
/**
* Read a normalized quaternion in 6 bytes + 4 bits instead of 16 bytes. Slightly lossy.
* @param w w
* @param x x
* @param y y
* @param z z
*/
bool ReadNormQuat( float &w, float &x, float &y, float &z);
/**
* Read an orthogonal matrix from a quaternion, reading 3 components of the quaternion in 2 bytes each and extrapolatig the 4th.
* for 6 bytes instead of 36
*/
bool ReadOrthMatrix(
float &m00, float &m01, float &m02,
float &m10, float &m11, float &m12,
float &m20, float &m21, float &m22 );
/**
* Read the types you wrote with WriteCompressed
* @param output The read value
* @return true on success, false on not enough data to read
*/
bool ReadCompressed( double &output );
/**
* Sets the read pointer back to the beginning of your data.
*/
void ResetReadPointer( void );
/**
* Sets the write pointer back to the beginning of your data.
*/
void ResetWritePointer( void );
/**
* This is good to call when you are done with the stream to make
* sure you didn't leave any data left over void
*/
void AssertStreamEmpty( void );
/**
* print to the standard output the state of the stream bit by bit
*/
void PrintBits( void ) const;
/**
* Ignore data we don't intend to read
* @param numberOfBits The number of bits to ignore
*/
void IgnoreBits( const int numberOfBits );
/**
* Move the write pointer to a position on the array.
* @param offset the offset from the start of the array.
* @attention
* Dangerous if you don't know what you are doing!
*
*/
void SetWriteOffset( const int offset );
/**
* Returns the length in bits of the stream
*/
int GetNumberOfBitsUsed( void ) const;
/**
* Returns the length in bytes of the stream
*/
int GetNumberOfBytesUsed( void ) const;
/**
* Returns the number of bits into the stream that we have read
*/
int GetReadOffset( void ) const;
/**
* Returns the number of bits left in the stream that haven't been read
*/
int GetNumberOfUnreadBits( void ) const;
/**
* Makes a copy of the internal data for you Data will point to
* the stream. Returns the length in bits of the stream. Partial
* bytes are left aligned
* @param _data the resulting byte copy of the internal state.
*/
int CopyData( unsigned char** _data ) const;
/**
* Set the stream to some initial data. For internal use
* Partial bytes are left aligned
* @param input The data
* @param numberOfBits the number of bits set in the data buffer
*/
void SetData( const unsigned char* input, const int numberOfBits );
/**
* Exposes the internal data.
* Partial bytes are left aligned.
* @return A pointer to the internal state
*/
unsigned char* GetData( void ) const;
/**
* Write numberToWrite bits from the input source Right aligned
* data means in the case of a partial byte, the bits are aligned
* from the right (bit 0) rather than the left (as in the normal
* internal representation) You would set this to true when
* writing user data, and false when copying bitstream data, such
* as writing one bitstream to another
* @param input The data
* @param numberOfBitsToWrite The number of bits to write
* @param rightAlignedBits if true data will be right aligned
*/
void WriteBits( const unsigned char* input,
int numberOfBitsToWrite, const bool rightAlignedBits = true );
/**
* Align the bitstream to the byte boundary and then write the
* specified number of bits. This is faster than WriteBits but
* wastes the bits to do the alignment and requires you to call
* ReadAlignedBits at the corresponding read position.
* @param input The data
* @param numberOfBytesToWrite The size of data.
*/
void WriteAlignedBytes( const unsigned char* input,
const int numberOfBytesToWrite );
/**
* Read bits, starting at the next aligned bits. Note that the
* modulus 8 starting offset of the sequence must be the same as
* was used with WriteBits. This will be a problem with packet
* coalescence unless you byte align the coalesced packets.
* @param output The byte array larger than @em numberOfBytesToRead
* @param numberOfBytesToRead The number of byte to read from the internal state
* @return true if there is enough byte.
*/
bool ReadAlignedBytes( unsigned char* output,
const int numberOfBytesToRead );
/**
* Align the next write and/or read to a byte boundary. This can
* be used to 'waste' bits to byte align for efficiency reasons It
* can also be used to force coalesced bitstreams to start on byte
* boundaries so so WriteAlignedBits and ReadAlignedBits both
* calculate the same offset when aligning.
*/
void AlignWriteToByteBoundary( void );
/**
* Align the next write and/or read to a byte boundary. This can
* be used to 'waste' bits to byte align for efficiency reasons It
* can also be used to force coalesced bitstreams to start on byte
* boundaries so so WriteAlignedBits and ReadAlignedBits both
* calculate the same offset when aligning.
*/
void AlignReadToByteBoundary( void );
/**
* Read numberOfBitsToRead bits to the output source
* alignBitsToRight should be set to true to convert internal
* bitstream data to userdata It should be false if you used
* WriteBits with rightAlignedBits false
* @param output The resulting bits array
* @param numberOfBitsToRead The number of bits to read
* @param alignsBitsToRight if true bits will be right aligned.
* @return true if there is enough bits to read
*/
bool ReadBits( unsigned char* output, int numberOfBitsToRead,
const bool alignBitsToRight = true );
/**
* --- Low level functions ---
* These are for when you want to deal
* with bits and don't care about type checking
* Write a 0
*/
void Write0( void );
/**
* --- Low level functions ---
* These are for when you want to deal
* with bits and don't care about type checking
* Write a 1
*/
void Write1( void );
/**
* --- Low level functions ---
* These are for when you want to deal
* with bits and don't care about type checking
* Reads 1 bit and returns true if that bit is 1 and false if it is 0
*/
bool ReadBit( void );
/**
* If we used the constructor version with copy data off, this
* makes sure it is set to on and the data pointed to is copied.
*/
void AssertCopyData( void );
/**
* Use this if you pass a pointer copy to the constructor
* (_copyData==false) and want to overallocate to prevent
* reallocation
*/
void SetNumberOfBitsAllocated( const unsigned int lengthInBits );
private:
/**
* Assume the input source points to a native type, compress and write it.
*/
void WriteCompressed( const unsigned char* input,
const int size, const bool unsignedData );
/**
* Assume the input source points to a compressed native type.
* Decompress and read it.
*/
bool ReadCompressed( unsigned char* output,
const int size, const bool unsignedData );
/**
* Reallocates (if necessary) in preparation of writing
* numberOfBitsToWrite
*/
void AddBitsAndReallocate( const int numberOfBitsToWrite );
/**
* Number of bits currently used
*/
int numberOfBitsUsed;
/**
* Number of bits currently allocated
*/
int numberOfBitsAllocated;
/**
* Current readOffset
*/
int readOffset;
/**
* array of byte storing the data. Points to stackData or if is bigger than that then is allocated
*/
unsigned char *data;
/**
* true if the internal buffer is copy of the data passed to the
* constructor
*/
bool copyData;
unsigned char stackData[BITSTREAM_STACK_ALLOCATION_SIZE];
};
}
#endif
#endif