OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/hpack_huffman_table.h" | 5 #include "net/spdy/hpack_huffman_table.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 // Maximum number of bits to index in successive decode tables. | 23 // Maximum number of bits to index in successive decode tables. |
24 const uint8 kDecodeTableBranchBits = 6; | 24 const uint8 kDecodeTableBranchBits = 6; |
25 | 25 |
26 bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a, | 26 bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a, |
27 const HpackHuffmanSymbol& b) { | 27 const HpackHuffmanSymbol& b) { |
28 if (a.length == b.length) { | 28 if (a.length == b.length) { |
29 return a.id < b.id; | 29 return a.id < b.id; |
30 } | 30 } |
31 return a.length < b.length; | 31 return a.length < b.length; |
32 } | 32 } |
33 bool SymbolIdCompare(const HpackHuffmanSymbol& a, | 33 bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) { |
34 const HpackHuffmanSymbol& b) { | |
35 return a.id < b.id; | 34 return a.id < b.id; |
36 } | 35 } |
37 | 36 |
38 } // namespace | 37 } // namespace |
39 | 38 |
40 HpackHuffmanTable::DecodeEntry::DecodeEntry() | 39 HpackHuffmanTable::DecodeEntry::DecodeEntry() |
41 : next_table_index(0), length(0), symbol_id(0) { | 40 : next_table_index(0), length(0), symbol_id(0) { |
42 } | 41 } |
43 HpackHuffmanTable::DecodeEntry::DecodeEntry(uint8 next_table_index, | 42 HpackHuffmanTable::DecodeEntry::DecodeEntry(uint8 next_table_index, |
44 uint8 length, | 43 uint8 length, |
45 uint16 symbol_id) | 44 uint16 symbol_id) |
46 : next_table_index(next_table_index), length(length), symbol_id(symbol_id) { | 45 : next_table_index(next_table_index), length(length), symbol_id(symbol_id) { |
47 } | 46 } |
48 size_t HpackHuffmanTable::DecodeTable::size() const { | 47 size_t HpackHuffmanTable::DecodeTable::size() const { |
49 return size_t(1) << indexed_length; | 48 return size_t(1) << indexed_length; |
50 } | 49 } |
51 | 50 |
52 HpackHuffmanTable::HpackHuffmanTable() {} | 51 HpackHuffmanTable::HpackHuffmanTable() { |
| 52 } |
53 | 53 |
54 HpackHuffmanTable::~HpackHuffmanTable() {} | 54 HpackHuffmanTable::~HpackHuffmanTable() { |
| 55 } |
55 | 56 |
56 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, | 57 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, |
57 size_t symbol_count) { | 58 size_t symbol_count) { |
58 CHECK(!IsInitialized()); | 59 CHECK(!IsInitialized()); |
59 | 60 |
60 std::vector<Symbol> symbols(symbol_count); | 61 std::vector<Symbol> symbols(symbol_count); |
61 // Validate symbol id sequence, and copy into |symbols|. | 62 // Validate symbol id sequence, and copy into |symbols|. |
62 for (size_t i = 0; i != symbol_count; i++) { | 63 for (size_t i = 0; i != symbol_count; i++) { |
63 if (i != input_symbols[i].id) { | 64 if (i != input_symbols[i].id) { |
64 failed_symbol_id_ = i; | 65 failed_symbol_id_ = i; |
65 return false; | 66 return false; |
66 } | 67 } |
67 symbols[i] = input_symbols[i]; | 68 symbols[i] = input_symbols[i]; |
68 } | 69 } |
69 // Order on length and ID ascending, to verify symbol codes are canonical. | 70 // Order on length and ID ascending, to verify symbol codes are canonical. |
70 std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare); | 71 std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare); |
71 if (symbols[0].code != 0) { | 72 if (symbols[0].code != 0) { |
72 failed_symbol_id_ = 0; | 73 failed_symbol_id_ = 0; |
73 return false; | 74 return false; |
74 } | 75 } |
75 for (size_t i = 1; i != symbols.size(); i++) { | 76 for (size_t i = 1; i != symbols.size(); i++) { |
76 unsigned code_shift = 32 - symbols[i-1].length; | 77 unsigned code_shift = 32 - symbols[i - 1].length; |
77 uint32 code = symbols[i-1].code + (1 << code_shift); | 78 uint32 code = symbols[i - 1].code + (1 << code_shift); |
78 | 79 |
79 if (code != symbols[i].code) { | 80 if (code != symbols[i].code) { |
80 failed_symbol_id_ = symbols[i].id; | 81 failed_symbol_id_ = symbols[i].id; |
81 return false; | 82 return false; |
82 } | 83 } |
83 if (code < symbols[i-1].code) { | 84 if (code < symbols[i - 1].code) { |
84 // An integer overflow occurred. This implies the input | 85 // An integer overflow occurred. This implies the input |
85 // lengths do not represent a valid Huffman code. | 86 // lengths do not represent a valid Huffman code. |
86 failed_symbol_id_ = symbols[i].id; | 87 failed_symbol_id_ = symbols[i].id; |
87 return false; | 88 return false; |
88 } | 89 } |
89 } | 90 } |
90 if (symbols.back().length < 8) { | 91 if (symbols.back().length < 8) { |
91 // At least one code (such as an EOS symbol) must be 8 bits or longer. | 92 // At least one code (such as an EOS symbol) must be 8 bits or longer. |
92 // Without this, some inputs will not be encodable in a whole number | 93 // Without this, some inputs will not be encodable in a whole number |
93 // of bytes. | 94 // of bytes. |
(...skipping 19 matching lines...) Expand all Loading... |
113 | 114 |
114 void HpackHuffmanTable::BuildDecodeTables(const std::vector<Symbol>& symbols) { | 115 void HpackHuffmanTable::BuildDecodeTables(const std::vector<Symbol>& symbols) { |
115 AddDecodeTable(0, kDecodeTableRootBits); | 116 AddDecodeTable(0, kDecodeTableRootBits); |
116 // We wish to maximize the flatness of the DecodeTable hierarchy (subject to | 117 // We wish to maximize the flatness of the DecodeTable hierarchy (subject to |
117 // the |kDecodeTableBranchBits| constraint), and to minimize the size of | 118 // the |kDecodeTableBranchBits| constraint), and to minimize the size of |
118 // child tables. To achieve this, we iterate in order of descending code | 119 // child tables. To achieve this, we iterate in order of descending code |
119 // length. This ensures that child tables are visited with their longest | 120 // length. This ensures that child tables are visited with their longest |
120 // entry first, and that the child can therefore be minimally sized to hold | 121 // entry first, and that the child can therefore be minimally sized to hold |
121 // that entry without fear of introducing unneccesary branches later. | 122 // that entry without fear of introducing unneccesary branches later. |
122 for (std::vector<Symbol>::const_reverse_iterator it = symbols.rbegin(); | 123 for (std::vector<Symbol>::const_reverse_iterator it = symbols.rbegin(); |
123 it != symbols.rend(); ++it) { | 124 it != symbols.rend(); |
| 125 ++it) { |
124 uint8 table_index = 0; | 126 uint8 table_index = 0; |
125 while (true) { | 127 while (true) { |
126 const DecodeTable table = decode_tables_[table_index]; | 128 const DecodeTable table = decode_tables_[table_index]; |
127 | 129 |
128 // Mask and shift the portion of the code being indexed into low bits. | 130 // Mask and shift the portion of the code being indexed into low bits. |
129 uint32 index = (it->code << table.prefix_length); | 131 uint32 index = (it->code << table.prefix_length); |
130 index = index >> (32 - table.indexed_length); | 132 index = index >> (32 - table.indexed_length); |
131 | 133 |
132 CHECK_LT(index, table.size()); | 134 CHECK_LT(index, table.size()); |
133 DecodeEntry entry = Entry(table, index); | 135 DecodeEntry entry = Entry(table, index); |
134 | 136 |
135 uint8 total_indexed = table.prefix_length + table.indexed_length; | 137 uint8 total_indexed = table.prefix_length + table.indexed_length; |
136 if (total_indexed >= it->length) { | 138 if (total_indexed >= it->length) { |
137 // We're writing a terminal entry. | 139 // We're writing a terminal entry. |
138 entry.length = it->length; | 140 entry.length = it->length; |
139 entry.symbol_id = it->id; | 141 entry.symbol_id = it->id; |
140 entry.next_table_index = table_index; | 142 entry.next_table_index = table_index; |
141 SetEntry(table, index, entry); | 143 SetEntry(table, index, entry); |
142 break; | 144 break; |
143 } | 145 } |
144 | 146 |
145 if (entry.length == 0) { | 147 if (entry.length == 0) { |
146 // First visit to this placeholder. We need to create a new table. | 148 // First visit to this placeholder. We need to create a new table. |
147 CHECK_EQ(entry.next_table_index, 0); | 149 CHECK_EQ(entry.next_table_index, 0); |
148 entry.length = it->length; | 150 entry.length = it->length; |
149 entry.next_table_index = AddDecodeTable( | 151 entry.next_table_index = |
150 total_indexed, // Becomes the new table prefix. | 152 AddDecodeTable(total_indexed, // Becomes the new table prefix. |
151 std::min<uint8>(kDecodeTableBranchBits, | 153 std::min<uint8>(kDecodeTableBranchBits, |
152 entry.length - total_indexed)); | 154 entry.length - total_indexed)); |
153 SetEntry(table, index, entry); | 155 SetEntry(table, index, entry); |
154 } | 156 } |
155 CHECK_NE(entry.next_table_index, table_index); | 157 CHECK_NE(entry.next_table_index, table_index); |
156 table_index = entry.next_table_index; | 158 table_index = entry.next_table_index; |
157 } | 159 } |
158 } | 160 } |
159 // Fill shorter table entries into the additional entry spots they map to. | 161 // Fill shorter table entries into the additional entry spots they map to. |
160 for (size_t i = 0; i != decode_tables_.size(); i++) { | 162 for (size_t i = 0; i != decode_tables_.size(); i++) { |
161 const DecodeTable& table = decode_tables_[i]; | 163 const DecodeTable& table = decode_tables_[i]; |
162 uint8 total_indexed = table.prefix_length + table.indexed_length; | 164 uint8 total_indexed = table.prefix_length + table.indexed_length; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 bits = bits << entry.length; | 316 bits = bits << entry.length; |
315 bits_available -= entry.length; | 317 bits_available -= entry.length; |
316 } | 318 } |
317 peeked_success = in->PeekBits(&bits_available, &bits); | 319 peeked_success = in->PeekBits(&bits_available, &bits); |
318 } | 320 } |
319 NOTREACHED(); | 321 NOTREACHED(); |
320 return false; | 322 return false; |
321 } | 323 } |
322 | 324 |
323 } // namespace net | 325 } // namespace net |
OLD | NEW |