xref: /isa-l/igzip/huff_codes.c (revision d06e14b9372be9cd5a8700b886ca02f3919a9e6c)
1660f49b0SGreg Tucker /**********************************************************************
2660f49b0SGreg Tucker   Copyright(c) 2011-2016 Intel Corporation All rights reserved.
3660f49b0SGreg Tucker 
4660f49b0SGreg Tucker   Redistribution and use in source and binary forms, with or without
5660f49b0SGreg Tucker   modification, are permitted provided that the following conditions
6660f49b0SGreg Tucker   are met:
7660f49b0SGreg Tucker     * Redistributions of source code must retain the above copyright
8660f49b0SGreg Tucker       notice, this list of conditions and the following disclaimer.
9660f49b0SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
10660f49b0SGreg Tucker       notice, this list of conditions and the following disclaimer in
11660f49b0SGreg Tucker       the documentation and/or other materials provided with the
12660f49b0SGreg Tucker       distribution.
13660f49b0SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
14660f49b0SGreg Tucker       contributors may be used to endorse or promote products derived
15660f49b0SGreg Tucker       from this software without specific prior written permission.
16660f49b0SGreg Tucker 
17660f49b0SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18660f49b0SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19660f49b0SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20660f49b0SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21660f49b0SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22660f49b0SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23660f49b0SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24660f49b0SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25660f49b0SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26660f49b0SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27660f49b0SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28660f49b0SGreg Tucker **********************************************************************/
29660f49b0SGreg Tucker 
30660f49b0SGreg Tucker #include <immintrin.h>
31660f49b0SGreg Tucker #include <stdint.h>
32660f49b0SGreg Tucker #include <string.h>
33660f49b0SGreg Tucker #include <assert.h>
34660f49b0SGreg Tucker #include "igzip_lib.h"
35660f49b0SGreg Tucker #include "huff_codes.h"
36660f49b0SGreg Tucker #include "huffman.h"
37660f49b0SGreg Tucker 
38660f49b0SGreg Tucker #define LENGTH_BITS 5
39660f49b0SGreg Tucker 
40660f49b0SGreg Tucker /* The order code length codes are written in the dynamic code header. This is
41660f49b0SGreg Tucker  * defined in RFC 1951 page 13 */
42660f49b0SGreg Tucker static const uint8_t code_length_code_order[] =
43660f49b0SGreg Tucker     { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
44660f49b0SGreg Tucker 
45*d06e14b9SRoy Oursler struct slver {
46*d06e14b9SRoy Oursler 	uint16_t snum;
47*d06e14b9SRoy Oursler 	uint8_t ver;
48*d06e14b9SRoy Oursler 	uint8_t core;
49*d06e14b9SRoy Oursler };
50*d06e14b9SRoy Oursler 
51*d06e14b9SRoy Oursler /* Version info */
52*d06e14b9SRoy Oursler struct slver isal_update_histogram_slver_00010085;
53*d06e14b9SRoy Oursler struct slver isal_update_histogram_slver = { 0x0085, 0x01, 0x00 };
54*d06e14b9SRoy Oursler struct slver isal_create_hufftables_slver_00010086;
55*d06e14b9SRoy Oursler struct slver isal_create_hufftables_slver = { 0x0086, 0x01, 0x00 };
56*d06e14b9SRoy Oursler 
57660f49b0SGreg Tucker int heap_push(struct huff_tree element, struct histheap *heap)
58660f49b0SGreg Tucker {
59660f49b0SGreg Tucker 	uint16_t index;
60660f49b0SGreg Tucker 	uint16_t parent;
61660f49b0SGreg Tucker 	assert(heap->size < MAX_HISTHEAP_SIZE);
62660f49b0SGreg Tucker 	index = heap->size;
63660f49b0SGreg Tucker 	heap->size += 1;
64660f49b0SGreg Tucker 	parent = (index - 1) / 2;
65660f49b0SGreg Tucker 	while ((index != 0) && (heap->tree[parent].frequency > element.frequency)) {
66660f49b0SGreg Tucker 		heap->tree[index] = heap->tree[parent];
67660f49b0SGreg Tucker 		index = parent;
68660f49b0SGreg Tucker 		parent = (index - 1) / 2;
69660f49b0SGreg Tucker 
70660f49b0SGreg Tucker 	}
71660f49b0SGreg Tucker 	heap->tree[index] = element;
72660f49b0SGreg Tucker 
73660f49b0SGreg Tucker 	return index;
74660f49b0SGreg Tucker }
75660f49b0SGreg Tucker 
76660f49b0SGreg Tucker struct huff_tree heap_pop(struct histheap *heap)
77660f49b0SGreg Tucker {
78660f49b0SGreg Tucker 	struct huff_tree root, temp;
79660f49b0SGreg Tucker 	uint16_t index = 0;
80660f49b0SGreg Tucker 	uint16_t child = 1;
81660f49b0SGreg Tucker 	assert(heap->size > 0);
82660f49b0SGreg Tucker 	root = heap->tree[index];
83660f49b0SGreg Tucker 	heap->size--;
84660f49b0SGreg Tucker 	heap->tree[index] = heap->tree[heap->size];
85660f49b0SGreg Tucker 
86660f49b0SGreg Tucker 	while (child + 1 < heap->size) {
87660f49b0SGreg Tucker 		if (heap->tree[child].frequency < heap->tree[index].frequency
88660f49b0SGreg Tucker 		    || heap->tree[child + 1].frequency < heap->tree[index].frequency) {
89660f49b0SGreg Tucker 			if (heap->tree[child].frequency > heap->tree[child + 1].frequency)
90660f49b0SGreg Tucker 				child += 1;
91660f49b0SGreg Tucker 			temp = heap->tree[index];
92660f49b0SGreg Tucker 			heap->tree[index] = heap->tree[child];
93660f49b0SGreg Tucker 			heap->tree[child] = temp;
94660f49b0SGreg Tucker 			index = child;
95660f49b0SGreg Tucker 			child = 2 * child + 1;
96660f49b0SGreg Tucker 		} else {
97660f49b0SGreg Tucker 			break;
98660f49b0SGreg Tucker 		}
99660f49b0SGreg Tucker 	}
100660f49b0SGreg Tucker 
101660f49b0SGreg Tucker 	if (child < heap->size) {
102660f49b0SGreg Tucker 		if (heap->tree[child].frequency < heap->tree[index].frequency) {
103660f49b0SGreg Tucker 			temp = heap->tree[index];
104660f49b0SGreg Tucker 			heap->tree[index] = heap->tree[child];
105660f49b0SGreg Tucker 			heap->tree[child] = temp;
106660f49b0SGreg Tucker 		}
107660f49b0SGreg Tucker 	}
108660f49b0SGreg Tucker 
109660f49b0SGreg Tucker 	return root;
110660f49b0SGreg Tucker 
111660f49b0SGreg Tucker }
112660f49b0SGreg Tucker 
113660f49b0SGreg Tucker struct linked_list_node *pop_from_front(struct linked_list *list)
114660f49b0SGreg Tucker {
115660f49b0SGreg Tucker 	struct linked_list_node *temp;
116660f49b0SGreg Tucker 
117660f49b0SGreg Tucker 	temp = list->start;
118660f49b0SGreg Tucker 	if (list->start != NULL) {
119660f49b0SGreg Tucker 		list->start = list->start->next;
120660f49b0SGreg Tucker 		if (list->start != NULL)
121660f49b0SGreg Tucker 			list->start->previous = NULL;
122660f49b0SGreg Tucker 		else
123660f49b0SGreg Tucker 			list->end = NULL;
124660f49b0SGreg Tucker 		list->length -= 1;
125660f49b0SGreg Tucker 	}
126660f49b0SGreg Tucker 	return temp;
127660f49b0SGreg Tucker }
128660f49b0SGreg Tucker 
129660f49b0SGreg Tucker void append_to_front(struct linked_list *list, struct linked_list_node *new_element)
130660f49b0SGreg Tucker {
131660f49b0SGreg Tucker 	new_element->next = list->start;
132660f49b0SGreg Tucker 	new_element->previous = NULL;
133660f49b0SGreg Tucker 	if (list->start != NULL)
134660f49b0SGreg Tucker 		list->start->previous = new_element;
135660f49b0SGreg Tucker 	else
136660f49b0SGreg Tucker 		list->end = new_element;
137660f49b0SGreg Tucker 	list->start = new_element;
138660f49b0SGreg Tucker 	list->length += 1;
139660f49b0SGreg Tucker 
140660f49b0SGreg Tucker 	return;
141660f49b0SGreg Tucker }
142660f49b0SGreg Tucker 
143660f49b0SGreg Tucker void append_to_back(struct linked_list *list, struct linked_list_node *new_element)
144660f49b0SGreg Tucker {
145660f49b0SGreg Tucker 	new_element->previous = list->end;
146660f49b0SGreg Tucker 	new_element->next = NULL;
147660f49b0SGreg Tucker 	if (list->end != NULL)
148660f49b0SGreg Tucker 		list->end->next = new_element;
149660f49b0SGreg Tucker 	else
150660f49b0SGreg Tucker 		list->start = new_element;
151660f49b0SGreg Tucker 	list->end = new_element;
152660f49b0SGreg Tucker 	list->length += 1;
153660f49b0SGreg Tucker 
154660f49b0SGreg Tucker 	return;
155660f49b0SGreg Tucker }
156660f49b0SGreg Tucker 
15731814483SRoy Oursler void isal_update_histogram_base(uint8_t * start_stream, int length,
158660f49b0SGreg Tucker 				struct isal_huff_histogram *histogram)
159660f49b0SGreg Tucker {
160660f49b0SGreg Tucker 	uint32_t literal = 0, hash;
161660f49b0SGreg Tucker 	uint8_t *last_seen[HASH_SIZE];
162660f49b0SGreg Tucker 	uint8_t *current, *seen, *end_stream, *next_hash, *end;
163660f49b0SGreg Tucker 	uint32_t match_length;
164660f49b0SGreg Tucker 	uint32_t dist;
165660f49b0SGreg Tucker 	uint64_t *lit_len_histogram = histogram->lit_len_histogram;
166660f49b0SGreg Tucker 	uint64_t *dist_histogram = histogram->dist_histogram;
167660f49b0SGreg Tucker 
168660f49b0SGreg Tucker 	if (length <= 0)
169660f49b0SGreg Tucker 		return;
170660f49b0SGreg Tucker 
171660f49b0SGreg Tucker 	end_stream = start_stream + length;
172660f49b0SGreg Tucker 	memset(last_seen, 0, sizeof(last_seen));	/* Initialize last_seen to be 0. */
173660f49b0SGreg Tucker 	for (current = start_stream; current < end_stream - 3; current++) {
174660f49b0SGreg Tucker 		literal = *(uint32_t *) current;
175660f49b0SGreg Tucker 		hash = compute_hash(literal) & HASH_MASK;
176660f49b0SGreg Tucker 		seen = last_seen[hash];
177660f49b0SGreg Tucker 		last_seen[hash] = current;
178660f49b0SGreg Tucker 		dist = current - seen;
179660f49b0SGreg Tucker 		if (dist < D) {
180660f49b0SGreg Tucker 			match_length = compare258(seen, current, end_stream - current);
181660f49b0SGreg Tucker 			if (match_length >= SHORTEST_MATCH) {
182660f49b0SGreg Tucker 				next_hash = current;
183660f49b0SGreg Tucker #ifdef LIMIT_HASH_UPDATE
184660f49b0SGreg Tucker 				end = next_hash + 3;
185660f49b0SGreg Tucker #else
186660f49b0SGreg Tucker 				end = next_hash + match_length;
187660f49b0SGreg Tucker #endif
188660f49b0SGreg Tucker 				if (end > end_stream - 3)
189660f49b0SGreg Tucker 					end = end_stream - 3;
190660f49b0SGreg Tucker 				next_hash++;
191660f49b0SGreg Tucker 				for (; next_hash < end; next_hash++) {
192660f49b0SGreg Tucker 					literal = *(uint32_t *) next_hash;
193660f49b0SGreg Tucker 					hash = compute_hash(literal) & HASH_MASK;
194660f49b0SGreg Tucker 					last_seen[hash] = next_hash;
195660f49b0SGreg Tucker 				}
196660f49b0SGreg Tucker 
197660f49b0SGreg Tucker 				dist_histogram[convert_dist_to_dist_sym(dist)] += 1;
198660f49b0SGreg Tucker 				lit_len_histogram[convert_length_to_len_sym(match_length)] +=
199660f49b0SGreg Tucker 				    1;
200660f49b0SGreg Tucker 				current += match_length - 1;
201660f49b0SGreg Tucker 				continue;
202660f49b0SGreg Tucker 			}
203660f49b0SGreg Tucker 		}
204660f49b0SGreg Tucker 		lit_len_histogram[literal & 0xFF] += 1;
205660f49b0SGreg Tucker 	}
206660f49b0SGreg Tucker 	literal = literal >> 8;
207660f49b0SGreg Tucker 	hash = compute_hash(literal) & HASH_MASK;
208660f49b0SGreg Tucker 	seen = last_seen[hash];
209660f49b0SGreg Tucker 	last_seen[hash] = current;
210660f49b0SGreg Tucker 	dist = current - seen;
211660f49b0SGreg Tucker 	if (dist < D) {
212660f49b0SGreg Tucker 		match_length = compare258(seen, current, end_stream - current);
213660f49b0SGreg Tucker 		if (match_length >= SHORTEST_MATCH) {
214660f49b0SGreg Tucker 			dist_histogram[convert_dist_to_dist_sym(dist)] += 1;
215660f49b0SGreg Tucker 			lit_len_histogram[convert_length_to_len_sym(match_length)] += 1;
216660f49b0SGreg Tucker 			lit_len_histogram[256] += 1;
217660f49b0SGreg Tucker 			return;
218660f49b0SGreg Tucker 		}
219660f49b0SGreg Tucker 	} else
220660f49b0SGreg Tucker 		lit_len_histogram[literal & 0xFF] += 1;
221660f49b0SGreg Tucker 	lit_len_histogram[(literal >> 8) & 0xFF] += 1;
222660f49b0SGreg Tucker 	lit_len_histogram[(literal >> 16) & 0xFF] += 1;
223660f49b0SGreg Tucker 	lit_len_histogram[256] += 1;
224660f49b0SGreg Tucker 	return;
225660f49b0SGreg Tucker }
226660f49b0SGreg Tucker 
227660f49b0SGreg Tucker uint32_t convert_dist_to_dist_sym(uint32_t dist)
228660f49b0SGreg Tucker {
229660f49b0SGreg Tucker 	assert(dist <= 32768 && dist > 0);
230660f49b0SGreg Tucker 	if (dist <= 2)
231660f49b0SGreg Tucker 		return dist - 1;
232660f49b0SGreg Tucker 	else if (dist <= 4)
233660f49b0SGreg Tucker 		return 0 + (dist - 1) / 1;
234660f49b0SGreg Tucker 	else if (dist <= 8)
235660f49b0SGreg Tucker 		return 2 + (dist - 1) / 2;
236660f49b0SGreg Tucker 	else if (dist <= 16)
237660f49b0SGreg Tucker 		return 4 + (dist - 1) / 4;
238660f49b0SGreg Tucker 	else if (dist <= 32)
239660f49b0SGreg Tucker 		return 6 + (dist - 1) / 8;
240660f49b0SGreg Tucker 	else if (dist <= 64)
241660f49b0SGreg Tucker 		return 8 + (dist - 1) / 16;
242660f49b0SGreg Tucker 	else if (dist <= 128)
243660f49b0SGreg Tucker 		return 10 + (dist - 1) / 32;
244660f49b0SGreg Tucker 	else if (dist <= 256)
245660f49b0SGreg Tucker 		return 12 + (dist - 1) / 64;
246660f49b0SGreg Tucker 	else if (dist <= 512)
247660f49b0SGreg Tucker 		return 14 + (dist - 1) / 128;
248660f49b0SGreg Tucker 	else if (dist <= 1024)
249660f49b0SGreg Tucker 		return 16 + (dist - 1) / 256;
250660f49b0SGreg Tucker 	else if (dist <= 2048)
251660f49b0SGreg Tucker 		return 18 + (dist - 1) / 512;
252660f49b0SGreg Tucker 	else if (dist <= 4096)
253660f49b0SGreg Tucker 		return 20 + (dist - 1) / 1024;
254660f49b0SGreg Tucker 	else if (dist <= 8192)
255660f49b0SGreg Tucker 		return 22 + (dist - 1) / 2048;
256660f49b0SGreg Tucker 	else if (dist <= 16384)
257660f49b0SGreg Tucker 		return 24 + (dist - 1) / 4096;
258660f49b0SGreg Tucker 	else if (dist <= 32768)
259660f49b0SGreg Tucker 		return 26 + (dist - 1) / 8192;
260660f49b0SGreg Tucker 	else
261660f49b0SGreg Tucker 		return ~0;	/* ~0 is an invalid distance code */
262660f49b0SGreg Tucker 
263660f49b0SGreg Tucker }
264660f49b0SGreg Tucker 
265660f49b0SGreg Tucker uint32_t convert_length_to_len_sym(uint32_t length)
266660f49b0SGreg Tucker {
267660f49b0SGreg Tucker 	assert(length > 2 && length < 259);
268660f49b0SGreg Tucker 
269660f49b0SGreg Tucker 	/* Based on tables on page 11 in RFC 1951 */
270660f49b0SGreg Tucker 	if (length < 11)
271660f49b0SGreg Tucker 		return 257 + length - 3;
272660f49b0SGreg Tucker 	else if (length < 19)
273660f49b0SGreg Tucker 		return 261 + (length - 3) / 2;
274660f49b0SGreg Tucker 	else if (length < 35)
275660f49b0SGreg Tucker 		return 265 + (length - 3) / 4;
276660f49b0SGreg Tucker 	else if (length < 67)
277660f49b0SGreg Tucker 		return 269 + (length - 3) / 8;
278660f49b0SGreg Tucker 	else if (length < 131)
279660f49b0SGreg Tucker 		return 273 + (length - 3) / 16;
280660f49b0SGreg Tucker 	else if (length < 258)
281660f49b0SGreg Tucker 		return 277 + (length - 3) / 32;
282660f49b0SGreg Tucker 	else
283660f49b0SGreg Tucker 		return 285;
284660f49b0SGreg Tucker }
285660f49b0SGreg Tucker 
286660f49b0SGreg Tucker struct huff_tree create_symbol_subset_huff_tree(struct huff_tree *tree_array,
287660f49b0SGreg Tucker 						uint64_t * histogram, uint32_t size)
288660f49b0SGreg Tucker {
289660f49b0SGreg Tucker 	/* Assumes there are at least 2 symbols. */
290660f49b0SGreg Tucker 	int i;
291660f49b0SGreg Tucker 	uint32_t node_index;
292660f49b0SGreg Tucker 	struct huff_tree tree;
293660f49b0SGreg Tucker 	struct histheap heap;
294660f49b0SGreg Tucker 
295660f49b0SGreg Tucker 	heap.size = 0;
296660f49b0SGreg Tucker 
297660f49b0SGreg Tucker 	tree.right = tree.left = NULL;
298660f49b0SGreg Tucker 
299660f49b0SGreg Tucker 	/* Intitializes heap for construction of the huffman tree */
300660f49b0SGreg Tucker 	for (i = 0; i < size; i++) {
301660f49b0SGreg Tucker 		tree.value = i;
302660f49b0SGreg Tucker 		tree.frequency = histogram[i];
303660f49b0SGreg Tucker 		tree_array[i] = tree;
304660f49b0SGreg Tucker 
305660f49b0SGreg Tucker 		/* If symbol does not appear (has frequency 0), ignore it. */
306660f49b0SGreg Tucker 		if (tree_array[i].frequency != 0)
307660f49b0SGreg Tucker 			heap_push(tree, &heap);
308660f49b0SGreg Tucker 	}
309660f49b0SGreg Tucker 
310660f49b0SGreg Tucker 	node_index = size;
311660f49b0SGreg Tucker 
312660f49b0SGreg Tucker 	/* Construct the huffman tree */
313660f49b0SGreg Tucker 	while (heap.size > 1) {
314660f49b0SGreg Tucker 
315660f49b0SGreg Tucker 		tree = heap_pop(&heap);
316660f49b0SGreg Tucker 		tree_array[node_index].frequency = tree.frequency;
317660f49b0SGreg Tucker 		tree_array[node_index].left = &tree_array[tree.value];
318660f49b0SGreg Tucker 
319660f49b0SGreg Tucker 		tree = heap_pop(&heap);
320660f49b0SGreg Tucker 		tree_array[node_index].frequency += tree.frequency;
321660f49b0SGreg Tucker 		tree_array[node_index].right = &tree_array[tree.value];
322660f49b0SGreg Tucker 
323660f49b0SGreg Tucker 		tree_array[node_index].value = node_index;
324660f49b0SGreg Tucker 		heap_push(tree_array[node_index], &heap);
325660f49b0SGreg Tucker 
326660f49b0SGreg Tucker 		node_index += 1;
327660f49b0SGreg Tucker 	}
328660f49b0SGreg Tucker 
329660f49b0SGreg Tucker 	return heap_pop(&heap);
330660f49b0SGreg Tucker }
331660f49b0SGreg Tucker 
332660f49b0SGreg Tucker struct huff_tree create_huff_tree(struct huff_tree *tree_array, uint64_t * histogram,
333660f49b0SGreg Tucker 				  uint32_t size)
334660f49b0SGreg Tucker {
335660f49b0SGreg Tucker 	int i;
336660f49b0SGreg Tucker 	uint32_t node_index;
337660f49b0SGreg Tucker 	struct huff_tree tree;
338660f49b0SGreg Tucker 	struct histheap heap;
339660f49b0SGreg Tucker 
340660f49b0SGreg Tucker 	heap.size = 0;
341660f49b0SGreg Tucker 
342660f49b0SGreg Tucker 	tree.right = tree.left = NULL;
343660f49b0SGreg Tucker 
344660f49b0SGreg Tucker 	/* Intitializes heap for construction of the huffman tree */
345660f49b0SGreg Tucker 	for (i = 0; i < size; i++) {
346660f49b0SGreg Tucker 		tree.value = i;
347660f49b0SGreg Tucker 		tree.frequency = histogram[i];
348660f49b0SGreg Tucker 		tree_array[i] = tree;
349660f49b0SGreg Tucker 		heap_push(tree, &heap);
350660f49b0SGreg Tucker 	}
351660f49b0SGreg Tucker 
352660f49b0SGreg Tucker 	node_index = size;
353660f49b0SGreg Tucker 
354660f49b0SGreg Tucker 	/* Construct the huffman tree */
355660f49b0SGreg Tucker 	while (heap.size > 1) {
356660f49b0SGreg Tucker 
357660f49b0SGreg Tucker 		tree = heap_pop(&heap);
358660f49b0SGreg Tucker 		tree_array[node_index].frequency = tree.frequency;
359660f49b0SGreg Tucker 		tree_array[node_index].left = &tree_array[tree.value];
360660f49b0SGreg Tucker 
361660f49b0SGreg Tucker 		tree = heap_pop(&heap);
362660f49b0SGreg Tucker 		tree_array[node_index].frequency += tree.frequency;
363660f49b0SGreg Tucker 		tree_array[node_index].right = &tree_array[tree.value];
364660f49b0SGreg Tucker 
365660f49b0SGreg Tucker 		tree_array[node_index].value = node_index;
366660f49b0SGreg Tucker 		heap_push(tree_array[node_index], &heap);
367660f49b0SGreg Tucker 
368660f49b0SGreg Tucker 		node_index += 1;
369660f49b0SGreg Tucker 	}
370660f49b0SGreg Tucker 
371660f49b0SGreg Tucker 	return heap_pop(&heap);
372660f49b0SGreg Tucker }
373660f49b0SGreg Tucker 
374660f49b0SGreg Tucker int create_huff_lookup(struct huff_code *huff_lookup_table, int table_length,
375660f49b0SGreg Tucker 		       struct huff_tree root, uint8_t max_depth)
376660f49b0SGreg Tucker {
377660f49b0SGreg Tucker 	/* Used to create a count of number of elements with a given code length */
378660f49b0SGreg Tucker 	uint16_t count[MAX_HUFF_TREE_DEPTH + 1];
379660f49b0SGreg Tucker 
380660f49b0SGreg Tucker 	memset(count, 0, sizeof(count));
381660f49b0SGreg Tucker 
382660f49b0SGreg Tucker 	if (find_code_lengths(huff_lookup_table, count, root, max_depth) != 0)
383660f49b0SGreg Tucker 		return 1;
384660f49b0SGreg Tucker 
385660f49b0SGreg Tucker 	set_huff_codes(huff_lookup_table, table_length, count);
386660f49b0SGreg Tucker 
387660f49b0SGreg Tucker 	return 0;
388660f49b0SGreg Tucker }
389660f49b0SGreg Tucker 
390660f49b0SGreg Tucker int find_code_lengths(struct huff_code *huff_lookup_table, uint16_t * count,
391660f49b0SGreg Tucker 		      struct huff_tree root, uint8_t max_depth)
392660f49b0SGreg Tucker {
393660f49b0SGreg Tucker 	struct linked_list depth_array[MAX_HUFF_TREE_DEPTH + 2];
394660f49b0SGreg Tucker 	struct linked_list_node linked_lists[MAX_HISTHEAP_SIZE];
395660f49b0SGreg Tucker 	struct linked_list_node *temp;
396660f49b0SGreg Tucker 	uint16_t extra_nodes = 0;
397660f49b0SGreg Tucker 	int i, j;
398660f49b0SGreg Tucker 
399660f49b0SGreg Tucker 	memset(depth_array, 0, sizeof(depth_array));
400660f49b0SGreg Tucker 	memset(linked_lists, 0, sizeof(linked_lists));
401660f49b0SGreg Tucker 	for (i = 0; i < MAX_HISTHEAP_SIZE; i++)
402660f49b0SGreg Tucker 		linked_lists[i].value = i;
403660f49b0SGreg Tucker 
404660f49b0SGreg Tucker 	huffman_tree_traversal(depth_array, linked_lists, &extra_nodes, max_depth, root, 0);
405660f49b0SGreg Tucker 
406660f49b0SGreg Tucker 	/* This for loop fixes up the huffman tree to have a maximum depth not exceeding
407660f49b0SGreg Tucker 	 * max_depth. This algorithm works by removing all elements below max_depth,
408660f49b0SGreg Tucker 	 * filling up the empty leafs which are created with elements form the huffman
409660f49b0SGreg Tucker 	 * tree and then iteratively pushing down the least frequent leaf that is above
410660f49b0SGreg Tucker 	 * max_depth to a depth 1 lower, and moving up a leaf below max_depth to that
411660f49b0SGreg Tucker 	 * same depth.*/
412660f49b0SGreg Tucker 	for (i = MAX_HUFF_TREE_DEPTH + 1; i > max_depth; i--) {
413660f49b0SGreg Tucker 
414660f49b0SGreg Tucker 		/* find element to push up the tree */
415660f49b0SGreg Tucker 		while (depth_array[i].start != NULL) {
416660f49b0SGreg Tucker 			if (extra_nodes > 0) {
417660f49b0SGreg Tucker 				temp = pop_from_front(&depth_array[i]);
418660f49b0SGreg Tucker 				append_to_back(&depth_array[max_depth], temp);
419660f49b0SGreg Tucker 				extra_nodes -= 1;
420660f49b0SGreg Tucker 
421660f49b0SGreg Tucker 			} else {
422660f49b0SGreg Tucker 				assert(depth_array[max_depth].length % 2 == 0);
423660f49b0SGreg Tucker 				assert(extra_nodes == 0);
424660f49b0SGreg Tucker 
425660f49b0SGreg Tucker 				/* find element to push down in the tree */
426660f49b0SGreg Tucker 				for (j = max_depth - 1; j >= 0; j--)
427660f49b0SGreg Tucker 					if (depth_array[j].start != NULL)
428660f49b0SGreg Tucker 						break;
429660f49b0SGreg Tucker 
430660f49b0SGreg Tucker 				/* No element available to push down further. */
431660f49b0SGreg Tucker 				if (j < 0)
432660f49b0SGreg Tucker 					return 1;
433660f49b0SGreg Tucker 
434660f49b0SGreg Tucker 				temp = pop_from_front(&depth_array[i]);
435660f49b0SGreg Tucker 				append_to_front(&depth_array[j + 1], temp);
436660f49b0SGreg Tucker 
437660f49b0SGreg Tucker 				temp = pop_from_front(&depth_array[j]);
438660f49b0SGreg Tucker 				append_to_back(&depth_array[j + 1], temp);
439660f49b0SGreg Tucker 			}
440660f49b0SGreg Tucker 		}
441660f49b0SGreg Tucker 	}
442660f49b0SGreg Tucker 
443660f49b0SGreg Tucker 	for (i = 0; i < MAX_HUFF_TREE_DEPTH + 2; i++) {
444660f49b0SGreg Tucker 		temp = depth_array[i].start;
445660f49b0SGreg Tucker 
446660f49b0SGreg Tucker 		while (temp != NULL) {
447660f49b0SGreg Tucker 			huff_lookup_table[temp->value].length = i;
448660f49b0SGreg Tucker 			count[i] += 1;
449660f49b0SGreg Tucker 			temp = temp->next;
450660f49b0SGreg Tucker 		}
451660f49b0SGreg Tucker 	}
452660f49b0SGreg Tucker 	return 0;
453660f49b0SGreg Tucker 
454660f49b0SGreg Tucker }
455660f49b0SGreg Tucker 
456660f49b0SGreg Tucker void huffman_tree_traversal(struct linked_list *depth_array,
457660f49b0SGreg Tucker 			    struct linked_list_node *linked_lists, uint16_t * extra_nodes,
458660f49b0SGreg Tucker 			    uint8_t max_depth, struct huff_tree current_node,
459660f49b0SGreg Tucker 			    uint16_t current_depth)
460660f49b0SGreg Tucker {
461660f49b0SGreg Tucker 	/* This algorithm performs a traversal of the huffman tree. It is setup
462660f49b0SGreg Tucker 	 * to visit the leaves in order of frequency and bin elements into a
463660f49b0SGreg Tucker 	 * linked list by depth.*/
464660f49b0SGreg Tucker 	if (current_node.left == NULL) {
465660f49b0SGreg Tucker 		if (current_depth < MAX_HUFF_TREE_DEPTH + 1)
466660f49b0SGreg Tucker 			append_to_front(&depth_array[current_depth],
467660f49b0SGreg Tucker 					&linked_lists[current_node.value]);
468660f49b0SGreg Tucker 		else
469660f49b0SGreg Tucker 			append_to_front(&depth_array[MAX_HUFF_TREE_DEPTH + 1],
470660f49b0SGreg Tucker 					&linked_lists[current_node.value]);
471660f49b0SGreg Tucker 		return;
472660f49b0SGreg Tucker 
473660f49b0SGreg Tucker 	} else if (current_depth == max_depth)
474660f49b0SGreg Tucker 		*extra_nodes += 1;
475660f49b0SGreg Tucker 
476660f49b0SGreg Tucker 	if (current_node.left->frequency < current_node.right->frequency) {
477660f49b0SGreg Tucker 		huffman_tree_traversal(depth_array, linked_lists, extra_nodes, max_depth,
478660f49b0SGreg Tucker 				       *current_node.right, current_depth + 1);
479660f49b0SGreg Tucker 		huffman_tree_traversal(depth_array, linked_lists, extra_nodes, max_depth,
480660f49b0SGreg Tucker 				       *current_node.left, current_depth + 1);
481660f49b0SGreg Tucker 
482660f49b0SGreg Tucker 	} else {
483660f49b0SGreg Tucker 		huffman_tree_traversal(depth_array, linked_lists, extra_nodes, max_depth,
484660f49b0SGreg Tucker 				       *current_node.left, current_depth + 1);
485660f49b0SGreg Tucker 		huffman_tree_traversal(depth_array, linked_lists, extra_nodes, max_depth,
486660f49b0SGreg Tucker 				       *current_node.right, current_depth + 1);
487660f49b0SGreg Tucker 	}
488660f49b0SGreg Tucker 
489660f49b0SGreg Tucker }
490660f49b0SGreg Tucker 
491660f49b0SGreg Tucker /*
492660f49b0SGreg Tucker  * Returns integer with first length bits reversed and all higher bits zeroed
493660f49b0SGreg Tucker  */
494660f49b0SGreg Tucker uint16_t bit_reverse(uint16_t bits, uint8_t length)
495660f49b0SGreg Tucker {
496660f49b0SGreg Tucker 	bits = ((bits >> 1) & 0x55555555) | ((bits & 0x55555555) << 1);	// swap bits
497660f49b0SGreg Tucker 	bits = ((bits >> 2) & 0x33333333) | ((bits & 0x33333333) << 2);	// swap pairs
498660f49b0SGreg Tucker 	bits = ((bits >> 4) & 0x0F0F0F0F) | ((bits & 0x0F0F0F0F) << 4);	// swap nibbles
499660f49b0SGreg Tucker 	bits = ((bits >> 8) & 0x00FF00FF) | ((bits & 0x00FF00FF) << 8);	// swap bytes
500660f49b0SGreg Tucker 	return bits >> (16 - length);
501660f49b0SGreg Tucker }
502660f49b0SGreg Tucker 
503660f49b0SGreg Tucker void set_huff_codes(struct huff_code *huff_code_table, int table_length, uint16_t * count)
504660f49b0SGreg Tucker {
505660f49b0SGreg Tucker 	/* Uses the algorithm mentioned in the deflate standard, Rfc 1951. */
506660f49b0SGreg Tucker 	int i;
507660f49b0SGreg Tucker 	uint16_t code = 0;
508660f49b0SGreg Tucker 	uint16_t next_code[MAX_HUFF_TREE_DEPTH + 1];
509660f49b0SGreg Tucker 
510660f49b0SGreg Tucker 	next_code[0] = code;
511660f49b0SGreg Tucker 
512660f49b0SGreg Tucker 	for (i = 1; i < MAX_HUFF_TREE_DEPTH + 1; i++)
513660f49b0SGreg Tucker 		next_code[i] = (next_code[i - 1] + count[i - 1]) << 1;
514660f49b0SGreg Tucker 
515660f49b0SGreg Tucker 	for (i = 0; i < table_length; i++) {
516660f49b0SGreg Tucker 		if (huff_code_table[i].length != 0) {
517660f49b0SGreg Tucker 			huff_code_table[i].code =
518660f49b0SGreg Tucker 			    bit_reverse(next_code[huff_code_table[i].length],
519660f49b0SGreg Tucker 					huff_code_table[i].length);
520660f49b0SGreg Tucker 			next_code[huff_code_table[i].length] += 1;
521660f49b0SGreg Tucker 		}
522660f49b0SGreg Tucker 	}
523660f49b0SGreg Tucker 
524660f49b0SGreg Tucker 	return;
525660f49b0SGreg Tucker }
526660f49b0SGreg Tucker 
527660f49b0SGreg Tucker int create_header(uint8_t * header, uint32_t header_length, struct huff_code *lit_huff_table,
528660f49b0SGreg Tucker 		  struct huff_code *dist_huff_table, uint32_t end_of_block)
529660f49b0SGreg Tucker {
530660f49b0SGreg Tucker 	int i;
531660f49b0SGreg Tucker 	uint64_t histogram[HUFF_LEN];
532660f49b0SGreg Tucker 	uint16_t huffman_rep[LIT_LEN + DIST_LEN];
533660f49b0SGreg Tucker 	uint16_t extra_bits[LIT_LEN + DIST_LEN];
534660f49b0SGreg Tucker 	uint16_t length;
535660f49b0SGreg Tucker 	struct huff_tree root;
536660f49b0SGreg Tucker 	struct huff_tree tree_array[2 * HUFF_LEN - 1];
537660f49b0SGreg Tucker 	struct huff_code lookup_table[HUFF_LEN];
538660f49b0SGreg Tucker 	struct huff_code combined_table[LIT_LEN + DIST_LEN];
539660f49b0SGreg Tucker 
540660f49b0SGreg Tucker 	/* hlit, hdist, and hclen are defined in RFC 1951 page 13 */
541660f49b0SGreg Tucker 	uint32_t hlit, hdist, hclen;
542660f49b0SGreg Tucker 	uint64_t bit_count;
543660f49b0SGreg Tucker 
544660f49b0SGreg Tucker 	memset(lookup_table, 0, sizeof(lookup_table));
545660f49b0SGreg Tucker 
546660f49b0SGreg Tucker 	/* Calculate hlit */
547660f49b0SGreg Tucker 	for (i = LIT_LEN - 1; i > 256; i--)
548660f49b0SGreg Tucker 		if (lit_huff_table[i].length != 0)
549660f49b0SGreg Tucker 			break;
550660f49b0SGreg Tucker 
551660f49b0SGreg Tucker 	hlit = i - 256;
552660f49b0SGreg Tucker 
553660f49b0SGreg Tucker 	/* Calculate hdist */
554660f49b0SGreg Tucker 	for (i = DIST_LEN - 1; i > 0; i--)
555660f49b0SGreg Tucker 		if (dist_huff_table[i].length != 0)
556660f49b0SGreg Tucker 			break;
557660f49b0SGreg Tucker 
558660f49b0SGreg Tucker 	hdist = i;
559660f49b0SGreg Tucker 
560660f49b0SGreg Tucker 	/* Combine huffman tables for run length encoding */
561660f49b0SGreg Tucker 	for (i = 0; i < 257 + hlit; i++)
562660f49b0SGreg Tucker 		combined_table[i] = lit_huff_table[i];
563660f49b0SGreg Tucker 	for (i = 0; i < 1 + hdist; i++)
564660f49b0SGreg Tucker 		combined_table[i + hlit + 257] = dist_huff_table[i];
565660f49b0SGreg Tucker 
566660f49b0SGreg Tucker 	memset(extra_bits, 0, LIT_LEN + DIST_LEN);
567660f49b0SGreg Tucker 	memset(histogram, 0, sizeof(histogram));
568660f49b0SGreg Tucker 
569660f49b0SGreg Tucker 	/* Create a run length encoded representation of the literal/lenght and
570660f49b0SGreg Tucker 	 * distance huffman trees. */
571660f49b0SGreg Tucker 	length = create_huffman_rep(huffman_rep, histogram, extra_bits,
572660f49b0SGreg Tucker 				    combined_table, hlit + 257 + hdist + 1);
573660f49b0SGreg Tucker 
574660f49b0SGreg Tucker 	/* Create a huffman tree to encode run length encoded representation. */
575660f49b0SGreg Tucker 	root = create_symbol_subset_huff_tree(tree_array, histogram, HUFF_LEN);
576660f49b0SGreg Tucker 	create_huff_lookup(lookup_table, HUFF_LEN, root, 7);
577660f49b0SGreg Tucker 
578660f49b0SGreg Tucker 	/* Calculate hclen */
579660f49b0SGreg Tucker 	for (i = CODE_LEN_CODES - 1; i > 3; i--)	/* i must be at least 4 */
580660f49b0SGreg Tucker 		if (lookup_table[code_length_code_order[i]].length != 0)
581660f49b0SGreg Tucker 			break;
582660f49b0SGreg Tucker 
583660f49b0SGreg Tucker 	hclen = i - 3;
584660f49b0SGreg Tucker 
585660f49b0SGreg Tucker 	/* Generate actual header. */
586660f49b0SGreg Tucker 	bit_count = create_huffman_header(header, header_length, lookup_table, huffman_rep,
587660f49b0SGreg Tucker 					  extra_bits, length, end_of_block, hclen, hlit,
588660f49b0SGreg Tucker 					  hdist);
589660f49b0SGreg Tucker 
590660f49b0SGreg Tucker 	return bit_count;
591660f49b0SGreg Tucker }
592660f49b0SGreg Tucker 
593660f49b0SGreg Tucker uint16_t create_huffman_rep(uint16_t * huffman_rep, uint64_t * histogram,
594660f49b0SGreg Tucker 			    uint16_t * extra_bits, struct huff_code * huff_table, uint16_t len)
595660f49b0SGreg Tucker {
596660f49b0SGreg Tucker 	uint16_t current_in_index = 0, current_out_index = 0, run_length, last_code;
597660f49b0SGreg Tucker 
598660f49b0SGreg Tucker 	while (current_in_index < len) {
599660f49b0SGreg Tucker 		last_code = huff_table[current_in_index].length;
600660f49b0SGreg Tucker 		run_length = 0;
601660f49b0SGreg Tucker 
602660f49b0SGreg Tucker 		while (current_in_index < len
603660f49b0SGreg Tucker 		       && last_code == huff_table[current_in_index].length) {
604660f49b0SGreg Tucker 			run_length += 1;
605660f49b0SGreg Tucker 			current_in_index += 1;
606660f49b0SGreg Tucker 		}
607660f49b0SGreg Tucker 
608660f49b0SGreg Tucker 		current_out_index = flush_repeats(huffman_rep, histogram, extra_bits,
609660f49b0SGreg Tucker 						  last_code, run_length, current_out_index);
610660f49b0SGreg Tucker 	}
611660f49b0SGreg Tucker 	return current_out_index;
612660f49b0SGreg Tucker }
613660f49b0SGreg Tucker 
614660f49b0SGreg Tucker uint16_t flush_repeats(uint16_t * huffman_rep, uint64_t * histogram, uint16_t * extra_bits,
615660f49b0SGreg Tucker 		       uint16_t last_code, uint16_t run_length, uint16_t current_index)
616660f49b0SGreg Tucker {
617660f49b0SGreg Tucker 	int j;
618660f49b0SGreg Tucker 
619660f49b0SGreg Tucker 	if (last_code != 0 && last_code < HUFF_LEN && run_length > 0) {
620660f49b0SGreg Tucker 		huffman_rep[current_index++] = last_code;
621660f49b0SGreg Tucker 		histogram[last_code] += 1;
622660f49b0SGreg Tucker 		run_length -= 1;
623660f49b0SGreg Tucker 
624660f49b0SGreg Tucker 	}
625660f49b0SGreg Tucker 
626660f49b0SGreg Tucker 	if (run_length < SHORTEST_MATCH) {
627660f49b0SGreg Tucker 		for (j = 0; j < run_length; j++) {
628660f49b0SGreg Tucker 			huffman_rep[current_index++] = last_code;
629660f49b0SGreg Tucker 			histogram[last_code] += 1;
630660f49b0SGreg Tucker 		}
631660f49b0SGreg Tucker 	} else {
632660f49b0SGreg Tucker 		if (last_code == 0) {
633660f49b0SGreg Tucker 			/* The values 138 is the maximum repeat length
634660f49b0SGreg Tucker 			 * represented with code 18. The value 10 is the maximum
635660f49b0SGreg Tucker 			 * repeate length represented with 17. */
636660f49b0SGreg Tucker 			for (; run_length > 138; run_length -= 138) {
637660f49b0SGreg Tucker 				huffman_rep[current_index] = 0x12;
638660f49b0SGreg Tucker 				extra_bits[current_index++] = 0x7F7;
639660f49b0SGreg Tucker 				histogram[18]++;
640660f49b0SGreg Tucker 			}
641660f49b0SGreg Tucker 
642660f49b0SGreg Tucker 			if (run_length > 10) {
643660f49b0SGreg Tucker 				huffman_rep[current_index] = 18;
644660f49b0SGreg Tucker 				extra_bits[current_index++] = ((run_length - 11) << 4) | 7;
645660f49b0SGreg Tucker 				histogram[18] += 1;
646660f49b0SGreg Tucker 
647660f49b0SGreg Tucker 			} else if (run_length >= SHORTEST_MATCH) {
648660f49b0SGreg Tucker 				huffman_rep[current_index] = 17;
649660f49b0SGreg Tucker 				extra_bits[current_index++] = ((run_length - 3) << 4) | 3;
650660f49b0SGreg Tucker 				histogram[17] += 1;
651660f49b0SGreg Tucker 
652660f49b0SGreg Tucker 			} else {
653660f49b0SGreg Tucker 				for (j = 0; j < run_length; j++) {
654660f49b0SGreg Tucker 					huffman_rep[current_index++] = last_code;
655660f49b0SGreg Tucker 					histogram[last_code] += 1;
656660f49b0SGreg Tucker 				}
657660f49b0SGreg Tucker 			}
658660f49b0SGreg Tucker 
659660f49b0SGreg Tucker 		} else {
660660f49b0SGreg Tucker 			for (; run_length > 6; run_length -= 6) {
661660f49b0SGreg Tucker 				huffman_rep[current_index] = 0x10;
662660f49b0SGreg Tucker 				extra_bits[current_index++] = 0x32;
663660f49b0SGreg Tucker 				histogram[16]++;
664660f49b0SGreg Tucker 			}
665660f49b0SGreg Tucker 
666660f49b0SGreg Tucker 			if (run_length >= SHORTEST_MATCH) {
667660f49b0SGreg Tucker 				huffman_rep[current_index] = 16;
668660f49b0SGreg Tucker 				extra_bits[current_index++] = ((run_length - 3) << 4) | 2;
669660f49b0SGreg Tucker 				histogram[16] += 1;
670660f49b0SGreg Tucker 
671660f49b0SGreg Tucker 			} else {
672660f49b0SGreg Tucker 				for (j = 0; j < run_length; j++) {
673660f49b0SGreg Tucker 					huffman_rep[current_index++] = last_code;
674660f49b0SGreg Tucker 					histogram[last_code] += 1;
675660f49b0SGreg Tucker 				}
676660f49b0SGreg Tucker 			}
677660f49b0SGreg Tucker 		}
678660f49b0SGreg Tucker 
679660f49b0SGreg Tucker 	}
680660f49b0SGreg Tucker 
681660f49b0SGreg Tucker 	return current_index;
682660f49b0SGreg Tucker }
683660f49b0SGreg Tucker 
684660f49b0SGreg Tucker int create_huffman_header(uint8_t * header, uint32_t header_length,
685660f49b0SGreg Tucker 			  struct huff_code *lookup_table, uint16_t * huffman_rep,
686660f49b0SGreg Tucker 			  uint16_t * extra_bits, uint16_t huffman_rep_length,
687660f49b0SGreg Tucker 			  uint32_t end_of_block, uint32_t hclen, uint32_t hlit, uint32_t hdist)
688660f49b0SGreg Tucker {
689660f49b0SGreg Tucker 	/* hlit, hdist, hclen are as defined in the deflate standard, head is the
690660f49b0SGreg Tucker 	 * first three deflate header bits.*/
691660f49b0SGreg Tucker 	int i;
692660f49b0SGreg Tucker 	uint32_t head;
693660f49b0SGreg Tucker 	uint64_t bit_count;
694660f49b0SGreg Tucker 	struct huff_code huffman_value;
695660f49b0SGreg Tucker 	struct BitBuf2 header_bitbuf;
696660f49b0SGreg Tucker 
697660f49b0SGreg Tucker 	if (end_of_block)
698660f49b0SGreg Tucker 		head = 0x05;
699660f49b0SGreg Tucker 	else
700660f49b0SGreg Tucker 		head = 0x04;
701660f49b0SGreg Tucker 
702660f49b0SGreg Tucker 	set_buf(&header_bitbuf, header, header_length);
703660f49b0SGreg Tucker 	init(&header_bitbuf);
704660f49b0SGreg Tucker 
705660f49b0SGreg Tucker 	write_bits(&header_bitbuf, (head | (hlit << 3) | (hdist << 8) | (hclen << 13)),
706660f49b0SGreg Tucker 		   DYN_HDR_START_LEN);
707660f49b0SGreg Tucker 
708660f49b0SGreg Tucker 	uint64_t tmp = 0;
709660f49b0SGreg Tucker 	for (i = hclen + 3; i >= 0; i--) {
710660f49b0SGreg Tucker 		tmp = (tmp << 3) | lookup_table[code_length_code_order[i]].length;
711660f49b0SGreg Tucker 	}
712660f49b0SGreg Tucker 
713660f49b0SGreg Tucker 	write_bits(&header_bitbuf, tmp, (hclen + 4) * 3);
714660f49b0SGreg Tucker 
715660f49b0SGreg Tucker 	for (i = 0; i < huffman_rep_length; i++) {
716660f49b0SGreg Tucker 		huffman_value = lookup_table[huffman_rep[i]];
717660f49b0SGreg Tucker 
718660f49b0SGreg Tucker 		write_bits(&header_bitbuf, (uint64_t) huffman_value.code,
719660f49b0SGreg Tucker 			   (uint32_t) huffman_value.length);
720660f49b0SGreg Tucker 
721660f49b0SGreg Tucker 		if (huffman_rep[i] > 15) {
722660f49b0SGreg Tucker 			write_bits(&header_bitbuf, (uint64_t) extra_bits[i] >> 4,
723660f49b0SGreg Tucker 				   (uint32_t) extra_bits[i] & 0xF);
724660f49b0SGreg Tucker 		}
725660f49b0SGreg Tucker 	}
726660f49b0SGreg Tucker 	bit_count = 8 * buffer_used(&header_bitbuf) + header_bitbuf.m_bit_count;
727660f49b0SGreg Tucker 	flush(&header_bitbuf);
728660f49b0SGreg Tucker 
729660f49b0SGreg Tucker 	return bit_count;
730660f49b0SGreg Tucker }
731660f49b0SGreg Tucker 
732660f49b0SGreg Tucker void create_code_tables(uint16_t * code_table, uint8_t * code_length_table, uint32_t length,
733660f49b0SGreg Tucker 			struct huff_code *hufftable)
734660f49b0SGreg Tucker {
735660f49b0SGreg Tucker 	int i;
736660f49b0SGreg Tucker 	for (i = 0; i < length; i++) {
737660f49b0SGreg Tucker 		code_table[i] = hufftable[i].code;
738660f49b0SGreg Tucker 		code_length_table[i] = hufftable[i].length;
739660f49b0SGreg Tucker 	}
740660f49b0SGreg Tucker }
741660f49b0SGreg Tucker 
742660f49b0SGreg Tucker void create_packed_len_table(uint32_t * packed_table, struct huff_code *lit_len_hufftable)
743660f49b0SGreg Tucker {
744660f49b0SGreg Tucker 	int i, count = 0;
745660f49b0SGreg Tucker 	uint16_t extra_bits;
746660f49b0SGreg Tucker 	uint16_t extra_bits_count = 0;
747660f49b0SGreg Tucker 
748660f49b0SGreg Tucker 	/* Gain extra bits is the next place where the number of extra bits in
749660f49b0SGreg Tucker 	 * lenght codes increases. */
750660f49b0SGreg Tucker 	uint16_t gain_extra_bits = LEN_EXTRA_BITS_START;
751660f49b0SGreg Tucker 
752660f49b0SGreg Tucker 	for (i = 257; i < LIT_LEN - 1; i++) {
753660f49b0SGreg Tucker 		for (extra_bits = 0; extra_bits < (1 << extra_bits_count); extra_bits++) {
754660f49b0SGreg Tucker 			if (count > 254)
755660f49b0SGreg Tucker 				break;
756660f49b0SGreg Tucker 			packed_table[count++] =
757660f49b0SGreg Tucker 			    (extra_bits << (lit_len_hufftable[i].length + LENGTH_BITS)) |
758660f49b0SGreg Tucker 			    (lit_len_hufftable[i].code << LENGTH_BITS) |
759660f49b0SGreg Tucker 			    (lit_len_hufftable[i].length + extra_bits_count);
760660f49b0SGreg Tucker 		}
761660f49b0SGreg Tucker 
762660f49b0SGreg Tucker 		if (i == gain_extra_bits) {
763660f49b0SGreg Tucker 			gain_extra_bits += LEN_EXTRA_BITS_INTERVAL;
764660f49b0SGreg Tucker 			extra_bits_count += 1;
765660f49b0SGreg Tucker 		}
766660f49b0SGreg Tucker 	}
767660f49b0SGreg Tucker 
768660f49b0SGreg Tucker 	packed_table[count] = (lit_len_hufftable[LIT_LEN - 1].code << LENGTH_BITS) |
769660f49b0SGreg Tucker 	    (lit_len_hufftable[LIT_LEN - 1].length);
770660f49b0SGreg Tucker }
771660f49b0SGreg Tucker 
772660f49b0SGreg Tucker void create_packed_dist_table(uint32_t * packed_table, uint32_t length,
773660f49b0SGreg Tucker 			      struct huff_code *dist_hufftable)
774660f49b0SGreg Tucker {
775660f49b0SGreg Tucker 	int i, count = 0;
776660f49b0SGreg Tucker 	uint16_t extra_bits;
777660f49b0SGreg Tucker 	uint16_t extra_bits_count = 0;
778660f49b0SGreg Tucker 
779660f49b0SGreg Tucker 	/* Gain extra bits is the next place where the number of extra bits in
780660f49b0SGreg Tucker 	 * distance codes increases. */
781660f49b0SGreg Tucker 	uint16_t gain_extra_bits = DIST_EXTRA_BITS_START;
782660f49b0SGreg Tucker 
783660f49b0SGreg Tucker 	for (i = 0; i < DIST_LEN; i++) {
784660f49b0SGreg Tucker 		for (extra_bits = 0; extra_bits < (1 << extra_bits_count); extra_bits++) {
785660f49b0SGreg Tucker 			if (count >= length)
786660f49b0SGreg Tucker 				return;
787660f49b0SGreg Tucker 
788660f49b0SGreg Tucker 			packed_table[count++] =
789660f49b0SGreg Tucker 			    (extra_bits << (dist_hufftable[i].length + LENGTH_BITS)) |
790660f49b0SGreg Tucker 			    (dist_hufftable[i].code << LENGTH_BITS) |
791660f49b0SGreg Tucker 			    (dist_hufftable[i].length + extra_bits_count);
792660f49b0SGreg Tucker 
793660f49b0SGreg Tucker 		}
794660f49b0SGreg Tucker 
795660f49b0SGreg Tucker 		if (i == gain_extra_bits) {
796660f49b0SGreg Tucker 			gain_extra_bits += DIST_EXTRA_BITS_INTERVAL;
797660f49b0SGreg Tucker 			extra_bits_count += 1;
798660f49b0SGreg Tucker 		}
799660f49b0SGreg Tucker 	}
800660f49b0SGreg Tucker }
801660f49b0SGreg Tucker 
802660f49b0SGreg Tucker int are_hufftables_useable(struct huff_code *lit_len_hufftable,
803660f49b0SGreg Tucker 			   struct huff_code *dist_hufftable)
804660f49b0SGreg Tucker {
805660f49b0SGreg Tucker 	int max_lit_code_len = 0, max_len_code_len = 0, max_dist_code_len = 0;
806660f49b0SGreg Tucker 	int dist_extra_bits = 0, len_extra_bits = 0;
807660f49b0SGreg Tucker 	int gain_dist_extra_bits = DIST_EXTRA_BITS_START;
808660f49b0SGreg Tucker 	int gain_len_extra_bits = LEN_EXTRA_BITS_START;
809660f49b0SGreg Tucker 	int max_code_len;
810660f49b0SGreg Tucker 	int i;
811660f49b0SGreg Tucker 
812660f49b0SGreg Tucker 	for (i = 0; i < LIT_LEN; i++)
813660f49b0SGreg Tucker 		if (lit_len_hufftable[i].length > max_lit_code_len)
814660f49b0SGreg Tucker 			max_lit_code_len = lit_len_hufftable[i].length;
815660f49b0SGreg Tucker 
816660f49b0SGreg Tucker 	for (i = 257; i < LIT_LEN - 1; i++) {
817660f49b0SGreg Tucker 		if (lit_len_hufftable[i].length + len_extra_bits > max_len_code_len)
818660f49b0SGreg Tucker 			max_len_code_len = lit_len_hufftable[i].length + len_extra_bits;
819660f49b0SGreg Tucker 
820660f49b0SGreg Tucker 		if (i == gain_len_extra_bits) {
821660f49b0SGreg Tucker 			gain_len_extra_bits += LEN_EXTRA_BITS_INTERVAL;
822660f49b0SGreg Tucker 			len_extra_bits += 1;
823660f49b0SGreg Tucker 		}
824660f49b0SGreg Tucker 	}
825660f49b0SGreg Tucker 
826660f49b0SGreg Tucker 	for (i = 0; i < DIST_LEN; i++) {
827660f49b0SGreg Tucker 		if (dist_hufftable[i].length + dist_extra_bits > max_dist_code_len)
828660f49b0SGreg Tucker 			max_dist_code_len = dist_hufftable[i].length + dist_extra_bits;
829660f49b0SGreg Tucker 
830660f49b0SGreg Tucker 		if (i == gain_dist_extra_bits) {
831660f49b0SGreg Tucker 			gain_dist_extra_bits += DIST_EXTRA_BITS_INTERVAL;
832660f49b0SGreg Tucker 			dist_extra_bits += 1;
833660f49b0SGreg Tucker 		}
834660f49b0SGreg Tucker 	}
835660f49b0SGreg Tucker 
836660f49b0SGreg Tucker 	max_code_len = max_lit_code_len + max_len_code_len + max_dist_code_len;
837660f49b0SGreg Tucker 
838660f49b0SGreg Tucker 	/* Some versions of igzip can write upto one literal, one length and one
839660f49b0SGreg Tucker 	 * distance code at the same time. This checks to make sure that is
840660f49b0SGreg Tucker 	 * always writeable in bitbuf*/
841660f49b0SGreg Tucker 	return (max_code_len > MAX_BITBUF_BIT_WRITE);
842660f49b0SGreg Tucker }
843660f49b0SGreg Tucker 
844660f49b0SGreg Tucker int isal_create_hufftables(struct isal_hufftables *hufftables,
845660f49b0SGreg Tucker 			   struct isal_huff_histogram *histogram)
846660f49b0SGreg Tucker {
847660f49b0SGreg Tucker 	struct huff_tree lit_tree, dist_tree;
848660f49b0SGreg Tucker 	struct huff_tree lit_tree_array[2 * LIT_LEN - 1], dist_tree_array[2 * DIST_LEN - 1];
849660f49b0SGreg Tucker 	struct huff_code lit_huff_table[LIT_LEN], dist_huff_table[DIST_LEN];
850660f49b0SGreg Tucker 	uint64_t bit_count;
851660f49b0SGreg Tucker 	int max_dist = convert_dist_to_dist_sym(IGZIP_D);
852660f49b0SGreg Tucker 
853660f49b0SGreg Tucker 	uint32_t *dist_table = hufftables->dist_table;
854660f49b0SGreg Tucker 	uint32_t *len_table = hufftables->len_table;
855660f49b0SGreg Tucker 	uint16_t *lit_table = hufftables->lit_table;
856660f49b0SGreg Tucker 	uint16_t *dcodes = hufftables->dcodes;
857660f49b0SGreg Tucker 	uint8_t *lit_table_sizes = hufftables->lit_table_sizes;
858660f49b0SGreg Tucker 	uint8_t *dcodes_sizes = hufftables->dcodes_sizes;
859660f49b0SGreg Tucker 	uint8_t *deflate_hdr = hufftables->deflate_hdr;
860660f49b0SGreg Tucker 	uint64_t *lit_len_histogram = histogram->lit_len_histogram;
861660f49b0SGreg Tucker 	uint64_t *dist_histogram = histogram->dist_histogram;
862660f49b0SGreg Tucker 
863660f49b0SGreg Tucker 	memset(hufftables, 0, sizeof(struct isal_hufftables));
864660f49b0SGreg Tucker 	memset(lit_tree_array, 0, sizeof(lit_tree_array));
865660f49b0SGreg Tucker 	memset(dist_tree_array, 0, sizeof(dist_tree_array));
866660f49b0SGreg Tucker 	memset(lit_huff_table, 0, sizeof(lit_huff_table));
867660f49b0SGreg Tucker 	memset(dist_huff_table, 0, sizeof(dist_huff_table));
868660f49b0SGreg Tucker 
869660f49b0SGreg Tucker 	lit_tree = create_huff_tree(lit_tree_array, lit_len_histogram, LIT_LEN);
870660f49b0SGreg Tucker 	dist_tree = create_huff_tree(dist_tree_array, dist_histogram, max_dist + 1);
871660f49b0SGreg Tucker 
872660f49b0SGreg Tucker 	if (create_huff_lookup(lit_huff_table, LIT_LEN, lit_tree, MAX_DEFLATE_CODE_LEN) > 0)
873660f49b0SGreg Tucker 		return INVALID_LIT_LEN_HUFFCODE;
874660f49b0SGreg Tucker 
875660f49b0SGreg Tucker 	if (create_huff_lookup(dist_huff_table, DIST_LEN, dist_tree, MAX_DEFLATE_CODE_LEN) > 0)
876660f49b0SGreg Tucker 		return INVALID_DIST_HUFFCODE;
877660f49b0SGreg Tucker 
878660f49b0SGreg Tucker 	if (are_hufftables_useable(lit_huff_table, dist_huff_table)) {
879660f49b0SGreg Tucker 		if (create_huff_lookup
880660f49b0SGreg Tucker 		    (lit_huff_table, LIT_LEN, lit_tree, MAX_SAFE_LIT_CODE_LEN) > 0)
881660f49b0SGreg Tucker 			return INVALID_LIT_LEN_HUFFCODE;
882660f49b0SGreg Tucker 
883660f49b0SGreg Tucker 		if (create_huff_lookup
884660f49b0SGreg Tucker 		    (dist_huff_table, DIST_LEN, dist_tree, MAX_SAFE_DIST_CODE_LEN) > 0)
885660f49b0SGreg Tucker 			return INVALID_DIST_HUFFCODE;
886660f49b0SGreg Tucker 
887660f49b0SGreg Tucker 		if (are_hufftables_useable(lit_huff_table, dist_huff_table))
888660f49b0SGreg Tucker 			return INVALID_HUFFCODE;
889660f49b0SGreg Tucker 	}
890660f49b0SGreg Tucker 
891660f49b0SGreg Tucker 	create_code_tables(dcodes, dcodes_sizes, DIST_LEN - DCODE_OFFSET,
892660f49b0SGreg Tucker 			   dist_huff_table + DCODE_OFFSET);
893660f49b0SGreg Tucker 
894660f49b0SGreg Tucker 	create_code_tables(lit_table, lit_table_sizes, LIT_TABLE_SIZE, lit_huff_table);
895660f49b0SGreg Tucker 
896660f49b0SGreg Tucker 	create_packed_len_table(len_table, lit_huff_table);
897660f49b0SGreg Tucker 	create_packed_dist_table(dist_table, DIST_TABLE_SIZE, dist_huff_table);
898660f49b0SGreg Tucker 
899660f49b0SGreg Tucker 	bit_count =
900660f49b0SGreg Tucker 	    create_header(deflate_hdr, sizeof(deflate_hdr), lit_huff_table, dist_huff_table,
901660f49b0SGreg Tucker 			  LAST_BLOCK);
902660f49b0SGreg Tucker 
903660f49b0SGreg Tucker 	hufftables->deflate_hdr_count = bit_count / 8;
904660f49b0SGreg Tucker 	hufftables->deflate_hdr_extra_bits = bit_count % 8;
905660f49b0SGreg Tucker 
906660f49b0SGreg Tucker 	return 0;
907660f49b0SGreg Tucker }
908660f49b0SGreg Tucker 
909660f49b0SGreg Tucker int isal_create_hufftables_subset(struct isal_hufftables *hufftables,
910660f49b0SGreg Tucker 				  struct isal_huff_histogram *histogram)
911660f49b0SGreg Tucker {
912660f49b0SGreg Tucker 	struct huff_tree lit_tree, dist_tree;
913660f49b0SGreg Tucker 	struct huff_tree lit_tree_array[2 * LIT_LEN - 1], dist_tree_array[2 * DIST_LEN - 1];
914660f49b0SGreg Tucker 	struct huff_code lit_huff_table[LIT_LEN], dist_huff_table[DIST_LEN];
915660f49b0SGreg Tucker 	uint64_t bit_count;
916660f49b0SGreg Tucker 	int j, max_dist = convert_dist_to_dist_sym(IGZIP_D);
917660f49b0SGreg Tucker 
918660f49b0SGreg Tucker 	uint32_t *dist_table = hufftables->dist_table;
919660f49b0SGreg Tucker 	uint32_t *len_table = hufftables->len_table;
920660f49b0SGreg Tucker 	uint16_t *lit_table = hufftables->lit_table;
921660f49b0SGreg Tucker 	uint16_t *dcodes = hufftables->dcodes;
922660f49b0SGreg Tucker 	uint8_t *lit_table_sizes = hufftables->lit_table_sizes;
923660f49b0SGreg Tucker 	uint8_t *dcodes_sizes = hufftables->dcodes_sizes;
924660f49b0SGreg Tucker 	uint8_t *deflate_hdr = hufftables->deflate_hdr;
925660f49b0SGreg Tucker 	uint64_t *lit_len_histogram = histogram->lit_len_histogram;
926660f49b0SGreg Tucker 	uint64_t *dist_histogram = histogram->dist_histogram;
927660f49b0SGreg Tucker 
928660f49b0SGreg Tucker 	memset(hufftables, 0, sizeof(struct isal_hufftables));
929660f49b0SGreg Tucker 	memset(lit_tree_array, 0, sizeof(lit_tree_array));
930660f49b0SGreg Tucker 	memset(dist_tree_array, 0, sizeof(dist_tree_array));
931660f49b0SGreg Tucker 	memset(lit_huff_table, 0, sizeof(lit_huff_table));
932660f49b0SGreg Tucker 	memset(dist_huff_table, 0, sizeof(dist_huff_table));
933660f49b0SGreg Tucker 
934660f49b0SGreg Tucker 	for (j = LIT_TABLE_SIZE; j < LIT_LEN; j++)
935660f49b0SGreg Tucker 		if (lit_len_histogram[j] == 0)
936660f49b0SGreg Tucker 			lit_len_histogram[j]++;
937660f49b0SGreg Tucker 
938660f49b0SGreg Tucker 	lit_tree = create_symbol_subset_huff_tree(lit_tree_array, lit_len_histogram, LIT_LEN);
939660f49b0SGreg Tucker 	dist_tree = create_huff_tree(dist_tree_array, dist_histogram, max_dist + 1);
940660f49b0SGreg Tucker 
941660f49b0SGreg Tucker 	if (create_huff_lookup(lit_huff_table, LIT_LEN, lit_tree, MAX_DEFLATE_CODE_LEN) > 0)
942660f49b0SGreg Tucker 		return INVALID_LIT_LEN_HUFFCODE;
943660f49b0SGreg Tucker 
944660f49b0SGreg Tucker 	if (create_huff_lookup(dist_huff_table, DIST_LEN, dist_tree, MAX_DEFLATE_CODE_LEN) > 0)
945660f49b0SGreg Tucker 		return INVALID_DIST_HUFFCODE;
946660f49b0SGreg Tucker 
947660f49b0SGreg Tucker 	if (are_hufftables_useable(lit_huff_table, dist_huff_table)) {
948660f49b0SGreg Tucker 		if (create_huff_lookup
949660f49b0SGreg Tucker 		    (lit_huff_table, LIT_LEN, lit_tree, MAX_SAFE_LIT_CODE_LEN) > 0)
950660f49b0SGreg Tucker 			return INVALID_LIT_LEN_HUFFCODE;
951660f49b0SGreg Tucker 
952660f49b0SGreg Tucker 		if (create_huff_lookup
953660f49b0SGreg Tucker 		    (dist_huff_table, DIST_LEN, dist_tree, MAX_SAFE_DIST_CODE_LEN) > 0)
954660f49b0SGreg Tucker 			return INVALID_DIST_HUFFCODE;
955660f49b0SGreg Tucker 
956660f49b0SGreg Tucker 		if (are_hufftables_useable(lit_huff_table, dist_huff_table))
957660f49b0SGreg Tucker 			return INVALID_HUFFCODE;
958660f49b0SGreg Tucker 	}
959660f49b0SGreg Tucker 
960660f49b0SGreg Tucker 	create_code_tables(dcodes, dcodes_sizes, DIST_LEN - DCODE_OFFSET,
961660f49b0SGreg Tucker 			   dist_huff_table + DCODE_OFFSET);
962660f49b0SGreg Tucker 
963660f49b0SGreg Tucker 	create_code_tables(lit_table, lit_table_sizes, LIT_TABLE_SIZE, lit_huff_table);
964660f49b0SGreg Tucker 
965660f49b0SGreg Tucker 	create_packed_len_table(len_table, lit_huff_table);
966660f49b0SGreg Tucker 	create_packed_dist_table(dist_table, DIST_TABLE_SIZE, dist_huff_table);
967660f49b0SGreg Tucker 
968660f49b0SGreg Tucker 	bit_count =
969660f49b0SGreg Tucker 	    create_header(deflate_hdr, sizeof(deflate_hdr), lit_huff_table, dist_huff_table,
970660f49b0SGreg Tucker 			  LAST_BLOCK);
971660f49b0SGreg Tucker 
972660f49b0SGreg Tucker 	hufftables->deflate_hdr_count = bit_count / 8;
973660f49b0SGreg Tucker 	hufftables->deflate_hdr_extra_bits = bit_count % 8;
974660f49b0SGreg Tucker 
975660f49b0SGreg Tucker 	return 0;
976660f49b0SGreg Tucker }
977