/// <summary> /// Writes a signed integer using 1 to 32 bits /// </summary> public BitWriter Write(Int32 source, int numberOfBits) { BitBufferException.Assert((numberOfBits > 0 && numberOfBits <= 32), "Write(int, numberOfBits) can only write between 1 and 32 bits"); EnsureBufferSize(_lengthBits + numberOfBits); if (numberOfBits != 32) { // make first bit sign int signBit = 1 << (numberOfBits - 1); if (source < 0) { source = (-source - 1) | signBit; } else { source &= (~signBit); } } BitReaderWriter.WriteUInt32((uint)source, numberOfBits, _data, _lengthBits); _lengthBits += numberOfBits; return(this); }
/// <summary> /// Reads the specified number of bits into an Int32 without advancing the read pointer /// </summary> public Int32 PeekInt32(int numberOfBits) { BitBufferException.Assert((numberOfBits > 0 && numberOfBits <= 32), "ReadInt() can only read between 1 and 32 bits"); ReadOverflowException.Assert(_lengthBits - _readPosition >= numberOfBits); uint retval = BitReaderWriter.ReadUInt32(_data, numberOfBits, _readPosition); if (numberOfBits == 32) { return((int)retval); } int signBit = 1 << (numberOfBits - 1); if ((retval & signBit) == 0) { return((int)retval); // positive } // negative unchecked { uint mask = ((uint)-1) >> (33 - numberOfBits); uint tmp = (retval & mask) + 1; return(-((int)tmp)); } }
//public static ulong ReadUInt64(byte[] fromBuffer, int numberOfBits, int readBitOffset) /// <summary> /// Writes an unsigned 16 bit integer /// </summary> public static void WriteUInt16(ushort source, int numberOfBits, byte[] destination, int destinationBitOffset) { if (numberOfBits == 0) { return; } BitBufferException.Assert((numberOfBits >= 0 && numberOfBits <= 16), "numberOfBits must be between 0 and 16"); #if BIGENDIAN // reorder bytes uint intSource = source; intSource = ((intSource & 0x0000ff00) >> 8) | ((intSource & 0x000000ff) << 8); source = (ushort)intSource; #endif if (numberOfBits <= 8) { BitReaderWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset); return; } BitReaderWriter.WriteByte((byte)source, 8, destination, destinationBitOffset); numberOfBits -= 8; if (numberOfBits > 0) { BitReaderWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset + 8); } }
/// <summary> /// Read 1-8 bits from a buffer into a byte /// </summary> public static byte ReadByte(byte[] fromBuffer, int numberOfBits, int readBitOffset) { BitBufferException.Assert(((numberOfBits > 0) && (numberOfBits < 9)), "Read() can only read between 1 and 8 bits"); int bytePtr = readBitOffset >> 3; int startReadAtIndex = readBitOffset - (bytePtr * 8); // (readBitOffset % 8); if (startReadAtIndex == 0 && numberOfBits == 8) { return(fromBuffer[bytePtr]); } // mask away unused bits lower than (right of) relevant bits in first byte byte returnValue = (byte)(fromBuffer[bytePtr] >> startReadAtIndex); int numberOfBitsInSecondByte = numberOfBits - (8 - startReadAtIndex); if (numberOfBitsInSecondByte < 1) { // we don't need to read from the second byte, but we DO need // to mask away unused bits higher than (left of) relevant bits return((byte)(returnValue & (255 >> (8 - numberOfBits)))); } byte second = fromBuffer[bytePtr + 1]; // mask away unused bits higher than (left of) relevant bits in second byte second &= (byte)(255 >> (8 - numberOfBitsInSecondByte)); return((byte)(returnValue | (byte)(second << (numberOfBits - numberOfBitsInSecondByte)))); }
/// <summary> /// Reads the specified number of bytes without advancing the read pointer /// </summary> public void PeekBytes(byte[] into, int offset, int numberOfBytes) { ReadOverflowException.Assert(_lengthBits - _readPosition >= (numberOfBytes * 8)); BitBufferException.Assert(offset + numberOfBytes <= into.Length); BitReaderWriter.ReadBytes(_data, numberOfBytes, _readPosition, into, offset); return; }
/// <summary> /// Reads 1 to 8 bits into a byte /// </summary> public byte ReadByte(int numberOfBits) { BitBufferException.Assert(numberOfBits > 0 && numberOfBits <= 8, "ReadByte(bits) can only read between 1 and 8 bits"); byte retval = BitReaderWriter.ReadByte(_data, numberOfBits, _readPosition); _readPosition += numberOfBits; return(retval); }
/// <summary> /// Writes a 32 bit signed integer /// </summary> public BitWriter Write(UInt32 source, int numberOfBits) { BitBufferException.Assert((numberOfBits > 0 && numberOfBits <= 32), "Write(uint, numberOfBits) can only write between 1 and 32 bits"); EnsureBufferSize(_lengthBits + numberOfBits); BitReaderWriter.WriteUInt32(source, numberOfBits, _data, _lengthBits); _lengthBits += numberOfBits; return(this); }
/// <summary> /// Reads the specified number of bits into a UInt32 without advancing the read pointer /// </summary> public UInt32 PeekUInt32(int numberOfBits) { BitBufferException.Assert((numberOfBits > 0 && numberOfBits <= 32), "ReadUInt() can only read between 1 and 32 bits"); //NetException.Assert(m_bitLength - m_readBitPtr >= numberOfBits, "tried to read past buffer size"); UInt32 retval = BitReaderWriter.ReadUInt32(_data, numberOfBits, _readPosition); return(retval); }
/// <summary> /// Compress (lossy) a float in the range 0..1 using numberOfBits bits /// </summary> public BitWriter WriteUnitSingle(float value, int numberOfBits) { BitBufferException.Assert(((value >= 0.0) && (value <= 1.0)), " WriteUnitSingle() must be passed a float in the range 0 to 1; val is " + value); int maxValue = (1 << numberOfBits) - 1; uint writeVal = (uint)(value * (float)maxValue); Write(writeVal, numberOfBits); return(this); }
/// <summary> /// Compress (lossy) a float in the range -1..1 using numberOfBits bits /// </summary> public BitWriter WriteSignedSingle(float value, int numberOfBits) { BitBufferException.Assert(((value >= -1.0) && (value <= 1.0)), " WriteSignedSingle() must be passed a float in the range -1 to 1; val is " + value); float unit = (value + 1.0f) * 0.5f; int maxVal = (1 << numberOfBits) - 1; uint writeVal = (uint)(unit * (float)maxVal); Write(writeVal, numberOfBits); return(this); }
/// <summary> /// Compress a float within a specified range using a certain number of bits /// </summary> public BitWriter WriteRangedSingle(float value, float min, float max, int numberOfBits) { BitBufferException.Assert(((value >= min) && (value <= max)), " WriteRangedSingle() must be passed a float in the range MIN to MAX; val is " + value); float range = max - min; float unit = ((value - min) / range); int maxVal = (1 << numberOfBits) - 1; Write((UInt32)((float)maxVal * unit), numberOfBits); return(this); }
/// <summary> /// Write 0-8 bits of data to buffer /// </summary> public static void WriteByte(byte source, int numberOfBits, byte[] destination, int destBitOffset) { if (numberOfBits == 0) { return; } BitBufferException.Assert(((numberOfBits >= 0) && (numberOfBits <= 8)), "Must write between 0 and 8 bits!"); // Mask out all the bits we dont want source = (byte)(source & (0xFF >> (8 - numberOfBits))); int p = destBitOffset >> 3; int bitsUsed = destBitOffset & 0x7; // mod 8 int bitsFree = 8 - bitsUsed; int bitsLeft = bitsFree - numberOfBits; // Fast path, everything fits in the first byte if (bitsLeft >= 0) { int mask = (0xFF >> bitsFree) | (0xFF << (8 - bitsLeft)); destination[p] = (byte)( // Mask out lower and upper bits (destination[p] & mask) | // Insert new bits (source << bitsUsed) ); return; } destination[p] = (byte)( // Mask out upper bits (destination[p] & (0xFF >> bitsFree)) | // Write the lower bits to the upper bits in the first byte (source << bitsUsed) ); p += 1; destination[p] = (byte)( // Mask out lower bits (destination[p] & (0xFF << (numberOfBits - bitsFree))) | // Write the upper bits to the lower bits of the second byte (source >> bitsFree) ); }
/// <summary> /// Writes an integer with the least amount of bits need for the specified range /// Returns number of bits written /// </summary> public BitWriter WriteRangedInteger(long min, long max, long value, out int bitsWritten) { BitBufferException.Assert(value >= min && value <= max, "Value not within min/max range!"); ulong range = (ulong)(max - min); int numBits = BitUtility.BitsToHoldUInt64(range); ulong rvalue = (ulong)(value - min); Write(rvalue, numBits); bitsWritten = numBits; return(this); }
public static uint ReadUInt32(byte[] fromBuffer, int numberOfBits, int readBitOffset) { BitBufferException.Assert(((numberOfBits > 0) && (numberOfBits <= 32)), "ReadUInt32() can only read between 1 and 32 bits"); #endif uint returnValue; if (numberOfBits <= 8) { returnValue = ReadByte(fromBuffer, numberOfBits, readBitOffset); return(returnValue); } returnValue = ReadByte(fromBuffer, 8, readBitOffset); numberOfBits -= 8; readBitOffset += 8; if (numberOfBits <= 8) { returnValue |= (uint)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 8); return(returnValue); } returnValue |= (uint)(ReadByte(fromBuffer, 8, readBitOffset) << 8); numberOfBits -= 8; readBitOffset += 8; if (numberOfBits <= 8) { uint r = ReadByte(fromBuffer, numberOfBits, readBitOffset); r <<= 16; returnValue |= r; return(returnValue); } returnValue |= (uint)(ReadByte(fromBuffer, 8, readBitOffset) << 16); numberOfBits -= 8; readBitOffset += 8; returnValue |= (uint)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 24); #if BIGENDIAN // reorder bytes return (((returnValue & 0xff000000) >> 24) | ((returnValue & 0x00ff0000) >> 8) | ((returnValue & 0x0000ff00) << 8) | ((returnValue & 0x000000ff) << 24)); #else return(returnValue); #endif }
/// <summary> /// Reads a UInt32 written using WriteUnsignedVarInt(); will increment offset! /// </summary> public static uint ReadVariableUInt32(byte[] buffer, ref int offset) { int num1 = 0; int num2 = 0; while (true) { BitBufferException.Assert(num2 != 0x23, "Bad 7-bit encoded integer"); byte num3 = buffer[offset++]; num1 |= (num3 & 0x7f) << (num2 & 0x1f); num2 += 7; if ((num3 & 0x80) == 0) { return((uint)num1); } } }
/// <summary> /// Reads the specified number of bits into an UInt64 without advancing the read pointer /// </summary> public UInt64 PeekUInt64(int numberOfBits) { BitBufferException.Assert((numberOfBits > 0 && numberOfBits <= 64), "ReadUInt() can only read between 1 and 64 bits"); ReadOverflowException.Assert(_lengthBits - _readPosition >= numberOfBits); ulong retval; if (numberOfBits <= 32) { retval = (ulong)BitReaderWriter.ReadUInt32(_data, numberOfBits, _readPosition); } else { retval = BitReaderWriter.ReadUInt32(_data, 32, _readPosition); retval |= (UInt64)BitReaderWriter.ReadUInt32(_data, numberOfBits - 32, _readPosition + 32) << 32; } return(retval); }
/// <summary> /// Reads the specified number of bits into a preallocated array /// </summary> /// <param name="into">The destination array</param> /// <param name="offset">The offset where to start writing in the destination array</param> /// <param name="numberOfBits">The number of bits to read</param> public BitReader ReadBits(byte[] into, int offset, int numberOfBits) { ReadOverflowException.Assert(_lengthBits - _readPosition >= numberOfBits); BitBufferException.Assert(offset + BitUtility.BytesToHoldBits(numberOfBits) <= into.Length); int numberOfWholeBytes = numberOfBits / 8; int extraBits = numberOfBits - (numberOfWholeBytes * 8); BitReaderWriter.ReadBytes(_data, numberOfWholeBytes, _readPosition, into, offset); _readPosition += (8 * numberOfWholeBytes); if (extraBits > 0) { into[offset + numberOfWholeBytes] = ReadByte(extraBits); } return(this); }
/// <summary> /// Reads the specified number of bits into an Int64 without advancing the read pointer /// </summary> public Int64 PeekInt64(int numberOfBits) { BitBufferException.Assert(((numberOfBits > 0) && (numberOfBits < 65)), "ReadInt64(bits) can only read between 1 and 64 bits"); return((long)PeekUInt64(numberOfBits)); }