Ejemplo n.º 1
0
        // Do I need array offsets/lengths in the public API? Might get a little hard to keep track of positions.
        // I can add them later if needed but I'll have to revisit the logic here because it's almost certainly wrong.
        // Alternate note: This function assumes it's being passed a big-endian bit arrays
        private void WriteInternal(int bitCount, byte[] data, int?offset, int?length)
        {
            offset = offset ?? 0;
            length = (length ?? data.Length) - offset.GetValueOrDefault() - 1;

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(data);
            }

            int bytePos      = ParseBitCountAndExpandStreamAsNeeded(bitCount);
            int srcBytePos   = offset.GetValueOrDefault() + length.GetValueOrDefault();
            int srcBitPos    = 1;
            int consumedBits = 0;

            while (consumedBits < bitCount)
            {
                int  bitsToConsume = Math.Min(bitCount - consumedBits, Constants.ByteSizeInBits);
                byte rawValue      = (byte)(data[srcBytePos] & PackedBitMasks.GetNarrowingMask(bitsToConsume));
                int  remainingBits = Constants.ByteSizeInBits - (BitPos - 1);

                // Extract only the bits we need for the current byte
                // Assuming we have more bits than our current byte boundary, we have to apply some bits to the next byte
                if (bitsToConsume > remainingBits)
                {
                    InternalStream[bytePos++] |= (byte)((byte)(rawValue >> (bitsToConsume - remainingBits)) & PackedBitMasks.GetNarrowingMask(remainingBits));
                    BitPos        = 1;
                    remainingBits = bitsToConsume - remainingBits;

                    InternalStream[bytePos] |= (byte)(rawValue << (Constants.ByteSizeInBits - remainingBits));
                    BitPos      += remainingBits;
                    ForceAddByte = false;
                }
                else
                {
                    InternalStream[bytePos] |= (byte)(rawValue << (remainingBits - bitsToConsume));
                    BitPos += bitsToConsume;
                    if (BitPos > Constants.ByteSizeInBits)
                    {
                        BitPos = 1;
                        bytePos++;
                        // If the bits are directly on the border of a byte boundary (e.g. packed 32 bits)
                        // Then we must indicate to the expansion function that it must add another byte
                        // Because it uses the position in the current byte to determine how many are needed
                        // But only if we end on this byte
                        ForceAddByte = true;
                    }
                    else
                    {
                        ForceAddByte = false;
                    }
                }

                srcBitPos += bitsToConsume;
                if (srcBitPos > Constants.ByteSizeInBits)
                {
                    srcBitPos = 1;
                    srcBytePos--;
                }

                consumedBits += bitsToConsume;
            }
        }
Ejemplo n.º 2
0
        private bool TryReadInternal(int bitCount, out byte[] data, int typeBytes)
        {
            if (bitCount > RemainingBits)
            {
                data = null;
                return(false);
            }

            data = new byte[typeBytes];

            int destBytePos  = data.Length - 1;
            int destBitPos   = 1;
            int consumedBits = 0;

            while (consumedBits < bitCount)
            {
                int  bitsToConsume      = Math.Min(bitCount - consumedBits, Constants.ByteSizeInBits);
                int  remainingBits      = Constants.ByteSizeInBits - (BitPos - 1);
                int  attemptConsumeBits = Math.Min(bitsToConsume, remainingBits);
                byte rawValue           = (byte)(InternalStream[BytePos] & PackedBitMasks.GetWideningMask(attemptConsumeBits, BitPos - 1));

                BitPos += attemptConsumeBits;
                if (BitPos > Constants.ByteSizeInBits)
                {
                    BitPos = 1;
                    BytePos++;
                }

                if (bitsToConsume > attemptConsumeBits)
                {
                    data[destBytePos] |= (byte)(rawValue << (bitsToConsume - attemptConsumeBits));
                    destBitPos        += attemptConsumeBits;
                    if (destBitPos > Constants.ByteSizeInBits)
                    {
                        destBitPos = 1;
                        destBytePos--;
                    }

                    remainingBits      = bitsToConsume - attemptConsumeBits;
                    rawValue           = (byte)(InternalStream[BytePos] & PackedBitMasks.GetWideningMask(remainingBits, BitPos - 1));
                    data[destBytePos] |= (byte)(rawValue >> (Constants.ByteSizeInBits - remainingBits));

                    destBitPos += remainingBits;
                    if (destBitPos > Constants.ByteSizeInBits)
                    {
                        destBitPos = 1;
                        destBytePos--;
                    }

                    BitPos += remainingBits;
                    if (BitPos > Constants.ByteSizeInBits)
                    {
                        BitPos = 1;
                        BytePos++;
                    }
                }
                else
                {
                    data[destBytePos] |= (byte)(rawValue >> (remainingBits - bitsToConsume));
                    destBitPos        += bitsToConsume;
                    if (destBitPos > Constants.ByteSizeInBits)
                    {
                        destBitPos = 1;
                        destBytePos--;
                    }
                }

                consumedBits += bitsToConsume;
            }

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(data);
            }
            return(true);
        }