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(); } }
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); }
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); }
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)); } }
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"); }