1 // Copyright 2012 Google Inc. All Rights Reserved.
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
8 // Utilities for building and looking up Huffman trees.
10 // Author: Urvang Joshi (urvang@google.com)
14 #include "./huffman.h"
15 #include "../utils/utils.h"
16 #include "../webp/format_constants.h"
18 #if defined(__cplusplus) || defined(c_plusplus)
22 #define NON_EXISTENT_SYMBOL (-1)
24 static void TreeNodeInit(HuffmanTreeNode* const node) {
25 node->children_ = -1; // means: 'unassigned so far'
28 static int NodeIsEmpty(const HuffmanTreeNode* const node) {
29 return (node->children_ < 0);
32 static int IsFull(const HuffmanTree* const tree) {
33 return (tree->num_nodes_ == tree->max_nodes_);
36 static void AssignChildren(HuffmanTree* const tree,
37 HuffmanTreeNode* const node) {
38 HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
39 node->children_ = (int)(children - node);
40 assert(children - node == (int)(children - node));
41 tree->num_nodes_ += 2;
42 TreeNodeInit(children + 0);
43 TreeNodeInit(children + 1);
46 static int TreeInit(HuffmanTree* const tree, int num_leaves) {
48 if (num_leaves == 0) return 0;
49 // We allocate maximum possible nodes in the tree at once.
50 // Note that a Huffman tree is a full binary tree; and in a full binary tree
51 // with L leaves, the total number of nodes N = 2 * L - 1.
52 tree->max_nodes_ = 2 * num_leaves - 1;
53 tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_,
54 sizeof(*tree->root_));
55 if (tree->root_ == NULL) return 0;
56 TreeNodeInit(tree->root_); // Initialize root.
61 void HuffmanTreeRelease(HuffmanTree* const tree) {
70 int HuffmanCodeLengthsToCodes(const int* const code_lengths,
71 int code_lengths_size, int* const huff_codes) {
74 int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
76 int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
77 int max_code_length = 0;
79 assert(code_lengths != NULL);
80 assert(code_lengths_size > 0);
81 assert(huff_codes != NULL);
83 // Calculate max code length.
84 for (symbol = 0; symbol < code_lengths_size; ++symbol) {
85 if (code_lengths[symbol] > max_code_length) {
86 max_code_length = code_lengths[symbol];
89 if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0;
91 // Calculate code length histogram.
92 for (symbol = 0; symbol < code_lengths_size; ++symbol) {
93 ++code_length_hist[code_lengths[symbol]];
95 code_length_hist[0] = 0;
97 // Calculate the initial values of 'next_codes' for each code length.
98 // next_codes[code_len] denotes the code to be assigned to the next symbol
99 // of code length 'code_len'.
101 next_codes[0] = -1; // Unused, as code length = 0 implies code doesn't exist.
102 for (code_len = 1; code_len <= max_code_length; ++code_len) {
103 curr_code = (curr_code + code_length_hist[code_len - 1]) << 1;
104 next_codes[code_len] = curr_code;
108 for (symbol = 0; symbol < code_lengths_size; ++symbol) {
109 if (code_lengths[symbol] > 0) {
110 huff_codes[symbol] = next_codes[code_lengths[symbol]]++;
112 huff_codes[symbol] = NON_EXISTENT_SYMBOL;
118 static int TreeAddSymbol(HuffmanTree* const tree,
119 int symbol, int code, int code_length) {
120 HuffmanTreeNode* node = tree->root_;
121 const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_;
122 while (code_length-- > 0) {
123 if (node >= max_node) {
126 if (NodeIsEmpty(node)) {
127 if (IsFull(tree)) return 0; // error: too many symbols.
128 AssignChildren(tree, node);
129 } else if (HuffmanTreeNodeIsLeaf(node)) {
130 return 0; // leaf is already occupied.
132 node += node->children_ + ((code >> code_length) & 1);
134 if (NodeIsEmpty(node)) {
135 node->children_ = 0; // turn newly created node into a leaf.
136 } else if (!HuffmanTreeNodeIsLeaf(node)) {
137 return 0; // trying to assign a symbol to already used code.
139 node->symbol_ = symbol; // Add symbol in this node.
143 int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
144 const int* const code_lengths,
145 int code_lengths_size) {
150 assert(tree != NULL);
151 assert(code_lengths != NULL);
153 // Find out number of symbols and the root symbol.
154 for (symbol = 0; symbol < code_lengths_size; ++symbol) {
155 if (code_lengths[symbol] > 0) {
156 // Note: code length = 0 indicates non-existent symbol.
158 root_symbol = symbol;
162 // Initialize the tree. Will fail for num_symbols = 0
163 if (!TreeInit(tree, num_symbols)) return 0;
166 if (num_symbols == 1) { // Trivial case.
167 const int max_symbol = code_lengths_size;
168 if (root_symbol < 0 || root_symbol >= max_symbol) {
169 HuffmanTreeRelease(tree);
172 return TreeAddSymbol(tree, root_symbol, 0, 0);
173 } else { // Normal case.
176 // Get Huffman codes from the code lengths.
178 (int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
179 if (codes == NULL) goto End;
181 if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
185 // Add symbols one-by-one.
186 for (symbol = 0; symbol < code_lengths_size; ++symbol) {
187 if (code_lengths[symbol] > 0) {
188 if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) {
196 ok = ok && IsFull(tree);
197 if (!ok) HuffmanTreeRelease(tree);
202 int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
203 const int* const code_lengths,
204 const int* const codes,
205 const int* const symbols, int max_symbol,
210 assert(tree != NULL);
211 assert(code_lengths != NULL);
212 assert(codes != NULL);
213 assert(symbols != NULL);
215 // Initialize the tree. Will fail if num_symbols = 0.
216 if (!TreeInit(tree, num_symbols)) return 0;
218 // Add symbols one-by-one.
219 for (i = 0; i < num_symbols; ++i) {
220 if (codes[i] != NON_EXISTENT_SYMBOL) {
221 if (symbols[i] < 0 || symbols[i] >= max_symbol) {
224 if (!TreeAddSymbol(tree, symbols[i], codes[i], code_lengths[i])) {
231 ok = ok && IsFull(tree);
232 if (!ok) HuffmanTreeRelease(tree);
236 #if defined(__cplusplus) || defined(c_plusplus)