~ubuntu-branches/ubuntu/karmic/me-tv/karmic

« back to all changes in this revision

Viewing changes to src/dvb_epg.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Lamothe
  • Date: 2007-12-19 23:30:16 UTC
  • Revision ID: james.westby@ubuntu.com-20071219233016-2ng2clfh00xtlevc
Tags: upstream-0.4.19
ImportĀ upstreamĀ versionĀ 0.4.19

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Michael Lamothe
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 * 
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU Library General Public License for more details.
 
13
 * 
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 
17
 */
 
18
 
 
19
#include "dvb_epg.h"
 
20
#include "log.h"
 
21
#include "string_utility.h"
 
22
#include <libgnome/libgnome.h>
 
23
 
 
24
#define SHORT_EVENT                     0x4D
 
25
 
 
26
static guint32 crc_table[256] = {
 
27
    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
 
28
    0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
 
29
    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
 
30
    0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
 
31
    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
 
32
    0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
 
33
    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
 
34
    0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
 
35
    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
 
36
    0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
 
37
    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
 
38
    0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
 
39
    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
 
40
    0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
 
41
    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
 
42
    0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
 
43
    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
 
44
    0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
 
45
    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
 
46
    0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
 
47
    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
 
48
    0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
 
49
    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
 
50
    0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
 
51
    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
 
52
    0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
 
53
    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
 
54
    0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
 
55
    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
 
56
    0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
 
57
    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
 
58
    0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
 
59
    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
 
60
    0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
 
61
    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
 
62
    0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
 
63
    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
 
64
    0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
 
65
    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
 
66
    0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
 
67
    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
 
68
    0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
 
69
    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 
70
};
 
71
 
 
72
static guint32 crc32(char *data, int len)
 
73
{
 
74
    register int i;
 
75
    u_long crc = 0xffffffff;
 
76
 
 
77
    for (i=0; i<len; i++)
 
78
        {
 
79
        crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
 
80
        }
 
81
        
 
82
    return crc;
 
83
}
 
84
 
 
85
DvbDescriptor::DvbDescriptor()
 
86
{
 
87
        event_id = 0;
 
88
        start_time_MJD = 0;
 
89
        start_time_UTC = 0;
 
90
        duration = 0;
 
91
        running_status = 0;
 
92
        free_CA_mode = 0;
 
93
        
 
94
        dur_hour = 0;
 
95
        dur_min = 0;
 
96
        dur_sec = 0;
 
97
        
 
98
        start_year = 0;
 
99
        start_month = 0;
 
100
        start_day = 0;
 
101
        
 
102
        start_hour = 0;
 
103
        start_min = 0;
 
104
        start_sec = 0;
 
105
}
 
106
 
 
107
gboolean DvbSectionParser::parse(DvbDemuxer& demuxer, DvbSection& section, unsigned char* buffer)
 
108
{
 
109
        gboolean result = true;
 
110
        guint bytes_read = demuxer.read_data(buffer, 3);
 
111
        
 
112
        if (bytes_read != 3)
 
113
        {
 
114
                return false;
 
115
        }
 
116
                
 
117
        unsigned int section_length = get_bits (buffer, 12, 12);
 
118
        unsigned int end_section_offset = section_length + 3;
 
119
        bytes_read = demuxer.read_data(buffer + 3, section_length);
 
120
        
 
121
        if (bytes_read != section_length)
 
122
        {
 
123
                return false;
 
124
        }
 
125
        
 
126
        guint32 crc = crc32((char *)buffer, end_section_offset);
 
127
        
 
128
        if (crc != 0)
 
129
        {
 
130
                Log::write("CRC32 check failed");
 
131
                return false;
 
132
        }
 
133
 
 
134
        section.table_id =                                              buffer[0];
 
135
        section.section_syntax_indicator =              get_bits (buffer, 8, 1);
 
136
        section.service_id =                                    get_bits (buffer, 24, 16);
 
137
        section.version_number =                                get_bits (buffer, 42, 5);
 
138
        section.current_next_indicator =                get_bits (buffer, 47, 1);
 
139
        section.section_number =                                get_bits (buffer, 48, 8);
 
140
        section.last_section_number =                   get_bits (buffer, 56, 8);
 
141
        section.transport_stream_id =                   get_bits (buffer, 64, 16);
 
142
        section.original_network_id =                   get_bits (buffer, 80, 16);
 
143
        section.segment_last_section_number =   get_bits (buffer, 96, 8);
 
144
        section.last_table_id =                                 get_bits (buffer, 104, 8);
 
145
                                
 
146
        unsigned int offset = 14;
 
147
        
 
148
        while (offset < (end_section_offset - CRC_BYTE_SIZE))
 
149
        {
 
150
                DvbDescriptor descriptor;
 
151
 
 
152
                descriptor.event_id                   = get_bits (&buffer[offset], 0, 16);
 
153
                descriptor.start_time_MJD             = get_bits (&buffer[offset], 16, 16);
 
154
                descriptor.start_time_UTC             = get_bits (&buffer[offset], 32, 24);
 
155
                descriptor.duration                   = get_bits (&buffer[offset], 56, 24);
 
156
                descriptor.running_status             = get_bits (&buffer[offset], 80, 3);
 
157
                descriptor.free_CA_mode               = get_bits (&buffer[offset], 83, 1);
 
158
 
 
159
                unsigned int descriptors_loop_length  = get_bits (&buffer[offset], 84, 12);
 
160
                offset += 12;
 
161
                unsigned int end_descriptor_offset = descriptors_loop_length + offset;
 
162
 
 
163
                descriptor.dur_hour = ((descriptor.duration >> 20)&0xf)*10+((descriptor.duration >> 16)&0xf);
 
164
                descriptor.dur_min =  ((descriptor.duration >> 12)&0xf)*10+((descriptor.duration >>  8)&0xf);
 
165
                descriptor.dur_sec =  ((descriptor.duration >>  4)&0xf)*10+((descriptor.duration      )&0xf);
 
166
 
 
167
                if ( descriptor.start_time_MJD > 0 )
 
168
                {
 
169
                        long year =  (long) ((descriptor.start_time_MJD  - 15078.2) / 365.25);
 
170
                        long month =  (long) ((descriptor.start_time_MJD - 14956.1 - (long)(year * 365.25) ) / 30.6001);
 
171
                        descriptor.start_day =  (long) (descriptor.start_time_MJD - 14956 - (long)(year * 365.25) - (long)(month * 30.6001));
 
172
 
 
173
                        long k = (month == 14 || month == 15) ? 1 : 0;
 
174
 
 
175
                        descriptor.start_year = year + k + 1900;
 
176
                        descriptor.start_month = month - 1 - k * 12;
 
177
                }
 
178
 
 
179
                descriptor.start_hour = ((descriptor.start_time_UTC >> 20)&0xf)*10+((descriptor.start_time_UTC >> 16)&0xf);
 
180
                descriptor.start_min =  ((descriptor.start_time_UTC >> 12)&0xf)*10+((descriptor.start_time_UTC >>  8)&0xf);
 
181
                descriptor.start_sec =  ((descriptor.start_time_UTC >>  4)&0xf)*10+((descriptor.start_time_UTC      )&0xf);
 
182
 
 
183
                while (offset < end_descriptor_offset)
 
184
                {
 
185
                        offset += decode_descriptor(&buffer[offset], descriptor);
 
186
                }
 
187
                
 
188
                if (offset > end_descriptor_offset)
 
189
                {
 
190
                        throw Exception("ASSERT: offset > end_descriptor_offset");
 
191
                }
 
192
 
 
193
                section.descriptors.push_back( descriptor );
 
194
        }
 
195
        section.crc = get_bits (&buffer[offset], 0, 32);
 
196
        offset += 4;
 
197
        
 
198
        if (offset > end_section_offset)
 
199
        {
 
200
                throw Exception("ASSERT: offset > end_section_offset");
 
201
        }
 
202
        
 
203
        return result;
 
204
}
 
205
 
 
206
unsigned int DvbSectionParser::decode_descriptor (u_char* buffer, DvbDescriptor& descriptor)
 
207
{
 
208
        if (buffer[1] == 0)
 
209
        {
 
210
                return 2;
 
211
        }
 
212
                
 
213
        unsigned int descriptor_length = buffer[1] + 2;
 
214
        
 
215
        switch(buffer[0])
 
216
        {
 
217
        case SHORT_EVENT:
 
218
                {
 
219
                        Glib::ustring title;
 
220
                        Glib::ustring description;
 
221
                        
 
222
                        unsigned int offset = 5;
 
223
                        offset += get_text(title, &buffer[offset]);
 
224
                        offset += get_text(description, &buffer[offset]);
 
225
                        
 
226
                        if (descriptor.title.length() == 0)
 
227
                        {
 
228
                                descriptor.title = title;
 
229
                        }
 
230
                        else if (descriptor.title != title)
 
231
                        {
 
232
                                descriptor.title += "-" + title;
 
233
                        }
 
234
                        
 
235
                        if (descriptor.description.length() == 0)
 
236
                        {
 
237
                                descriptor.description = description;
 
238
                        }
 
239
                        else if (descriptor.description != description)
 
240
                        {
 
241
                                descriptor.description += "-" + description;
 
242
                        }
 
243
                }
 
244
                break;
 
245
        default:
 
246
                break;
 
247
        }
 
248
 
 
249
        return descriptor_length;
 
250
}
 
251
 
 
252
unsigned int DvbSectionParser::get_bits(unsigned char *buffer, unsigned int bitpos, unsigned int bitcount)
 
253
{
 
254
        unsigned int i;
 
255
        unsigned int val = 0;
 
256
 
 
257
        for (i = bitpos; i < bitcount + bitpos; i++)
 
258
        {
 
259
                val = val << 1;
 
260
                val = val + ((buffer[i >> 3] & (0x80 >> (i & 7))) ? 1 : 0);
 
261
        }
 
262
        return val;
 
263
}
 
264
 
 
265
unsigned int DvbSectionParser::get_text(Glib::ustring& s, u_char* buffer)
 
266
{
 
267
        guint length = buffer[0];
 
268
        guint text_index = 0;
 
269
        gchar text[length];
 
270
        guint index = 0;
 
271
        gchar* codeset = "ISO-8859-15";
 
272
 
 
273
        if (length > 0)
 
274
        {       
 
275
                // Skip over length byte
 
276
                index++;
 
277
                
 
278
                if (buffer[index] < 0x20)
 
279
                {
 
280
                        switch (buffer[index])
 
281
                        {
 
282
                        case 0x01: codeset = "ISO-8859-5"; break;
 
283
                        case 0x02: codeset = "ISO-8859-6"; break;
 
284
                        case 0x03: codeset = "ISO-8859-7"; break;
 
285
                        case 0x04: codeset = "ISO-8859-8"; break;
 
286
                        case 0x05: codeset = "ISO-8859-9"; break;
 
287
                        case 0x06: codeset = "ISO-8859-10"; break;
 
288
                        case 0x07: codeset = "ISO-8859-11"; break;
 
289
                        case 0x08: codeset = "ISO-8859-12"; break;
 
290
                        case 0x09: codeset = "ISO-8859-13"; break;
 
291
                        case 0x0A: codeset = "ISO-8859-14"; break;
 
292
                        case 0x0B: codeset = "ISO-8859-15"; break;
 
293
 
 
294
                        case 0x10:
 
295
                                {
 
296
                                        // Skip 0x00
 
297
                                        index++;
 
298
                                        
 
299
                                        switch(buffer[index])
 
300
                                        {
 
301
                                        case 0x01: codeset = "ISO-8859-1"; break;
 
302
                                        case 0x02: codeset = "ISO-8859-2"; break;
 
303
                                        case 0x03: codeset = "ISO-8859-3"; break;
 
304
                                        case 0x04: codeset = "ISO-8859-4"; break;
 
305
                                        case 0x05: codeset = "ISO-8859-5"; break;
 
306
                                        case 0x06: codeset = "ISO-8859-6"; break;
 
307
                                        case 0x07: codeset = "ISO-8859-7"; break;
 
308
                                        case 0x08: codeset = "ISO-8859-8"; break;
 
309
                                        case 0x09: codeset = "ISO-8859-9"; break;
 
310
                                        case 0x0A: codeset = "ISO-8859-10"; break;
 
311
                                        case 0x0B: codeset = "ISO-8859-11"; break;
 
312
                                        case 0x0C: codeset = "ISO-8859-12"; break;
 
313
                                        case 0x0D: codeset = "ISO-8859-13"; break;
 
314
                                        case 0x0E: codeset = "ISO-8859-14"; break;
 
315
                                        case 0x0F: codeset = "ISO-8859-15"; break;
 
316
                                        }
 
317
                                        
 
318
                                        index++;
 
319
                                }
 
320
                        }
 
321
                        
 
322
                        index++;
 
323
                }
 
324
                                
 
325
                s = "";
 
326
                
 
327
                if (index < (length + 1))
 
328
                {
 
329
                        while (index < (length + 1))
 
330
                        {
 
331
                                u_char ch = buffer[index];
 
332
 
 
333
                                if (ch == 0x86 || ch == 0x87)
 
334
                                {
 
335
                                        // Ignore formatting
 
336
                                }
 
337
                                else if (ch == 0x8A)
 
338
                                {
 
339
                                        text[text_index++] = '\n';
 
340
                                }
 
341
                                else if (ch >= 0x80 && ch < 0xA0)
 
342
                                {
 
343
                                        text[text_index++] = '.';
 
344
                                }
 
345
                                else
 
346
                                {
 
347
                                        text[text_index++] = ch;
 
348
                                }
 
349
                                
 
350
                                index++;
 
351
                        }
 
352
 
 
353
                        /*
 
354
                        Log::write(G_LOG_LEVEL_DEBUG, "Codeset: %s", codeset);
 
355
                        Log::write(G_LOG_LEVEL_DEBUG, "Length: %d", length);
 
356
                        for (guint i = 0; i < (length+1); i++)
 
357
                        {
 
358
                                gchar ch = buffer[i];
 
359
                                if (!isprint(ch))
 
360
                                {
 
361
                                        Log::write(G_LOG_LEVEL_DEBUG, "buffer[%d]\t= 0x%02X", i, buffer[i]);
 
362
                                }
 
363
                                else
 
364
                                {
 
365
                                        Log::write(G_LOG_LEVEL_DEBUG, "buffer[%d]\t= 0x%02X '%c'", i, buffer[i], buffer[i]);
 
366
                                }
 
367
                        }
 
368
                        */
 
369
                        
 
370
                        gsize bytes_read;
 
371
                        gsize bytes_written;
 
372
                        GError* error = NULL;
 
373
 
 
374
                        gchar* result = g_convert(
 
375
                                text,
 
376
                                text_index,
 
377
                                "UTF-8",
 
378
                                codeset,
 
379
                                &bytes_read,
 
380
                                &bytes_written,
 
381
                                &error);
 
382
                        
 
383
                        if (error != NULL)
 
384
                        {
 
385
                                Glib::ustring message = StringUtility::format(N_("Failed to convert to UTF-8: %s"), error->message);
 
386
                                Log::write(message);
 
387
                                Log::write("Codeset: %s", codeset);
 
388
                                Log::write("Length: %d", length);
 
389
                                for (guint i = 0; i < (length+1); i++)
 
390
                                {
 
391
                                        gchar ch = buffer[i];
 
392
                                        if (!isprint(ch))
 
393
                                        {
 
394
                                                Log::write("buffer[%d]\t= 0x%02X", i, buffer[i]);
 
395
                                        }
 
396
                                        else
 
397
                                        {
 
398
                                                Log::write("buffer[%d]\t= 0x%02X '%c'", i, buffer[i], buffer[i]);
 
399
                                        }
 
400
                                }
 
401
                                throw Exception(message);
 
402
                        }
 
403
                        
 
404
                        if (result == NULL)
 
405
                        {
 
406
                                throw Exception(N_("Failed to convert to UTF-8"));
 
407
                        }
 
408
                        s = result;
 
409
                        g_free(result);
 
410
                }
 
411
        }
 
412
        
 
413
        return length + 1;
 
414
}