diff --git a/src/huffman.c b/src/huffman.c new file mode 100644 index 00000000..fef49b38 --- /dev/null +++ b/src/huffman.c @@ -0,0 +1,109 @@ +/* + * TV headend - Huffman decoder + * Copyb1 (C) 2012 Adam Sutton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "huffman.h" +#include "htsmsg.h" +#include "settings.h" + +void huffman_tree_destroy ( huffman_node_t *n ) +{ + if (!n) return; + huffman_tree_destroy(n->b0); + huffman_tree_destroy(n->b1); + if (n->data) free(n->data); + free(n); +} + +huffman_node_t *huffman_tree_load ( const char *path ) +{ + htsmsg_t *m; + if (!(m = hts_settings_load(path))) return NULL; + return huffman_tree_build(m); +} + +huffman_node_t *huffman_tree_build ( htsmsg_t *m ) +{ + const char *code, *data, *c; + htsmsg_t *e; + htsmsg_field_t *f; + huffman_node_t *root = calloc(1, sizeof(huffman_node_t)); + HTSMSG_FOREACH(f, m) { + e = htsmsg_get_map_by_field(f); + c = code = htsmsg_get_str(e, "code"); + data = htsmsg_get_str(e, "data"); + if (code && data) { + huffman_node_t *node = root; + while (*c) { + if ( *c == '0' ) { + if (!node->b0) node->b0 = calloc(1, sizeof(huffman_node_t)); + node = node->b0; + } else if ( *c == '1' ) { + if (!node->b1) node->b1 = calloc(1, sizeof(huffman_node_t)); + node = node->b1; + } else { + htsmsg_destroy(m); + huffman_tree_destroy(root); + return NULL; + } + c++; + } + node->data = strdup(data); + } + } + + htsmsg_destroy(m); + return root; +} + +char *huffman_decode + ( huffman_node_t *tree, const char *data, size_t len, uint8_t mask ) +{ + char* ret; + size_t nalloc = len, nused = 0; + huffman_node_t *node = tree; + if (!len) return NULL; + + ret = malloc(nalloc); + ret[0] = '\0'; + while (len) { + len--; + while (mask) { + if (*data & mask) { + node = node->b1; + } else { + node = node->b0; + } + mask >>= 1; + if (!node) return ret; + if (node->data) { + size_t l = strlen(node->data); + if ((nalloc - nused) < l) { + nalloc *= 2; + ret = realloc(ret, nalloc); + } + strcat(ret, node->data); + node = tree; + } + } + mask = 0x80; + } + return ret; +} diff --git a/src/huffman.h b/src/huffman.h new file mode 100644 index 00000000..08ce873e --- /dev/null +++ b/src/huffman.h @@ -0,0 +1,38 @@ +/* + * TV headend - Huffman decoder + * Copyright (C) 2012 Adam Sutton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TVH_HUFFMAN_H__ +#define __TVH_HUFFMAN_H__ + +#include +#include "htsmsg.h" + +typedef struct huffman_node +{ + struct huffman_node *b0; + struct huffman_node *b1; + char *data; +} huffman_node_t; + +void huffman_tree_destroy ( huffman_node_t *tree ); +huffman_node_t *huffman_tree_load ( const char *path ); +huffman_node_t *huffman_tree_build ( htsmsg_t *codes ); +char *huffman_decode + ( huffman_node_t *tree, const char *data, size_t len, uint8_t mask ); + +#endif