huangcm
2025-09-01 53d8e046ac1bf2ebe94f671983e3d3be059df91a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
#ifndef SRC_HUFFMAN_TABLE_H_
#define SRC_HUFFMAN_TABLE_H_
 
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
 
#include "puffin/src/bit_reader.h"
#include "puffin/src/bit_writer.h"
#include "puffin/src/include/puffin/common.h"
#include "puffin/src/logging.h"
 
namespace puffin {
 
// Maximum Huffman code length based on RFC1951.
constexpr size_t kMaxHuffmanBits = 15;
 
// Permutations of input Huffman code lengths (used only to read
// |dynamic_code_lens_|).
extern const uint8_t kPermutations[];
 
// The bases of each alphabet which is added to the integer value of extra
// bits that comes after the Huffman code in the input to create the given
// length value. The last element is a guard.
extern const uint16_t kLengthBases[];
 
// Number of extra bits that comes after the associating Huffman code.
extern const uint8_t kLengthExtraBits[];
 
// same as |kLengthBases| except for the the distances instead of lengths.
// The last element is a guard.
extern const uint16_t kDistanceBases[];
 
// Same as |kLengthExtraBits| except for distances instead of lengths.
extern const uint8_t kDistanceExtraBits[];
 
class HuffmanTable {
 public:
  HuffmanTable();
  virtual ~HuffmanTable() = default;
 
  // Checks the lengths of Huffman length arrays for correctness
  //
  // |num_lit_len|  IN  The number of literal/lengths code lengths
  // |num_distance| IN  The number of distance code lengths
  // |num_codes|    IN  The number of code lengths for reading Huffman table.
  inline bool CheckHuffmanArrayLengths(size_t num_lit_len,
                                       size_t num_distance,
                                       size_t num_codes) {
    if (num_lit_len > 286 || num_distance > 30 || num_codes > 19) {
      LOG(ERROR) << "The lengths of the dynamic Huffman table are invalid: "
                 << "num_lit_len(" << num_lit_len << ") "
                 << "num_distance(" << num_distance << ") "
                 << "num_codes(" << num_codes << ")";
      return false;
    }
    return true;
  }
 
  // Returns the maximum number of bits used in the current literal/length
  // Huffman codes.
  inline size_t LitLenMaxBits() { return lit_len_max_bits_; }
 
  // Returns the maximum number of bits used in the current distance Huffman
  // codes.
  inline size_t DistanceMaxBits() { return distance_max_bits_; }
 
  // Returns the alphabet associated with the set of input bits for the code
  // length array.
  //
  // |bits|     IN   The input Huffman bits read from the deflate stream.
  // |alphabet| OUT  The alphabet associated with the given |bits|.
  // |nbits|    OUT  The number of bits in the Huffman code of alphabet.
  // Returns true if there is an alphabet associated with |bits|.
  inline bool CodeAlphabet(uint32_t bits, uint16_t* alphabet, size_t* nbits) {
    auto hc = code_hcodes_[bits];
    TEST_AND_RETURN_FALSE(hc & 0x8000);
    *alphabet = hc & 0x7FFF;
    *nbits = code_lens_[*alphabet];
    return true;
  }
 
  // Returns the alphabet associated with the set of input bits for the
  // literal/length code length array.
  //
  // |bits|     IN   The input Huffman bits read from the deflate stream.
  // |alphabet| OUT  The alphabet associated with the given |bits|.
  // |nbits|    OUT  The number of bits in the Huffman code of the |alphabet|.
  // Returns true if there is an alphabet associated with |bits|.
  inline bool LitLenAlphabet(uint32_t bits, uint16_t* alphabet, size_t* nbits) {
    auto hc = lit_len_hcodes_[bits];
    TEST_AND_RETURN_FALSE(hc & 0x8000);
    *alphabet = hc & 0x7FFF;
    *nbits = lit_len_lens_[*alphabet];
    return true;
  }
 
  // Returns the alphabet associated with the set of input bits for the
  // distance code length array.
  //
  // |bits|     IN   The input Huffman bits read from the deflate stream.
  // |alphabet| OUT  The alphabet associated with the given |bits|.
  // |nbits|    OUT  The number of bits in the Huffman code of the |alphabet|.
  // Returns true if there is an alphabet associated with |bits|.
  inline bool DistanceAlphabet(uint32_t bits,
                               uint16_t* alphabet,
                               size_t* nbits) {
    auto hc = distance_hcodes_[bits];
    TEST_AND_RETURN_FALSE(hc & 0x8000);
    *alphabet = hc & 0x7FFF;
    *nbits = distance_lens_[*alphabet];
    return true;
  }
 
  // Returns the Huffman code of a give alphabet for Huffman table codes.
  //
  // |alphabet| IN   The alphabet.
  // |huffman|  OUT  The Huffman code for |alphabet|.
  // |nbits|    OUT  The maximum number of bits in the Huffman code of the
  //                 |alphabet|.
  inline bool CodeHuffman(uint16_t alphabet, uint16_t* huffman, size_t* nbits) {
    TEST_AND_RETURN_FALSE(alphabet < code_lens_.size());
    *huffman = code_rcodes_[alphabet];
    *nbits = code_lens_[alphabet];
    return true;
  }
 
  // Returns the Huffman code of a give alphabet for literal/length codes.
  //
  // |alphabet| IN   The alphabet.
  // |huffman|  OUT  The Huffman code for |alphabet|.
  // |nbits|    OUT  The maximum number of bits in the Huffman code of the
  //                 |alphabet|.
  inline bool LitLenHuffman(uint16_t alphabet,
                            uint16_t* huffman,
                            size_t* nbits) {
    TEST_AND_RETURN_FALSE(alphabet < lit_len_lens_.size());
    *huffman = lit_len_rcodes_[alphabet];
    *nbits = lit_len_lens_[alphabet];
    return true;
  }
 
  inline bool EndOfBlockBitLength(size_t* nbits) {
    TEST_AND_RETURN_FALSE(256 < lit_len_lens_.size());
    *nbits = lit_len_lens_[256];
    return true;
  }
 
  // Returns the Huffman code of a give alphabet for distance codes.
  //
  // |alphabet| IN   The alphabet.
  // |huffman|  OUT  The Huffman code for |alphabet|.
  // |nbits|    OUT  The maximum number of bits in the Huffman code of the
  //                 |alphabet|.
  inline bool DistanceHuffman(uint16_t alphabet,
                              uint16_t* huffman,
                              size_t* nbits) {
    TEST_AND_RETURN_FALSE(alphabet < distance_lens_.size());
    *huffman = distance_rcodes_[alphabet];
    *nbits = distance_lens_[alphabet];
    return true;
  }
 
  // This populates the object with fixed huffman table parameters.
  // TODO(ahassani): Revamp the use of this function to be initiliazed once in
  // the lifetime of the program and only one instance needed.
  bool BuildFixedHuffmanTable();
 
  // This functions first reads the Huffman code length arrays from the input
  // deflate stream, then builds both literal/length and distance Huffman
  // code arrays. It also writes the Huffman table into the puffed stream.
  //
  // |br|      IN      The |BitReaderInterface| reading the deflate stream.
  // |buffer|  OUT     The object to write the Huffman table.
  // |length|  IN/OUT  The length available in the |buffer| and in return it
  //                   will be the length of Huffman table data written into
  //                   the |buffer|.
  bool BuildDynamicHuffmanTable(BitReaderInterface* br,
                                uint8_t* buffer,
                                size_t* length);
 
  // This functions first reads the Huffman code length arrays from the input
  // puffed |buffer|, then builds both literal/length and distance Huffman code
  // arrays. It also writes the coded Huffman table arrays into the deflate
  // stream.
  //
  // |buffer| IN      The array to read the Huffman table from.
  // |length| IN      The length available in the |buffer|.
  // |bw|     IN/OUT  The |BitWriterInterface| for writing into the deflate
  //                  stream.
  bool BuildDynamicHuffmanTable(const uint8_t* buffer,
                                size_t length,
                                BitWriterInterface* bw);
 
 protected:
  // Initializes the Huffman codes from an array of lengths.
  //
  // |lens|     IN   The input array of code lengths.
  // |max_bits| OUT  The maximum number of bits used for the Huffman codes.
  bool InitHuffmanCodes(const Buffer& lens, size_t* max_bits);
 
  // Creates the Huffman code to alphabet array.
  // |lens|     IN   The input array of code lengths.
  // |hcodes|   OUT  The Huffman to alphabet array.
  // |max_bits| OUT  The maximum number of bits used for the Huffman codes.
  bool BuildHuffmanCodes(const Buffer& lens,
                         std::vector<uint16_t>* hcodes,
                         size_t* max_bits);
 
  // Creates the alphabet to Huffman code array.
  // |lens|     IN   The input array of code lengths.
  // |rcodes|   OUT  The Huffman to Huffman array.
  // |max_bits| OUT  The maximum number of bits used for the Huffman codes.
  bool BuildHuffmanReverseCodes(const Buffer& lens,
                                std::vector<uint16_t>* rcodes,
                                size_t* max_bits);
 
  // Reads a specific Huffman code length array from input. At the same time
  // writes the array into the puffed stream. The Huffman code length array is
  // either the literal/lengths or distance codes.
  //
  // |br|        IN      The |BitReaderInterface| for reading the deflate
  //                      stream.
  // |buffer|    OUT     The array to write the Huffman table.
  // |length|    IN/OUT  The length available in the |buffer| and in return it
  //                     will be the length of data written into the |buffer|.
  // |max_bits|  IN      The maximum number of bits in the Huffman codes.
  // |num_codes| IN      The size of the Huffman code length array in the input.
  // |lens|      OUT     The resulting Huffman code length array.
  bool BuildHuffmanCodeLengths(BitReaderInterface* br,
                               uint8_t* buffer,
                               size_t* length,
                               size_t max_bits,
                               size_t num_codes,
                               Buffer* lens);
 
  // Similar to |BuildHuffmanCodeLengths| but for reading from puffed buffer and
  // writing into deflate stream.
  //
  // |buffer|    IN      The array to read the Huffman table from.
  // |length|    IN      The length available in the |buffer|.
  // |bw|        IN/OUT  The |BitWriterInterface| for writing into the deflate
  //                     stream.
  // |num_codes| IN      Number of Huffman code lengths to read from the
  //                     |buffer|.
  // |lens|      OUT     The Huffman code lengths array.
  bool BuildHuffmanCodeLengths(const uint8_t* buffer,
                               size_t* length,
                               BitWriterInterface* bw,
                               size_t num_codes,
                               Buffer* lens);
 
 private:
  // A utility struct used to create Huffman codes.
  struct CodeIndexPair {
    uint16_t code;   // The Huffman code
    uint16_t index;  // The alphabet
  };
  // A vector with maximum size of 286 that is only uses as temporary space for
  // building Huffman codes.
  std::vector<CodeIndexPair> codeindexpairs_;
 
  // Used in building Huffman codes for literals/lengths and distances.
  std::vector<uint8_t> lit_len_lens_;
  std::vector<uint16_t> lit_len_hcodes_;
  std::vector<uint16_t> lit_len_rcodes_;
  size_t lit_len_max_bits_;
  std::vector<uint8_t> distance_lens_;
  std::vector<uint16_t> distance_hcodes_;
  std::vector<uint16_t> distance_rcodes_;
  size_t distance_max_bits_;
 
  // The reason for keeping a temporary buffer here is to avoid reallocing each
  // time.
  std::vector<uint8_t> tmp_lens_;
 
  // Used in building Huffman codes for reading and decoding literal/length and
  // distance Huffman code length arrays.
  std::vector<uint8_t> code_lens_;
  std::vector<uint16_t> code_hcodes_;
  std::vector<uint16_t> code_rcodes_;
  size_t code_max_bits_;
 
  bool initialized_;
 
  DISALLOW_COPY_AND_ASSIGN(HuffmanTable);
};
 
// The type of a block in a deflate stream.
enum class BlockType : uint8_t {
  kUncompressed = 0x00,
  kFixed = 0x01,
  kDynamic = 0x02,
};
 
std::string BlockTypeToString(BlockType type);
 
}  // namespace puffin
 
#endif  // SRC_HUFFMAN_TABLE_H_