Beispiel #1
0
        public static ulong ReadUInt64(ref ReadableBuffer buffer, int firstByte, int n)
        {
            if (n < 0 || n > 8)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }
            int mask   = ~(~0 << n);
            int prefix = firstByte & mask;

            if (prefix != mask)
            {
                return((ulong)prefix); // short value encoded directly
            }
            ulong value = 0;
            int   shift = 0, nextByte;

            for (int i = 0; i < 9; i++)
            {
                nextByte = buffer.Peek();
                if (nextByte < 0)
                {
                    ThrowEndOfStreamException();
                }
                buffer = buffer.Slice(1);
                value |= ((ulong)nextByte & 0x7F) << shift;

                if ((nextByte & 0x80) == 0)
                {
                    // lack of continuation bit
                    return(value + (ulong)mask);
                }
                shift += 7;
            }
            switch (nextByte = buffer.Peek())
            {
            case 0:
            case 1:
                // note: lack of continuation bit (or anything else)
                buffer = buffer.Slice(1);
                value |= ((ulong)nextByte & 0x7F) << shift;
                return(value + (ulong)mask);

            default:
                if (nextByte < 0)
                {
                    ThrowEndOfStreamException();
                }
                // 7*9=63, so max 9 groups of 7 bits plus either 0 or 1;
                // after that: we've overflown
                throw new OverflowException();
            }
        }
Beispiel #2
0
        public static string ReadString(ref ReadableBuffer buffer, out bool compressed)
        {
            int header = buffer.Peek();

            if (header < 0)
            {
                ThrowEndOfStreamException();
            }

            compressed = (header & 0x80) != 0;
            buffer     = buffer.Slice(1);
            int    len = checked ((int)ReadUInt64(ref buffer, header, 7));
            string result;

            if (compressed)
            {
                result = HuffmanCode.ReadString(buffer.Slice(0, len));
            }
            else
            {
                result = buffer.Slice(0, len).GetAsciiString();
            }

            buffer = buffer.Slice(len);
            return(result);
        }
Beispiel #3
0
        public static ulong ReadUInt64(ref ReadableBuffer buffer, int n)
        {
            int firstByte = buffer.Peek();

            if (firstByte < 0)
            {
                throw new EndOfStreamException();
            }
            buffer = buffer.Slice(1);
            return(ReadUInt64(ref buffer, firstByte, n));
        }
        public static ReadableBuffer TrimStart(this ReadableBuffer buffer)
        {
            int ch;

            while ((ch = buffer.Peek()) != -1)
            {
                if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
                {
                    buffer = buffer.Slice(1);
                }
                else
                {
                    break;
                }
            }

            return(buffer);
        }
Beispiel #5
0
        public static Header ReadHeader(ref ReadableBuffer buffer, ref HeaderTable headerTable, IBufferPool memoryPool)
        {
            int firstByte = buffer.Peek();

            if (firstByte < 0)
            {
                ThrowEndOfStreamException();
            }
            buffer = buffer.Slice(1);
            if ((firstByte & 0x80) != 0)
            {
                // 6.1.  Indexed Header Field Representation
                return(headerTable.GetHeader(ReadUInt32(ref buffer, firstByte, 7)));
            }
            else if ((firstByte & 0x40) != 0)
            {
                // 6.2.1.  Literal Header Field with Incremental Indexing
                var result = ReadHeader(ref buffer, ref headerTable, firstByte, 6, HeaderOptions.IndexAddNewValue);
                headerTable = headerTable.Add(result, memoryPool);
                return(result);
            }
            else if ((firstByte & 0x20) != 0)
            {
                // 6.3. Dynamic Table Size Update
                var newSize = ReadInt32(ref buffer, firstByte, 5);
                headerTable = headerTable.SetMaxLength(newSize, memoryPool);
                return(Header.Resize(newSize));
            }
            else
            {
                // 6.2.2.Literal Header Field without Indexing
                // 6.2.3.Literal Header Field Never Indexed
                return(ReadHeader(ref buffer, ref headerTable, firstByte, 4,
                                  (firstByte & 0x10) == 0
                    ? HeaderOptions.IndexNotIndexed
                    : HeaderOptions.IndexNeverIndexed));
            }
        }
Beispiel #6
0
        public int ReadNext()
        {
            int index;

            switch (_bitCount)
            {
            case 0:
                _bits = _buffer.Peek();
                if (_bits < 0)
                {
                    return(-1);
                }
                _buffer   = _buffer.Slice(1);
                _bitCount = 8;
                goto case 8;

            case 1:
            case 2:
            case 3:
            case 4:
                // the 5  bits we need spans 2 bytes
                int bitsFromSecondByte = (5 - _bitCount);
                // we're going to need more; we'll take the remains of the current,
                // and shift it to populate the left part of the index
                index = (_bits & ~(~0 << _bitCount)) << bitsFromSecondByte;

                _bits = _buffer.Peek();
                if (_bits < 0)
                {
                    // EOF; only valid if all the padding is 1
                    // so: we'll populate the rest with 1, and check we get 31
                    if ((index | (~(~0 << bitsFromSecondByte))) == 0x1F)
                    {
                        return(-1);
                    }
                    throw new EndOfStreamException();
                }
                _buffer = _buffer.Slice(1);
                index  |= _bits >> (8 - bitsFromSecondByte);
                // if we had 1 bit, we'll take 8 and use 4 => 4 left;
                // if we had 3, we'll take 5 and use 2 => 6 left
                _bitCount += 3;
                break;

            case 5:
            case 6:
            case 7:
            case 8:
                // we have enough in the byte
                index      = (_bits >> (_bitCount - 5)) & 0x1F;
                _bitCount -= 5;
                break;

            default:
                throw new InvalidOperationException();
            }

            // double the index because it is actually *pairs*
            index <<= 1;
            short left = _linearizedTree[index], right = _linearizedTree[index + 1];

            if (left == right)
            {   // note that this can only possibly apply to the 5-bit roots,
                // hence not replicated in the loop below
                return(-left);
            }

            int bitsRead = 5;
            int bit      = _bitCount == 0 ? 0 : 1 << (_bitCount - 1);

            do
            {
                // we need moar data!
                if (bit == 0)
                {
                    var lastBits = _bits;
                    _bits = _buffer.Peek();
                    if (_bits < 0)
                    {
                        // this is OK as long as the rest is padding and all 1
                        int mask = ~(~0 << bitsRead);
                        if (bitsRead <= 7 && (lastBits & mask) == mask)
                        {
                            return(-1);
                        }
                        throw new EndOfStreamException();
                    }
                    _buffer   = _buffer.Slice(1);
                    _bitCount = 8;
                    bit       = 0x80;
                }

                index = (_bits & bit) == 0 ? left: right;
                _bitCount--;
                if (index <= 0)
                {
                    return(-index); // leaf
                }
                bit >>= 1;
                bitsRead++;
                index <<= 1; // double it as before, and find the next left/right paths
                left    = _linearizedTree[index];
                right   = _linearizedTree[index + 1];
            } while (bitsRead <= MaximumCodeLength);
            throw new InvalidOperationException("Huffman code not recognized");
        }