// 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/varint/hpack_varint_encoder.h"

#include <limits>

#include "quiche/common/platform/api/quiche_logging.h"

namespace http2 {

// static
void HpackVarintEncoder::Encode(uint8_t high_bits, uint8_t prefix_length,
                                uint64_t varint, std::string* output) {
  QUICHE_DCHECK_LE(1u, prefix_length);
  QUICHE_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;
  QUICHE_DCHECK_EQ(0, high_bits & prefix_mask);

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

  // Extension bytes are needed.
  unsigned char first_byte = high_bits | prefix_mask;
  output->push_back(first_byte);

  varint -= prefix_mask;
  while (varint >= 128) {
    // Encode the next seven bits, with continuation bit set to one.
    output->push_back(0b10000000 | (varint % 128));
    varint >>= 7;
  }

  // Encode final seven bits, with continuation bit set to zero.
  output->push_back(varint);
}

}  // namespace http2
