| // Copyright 2016 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef QUICHE_HTTP2_HPACK_HUFFMAN_HPACK_HUFFMAN_DECODER_H_ | |
| #define QUICHE_HTTP2_HPACK_HUFFMAN_HPACK_HUFFMAN_DECODER_H_ | |
| // HpackHuffmanDecoder is an incremental decoder of strings that have been | |
| // encoded using the Huffman table defined in the HPACK spec. | |
| // By incremental, we mean that the HpackHuffmanDecoder::Decode method does | |
| // not require the entire string to be provided, and can instead decode the | |
| // string as fragments of it become available (e.g. as HPACK block fragments | |
| // are received for decoding by HpackEntryDecoder). | |
| #include <stddef.h> | |
| #include <cstdint> | |
| #include <iosfwd> | |
| #include <string> | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_export.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h" | |
| namespace http2 { | |
| // HuffmanAccumulator is used to store bits during decoding, e.g. next N bits | |
| // that have not yet been decoded, but have been extracted from the encoded | |
| // string). An advantage of using a uint64 for the accumulator | |
| // is that it has room for the bits of the longest code plus the bits of a full | |
| // byte; that means that when adding more bits to the accumulator, it can always | |
| // be done in whole bytes. For example, if we currently have 26 bits in the | |
| // accumulator, and need more to decode the current symbol, we can add a whole | |
| // byte to the accumulator, and not have to do juggling with adding 6 bits (to | |
| // reach 30), and then keep track of the last two bits we've not been able to | |
| // add to the accumulator. | |
| typedef uint64_t HuffmanAccumulator; | |
| typedef size_t HuffmanAccumulatorBitCount; | |
| // HuffmanBitBuffer stores the leading edge of bits to be decoded. The high | |
| // order bit of accumulator_ is the next bit to be decoded. | |
| class HTTP2_EXPORT_PRIVATE HuffmanBitBuffer { | |
| public: | |
| HuffmanBitBuffer(); | |
| // Prepare for decoding a new Huffman encoded string. | |
| void Reset(); | |
| // Add as many whole bytes to the accumulator (accumulator_) as possible, | |
| // returning the number of bytes added. | |
| size_t AppendBytes(Http2StringPiece input); | |
| // Get the bits of the accumulator. | |
| HuffmanAccumulator value() const { return accumulator_; } | |
| // Number of bits of the encoded string that are in the accumulator | |
| // (accumulator_). | |
| HuffmanAccumulatorBitCount count() const { return count_; } | |
| // Are there no bits in the accumulator? | |
| bool IsEmpty() const { return count_ == 0; } | |
| // Number of additional bits that can be added to the accumulator. | |
| HuffmanAccumulatorBitCount free_count() const; | |
| // Consume the leading |code_length| bits of the accumulator. | |
| void ConsumeBits(HuffmanAccumulatorBitCount code_length); | |
| // Are the contents valid for the end of a Huffman encoded string? The RFC | |
| // states that EOS (end-of-string) symbol must not be explicitly encoded in | |
| // the bit stream, but any unused bits in the final byte must be set to the | |
| // prefix of the EOS symbol, which is all 1 bits. So there can be at most 7 | |
| // such bits. | |
| // Returns true if the bit buffer is empty, or contains at most 7 bits, all | |
| // of them 1. Otherwise returns false. | |
| bool InputProperlyTerminated() const; | |
| std::string DebugString() const; | |
| private: | |
| HuffmanAccumulator accumulator_; | |
| HuffmanAccumulatorBitCount count_; | |
| }; | |
| inline std::ostream& operator<<(std::ostream& out, const HuffmanBitBuffer& v) { | |
| return out << v.DebugString(); | |
| } | |
| class HTTP2_EXPORT_PRIVATE HpackHuffmanDecoder { | |
| public: | |
| HpackHuffmanDecoder(); | |
| ~HpackHuffmanDecoder(); | |
| // Prepare for decoding a new Huffman encoded string. | |
| void Reset() { bit_buffer_.Reset(); } | |
| // Decode the portion of a HPACK Huffman encoded string that is in |input|, | |
| // appending the decoded symbols into |*output|, stopping when more bits are | |
| // needed to determine the next symbol, which/ means that the input has been | |
| // drained, and also that the bit_buffer_ is empty or that the bits that are | |
| // in it are not a whole symbol. | |
| // If |input| is the start of a string, the caller must first call Reset. | |
| // If |input| includes the end of the encoded string, the caller must call | |
| // InputProperlyTerminated after Decode has returned true in order to | |
| // determine if the encoded string was properly terminated. | |
| // Returns false if something went wrong (e.g. the encoding contains the code | |
| // EOS symbol). Otherwise returns true, in which case input has been fully | |
| // decoded or buffered; in particular, if the low-order bit of the final byte | |
| // of the input is not the last bit of an encoded symbol, then bit_buffer_ | |
| // will contain the leading bits of the code for that symbol, but not the | |
| // final bits of that code. | |
| // Note that output should be empty, but that it is not cleared by Decode(). | |
| bool Decode(Http2StringPiece input, std::string* output); | |
| // Is what remains in the bit_buffer_ valid at the end of an encoded string? | |
| // Call after passing the the final portion of a Huffman string to Decode, | |
| // and getting true as the result. | |
| bool InputProperlyTerminated() const { | |
| return bit_buffer_.InputProperlyTerminated(); | |
| } | |
| std::string DebugString() const; | |
| private: | |
| HuffmanBitBuffer bit_buffer_; | |
| }; | |
| inline std::ostream& operator<<(std::ostream& out, | |
| const HpackHuffmanDecoder& v) { | |
| return out << v.DebugString(); | |
| } | |
| } // namespace http2 | |
| #endif // QUICHE_HTTP2_HPACK_HUFFMAN_HPACK_HUFFMAN_DECODER_H_ |