Example #1
0
        private int DecodeContByteData(ArraySegment <byte> buf)
        {
            var offset = buf.Offset;
            var count  = buf.Count;

            // Check how many bytes are available and how much we need
            var available = count;
            var need      = this._octetLength - this._bufferOffset;

            var toCopy = available >= need ? need : available;

            if (toCopy > 0)
            {
                // Return is wrong because it doesn't handle 0byte strings
                // Copy that amount of data into our target buffer
                Array.Copy(buf.Array, offset, this._stringBuffer, this._bufferOffset, toCopy);
                this._bufferOffset += toCopy;
                // Adjust the offset of the input and output buffer
                offset += toCopy;
                count  -= toCopy;
            }

            if (this._bufferOffset == this._octetLength)
            {
                // Copied everything
                var view = new ArraySegment <byte>(
                    this._stringBuffer, 0, this._octetLength
                    );
                if (this._huffman)
                {
                    // We need to perform huffman decoding
                    this.Result = Huffman.Decode(view, _bufferPool);
                }
                else
                {
                    // TODO: Check if encoding is really correct
                    this.Result =
                        Encoding.ASCII.GetString(view.Array, view.Offset, view.Count);
                }
                // TODO: Optionally check here for valid HTTP/2 header names
                this.Done = true;
                // The string length for the table is used without huffman encoding
                // TODO: This might by a different result than Encoding.ASCII.GetByteCount
                // Might be required to streamline that
                this.StringLength = this.Result.Length;
                this._state       = State.StartDecode;

                _bufferPool.Return(this._stringBuffer);
                this._stringBuffer = null;
            }
            // Else we need more input data

            return(offset - buf.Offset);
        }
Example #2
0
        /// <summary>
        /// Encodes the given string into the target buffer
        /// </summary>
        /// <param name="buf">The buffer into which the string should be serialized</param>
        /// <param name="value">The value to encode</param>
        /// <param name="valueByteLen">
        /// The length of the string in bytes in non-huffman-encoded form.
        /// This can be retrieved through the GetByteLength method.
        /// </param>
        /// <param name="huffman">Controls the huffman encoding</param>
        /// <returns>
        /// The number of bytes that were required to encode the value.
        /// -1 if the value did not fit into the buffer.
        /// </returns>
        public static int EncodeInto(
            ArraySegment <byte> buf,
            string value, int valueByteLen, HuffmanStrategy huffman)
        {
            var offset = buf.Offset;
            var free   = buf.Count;

            // Fast check for free space. Doesn't need to be exact
            if (free < 1 + valueByteLen)
            {
                return(-1);
            }

            var encodedByteLen       = valueByteLen;
            var requiredHuffmanBytes = 0;
            var useHuffman           = huffman == HuffmanStrategy.Always;

            byte[] huffmanInputBuf = null;

            // Check if the string should be reencoded with huffman encoding
            if (huffman == HuffmanStrategy.Always || huffman == HuffmanStrategy.IfSmaller)
            {
                huffmanInputBuf      = Encoding.ASCII.GetBytes(value);
                requiredHuffmanBytes = Huffman.EncodedLength(
                    new ArraySegment <byte>(huffmanInputBuf));
                if (huffman == HuffmanStrategy.IfSmaller && requiredHuffmanBytes < encodedByteLen)
                {
                    useHuffman = true;
                }
            }

            if (useHuffman)
            {
                encodedByteLen = requiredHuffmanBytes;
            }

            // Write the required length to the target buffer
            var prefixContent = useHuffman ? (byte)0x80 : (byte)0;
            var used          = IntEncoder.EncodeInto(
                new ArraySegment <byte>(buf.Array, offset, free),
                encodedByteLen, prefixContent, 7);

            if (used == -1)
            {
                return(-1);            // Couldn't write length
            }
            offset += used;
            free   -= used;

            if (useHuffman)
            {
                if (free < requiredHuffmanBytes)
                {
                    return(-1);
                }
                // Use the huffman encoder to write bytes to target buffer
                used = Huffman.EncodeInto(
                    new ArraySegment <byte>(buf.Array, offset, free),
                    new ArraySegment <byte>(huffmanInputBuf));
                if (used == -1)
                {
                    return(-1);            // Couldn't write length
                }
                offset += used;
            }
            else
            {
                if (free < valueByteLen)
                {
                    return(-1);
                }
                // Use ASCII encoder to write bytes to target buffer
                used = Encoding.ASCII.GetBytes(
                    value, 0, value.Length, buf.Array, offset);
                offset += used;
            }

            // Return the number amount of used bytes
            return(offset - buf.Offset);
        }