// 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 "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_encoder.h"

#include "base/logging.h"

namespace http2 {

HpackVarintEncoder::HpackVarintEncoder()
    : varint_(0), encoding_in_progress_(false) {}

unsigned char HpackVarintEncoder::StartEncoding(uint8_t high_bits,
                                                uint8_t prefix_length,
                                                uint64_t varint) {
  DCHECK(!encoding_in_progress_);
  DCHECK_EQ(0u, varint_);
  DCHECK_LE(1u, prefix_length);
  DCHECK_LE(prefix_length, 8u);

  // prefix_mask defines the sequence of low-order bits of the first byte
  // that encode the prefix of the value. It is also the marker in those bits
  // of the first byte indicating that at least one extension byte is needed.
  const uint8_t prefix_mask = (1 << prefix_length) - 1;
  DCHECK_EQ(0, high_bits & prefix_mask);

  if (varint < prefix_mask) {
    // The integer fits into the prefix in its entirety.
    return high_bits | static_cast<unsigned char>(varint);
  }

  // We need extension bytes.
  varint_ = varint - prefix_mask;
  encoding_in_progress_ = true;
  return high_bits | prefix_mask;
}

size_t HpackVarintEncoder::ResumeEncoding(size_t max_encoded_bytes,
                                          Http2String* output) {
  DCHECK(encoding_in_progress_);
  DCHECK_NE(0u, max_encoded_bytes);

  size_t encoded_bytes = 0;
  while (encoded_bytes < max_encoded_bytes) {
    ++encoded_bytes;
    if (varint_ < 128) {
      // Encode final seven bits, with continuation bit set to zero.
      output->push_back(varint_);
      varint_ = 0;
      encoding_in_progress_ = false;
      break;
    }
    // Encode the next seven bits, with continuation bit set to one.
    output->push_back(0b10000000 | (varint_ % 128));
    varint_ >>= 7;
  }
  return encoded_bytes;
}

bool HpackVarintEncoder::IsEncodingInProgress() const {
  return encoding_in_progress_;
}

}  // namespace http2
