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