text: // Copyright 2018 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_QUIC_CORE_QPACK_QPACK_INSTRUCTION_ENCODER_H_
  #define QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTION_ENCODER_H_
  
  #include <cstdint>
  #include <string>
  
  #include "absl/strings/string_view.h"
  #include "quic/core/qpack/qpack_instructions.h"
  #include "quic/platform/api/quic_export.h"
  
  namespace quic {
  
  // Generic instruction encoder class.  Takes a QpackLanguage that describes a
  // language, that is, a set of instruction opcodes together with a list of
  // fields that follow each instruction.
  class QUIC_EXPORT_PRIVATE QpackInstructionEncoder {
   public:
    QpackInstructionEncoder();
    QpackInstructionEncoder(const QpackInstructionEncoder&) = delete;
    QpackInstructionEncoder& operator=(const QpackInstructionEncoder&) = delete;
  
    // Append encoded instruction to |output|.
    void Encode(const QpackInstructionWithValues& instruction_with_values,
                std::string* output);
  
   private:
    enum class State {
      // Write instruction opcode to |byte_|.
      kOpcode,
      // Select state based on type of current field.
      kStartField,
      // Write static bit to |byte_|.
      kSbit,
      // Encode an integer (|varint_| or |varint2_| or string length) with a
      // prefix, using |byte_| for the high bits.
      kVarintEncode,
      // Determine if Huffman encoding should be used for the header name or
      // value, set |use_huffman_| and |string_length_| appropriately, write the
      // Huffman bit to |byte_|.
      kStartString,
      // Write header name or value, performing Huffman encoding if |use_huffman_|
      // is true.
      kWriteString
    };
  
    // One method for each state.  Some append encoded bytes to |output|.
    // Some only change internal state.
    void DoOpcode();
    void DoStartField();
    void DoSBit(bool s_bit);
    void DoVarintEncode(uint64_t varint, uint64_t varint2, std::string* output);
    void DoStartString(absl::string_view name, absl::string_view value);
    void DoWriteString(absl::string_view name,
                       absl::string_view value,
                       std::string* output);
  
    // True if name or value should be Huffman encoded.
    bool use_huffman_;
  
    // Length of name or value string to be written.
    // If |use_huffman_| is true, length is after Huffman encoding.
    size_t string_length_;
  
    // Storage for a single byte that contains multiple fields, that is, multiple
    // states are writing it.
    uint8_t byte_;
  
    // Encoding state.
    State state_;
  
    // Instruction currently being decoded.
    const QpackInstruction* instruction_;
  
    // Field currently being decoded.
    QpackInstructionFields::const_iterator field_;
  };
  
  }  // namespace quic
  
  #endif  // QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTION_ENCODER_H_
  