// 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.

#include "quiche/http2/hpack/decoder/hpack_entry_type_decoder.h"

#include "absl/strings/str_cat.h"
#include "quiche/common/platform/api/quiche_bug_tracker.h"
#include "quiche/common/platform/api/quiche_flag_utils.h"
#include "quiche/common/platform/api/quiche_logging.h"

namespace http2 {

std::string HpackEntryTypeDecoder::DebugString() const {
  return absl::StrCat(
      "HpackEntryTypeDecoder(varint_decoder=", varint_decoder_.DebugString(),
      ", entry_type=", entry_type_, ")");
}

std::ostream& operator<<(std::ostream& out, const HpackEntryTypeDecoder& v) {
  return out << v.DebugString();
}

// This ridiculous looking function turned out to be the winner in benchmarking
// of several very different alternative implementations. It would be even
// faster (~7%) if inlined in the header file, but I'm not sure if that is
// worth doing... yet.
// TODO(jamessynge): Benchmark again at a higher level (e.g. at least at the
// full HTTP/2 decoder level, but preferably still higher) to determine if the
// alternatives that take less code/data space are preferable in that situation.
DecodeStatus HpackEntryTypeDecoder::Start(DecodeBuffer* db) {
  QUICHE_DCHECK(db != nullptr);
  QUICHE_DCHECK(db->HasData());

  // The high four bits (nibble) of first byte of the entry determine the type
  // of the entry, and may also be the initial bits of the varint that
  // represents an index or table size. Note the use of the word 'initial'
  // rather than 'high'; the HPACK encoding of varints is not in network
  // order (i.e. not big-endian, the high-order byte isn't first), nor in
  // little-endian order. See:
  // http://httpwg.org/specs/rfc7541.html#integer.representation
  uint8_t byte = db->DecodeUInt8();
  switch (byte) {
    case 0b00000000:
    case 0b00000001:
    case 0b00000010:
    case 0b00000011:
    case 0b00000100:
    case 0b00000101:
    case 0b00000110:
    case 0b00000111:
    case 0b00001000:
    case 0b00001001:
    case 0b00001010:
    case 0b00001011:
    case 0b00001100:
    case 0b00001101:
    case 0b00001110:
      // The low 4 bits of |byte| are the initial bits of the varint.
      // One of those bits is 0, so the varint is only one byte long.
      entry_type_ = HpackEntryType::kUnindexedLiteralHeader;
      varint_decoder_.set_value(byte);
      return DecodeStatus::kDecodeDone;

    case 0b00001111:
      // The low 4 bits of |byte| are the initial bits of the varint. All 4
      // are 1, so the varint extends into another byte.
      entry_type_ = HpackEntryType::kUnindexedLiteralHeader;
      return varint_decoder_.StartExtended(4, db);

    case 0b00010000:
    case 0b00010001:
    case 0b00010010:
    case 0b00010011:
    case 0b00010100:
    case 0b00010101:
    case 0b00010110:
    case 0b00010111:
    case 0b00011000:
    case 0b00011001:
    case 0b00011010:
    case 0b00011011:
    case 0b00011100:
    case 0b00011101:
    case 0b00011110:
      // The low 4 bits of |byte| are the initial bits of the varint.
      // One of those bits is 0, so the varint is only one byte long.
      entry_type_ = HpackEntryType::kNeverIndexedLiteralHeader;
      varint_decoder_.set_value(byte & 0x0f);
      return DecodeStatus::kDecodeDone;

    case 0b00011111:
      // The low 4 bits of |byte| are the initial bits of the varint.
      // All of those bits are 1, so the varint extends into another byte.
      entry_type_ = HpackEntryType::kNeverIndexedLiteralHeader;
      return varint_decoder_.StartExtended(4, db);

    case 0b00100000:
    case 0b00100001:
    case 0b00100010:
    case 0b00100011:
    case 0b00100100:
    case 0b00100101:
    case 0b00100110:
    case 0b00100111:
    case 0b00101000:
    case 0b00101001:
    case 0b00101010:
    case 0b00101011:
    case 0b00101100:
    case 0b00101101:
    case 0b00101110:
    case 0b00101111:
    case 0b00110000:
    case 0b00110001:
    case 0b00110010:
    case 0b00110011:
    case 0b00110100:
    case 0b00110101:
    case 0b00110110:
    case 0b00110111:
    case 0b00111000:
    case 0b00111001:
    case 0b00111010:
    case 0b00111011:
    case 0b00111100:
    case 0b00111101:
    case 0b00111110:
      entry_type_ = HpackEntryType::kDynamicTableSizeUpdate;
      // The low 5 bits of |byte| are the initial bits of the varint.
      // One of those bits is 0, so the varint is only one byte long.
      varint_decoder_.set_value(byte & 0x01f);
      return DecodeStatus::kDecodeDone;

    case 0b00111111:
      entry_type_ = HpackEntryType::kDynamicTableSizeUpdate;
      // The low 5 bits of |byte| are the initial bits of the varint.
      // All of those bits are 1, so the varint extends into another byte.
      return varint_decoder_.StartExtended(5, db);

    case 0b01000000:
    case 0b01000001:
    case 0b01000010:
    case 0b01000011:
    case 0b01000100:
    case 0b01000101:
    case 0b01000110:
    case 0b01000111:
    case 0b01001000:
    case 0b01001001:
    case 0b01001010:
    case 0b01001011:
    case 0b01001100:
    case 0b01001101:
    case 0b01001110:
    case 0b01001111:
    case 0b01010000:
    case 0b01010001:
    case 0b01010010:
    case 0b01010011:
    case 0b01010100:
    case 0b01010101:
    case 0b01010110:
    case 0b01010111:
    case 0b01011000:
    case 0b01011001:
    case 0b01011010:
    case 0b01011011:
    case 0b01011100:
    case 0b01011101:
    case 0b01011110:
    case 0b01011111:
    case 0b01100000:
    case 0b01100001:
    case 0b01100010:
    case 0b01100011:
    case 0b01100100:
    case 0b01100101:
    case 0b01100110:
    case 0b01100111:
    case 0b01101000:
    case 0b01101001:
    case 0b01101010:
    case 0b01101011:
    case 0b01101100:
    case 0b01101101:
    case 0b01101110:
    case 0b01101111:
    case 0b01110000:
    case 0b01110001:
    case 0b01110010:
    case 0b01110011:
    case 0b01110100:
    case 0b01110101:
    case 0b01110110:
    case 0b01110111:
    case 0b01111000:
    case 0b01111001:
    case 0b01111010:
    case 0b01111011:
    case 0b01111100:
    case 0b01111101:
    case 0b01111110:
      entry_type_ = HpackEntryType::kIndexedLiteralHeader;
      // The low 6 bits of |byte| are the initial bits of the varint.
      // One of those bits is 0, so the varint is only one byte long.
      varint_decoder_.set_value(byte & 0x03f);
      return DecodeStatus::kDecodeDone;

    case 0b01111111:
      entry_type_ = HpackEntryType::kIndexedLiteralHeader;
      // The low 6 bits of |byte| are the initial bits of the varint.
      // All of those bits are 1, so the varint extends into another byte.
      return varint_decoder_.StartExtended(6, db);

    case 0b10000000:
    case 0b10000001:
    case 0b10000010:
    case 0b10000011:
    case 0b10000100:
    case 0b10000101:
    case 0b10000110:
    case 0b10000111:
    case 0b10001000:
    case 0b10001001:
    case 0b10001010:
    case 0b10001011:
    case 0b10001100:
    case 0b10001101:
    case 0b10001110:
    case 0b10001111:
    case 0b10010000:
    case 0b10010001:
    case 0b10010010:
    case 0b10010011:
    case 0b10010100:
    case 0b10010101:
    case 0b10010110:
    case 0b10010111:
    case 0b10011000:
    case 0b10011001:
    case 0b10011010:
    case 0b10011011:
    case 0b10011100:
    case 0b10011101:
    case 0b10011110:
    case 0b10011111:
    case 0b10100000:
    case 0b10100001:
    case 0b10100010:
    case 0b10100011:
    case 0b10100100:
    case 0b10100101:
    case 0b10100110:
    case 0b10100111:
    case 0b10101000:
    case 0b10101001:
    case 0b10101010:
    case 0b10101011:
    case 0b10101100:
    case 0b10101101:
    case 0b10101110:
    case 0b10101111:
    case 0b10110000:
    case 0b10110001:
    case 0b10110010:
    case 0b10110011:
    case 0b10110100:
    case 0b10110101:
    case 0b10110110:
    case 0b10110111:
    case 0b10111000:
    case 0b10111001:
    case 0b10111010:
    case 0b10111011:
    case 0b10111100:
    case 0b10111101:
    case 0b10111110:
    case 0b10111111:
    case 0b11000000:
    case 0b11000001:
    case 0b11000010:
    case 0b11000011:
    case 0b11000100:
    case 0b11000101:
    case 0b11000110:
    case 0b11000111:
    case 0b11001000:
    case 0b11001001:
    case 0b11001010:
    case 0b11001011:
    case 0b11001100:
    case 0b11001101:
    case 0b11001110:
    case 0b11001111:
    case 0b11010000:
    case 0b11010001:
    case 0b11010010:
    case 0b11010011:
    case 0b11010100:
    case 0b11010101:
    case 0b11010110:
    case 0b11010111:
    case 0b11011000:
    case 0b11011001:
    case 0b11011010:
    case 0b11011011:
    case 0b11011100:
    case 0b11011101:
    case 0b11011110:
    case 0b11011111:
    case 0b11100000:
    case 0b11100001:
    case 0b11100010:
    case 0b11100011:
    case 0b11100100:
    case 0b11100101:
    case 0b11100110:
    case 0b11100111:
    case 0b11101000:
    case 0b11101001:
    case 0b11101010:
    case 0b11101011:
    case 0b11101100:
    case 0b11101101:
    case 0b11101110:
    case 0b11101111:
    case 0b11110000:
    case 0b11110001:
    case 0b11110010:
    case 0b11110011:
    case 0b11110100:
    case 0b11110101:
    case 0b11110110:
    case 0b11110111:
    case 0b11111000:
    case 0b11111001:
    case 0b11111010:
    case 0b11111011:
    case 0b11111100:
    case 0b11111101:
    case 0b11111110:
      entry_type_ = HpackEntryType::kIndexedHeader;
      // The low 7 bits of |byte| are the initial bits of the varint.
      // One of those bits is 0, so the varint is only one byte long.
      varint_decoder_.set_value(byte & 0x07f);
      return DecodeStatus::kDecodeDone;

    case 0b11111111:
      entry_type_ = HpackEntryType::kIndexedHeader;
      // The low 7 bits of |byte| are the initial bits of the varint.
      // All of those bits are 1, so the varint extends into another byte.
      return varint_decoder_.StartExtended(7, db);
  }
  QUICHE_BUG(http2_bug_66_1)
      << "Unreachable, byte=" << std::hex << static_cast<uint32_t>(byte);
  QUICHE_CODE_COUNT_N(decompress_failure_3, 17, 23);
  return DecodeStatus::kDecodeError;
}

}  // namespace http2
