mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 09:46:09 +03:00
134 lines
3.4 KiB
C++
134 lines
3.4 KiB
C++
// Copyright (c) 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/tools/huffman_trie/trie/trie_bit_buffer.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "net/tools/huffman_trie/bit_writer.h"
|
|
|
|
namespace net {
|
|
|
|
namespace huffman_trie {
|
|
|
|
TrieBitBuffer::TrieBitBuffer() = default;
|
|
|
|
TrieBitBuffer::~TrieBitBuffer() = default;
|
|
|
|
void TrieBitBuffer::WriteBit(uint8_t bit) {
|
|
current_byte_ |= bit << (7 - used_);
|
|
used_++;
|
|
|
|
if (used_ == 8) {
|
|
Flush();
|
|
}
|
|
}
|
|
|
|
void TrieBitBuffer::WriteBits(uint32_t bits, uint8_t number_of_bits) {
|
|
DCHECK(number_of_bits <= 32);
|
|
for (uint8_t i = 1; i <= number_of_bits; i++) {
|
|
uint8_t bit = 1 & (bits >> (number_of_bits - i));
|
|
WriteBit(bit);
|
|
}
|
|
}
|
|
|
|
void TrieBitBuffer::WritePosition(uint32_t position, int32_t* last_position) {
|
|
if (*last_position != -1) {
|
|
int32_t delta = position - *last_position;
|
|
DCHECK(delta > 0) << "delta position is not positive.";
|
|
|
|
uint8_t number_of_bits = BitLength(delta);
|
|
DCHECK(number_of_bits <= 7 + 15) << "positive position delta too large.";
|
|
|
|
if (number_of_bits <= 7) {
|
|
WriteBits(0, 1);
|
|
WriteBits(delta, 7);
|
|
} else {
|
|
WriteBits(1, 1);
|
|
WriteBits(number_of_bits - 8, 4);
|
|
WriteBits(delta, number_of_bits);
|
|
}
|
|
|
|
*last_position = position;
|
|
return;
|
|
}
|
|
|
|
if (used_ != 0) {
|
|
Flush();
|
|
}
|
|
|
|
AppendPositionElement(position);
|
|
|
|
*last_position = position;
|
|
}
|
|
|
|
uint8_t TrieBitBuffer::BitLength(uint32_t input) const {
|
|
uint8_t number_of_bits = 0;
|
|
while (input != 0) {
|
|
number_of_bits++;
|
|
input >>= 1;
|
|
}
|
|
return number_of_bits;
|
|
}
|
|
|
|
void TrieBitBuffer::WriteChar(uint8_t byte,
|
|
const HuffmanRepresentationTable& table,
|
|
HuffmanBuilder* huffman_builder) {
|
|
HuffmanRepresentationTable::const_iterator item;
|
|
item = table.find(byte);
|
|
DCHECK(item != table.end());
|
|
if (huffman_builder) {
|
|
huffman_builder->RecordUsage(byte);
|
|
}
|
|
WriteBits(item->second.bits, item->second.number_of_bits);
|
|
}
|
|
|
|
void TrieBitBuffer::AppendBitsElement(uint8_t bits, uint8_t number_of_bits) {
|
|
BitsOrPosition element;
|
|
element.bits = current_byte_;
|
|
element.number_of_bits = used_;
|
|
elements_.push_back(element);
|
|
}
|
|
|
|
void TrieBitBuffer::AppendPositionElement(uint32_t position) {
|
|
BitsOrPosition element;
|
|
element.position = position;
|
|
element.number_of_bits = 0;
|
|
elements_.push_back(element);
|
|
}
|
|
|
|
uint32_t TrieBitBuffer::WriteToBitWriter(BitWriter* writer) {
|
|
Flush();
|
|
|
|
uint32_t old_position = writer->position();
|
|
for (auto const& element : elements_) {
|
|
if (element.number_of_bits) {
|
|
writer->WriteBits(element.bits >> (8 - element.number_of_bits),
|
|
element.number_of_bits);
|
|
} else {
|
|
uint32_t current = old_position;
|
|
uint32_t target = element.position;
|
|
DCHECK(target < current) << "Reference is not backwards";
|
|
uint32_t delta = current - target;
|
|
uint8_t delta_number_of_bits = BitLength(delta);
|
|
DCHECK(delta_number_of_bits < 32) << "Delta to large";
|
|
writer->WriteBits(delta_number_of_bits, 5);
|
|
writer->WriteBits(delta, delta_number_of_bits);
|
|
}
|
|
}
|
|
return old_position;
|
|
}
|
|
|
|
void TrieBitBuffer::Flush() {
|
|
if (used_) {
|
|
AppendBitsElement(current_byte_, used_);
|
|
|
|
used_ = 0;
|
|
current_byte_ = 0;
|
|
}
|
|
}
|
|
|
|
} // namespace huffman_trie
|
|
|
|
} // namespace net
|