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); }
/// <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); }