/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018, 2019 * Jonathan Schleifer <js@heap.zone> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <stdint.h> #include <stdlib.h> #import "huffman_tree.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" static struct of_huffman_tree * newTree(void) { struct of_huffman_tree *tree; if ((tree = malloc(sizeof(*tree))) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: sizeof(*tree)]; tree->leaves[0] = tree->leaves[1] = NULL; tree->value = 0xFFFF; return tree; } static void insertTree(struct of_huffman_tree *tree, uint16_t code, uint8_t length, uint16_t value) { while (length > 0) { uint8_t bit; length--; bit = (code & (1 << length)) >> length; if (tree->leaves[bit] == NULL) tree->leaves[bit] = newTree(); tree = tree->leaves[bit]; } tree->value = value; } struct of_huffman_tree * of_huffman_tree_construct(uint8_t lengths[], uint16_t count) { struct of_huffman_tree *tree; uint16_t *lengthCount = NULL; uint16_t code, maxCode = 0, *nextCode = NULL; uint_fast8_t maxBit = 0; @try { for (uint16_t i = 0; i < count; i++) { uint_fast8_t length = lengths[i]; if OF_UNLIKELY (length > maxBit) { size_t size = (length + 1) * sizeof(uint16_t); uint16_t *new; if ((new = realloc(lengthCount, size)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: size]; lengthCount = new; if ((new = realloc(nextCode, size)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: size]; nextCode = new; for (uint_fast8_t j = maxBit + 1; j <= length; j++) { lengthCount[j] = 0; nextCode[j] = 0; } maxBit = length; } if (length > 0) { lengthCount[length]++; maxCode = i; } } code = 0; for (size_t i = 1; i <= maxBit; i++) { code = (code + lengthCount[i - 1]) << 1; nextCode[i] = code; } tree = newTree(); for (uint16_t i = 0; i <= maxCode; i++) { uint8_t length = lengths[i]; if (length > 0) insertTree(tree, nextCode[length]++, length, i); } } @finally { free(lengthCount); free(nextCode); } return tree; } struct of_huffman_tree * of_huffman_tree_construct_single(uint16_t value) { struct of_huffman_tree *tree = newTree(); tree->value = value; return tree; } bool of_huffman_tree_walk(id stream, bool (*bitReader)(id, uint16_t *, uint8_t), struct of_huffman_tree **tree, uint16_t *value) { struct of_huffman_tree *iter = *tree; uint16_t bits; while (iter->value == 0xFFFF) { if OF_UNLIKELY (!bitReader(stream, &bits, 1)) { *tree = iter; return false; } if OF_UNLIKELY (iter->leaves[bits] == NULL) @throw [OFInvalidFormatException exception]; iter = iter->leaves[bits]; } *value = iter->value; return true; } void of_huffman_tree_release(struct of_huffman_tree *tree) { for (uint_fast8_t i = 0; i < 2; i++) if OF_LIKELY (tree->leaves[i] != NULL) of_huffman_tree_release(tree->leaves[i]); free(tree); }