| Index: net/spdy/hpack/hpack_huffman_table.cc
|
| diff --git a/net/spdy/hpack/hpack_huffman_table.cc b/net/spdy/hpack/hpack_huffman_table.cc
|
| deleted file mode 100644
|
| index a398d263a733a011f964f66c28e6430d18bb1824..0000000000000000000000000000000000000000
|
| --- a/net/spdy/hpack/hpack_huffman_table.cc
|
| +++ /dev/null
|
| @@ -1,326 +0,0 @@
|
| -// Copyright 2014 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/spdy/hpack/hpack_huffman_table.h"
|
| -
|
| -#include <algorithm>
|
| -#include <cmath>
|
| -#include <memory>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/numerics/safe_conversions.h"
|
| -#include "net/spdy/hpack/hpack_input_stream.h"
|
| -#include "net/spdy/hpack/hpack_output_stream.h"
|
| -#include "net/spdy/platform/api/spdy_estimate_memory_usage.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// How many bits to index in the root decode table.
|
| -const uint8_t kDecodeTableRootBits = 9;
|
| -// Maximum number of bits to index in successive decode tables.
|
| -const uint8_t kDecodeTableBranchBits = 6;
|
| -
|
| -bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a,
|
| - const HpackHuffmanSymbol& b) {
|
| - if (a.length == b.length) {
|
| - return a.id < b.id;
|
| - }
|
| - return a.length < b.length;
|
| -}
|
| -bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) {
|
| - return a.id < b.id;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -HpackHuffmanTable::DecodeEntry::DecodeEntry()
|
| - : next_table_index(0), length(0), symbol_id(0) {}
|
| -HpackHuffmanTable::DecodeEntry::DecodeEntry(uint8_t next_table_index,
|
| - uint8_t length,
|
| - uint16_t symbol_id)
|
| - : next_table_index(next_table_index),
|
| - length(length),
|
| - symbol_id(symbol_id) {}
|
| -size_t HpackHuffmanTable::DecodeTable::size() const {
|
| - return size_t(1) << indexed_length;
|
| -}
|
| -
|
| -HpackHuffmanTable::HpackHuffmanTable() : pad_bits_(0), failed_symbol_id_(0) {}
|
| -
|
| -HpackHuffmanTable::~HpackHuffmanTable() {}
|
| -
|
| -bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols,
|
| - size_t symbol_count) {
|
| - CHECK(!IsInitialized());
|
| - DCHECK(base::IsValueInRangeForNumericType<uint16_t>(symbol_count));
|
| -
|
| - std::vector<Symbol> symbols(symbol_count);
|
| - // Validate symbol id sequence, and copy into |symbols|.
|
| - for (uint16_t i = 0; i < symbol_count; i++) {
|
| - if (i != input_symbols[i].id) {
|
| - failed_symbol_id_ = i;
|
| - return false;
|
| - }
|
| - symbols[i] = input_symbols[i];
|
| - }
|
| - // Order on length and ID ascending, to verify symbol codes are canonical.
|
| - std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare);
|
| - if (symbols[0].code != 0) {
|
| - failed_symbol_id_ = 0;
|
| - return false;
|
| - }
|
| - for (size_t i = 1; i != symbols.size(); i++) {
|
| - unsigned code_shift = 32 - symbols[i - 1].length;
|
| - uint32_t code = symbols[i - 1].code + (1 << code_shift);
|
| -
|
| - if (code != symbols[i].code) {
|
| - failed_symbol_id_ = symbols[i].id;
|
| - return false;
|
| - }
|
| - if (code < symbols[i - 1].code) {
|
| - // An integer overflow occurred. This implies the input
|
| - // lengths do not represent a valid Huffman code.
|
| - failed_symbol_id_ = symbols[i].id;
|
| - return false;
|
| - }
|
| - }
|
| - if (symbols.back().length < 8) {
|
| - // At least one code (such as an EOS symbol) must be 8 bits or longer.
|
| - // Without this, some inputs will not be encodable in a whole number
|
| - // of bytes.
|
| - return false;
|
| - }
|
| - pad_bits_ = static_cast<uint8_t>(symbols.back().code >> 24);
|
| -
|
| - BuildDecodeTables(symbols);
|
| - // Order on symbol ID ascending.
|
| - std::sort(symbols.begin(), symbols.end(), SymbolIdCompare);
|
| - BuildEncodeTable(symbols);
|
| - return true;
|
| -}
|
| -
|
| -void HpackHuffmanTable::BuildEncodeTable(const std::vector<Symbol>& symbols) {
|
| - for (size_t i = 0; i != symbols.size(); i++) {
|
| - const Symbol& symbol = symbols[i];
|
| - CHECK_EQ(i, symbol.id);
|
| - code_by_id_.push_back(symbol.code);
|
| - length_by_id_.push_back(symbol.length);
|
| - }
|
| -}
|
| -
|
| -void HpackHuffmanTable::BuildDecodeTables(const std::vector<Symbol>& symbols) {
|
| - AddDecodeTable(0, kDecodeTableRootBits);
|
| - // We wish to maximize the flatness of the DecodeTable hierarchy (subject to
|
| - // the |kDecodeTableBranchBits| constraint), and to minimize the size of
|
| - // child tables. To achieve this, we iterate in order of descending code
|
| - // length. This ensures that child tables are visited with their longest
|
| - // entry first, and that the child can therefore be minimally sized to hold
|
| - // that entry without fear of introducing unneccesary branches later.
|
| - for (std::vector<Symbol>::const_reverse_iterator it = symbols.rbegin();
|
| - it != symbols.rend(); ++it) {
|
| - uint8_t table_index = 0;
|
| - while (true) {
|
| - const DecodeTable table = decode_tables_[table_index];
|
| -
|
| - // Mask and shift the portion of the code being indexed into low bits.
|
| - uint32_t index = (it->code << table.prefix_length);
|
| - index = index >> (32 - table.indexed_length);
|
| -
|
| - CHECK_LT(index, table.size());
|
| - DecodeEntry entry = Entry(table, index);
|
| -
|
| - uint8_t total_indexed = table.prefix_length + table.indexed_length;
|
| - if (total_indexed >= it->length) {
|
| - // We're writing a terminal entry.
|
| - entry.length = it->length;
|
| - entry.symbol_id = it->id;
|
| - entry.next_table_index = table_index;
|
| - SetEntry(table, index, entry);
|
| - break;
|
| - }
|
| -
|
| - if (entry.length == 0) {
|
| - // First visit to this placeholder. We need to create a new table.
|
| - CHECK_EQ(entry.next_table_index, 0);
|
| - entry.length = it->length;
|
| - entry.next_table_index =
|
| - AddDecodeTable(total_indexed, // Becomes the new table prefix.
|
| - std::min<uint8_t>(kDecodeTableBranchBits,
|
| - entry.length - total_indexed));
|
| - SetEntry(table, index, entry);
|
| - }
|
| - CHECK_NE(entry.next_table_index, table_index);
|
| - table_index = entry.next_table_index;
|
| - }
|
| - }
|
| - // Fill shorter table entries into the additional entry spots they map to.
|
| - for (size_t i = 0; i != decode_tables_.size(); i++) {
|
| - const DecodeTable& table = decode_tables_[i];
|
| - uint8_t total_indexed = table.prefix_length + table.indexed_length;
|
| -
|
| - size_t j = 0;
|
| - while (j != table.size()) {
|
| - const DecodeEntry& entry = Entry(table, j);
|
| - if (entry.length != 0 && entry.length < total_indexed) {
|
| - // The difference between entry & table bit counts tells us how
|
| - // many additional entries map to this one.
|
| - size_t fill_count = static_cast<size_t>(1)
|
| - << (total_indexed - entry.length);
|
| - CHECK_LE(j + fill_count, table.size());
|
| -
|
| - for (size_t k = 1; k != fill_count; k++) {
|
| - CHECK_EQ(Entry(table, j + k).length, 0);
|
| - SetEntry(table, j + k, entry);
|
| - }
|
| - j += fill_count;
|
| - } else {
|
| - j++;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -uint8_t HpackHuffmanTable::AddDecodeTable(uint8_t prefix, uint8_t indexed) {
|
| - CHECK_LT(decode_tables_.size(), 255u);
|
| - {
|
| - DecodeTable table;
|
| - table.prefix_length = prefix;
|
| - table.indexed_length = indexed;
|
| - table.entries_offset = decode_entries_.size();
|
| - decode_tables_.push_back(table);
|
| - }
|
| - decode_entries_.resize(decode_entries_.size() + (size_t(1) << indexed));
|
| - return static_cast<uint8_t>(decode_tables_.size() - 1);
|
| -}
|
| -
|
| -const HpackHuffmanTable::DecodeEntry& HpackHuffmanTable::Entry(
|
| - const DecodeTable& table,
|
| - uint32_t index) const {
|
| - DCHECK_LT(index, table.size());
|
| - DCHECK_LT(table.entries_offset + index, decode_entries_.size());
|
| - return decode_entries_[table.entries_offset + index];
|
| -}
|
| -
|
| -void HpackHuffmanTable::SetEntry(const DecodeTable& table,
|
| - uint32_t index,
|
| - const DecodeEntry& entry) {
|
| - CHECK_LT(index, table.size());
|
| - CHECK_LT(table.entries_offset + index, decode_entries_.size());
|
| - decode_entries_[table.entries_offset + index] = entry;
|
| -}
|
| -
|
| -bool HpackHuffmanTable::IsInitialized() const {
|
| - return !code_by_id_.empty();
|
| -}
|
| -
|
| -void HpackHuffmanTable::EncodeString(SpdyStringPiece in,
|
| - HpackOutputStream* out) const {
|
| - size_t bit_remnant = 0;
|
| - for (size_t i = 0; i != in.size(); i++) {
|
| - uint16_t symbol_id = static_cast<uint8_t>(in[i]);
|
| - CHECK_GT(code_by_id_.size(), symbol_id);
|
| -
|
| - // Load, and shift code to low bits.
|
| - unsigned length = length_by_id_[symbol_id];
|
| - uint32_t code = code_by_id_[symbol_id] >> (32 - length);
|
| -
|
| - bit_remnant = (bit_remnant + length) % 8;
|
| -
|
| - if (length > 24) {
|
| - out->AppendBits(static_cast<uint8_t>(code >> 24), length - 24);
|
| - length = 24;
|
| - }
|
| - if (length > 16) {
|
| - out->AppendBits(static_cast<uint8_t>(code >> 16), length - 16);
|
| - length = 16;
|
| - }
|
| - if (length > 8) {
|
| - out->AppendBits(static_cast<uint8_t>(code >> 8), length - 8);
|
| - length = 8;
|
| - }
|
| - out->AppendBits(static_cast<uint8_t>(code), length);
|
| - }
|
| - if (bit_remnant != 0) {
|
| - // Pad current byte as required.
|
| - out->AppendBits(pad_bits_ >> bit_remnant, 8 - bit_remnant);
|
| - }
|
| -}
|
| -
|
| -size_t HpackHuffmanTable::EncodedSize(SpdyStringPiece in) const {
|
| - size_t bit_count = 0;
|
| - for (size_t i = 0; i != in.size(); i++) {
|
| - uint16_t symbol_id = static_cast<uint8_t>(in[i]);
|
| - CHECK_GT(code_by_id_.size(), symbol_id);
|
| -
|
| - bit_count += length_by_id_[symbol_id];
|
| - }
|
| - if (bit_count % 8 != 0) {
|
| - bit_count += 8 - bit_count % 8;
|
| - }
|
| - return bit_count / 8;
|
| -}
|
| -
|
| -bool HpackHuffmanTable::GenericDecodeString(HpackInputStream* in,
|
| - SpdyString* out) const {
|
| - // Number of decode iterations required for a 32-bit code.
|
| - const int kDecodeIterations = static_cast<int>(
|
| - std::ceil((32.f - kDecodeTableRootBits) / kDecodeTableBranchBits));
|
| -
|
| - out->clear();
|
| -
|
| - // Current input, stored in the high |bits_available| bits of |bits|.
|
| - uint32_t bits = 0;
|
| - size_t bits_available = 0;
|
| - bool peeked_success = in->PeekBits(&bits_available, &bits);
|
| -
|
| - while (true) {
|
| - const DecodeTable* table = &decode_tables_[0];
|
| - uint32_t index = bits >> (32 - kDecodeTableRootBits);
|
| -
|
| - for (int i = 0; i != kDecodeIterations; i++) {
|
| - DCHECK_LT(index, table->size());
|
| - DCHECK_LT(Entry(*table, index).next_table_index, decode_tables_.size());
|
| -
|
| - table = &decode_tables_[Entry(*table, index).next_table_index];
|
| - // Mask and shift the portion of the code being indexed into low bits.
|
| - index = (bits << table->prefix_length) >> (32 - table->indexed_length);
|
| - }
|
| - const DecodeEntry& entry = Entry(*table, index);
|
| -
|
| - if (entry.length > bits_available) {
|
| - if (!peeked_success) {
|
| - // Unable to read enough input for a match. If only a portion of
|
| - // the last byte remains, this is a successful EOF condition.
|
| - in->ConsumeByteRemainder();
|
| - return !in->HasMoreData();
|
| - }
|
| - } else if (entry.length == 0) {
|
| - // The input is an invalid prefix, larger than any prefix in the table.
|
| - return false;
|
| - } else {
|
| - if (entry.symbol_id < 256) {
|
| - // Assume symbols >= 256 are used for padding.
|
| - out->push_back(static_cast<char>(entry.symbol_id));
|
| - }
|
| -
|
| - in->ConsumeBits(entry.length);
|
| - bits = bits << entry.length;
|
| - bits_available -= entry.length;
|
| - }
|
| - peeked_success = in->PeekBits(&bits_available, &bits);
|
| - }
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -size_t HpackHuffmanTable::EstimateMemoryUsage() const {
|
| - return SpdyEstimateMemoryUsage(decode_tables_) +
|
| - SpdyEstimateMemoryUsage(decode_entries_) +
|
| - SpdyEstimateMemoryUsage(code_by_id_) +
|
| - SpdyEstimateMemoryUsage(length_by_id_);
|
| -}
|
| -
|
| -} // namespace net
|
|
|