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