1 /*
2 * TV headend - Huffman decoder
3 * Copyb1 (C) 2012 Adam Sutton
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include "huffman.h"
23 #include "htsmsg.h"
24 #include "settings.h"
25
huffman_tree_destroy(huffman_node_t * n)26 void huffman_tree_destroy ( huffman_node_t *n )
27 {
28 if (!n) return;
29 huffman_tree_destroy(n->b0);
30 huffman_tree_destroy(n->b1);
31 if (n->data) free(n->data);
32 free(n);
33 }
34
huffman_tree_load(const char * path)35 huffman_node_t *huffman_tree_load ( const char *path )
36 {
37 htsmsg_t *m;
38 huffman_node_t *ret;
39 if (!(m = hts_settings_load(path))) return NULL;
40 ret = huffman_tree_build(m);
41 htsmsg_destroy(m);
42 return ret;
43 }
44
huffman_tree_build(htsmsg_t * m)45 huffman_node_t *huffman_tree_build ( htsmsg_t *m )
46 {
47 const char *code, *data, *c;
48 htsmsg_t *e;
49 htsmsg_field_t *f;
50 huffman_node_t *root = calloc(1, sizeof(huffman_node_t));
51 HTSMSG_FOREACH(f, m) {
52 e = htsmsg_get_map_by_field(f);
53 c = code = htsmsg_get_str(e, "code");
54 data = htsmsg_get_str(e, "data");
55 if (code && data) {
56 huffman_node_t *node = root;
57 while (*c) {
58 if ( *c == '0' ) {
59 if (!node->b0) node->b0 = calloc(1, sizeof(huffman_node_t));
60 node = node->b0;
61 } else if ( *c == '1' ) {
62 if (!node->b1) node->b1 = calloc(1, sizeof(huffman_node_t));
63 node = node->b1;
64 } else {
65 huffman_tree_destroy(root);
66 return NULL;
67 }
68 c++;
69 }
70 node->data = strdup(data);
71 }
72 }
73 return root;
74 }
75
huffman_decode(huffman_node_t * tree,const uint8_t * data,size_t len,uint8_t mask,char * outb,int outl)76 char *huffman_decode
77 ( huffman_node_t *tree, const uint8_t *data, size_t len, uint8_t mask,
78 char *outb, int outl )
79 {
80 char *ret = outb;
81 huffman_node_t *node = tree;
82 if (!len) return NULL;
83
84 outl--; // leave space for NULL
85 while (len) {
86 len--;
87 while (mask) {
88 if (*data & mask) {
89 node = node->b1;
90 } else {
91 node = node->b0;
92 }
93 mask >>= 1;
94 if (!node) goto end;
95 if (node->data) {
96 char *t = node->data;
97 while (*t && outl) {
98 *outb = *t;
99 outb++; t++; outl--;
100 }
101 if (!outl) goto end;
102 node = tree;
103 }
104 }
105 mask = 0x80;
106 data++;
107 }
108 end:
109 *outb = '\0';
110 return ret;
111 }
112