File: runtime\Http2\HuffmanDecodingTests.cs
Web Access
Project: src\src\Shared\test\Shared.Tests\Microsoft.AspNetCore.Shared.Tests.csproj (Microsoft.AspNetCore.Shared.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.HPack;
using System.Text;
using Xunit;
 
namespace System.Net.Http.Unit.Tests.HPack
{
    public class HuffmanDecodingTests
    {
        // Encoded values are 30 bits at most, so are stored in the table in a uint.
        // Convert to ulong here and put the encoded value in the most significant bits.
        // This makes the encoding logic below simpler.
        private static (ulong code, int bitLength) GetEncodedValue(byte b)
        {
            (uint code, int bitLength) = Huffman.Encode(b);
            return (((ulong)code) << 32, bitLength);
        }
 
        private static int Encode(byte[] source, byte[] destination, bool injectEOS)
        {
            ulong currentBits = 0;  // We can have 7 bits of rollover plus 30 bits for the next encoded value, so use a ulong
            int currentBitCount = 0;
            int dstOffset = 0;
 
            for (int i = 0; i < source.Length; i++)
            {
                (ulong code, int bitLength) = GetEncodedValue(source[i]);
 
                // inject EOS if instructed to
                if (injectEOS)
                {
                    code |= (ulong)0b11111111_11111111_11111111_11111100 << (32 - bitLength);
                    bitLength += 30;
                    injectEOS = false;
                }
 
                currentBits |= code >> currentBitCount;
                currentBitCount += bitLength;
 
                while (currentBitCount >= 8)
                {
                    destination[dstOffset++] = (byte)(currentBits >> 56);
                    currentBits = currentBits << 8;
                    currentBitCount -= 8;
                }
            }
 
            // Fill any trailing bits with ones, per RFC
            if (currentBitCount > 0)
            {
                currentBits |= 0xFFFFFFFFFFFFFFFF >> currentBitCount;
                destination[dstOffset++] = (byte)(currentBits >> 56);
            }
 
            return dstOffset;
        }
 
        [Fact]
        public void HuffmanDecoding_ValidEncoding_Succeeds()
        {
            foreach (byte[] input in TestData())
            {
                // Worst case encoding is 30 bits per input byte, so make the encoded buffer 4 times as big
                byte[] encoded = new byte[input.Length * 4];
                int encodedByteCount = Encode(input, encoded, false);
 
                // Worst case decoding is an output byte per 5 input bits, so make the decoded buffer 2 times as big
                byte[] decoded = new byte[encoded.Length * 2];
 
                int decodedByteCount = Huffman.Decode(new ReadOnlySpan<byte>(encoded, 0, encodedByteCount), ref decoded);
 
                Assert.Equal(input.Length, decodedByteCount);
                Assert.Equal(input, decoded.Take(decodedByteCount));
            }
        }
 
        [Fact]
        public void HuffmanDecoding_InvalidEncoding_Throws()
        {
            foreach (byte[] encoded in InvalidEncodingData())
            {
                // Worst case decoding is an output byte per 5 input bits, so make the decoded buffer 2 times as big
                byte[] decoded = new byte[encoded.Length * 2];
 
                Assert.Throws<HuffmanDecodingException>(() => Huffman.Decode(encoded, ref decoded));
            }
        }
 
        // This input sequence will encode to 17 bits, thus offsetting the next character to encode
        // by exactly one bit. We use this below to generate a prefix that encodes all of the possible starting
        // bit offsets for a character, from 0 to 7.
        private static readonly byte[] s_offsetByOneBit = new byte[] { (byte)'c', (byte)'l', (byte)'r' };
 
        public static IEnumerable<byte[]> TestData()
        {
            // Single byte data
            for (int i = 0; i < 256; i++)
            {
                yield return new byte[] { (byte)i };
            }
 
            // Ensure that decoding every possible value leaves the decoder in a correct state so that
            // a subsequent value can be decoded (here, 'a')
            for (int i = 0; i < 256; i++)
            {
                yield return new byte[] { (byte)i, (byte)'a' };
            }
 
            // Ensure that every possible bit starting position for every value is encoded properly
            // s_offsetByOneBit encodes to exactly 17 bits, leaving 1 bit for the next byte
            // So by repeating this sequence, we can generate any starting bit position we want.
            byte[] currentPrefix = new byte[0];
            for (int prefixBits = 1; prefixBits <= 8; prefixBits++)
            {
                currentPrefix = currentPrefix.Concat(s_offsetByOneBit).ToArray();
 
                // Make sure we're actually getting the correct number of prefix bits
                int encodedBits = currentPrefix.Select(b => Huffman.Encode(b).bitLength).Sum();
                Assert.Equal(prefixBits % 8, encodedBits % 8);
 
                for (int i = 0; i < 256; i++)
                {
                    yield return currentPrefix.Concat(new byte[] { (byte)i }.Concat(currentPrefix)).ToArray();
                }
            }
 
            // Finally, one really big chunk of randomly generated data.
            byte[] data = new byte[1024 * 1024];
            new Random(42).NextBytes(data);
            yield return data;
        }
 
        private static IEnumerable<byte[]> InvalidEncodingData()
        {
            // For encodings greater than 8 bits, truncate one or more bytes to generate an invalid encoding
            byte[] source = new byte[1];
            byte[] destination = new byte[10];
            for (int i = 0; i < 256; i++)
            {
                source[0] = (byte)i;
                int encodedByteCount = Encode(source, destination, false);
                if (encodedByteCount > 1)
                {
                    yield return destination.Take(encodedByteCount - 1).ToArray();
                    if (encodedByteCount > 2)
                    {
                        yield return destination.Take(encodedByteCount - 2).ToArray();
                        if (encodedByteCount > 3)
                        {
                            yield return destination.Take(encodedByteCount - 3).ToArray();
                        }
                    }
                }
            }
 
            // Pad encodings with invalid trailing one bits. This is disallowed.
            byte[] pad1 = new byte[] { 0xFF };
            byte[] pad2 = new byte[] { 0xFF, 0xFF, };
            byte[] pad3 = new byte[] { 0xFF, 0xFF, 0xFF };
            byte[] pad4 = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF };
 
            for (int i = 0; i < 256; i++)
            {
                source[0] = (byte)i;
                int encodedByteCount = Encode(source, destination, false);
                yield return destination.Take(encodedByteCount).Concat(pad1).ToArray();
                yield return destination.Take(encodedByteCount).Concat(pad2).ToArray();
                yield return destination.Take(encodedByteCount).Concat(pad3).ToArray();
                yield return destination.Take(encodedByteCount).Concat(pad4).ToArray();
            }
 
            // send single EOS
            yield return new byte[] { 0b11111111, 0b11111111, 0b11111111, 0b11111100 };
 
            // send combinations with EOS in the middle
            source = new byte[2];
            destination = new byte[24];
            for (int i = 0; i < 256; i++)
            {
                source[0] = source[1] = (byte)i;
                int encodedByteCount = Encode(source, destination, true);
                yield return destination.Take(encodedByteCount).ToArray();
            }
        }
 
        public static readonly TheoryData<byte[], byte[]> _validData = new TheoryData<byte[], byte[]>
        {
            // Single 5-bit symbol
            { new byte[] { 0x07 }, Encoding.ASCII.GetBytes("0") },
            // Single 6-bit symbol
            { new byte[] { 0x57 }, Encoding.ASCII.GetBytes("%") },
            // Single 7-bit symbol
            { new byte[] { 0xb9 }, Encoding.ASCII.GetBytes(":") },
            // Single 8-bit symbol
            { new byte[] { 0xf8 }, Encoding.ASCII.GetBytes("&") },
            // Single 10-bit symbol
            { new byte[] { 0xfe, 0x3f }, Encoding.ASCII.GetBytes("!") },
            // Single 11-bit symbol
            { new byte[] { 0xff, 0x7f }, Encoding.ASCII.GetBytes("+") },
            // Single 12-bit symbol
            { new byte[] { 0xff, 0xaf }, Encoding.ASCII.GetBytes("#") },
            // Single 13-bit symbol
            { new byte[] { 0xff, 0xcf }, Encoding.ASCII.GetBytes("$") },
            // Single 14-bit symbol
            { new byte[] { 0xff, 0xf3 }, Encoding.ASCII.GetBytes("^") },
            // Single 15-bit symbol
            { new byte[] { 0xff, 0xf9 }, Encoding.ASCII.GetBytes("<") },
            // Single 19-bit symbol
            { new byte[] { 0xff, 0xfe, 0x1f }, Encoding.ASCII.GetBytes("\\") },
            // Single 20-bit symbol
            { new byte[] { 0xff, 0xfe, 0x6f }, new byte[] { 0x80 } },
            // Single 21-bit symbol
            { new byte[] { 0xff, 0xfe, 0xe7 }, new byte[] { 0x99 } },
            // Single 22-bit symbol
            { new byte[] { 0xff, 0xff, 0x4b }, new byte[] { 0x81 } },
            // Single 23-bit symbol
            { new byte[] { 0xff, 0xff, 0xb1 }, new byte[] { 0x01 } },
            // Single 24-bit symbol
            { new byte[] { 0xff, 0xff, 0xea }, new byte[] { 0x09 } },
            // Single 25-bit symbol
            { new byte[] { 0xff, 0xff, 0xf6, 0x7f }, new byte[] { 0xc7 } },
            // Single 26-bit symbol
            { new byte[] { 0xff, 0xff, 0xf8, 0x3f }, new byte[] { 0xc0 } },
            // Single 27-bit symbol
            { new byte[] { 0xff, 0xff, 0xfb, 0xdf }, new byte[] { 0xcb } },
            // Single 28-bit symbol
            { new byte[] { 0xff, 0xff, 0xfe, 0x2f }, new byte[] { 0x02 } },
            // Single 30-bit symbol
            { new byte[] { 0xff, 0xff, 0xff, 0xf3 }, new byte[] { 0x0a } },
 
            //               h      e         l          l      o         *
            { new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1111 }, Encoding.ASCII.GetBytes("hello") },
 
            // Sequences that uncovered errors
            { new byte[] { 0xb6, 0xb9, 0xac, 0x1c, 0x85, 0x58, 0xd5, 0x20, 0xa4, 0xb6, 0xc2, 0xad, 0x61, 0x7b, 0x5a, 0x54, 0x25, 0x1f }, Encoding.ASCII.GetBytes("upgrade-insecure-requests") },
            { new byte[] { 0xfe, 0x53 }, Encoding.ASCII.GetBytes("\"t") },
            { new byte[] { 0xff, 0xff, 0xf6, 0xff, 0xff, 0xfd, 0x68 }, new byte[] { 0xcf, 0xf0, 0x73 } },
            { new byte[] { 0xff, 0xff, 0xf9, 0xff, 0xff, 0xfd, 0x86 }, new byte[] { 0xd5, 0xc7, 0x69 } },
        };
 
        [Theory]
        [MemberData(nameof(_validData))]
        public void HuffmanDecodeArray(byte[] encoded, byte[] expected)
        {
            byte[] dst = new byte[expected.Length];
            Assert.Equal(expected.Length, Huffman.Decode(new ReadOnlySpan<byte>(encoded), ref dst));
            Assert.Equal(expected, dst);
        }
 
        public static readonly TheoryData<byte[]> _longPaddingData = new TheoryData<byte[]>
        {
            //             h      e         l          l      o         *
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1111, 0b11111111 },
 
            // '&' (8 bits) + 8 bit padding
            new byte[] { 0xf8, 0xff },
 
            // ':' (7 bits) + 9 bit padding
            new byte[] { 0xb9, 0xff }
        };
 
        [Theory]
        [MemberData(nameof(_longPaddingData))]
        public void ThrowsOnPaddingLongerThanSevenBits(byte[] encoded)
        {
            byte[] dst = new byte[encoded.Length * 2];
            Exception exception = Assert.Throws<HuffmanDecodingException>(() => Huffman.Decode(new ReadOnlySpan<byte>(encoded), ref dst));
            Assert.Equal(SR.net_http_hpack_huffman_decode_failed, exception.Message);
        }
 
        public static readonly TheoryData<byte[]> _eosData = new TheoryData<byte[]>
        {
            // EOS
            new byte[] { 0xff, 0xff, 0xff, 0xff },
            // '&' + EOS + '0'
            new byte[] { 0xf8, 0xff, 0xff, 0xff, 0xfc, 0x1f }
        };
 
        [Theory]
        [MemberData(nameof(_eosData))]
        public void ThrowsOnEOS(byte[] encoded)
        {
            byte[] dst = new byte[encoded.Length * 2];
            Exception exception = Assert.Throws<HuffmanDecodingException>(() => Huffman.Decode(new ReadOnlySpan<byte>(encoded), ref dst));
            Assert.Equal(SR.net_http_hpack_huffman_decode_failed, exception.Message);
        }
 
        [Fact]
        public void ResizesOnDestinationBufferTooSmall()
        {
            //                           h      e         l          l      o         *
            byte[] encoded = new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1111 };
            byte[] originalDestination = new byte[encoded.Length];
            byte[] actualDestination = originalDestination;
            int decodedCount = Huffman.Decode(new ReadOnlySpan<byte>(encoded), ref actualDestination);
            Assert.Equal(5, decodedCount);
            Assert.NotSame(originalDestination, actualDestination);
        }
 
        public static readonly TheoryData<byte[]> _incompleteSymbolData = new TheoryData<byte[]>
        {
            //             h      e         l          l      o (incomplete)
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0 },
 
            // Non-zero padding will be seen as incomplete symbol
            //             h      e         l          l      o         *
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0000 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0001 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0010 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0011 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0100 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0101 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0110 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_0111 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1000 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1001 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1010 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1011 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1100 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1101 },
            new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1110 }
        };
 
        [Theory]
        [MemberData(nameof(_incompleteSymbolData))]
        public void ThrowsOnIncompleteSymbol(byte[] encoded)
        {
            byte[] dst = new byte[encoded.Length * 2];
            Exception exception = Assert.Throws<HuffmanDecodingException>(() => Huffman.Decode(new ReadOnlySpan<byte>(encoded), ref dst));
            Assert.Equal(SR.net_http_hpack_huffman_decode_failed, exception.Message);
        }
 
        [Fact]
        public void DecodeCharactersThatSpans5Octets()
        {
            int expectedLength = 2;
            byte[] decodedBytes = new byte[expectedLength];
            //                           B       LF                                             EOS
            byte[] encoded = new byte[] { 0b1011101_1, 0b11111111, 0b11111111, 0b11111111, 0b11100_111 };
            int decodedLength = Huffman.Decode(new ReadOnlySpan<byte>(encoded, 0, encoded.Length), ref decodedBytes);
 
            Assert.Equal(expectedLength, decodedLength);
            Assert.Equal(new byte[] { (byte)'B', (byte)'\n' }, decodedBytes);
        }
 
        [Theory]
        [MemberData(nameof(HuffmanData))]
        public void HuffmanEncode(int code, uint expectedEncoded, int expectedBitLength)
        {
            (uint encoded, int bitLength) = Huffman.Encode(code);
            Assert.Equal(expectedEncoded, encoded);
            Assert.Equal(expectedBitLength, bitLength);
        }
 
        public static TheoryData<int, uint, int> HuffmanData
        {
            get
            {
                TheoryData<int, uint, int> data = new TheoryData<int, uint, int>();
 
                data.Add(0, 0b11111111_11000000_00000000_00000000, 13);
                data.Add(1, 0b11111111_11111111_10110000_00000000, 23);
                data.Add(2, 0b11111111_11111111_11111110_00100000, 28);
                data.Add(3, 0b11111111_11111111_11111110_00110000, 28);
                data.Add(4, 0b11111111_11111111_11111110_01000000, 28);
                data.Add(5, 0b11111111_11111111_11111110_01010000, 28);
                data.Add(6, 0b11111111_11111111_11111110_01100000, 28);
                data.Add(7, 0b11111111_11111111_11111110_01110000, 28);
                data.Add(8, 0b11111111_11111111_11111110_10000000, 28);
                data.Add(9, 0b11111111_11111111_11101010_00000000, 24);
                data.Add(10, 0b11111111_11111111_11111111_11110000, 30);
                data.Add(11, 0b11111111_11111111_11111110_10010000, 28);
                data.Add(12, 0b11111111_11111111_11111110_10100000, 28);
                data.Add(13, 0b11111111_11111111_11111111_11110100, 30);
                data.Add(14, 0b11111111_11111111_11111110_10110000, 28);
                data.Add(15, 0b11111111_11111111_11111110_11000000, 28);
                data.Add(16, 0b11111111_11111111_11111110_11010000, 28);
                data.Add(17, 0b11111111_11111111_11111110_11100000, 28);
                data.Add(18, 0b11111111_11111111_11111110_11110000, 28);
                data.Add(19, 0b11111111_11111111_11111111_00000000, 28);
                data.Add(20, 0b11111111_11111111_11111111_00010000, 28);
                data.Add(21, 0b11111111_11111111_11111111_00100000, 28);
                data.Add(22, 0b11111111_11111111_11111111_11111000, 30);
                data.Add(23, 0b11111111_11111111_11111111_00110000, 28);
                data.Add(24, 0b11111111_11111111_11111111_01000000, 28);
                data.Add(25, 0b11111111_11111111_11111111_01010000, 28);
                data.Add(26, 0b11111111_11111111_11111111_01100000, 28);
                data.Add(27, 0b11111111_11111111_11111111_01110000, 28);
                data.Add(28, 0b11111111_11111111_11111111_10000000, 28);
                data.Add(29, 0b11111111_11111111_11111111_10010000, 28);
                data.Add(30, 0b11111111_11111111_11111111_10100000, 28);
                data.Add(31, 0b11111111_11111111_11111111_10110000, 28);
                data.Add(32, 0b01010000_00000000_00000000_00000000, 6);
                data.Add(33, 0b11111110_00000000_00000000_00000000, 10);
                data.Add(34, 0b11111110_01000000_00000000_00000000, 10);
                data.Add(35, 0b11111111_10100000_00000000_00000000, 12);
                data.Add(36, 0b11111111_11001000_00000000_00000000, 13);
                data.Add(37, 0b01010100_00000000_00000000_00000000, 6);
                data.Add(38, 0b11111000_00000000_00000000_00000000, 8);
                data.Add(39, 0b11111111_01000000_00000000_00000000, 11);
                data.Add(40, 0b11111110_10000000_00000000_00000000, 10);
                data.Add(41, 0b11111110_11000000_00000000_00000000, 10);
                data.Add(42, 0b11111001_00000000_00000000_00000000, 8);
                data.Add(43, 0b11111111_01100000_00000000_00000000, 11);
                data.Add(44, 0b11111010_00000000_00000000_00000000, 8);
                data.Add(45, 0b01011000_00000000_00000000_00000000, 6);
                data.Add(46, 0b01011100_00000000_00000000_00000000, 6);
                data.Add(47, 0b01100000_00000000_00000000_00000000, 6);
                data.Add(48, 0b00000000_00000000_00000000_00000000, 5);
                data.Add(49, 0b00001000_00000000_00000000_00000000, 5);
                data.Add(50, 0b00010000_00000000_00000000_00000000, 5);
                data.Add(51, 0b01100100_00000000_00000000_00000000, 6);
                data.Add(52, 0b01101000_00000000_00000000_00000000, 6);
                data.Add(53, 0b01101100_00000000_00000000_00000000, 6);
                data.Add(54, 0b01110000_00000000_00000000_00000000, 6);
                data.Add(55, 0b01110100_00000000_00000000_00000000, 6);
                data.Add(56, 0b01111000_00000000_00000000_00000000, 6);
                data.Add(57, 0b01111100_00000000_00000000_00000000, 6);
                data.Add(58, 0b10111000_00000000_00000000_00000000, 7);
                data.Add(59, 0b11111011_00000000_00000000_00000000, 8);
                data.Add(60, 0b11111111_11111000_00000000_00000000, 15);
                data.Add(61, 0b10000000_00000000_00000000_00000000, 6);
                data.Add(62, 0b11111111_10110000_00000000_00000000, 12);
                data.Add(63, 0b11111111_00000000_00000000_00000000, 10);
                data.Add(64, 0b11111111_11010000_00000000_00000000, 13);
                data.Add(65, 0b10000100_00000000_00000000_00000000, 6);
                data.Add(66, 0b10111010_00000000_00000000_00000000, 7);
                data.Add(67, 0b10111100_00000000_00000000_00000000, 7);
                data.Add(68, 0b10111110_00000000_00000000_00000000, 7);
                data.Add(69, 0b11000000_00000000_00000000_00000000, 7);
                data.Add(70, 0b11000010_00000000_00000000_00000000, 7);
                data.Add(71, 0b11000100_00000000_00000000_00000000, 7);
                data.Add(72, 0b11000110_00000000_00000000_00000000, 7);
                data.Add(73, 0b11001000_00000000_00000000_00000000, 7);
                data.Add(74, 0b11001010_00000000_00000000_00000000, 7);
                data.Add(75, 0b11001100_00000000_00000000_00000000, 7);
                data.Add(76, 0b11001110_00000000_00000000_00000000, 7);
                data.Add(77, 0b11010000_00000000_00000000_00000000, 7);
                data.Add(78, 0b11010010_00000000_00000000_00000000, 7);
                data.Add(79, 0b11010100_00000000_00000000_00000000, 7);
                data.Add(80, 0b11010110_00000000_00000000_00000000, 7);
                data.Add(81, 0b11011000_00000000_00000000_00000000, 7);
                data.Add(82, 0b11011010_00000000_00000000_00000000, 7);
                data.Add(83, 0b11011100_00000000_00000000_00000000, 7);
                data.Add(84, 0b11011110_00000000_00000000_00000000, 7);
                data.Add(85, 0b11100000_00000000_00000000_00000000, 7);
                data.Add(86, 0b11100010_00000000_00000000_00000000, 7);
                data.Add(87, 0b11100100_00000000_00000000_00000000, 7);
                data.Add(88, 0b11111100_00000000_00000000_00000000, 8);
                data.Add(89, 0b11100110_00000000_00000000_00000000, 7);
                data.Add(90, 0b11111101_00000000_00000000_00000000, 8);
                data.Add(91, 0b11111111_11011000_00000000_00000000, 13);
                data.Add(92, 0b11111111_11111110_00000000_00000000, 19);
                data.Add(93, 0b11111111_11100000_00000000_00000000, 13);
                data.Add(94, 0b11111111_11110000_00000000_00000000, 14);
                data.Add(95, 0b10001000_00000000_00000000_00000000, 6);
                data.Add(96, 0b11111111_11111010_00000000_00000000, 15);
                data.Add(97, 0b00011000_00000000_00000000_00000000, 5);
                data.Add(98, 0b10001100_00000000_00000000_00000000, 6);
                data.Add(99, 0b00100000_00000000_00000000_00000000, 5);
                data.Add(100, 0b10010000_00000000_00000000_00000000, 6);
                data.Add(101, 0b00101000_00000000_00000000_00000000, 5);
                data.Add(102, 0b10010100_00000000_00000000_00000000, 6);
                data.Add(103, 0b10011000_00000000_00000000_00000000, 6);
                data.Add(104, 0b10011100_00000000_00000000_00000000, 6);
                data.Add(105, 0b00110000_00000000_00000000_00000000, 5);
                data.Add(106, 0b11101000_00000000_00000000_00000000, 7);
                data.Add(107, 0b11101010_00000000_00000000_00000000, 7);
                data.Add(108, 0b10100000_00000000_00000000_00000000, 6);
                data.Add(109, 0b10100100_00000000_00000000_00000000, 6);
                data.Add(110, 0b10101000_00000000_00000000_00000000, 6);
                data.Add(111, 0b00111000_00000000_00000000_00000000, 5);
                data.Add(112, 0b10101100_00000000_00000000_00000000, 6);
                data.Add(113, 0b11101100_00000000_00000000_00000000, 7);
                data.Add(114, 0b10110000_00000000_00000000_00000000, 6);
                data.Add(115, 0b01000000_00000000_00000000_00000000, 5);
                data.Add(116, 0b01001000_00000000_00000000_00000000, 5);
                data.Add(117, 0b10110100_00000000_00000000_00000000, 6);
                data.Add(118, 0b11101110_00000000_00000000_00000000, 7);
                data.Add(119, 0b11110000_00000000_00000000_00000000, 7);
                data.Add(120, 0b11110010_00000000_00000000_00000000, 7);
                data.Add(121, 0b11110100_00000000_00000000_00000000, 7);
                data.Add(122, 0b11110110_00000000_00000000_00000000, 7);
                data.Add(123, 0b11111111_11111100_00000000_00000000, 15);
                data.Add(124, 0b11111111_10000000_00000000_00000000, 11);
                data.Add(125, 0b11111111_11110100_00000000_00000000, 14);
                data.Add(126, 0b11111111_11101000_00000000_00000000, 13);
                data.Add(127, 0b11111111_11111111_11111111_11000000, 28);
                data.Add(128, 0b11111111_11111110_01100000_00000000, 20);
                data.Add(129, 0b11111111_11111111_01001000_00000000, 22);
                data.Add(130, 0b11111111_11111110_01110000_00000000, 20);
                data.Add(131, 0b11111111_11111110_10000000_00000000, 20);
                data.Add(132, 0b11111111_11111111_01001100_00000000, 22);
                data.Add(133, 0b11111111_11111111_01010000_00000000, 22);
                data.Add(134, 0b11111111_11111111_01010100_00000000, 22);
                data.Add(135, 0b11111111_11111111_10110010_00000000, 23);
                data.Add(136, 0b11111111_11111111_01011000_00000000, 22);
                data.Add(137, 0b11111111_11111111_10110100_00000000, 23);
                data.Add(138, 0b11111111_11111111_10110110_00000000, 23);
                data.Add(139, 0b11111111_11111111_10111000_00000000, 23);
                data.Add(140, 0b11111111_11111111_10111010_00000000, 23);
                data.Add(141, 0b11111111_11111111_10111100_00000000, 23);
                data.Add(142, 0b11111111_11111111_11101011_00000000, 24);
                data.Add(143, 0b11111111_11111111_10111110_00000000, 23);
                data.Add(144, 0b11111111_11111111_11101100_00000000, 24);
                data.Add(145, 0b11111111_11111111_11101101_00000000, 24);
                data.Add(146, 0b11111111_11111111_01011100_00000000, 22);
                data.Add(147, 0b11111111_11111111_11000000_00000000, 23);
                data.Add(148, 0b11111111_11111111_11101110_00000000, 24);
                data.Add(149, 0b11111111_11111111_11000010_00000000, 23);
                data.Add(150, 0b11111111_11111111_11000100_00000000, 23);
                data.Add(151, 0b11111111_11111111_11000110_00000000, 23);
                data.Add(152, 0b11111111_11111111_11001000_00000000, 23);
                data.Add(153, 0b11111111_11111110_11100000_00000000, 21);
                data.Add(154, 0b11111111_11111111_01100000_00000000, 22);
                data.Add(155, 0b11111111_11111111_11001010_00000000, 23);
                data.Add(156, 0b11111111_11111111_01100100_00000000, 22);
                data.Add(157, 0b11111111_11111111_11001100_00000000, 23);
                data.Add(158, 0b11111111_11111111_11001110_00000000, 23);
                data.Add(159, 0b11111111_11111111_11101111_00000000, 24);
                data.Add(160, 0b11111111_11111111_01101000_00000000, 22);
                data.Add(161, 0b11111111_11111110_11101000_00000000, 21);
                data.Add(162, 0b11111111_11111110_10010000_00000000, 20);
                data.Add(163, 0b11111111_11111111_01101100_00000000, 22);
                data.Add(164, 0b11111111_11111111_01110000_00000000, 22);
                data.Add(165, 0b11111111_11111111_11010000_00000000, 23);
                data.Add(166, 0b11111111_11111111_11010010_00000000, 23);
                data.Add(167, 0b11111111_11111110_11110000_00000000, 21);
                data.Add(168, 0b11111111_11111111_11010100_00000000, 23);
                data.Add(169, 0b11111111_11111111_01110100_00000000, 22);
                data.Add(170, 0b11111111_11111111_01111000_00000000, 22);
                data.Add(171, 0b11111111_11111111_11110000_00000000, 24);
                data.Add(172, 0b11111111_11111110_11111000_00000000, 21);
                data.Add(173, 0b11111111_11111111_01111100_00000000, 22);
                data.Add(174, 0b11111111_11111111_11010110_00000000, 23);
                data.Add(175, 0b11111111_11111111_11011000_00000000, 23);
                data.Add(176, 0b11111111_11111111_00000000_00000000, 21);
                data.Add(177, 0b11111111_11111111_00001000_00000000, 21);
                data.Add(178, 0b11111111_11111111_10000000_00000000, 22);
                data.Add(179, 0b11111111_11111111_00010000_00000000, 21);
                data.Add(180, 0b11111111_11111111_11011010_00000000, 23);
                data.Add(181, 0b11111111_11111111_10000100_00000000, 22);
                data.Add(182, 0b11111111_11111111_11011100_00000000, 23);
                data.Add(183, 0b11111111_11111111_11011110_00000000, 23);
                data.Add(184, 0b11111111_11111110_10100000_00000000, 20);
                data.Add(185, 0b11111111_11111111_10001000_00000000, 22);
                data.Add(186, 0b11111111_11111111_10001100_00000000, 22);
                data.Add(187, 0b11111111_11111111_10010000_00000000, 22);
                data.Add(188, 0b11111111_11111111_11100000_00000000, 23);
                data.Add(189, 0b11111111_11111111_10010100_00000000, 22);
                data.Add(190, 0b11111111_11111111_10011000_00000000, 22);
                data.Add(191, 0b11111111_11111111_11100010_00000000, 23);
                data.Add(192, 0b11111111_11111111_11111000_00000000, 26);
                data.Add(193, 0b11111111_11111111_11111000_01000000, 26);
                data.Add(194, 0b11111111_11111110_10110000_00000000, 20);
                data.Add(195, 0b11111111_11111110_00100000_00000000, 19);
                data.Add(196, 0b11111111_11111111_10011100_00000000, 22);
                data.Add(197, 0b11111111_11111111_11100100_00000000, 23);
                data.Add(198, 0b11111111_11111111_10100000_00000000, 22);
                data.Add(199, 0b11111111_11111111_11110110_00000000, 25);
                data.Add(200, 0b11111111_11111111_11111000_10000000, 26);
                data.Add(201, 0b11111111_11111111_11111000_11000000, 26);
                data.Add(202, 0b11111111_11111111_11111001_00000000, 26);
                data.Add(203, 0b11111111_11111111_11111011_11000000, 27);
                data.Add(204, 0b11111111_11111111_11111011_11100000, 27);
                data.Add(205, 0b11111111_11111111_11111001_01000000, 26);
                data.Add(206, 0b11111111_11111111_11110001_00000000, 24);
                data.Add(207, 0b11111111_11111111_11110110_10000000, 25);
                data.Add(208, 0b11111111_11111110_01000000_00000000, 19);
                data.Add(209, 0b11111111_11111111_00011000_00000000, 21);
                data.Add(210, 0b11111111_11111111_11111001_10000000, 26);
                data.Add(211, 0b11111111_11111111_11111100_00000000, 27);
                data.Add(212, 0b11111111_11111111_11111100_00100000, 27);
                data.Add(213, 0b11111111_11111111_11111001_11000000, 26);
                data.Add(214, 0b11111111_11111111_11111100_01000000, 27);
                data.Add(215, 0b11111111_11111111_11110010_00000000, 24);
                data.Add(216, 0b11111111_11111111_00100000_00000000, 21);
                data.Add(217, 0b11111111_11111111_00101000_00000000, 21);
                data.Add(218, 0b11111111_11111111_11111010_00000000, 26);
                data.Add(219, 0b11111111_11111111_11111010_01000000, 26);
                data.Add(220, 0b11111111_11111111_11111111_11010000, 28);
                data.Add(221, 0b11111111_11111111_11111100_01100000, 27);
                data.Add(222, 0b11111111_11111111_11111100_10000000, 27);
                data.Add(223, 0b11111111_11111111_11111100_10100000, 27);
                data.Add(224, 0b11111111_11111110_11000000_00000000, 20);
                data.Add(225, 0b11111111_11111111_11110011_00000000, 24);
                data.Add(226, 0b11111111_11111110_11010000_00000000, 20);
                data.Add(227, 0b11111111_11111111_00110000_00000000, 21);
                data.Add(228, 0b11111111_11111111_10100100_00000000, 22);
                data.Add(229, 0b11111111_11111111_00111000_00000000, 21);
                data.Add(230, 0b11111111_11111111_01000000_00000000, 21);
                data.Add(231, 0b11111111_11111111_11100110_00000000, 23);
                data.Add(232, 0b11111111_11111111_10101000_00000000, 22);
                data.Add(233, 0b11111111_11111111_10101100_00000000, 22);
                data.Add(234, 0b11111111_11111111_11110111_00000000, 25);
                data.Add(235, 0b11111111_11111111_11110111_10000000, 25);
                data.Add(236, 0b11111111_11111111_11110100_00000000, 24);
                data.Add(237, 0b11111111_11111111_11110101_00000000, 24);
                data.Add(238, 0b11111111_11111111_11111010_10000000, 26);
                data.Add(239, 0b11111111_11111111_11101000_00000000, 23);
                data.Add(240, 0b11111111_11111111_11111010_11000000, 26);
                data.Add(241, 0b11111111_11111111_11111100_11000000, 27);
                data.Add(242, 0b11111111_11111111_11111011_00000000, 26);
                data.Add(243, 0b11111111_11111111_11111011_01000000, 26);
                data.Add(244, 0b11111111_11111111_11111100_11100000, 27);
                data.Add(245, 0b11111111_11111111_11111101_00000000, 27);
                data.Add(246, 0b11111111_11111111_11111101_00100000, 27);
                data.Add(247, 0b11111111_11111111_11111101_01000000, 27);
                data.Add(248, 0b11111111_11111111_11111101_01100000, 27);
                data.Add(249, 0b11111111_11111111_11111111_11100000, 28);
                data.Add(250, 0b11111111_11111111_11111101_10000000, 27);
                data.Add(251, 0b11111111_11111111_11111101_10100000, 27);
                data.Add(252, 0b11111111_11111111_11111101_11000000, 27);
                data.Add(253, 0b11111111_11111111_11111101_11100000, 27);
                data.Add(254, 0b11111111_11111111_11111110_00000000, 27);
                data.Add(255, 0b11111111_11111111_11111011_10000000, 26);
                data.Add(256, 0b11111111_11111111_11111111_11111100, 30);
 
                return data;
            }
        }
    }
}