Update EPG Cache(thanks to open source community)
[vuplus_dvbapp] / lib / base / freesatv2.cpp
1 /*
2 FreeSat Huffman decoder for VDR
3 Copyright (C) 2008  DOM http://www.rst38.org.uk/vdr/
4 Port to C++ / Enigma 2
5 Copyright (C) 2008  Martin Croome
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 */
17 #include "freesatv2.h"
18 #ifdef FREESATV2_DEBUG
19 #       include "eerror.h"
20 #endif
21 #include <asm/types.h>
22
23 #define START   '\0'
24 #define STOP    '\0'
25 #define ESCAPE  '\1'
26
27 #ifndef DATADIR
28 #       define DATADIR "/usr/share"
29 #endif
30
31 #ifndef FREESAT_DATA_DIRECTORY
32 #define FREESAT_DATA_DIRECTORY       DATADIR
33 #endif
34 #define TABLE1_FILENAME FREESAT_DATA_DIRECTORY "/enigma2/freesat.t1"
35 #define TABLE2_FILENAME FREESAT_DATA_DIRECTORY "/enigma2/freesat.t2"
36
37 static void loadFile(huffTableEntry **table, const char *filename);
38
39
40 struct huffTableEntry
41 {
42         uint32_t value;
43         uint16_t bits;
44         char next;
45         huffTableEntry * nextEntry;
46
47         huffTableEntry(unsigned int value, short bits, char next) : value(value), bits(bits), next(next), nextEntry(NULL)
48         { }
49 };
50
51 freesatHuffmanDecoder::freesatHuffmanDecoder()
52 {
53         memset(m_tables, 0, sizeof(m_tables));
54         loadFile(&m_tables[0][0], TABLE1_FILENAME);
55         loadFile(&m_tables[1][0], TABLE2_FILENAME);
56 }
57
58 freesatHuffmanDecoder::~freesatHuffmanDecoder()
59 {
60         int     i, j;
61         huffTableEntry *currentEntry, *nextEntry;
62         for ( j = 0 ; j < 2; j++ )
63         {
64                 for ( i = 0 ; i < 256; i++ )
65                 {
66                         currentEntry = m_tables[j][i];
67                         while ( currentEntry != NULL )
68                         {
69                                 nextEntry = currentEntry->nextEntry;
70                                 delete currentEntry;
71                                 currentEntry = nextEntry;
72                         }
73                         m_tables[j][i] = NULL;
74                 }
75         }
76 }
77
78
79 /** \brief Convert a textual character description into a value
80 *
81 *  \param str - Encoded (in someway) string
82 *
83 *  \return Raw character
84 */
85 static unsigned char resolveChar(const char *str)
86 {
87         const char *p = str;
88         unsigned c0 = *p++, c1 = *p++;
89         if (c1)
90                 switch(c0|c1<<8)
91                 {
92                         case '0'|'x'<<8:
93                                 if ( sscanf(p,"%02x", &c1) == 1 )
94                                         c0 = c1;
95                                 break;
96                         case 'E'|'S'<<8:
97                                 if ( !strcmp(p,"CAPE") )
98                                         c0 = ESCAPE;
99                                 break;
100                         case 'S'|'T'<<8:
101                                 if ( !strcmp(p,"OP") )
102                                         c0 = STOP;
103                                 else if ( !strcmp(p,"ART") )
104                                         c0 = START;
105                                 break;
106                 }
107         return c0;
108 }
109
110
111 /** \brief Decode a binary string into a value
112 *
113 *  \param binary - Binary string to decode
114 *
115 *  \return Decoded value
116 */
117 static unsigned long decodeBinary(const char *binary)
118 {
119         unsigned long mask = 0x80000000;
120         unsigned long val = 0;
121
122         while (*binary)
123         {
124                 if ( *binary == '1' )
125                 {
126                         val |= mask;
127                 }
128                 mask >>= 1;
129                 ++binary;
130         }
131         return val;
132 }
133
134 static void loadFile(huffTableEntry **table, const char *filename)
135 {
136         char buf[1024];
137         char *from;
138         char *to;
139         char *binary;
140         char *colon;
141
142         FILE *fp = fopen(filename, "r");
143         if ( fp )
144         {
145                 while ( fgets(buf,sizeof(buf),fp) != NULL )
146                 {
147                         // Tokenize string "in place"
148                         from = buf;
149                         colon = strchr(buf, ':');
150                         if (colon == NULL)
151                                 continue;
152                         binary = colon + 1;
153                         *colon = 0;
154                         colon = strchr(binary, ':');
155                         if (colon == NULL)
156                                 continue;
157                         *colon = 0;
158                         to = colon + 1;
159                         colon = strchr(to, ':');
160                         if (colon != NULL)
161                                 *colon = 0;
162                         {
163                                 int bin_len = strlen(binary);
164                                 int from_char = resolveChar(from);
165                                 char to_char = resolveChar(to);
166                                 unsigned long bin = decodeBinary(binary);
167
168                                 // Add entry to end of bucket
169                                 huffTableEntry **pCurrent = &table[from_char];
170                                 while ( *pCurrent != NULL )
171                                 {
172                                         pCurrent = &((*pCurrent)->nextEntry);
173                                 }
174                                 *pCurrent = new huffTableEntry(bin, bin_len, to_char);
175                         }
176                 }
177                 fclose(fp);
178         }
179 #ifdef FREESATV2_DEBUG
180         else
181         {
182                 eDebug("[FREESAT] Cannot load '%s'",filename);
183         }
184 #endif
185 }
186
187
188 /** \brief Decode an EPG string as necessary
189 *
190 *  \param src - Possibly encoded string
191 *  \param size - Size of the buffer
192 *
193 *  \retval NULL - Can't decode
194 *  \return A decoded string
195 */
196 std::string freesatHuffmanDecoder::decode(const unsigned char *src, size_t size)
197 {
198         std::string uncompressed;
199
200         if (src[0] != 0x1f)
201                 return uncompressed;
202
203         const unsigned int table_index = src[1] - 1;
204
205         if (table_index <= 1)
206         {
207                 huffTableEntry **table = &m_tables[table_index][0];
208                 unsigned int value = 0;
209                 unsigned int byte = 2;
210                 unsigned int bit = 0;
211                 int lastch = START;
212
213                 while (byte < 6 && byte < size)
214                 {
215                         value |= src[byte] << ((5-byte) * 8);
216                         byte++;
217                 }
218
219                 do
220                 {
221                         int found = 0;
222                         unsigned bitShift = 0;
223                         if (lastch == ESCAPE)
224                         {
225                                 char nextCh = (value >> 24) & 0xff;
226                                 found = 1;
227                                 // Encoded in the next 8 bits.
228                                 // Terminated by the first ASCII character.
229                                 bitShift = 8;
230                                 if ((nextCh & 0x80) == 0)
231                                         lastch = nextCh;
232                                 uncompressed.append(&nextCh, 1);
233                         }
234                         else
235                         {
236                                 huffTableEntry * currentEntry = table[lastch];
237                                 while ( currentEntry != NULL )
238                                 {
239                                         unsigned mask = 0, maskbit = 0x80000000;
240                                         short kk;
241                                         for ( kk = 0; kk < currentEntry->bits; kk++)
242                                         {
243                                                 mask |= maskbit;
244                                                 maskbit >>= 1;
245                                         }
246                                         if ((value & mask) == currentEntry->value)
247                                         {
248                                                 char nextCh = currentEntry->next;
249                                                 bitShift = currentEntry->bits;
250                                                 if (nextCh != STOP && nextCh != ESCAPE)
251                                                 {
252                                                         uncompressed.append(&nextCh, 1);
253                                                 }
254                                                 found = 1;
255                                                 lastch = nextCh;
256                                                 break;
257                                         }
258                                         currentEntry = currentEntry->nextEntry;
259                                 }
260                         }
261                         if (found)
262                         {
263                                 // Shift up by the number of bits.
264                                 unsigned b;
265                                 for ( b = 0; b < bitShift; b++)
266                                 {
267                                         value = (value << 1) & 0xfffffffe;
268                                         if (byte < size)
269                                                 value |= (src[byte] >> (7-bit)) & 1;
270                                         if (bit == 7)
271                                         {
272                                                 bit = 0;
273                                                 byte++;
274                                         }
275                                         else bit++;
276                                 }
277                         }
278                         else
279                         {
280 #ifdef FREESATV2_DEBUG
281                                 eDebug("[FREESAT] Missing table %d entry: <%s>", table_index + 1, uncompressed.c_str());
282 #endif
283                                 return uncompressed;
284                         }
285                 } while (lastch != STOP && value != 0);
286         }
287         return uncompressed;
288 }