1 #include "lib_ccx.h"
2 #include "ccx_common_option.h"
3 #include "dvb_subtitle_decoder.h"
4 #include "utility.h"
5 #include <stdbool.h>
6 #ifdef WIN32
7 #include "..\\win_iconv\\iconv.h"
8 #else
9 #include "iconv.h"
10 #endif
11
12 //Prints a string to a file pointer, escaping XML special chars
13 //Works with UTF-8
EPG_fprintxml(FILE * f,char * string)14 void EPG_fprintxml(FILE *f, char *string)
15 {
16 char *p = string;
17 char *start = p;
18 while(*p!='\0')
19 {
20 switch(*p) {
21 case '<':
22 fwrite(start, 1, p-start, f);
23 fprintf(f, "<");
24 start = p+1;
25 break;
26 case '>':
27 fwrite(start, 1, p-start, f);
28 fprintf(f, ">");
29 start = p+1;
30 break;
31 case '"':
32 fwrite(start, 1, p-start, f);
33 fprintf(f, """);
34 start = p+1;
35 break;
36 case '&':
37 fwrite(start, 1, p-start, f);
38 fprintf(f, "&");
39 start = p+1;
40 break;
41 case '\'':
42 fwrite(start, 1, p-start, f);
43 fprintf(f, "'");
44 start = p+1;
45 break;
46 }
47 p++;
48 }
49 fwrite(start, 1, p-start, f);
50 }
51
52 // Fills given string with given (event.*_time_string) ATSC time converted to XMLTV style time string
EPG_ATSC_calc_time(char * output,uint32_t time)53 void EPG_ATSC_calc_time(char *output, uint32_t time)
54 {
55 struct tm timeinfo;
56 timeinfo.tm_year = 1980-1900;
57 timeinfo.tm_mon = 0;
58 timeinfo.tm_mday = 6;
59 timeinfo.tm_sec = 0+time;
60 timeinfo.tm_min = 0;
61 timeinfo.tm_hour = 0;
62 timeinfo.tm_isdst = -1;
63 mktime(&timeinfo);
64 sprintf(output, "%02d%02d%02d%02d%02d%02d +0000", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
65 }
66
67 // Fills event.start_time_string in XMLTV format with passed DVB time
EPG_DVB_calc_start_time(struct EPG_event * event,uint64_t time)68 void EPG_DVB_calc_start_time(struct EPG_event *event, uint64_t time)
69 {
70 uint64_t mjd = time>>24;
71 event->start_time_string[0]='\0';
72 if (mjd > 0)
73 {
74 long y,m,d ,k;
75
76 // algo: ETSI EN 300 468 - ANNEX C
77 y = (long) ((mjd - 15078.2) / 365.25);
78 m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
79 d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
80 k = (m == 14 || m == 15) ? 1 : 0;
81 y = y + k + 1900;
82 m = m - 1 - k*12;
83
84 sprintf(event->start_time_string, "%02ld%02ld%02ld%06"PRIu64 "+0000",y,m,d,time&0xffffff);
85 }
86 }
87
88 // Fills event.end_time_string in XMLTV with passed DVB time + duration
EPG_DVB_calc_end_time(struct EPG_event * event,uint64_t time,uint32_t duration)89 void EPG_DVB_calc_end_time(struct EPG_event *event, uint64_t time, uint32_t duration)
90 {
91 uint64_t mjd = time>>24;
92 event->end_time_string[0]='\0';
93 if (mjd > 0)
94 {
95 long y,m,d ,k;
96 struct tm timeinfo;
97
98 // algo: ETSI EN 300 468 - ANNEX C
99 y = (long) ((mjd - 15078.2) / 365.25);
100 m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
101 d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
102 k = (m == 14 || m == 15) ? 1 : 0;
103 y = y + k + 1900;
104 m = m - 1 - k*12;
105
106 timeinfo.tm_year = y-1900;
107 timeinfo.tm_mon = m-1;
108 timeinfo.tm_mday = d;
109
110 timeinfo.tm_sec = (time&0x0f) + (10*((time&0xf0)>>4)) + (duration&0x0f) + (10*((duration&0xf0)>>4));
111 timeinfo.tm_min = ((time&0x0f00)>>8) + (10*((time&0xf000)>>4)>>8) + ((duration&0x0f00)>>8) + (10*((duration&0xf000)>>4)>>8);
112 timeinfo.tm_hour = ((time&0x0f0000)>>16) + (10*((time&0xf00000)>>4)>>16) + ((duration&0x0f0000)>>16) + (10*((duration&0xf00000)>>4)>>16);
113 timeinfo.tm_isdst = -1;
114 mktime(&timeinfo);
115 sprintf(event->end_time_string, "%02d%02d%02d%02d%02d%02d +0000", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
116 }
117 }
118
119 // returns english string description of the passed DVB category ID
EPG_DVB_content_type_to_string(uint8_t cat)120 char *EPG_DVB_content_type_to_string(uint8_t cat)
121 {
122 struct table {
123 uint8_t cat;
124 char *name;
125 };
126 struct table t[] = {
127 {0x00, "reserved"}, { 0x10, "movie/drama (general)" }, { 0x11, "detective/thriller" }, { 0x12, "adventure/western/war" }, { 0x13, "science fiction/fantasy/horror" },{ 0x14, "comedy" },
128 { 0x15, "soap/melodram/folkloric" }, { 0x16, "romance" }, { 0x17, "serious/classical/religious/historical movie/drama" }, { 0x18, "adult movie/drama" }, { 0x1E, "reserved" },
129 { 0x1F, "user defined" }, { 0x20, "news/current affairs (general)" }, { 0x21, "news/weather report" }, { 0x22, "news magazine" }, { 0x23, "documentary" }, { 0x24, "discussion/interview/debate" },
130 { 0x2E, "reserved" }, { 0x2F, "user defined" }, { 0x30, "show/game show (general)" }, { 0x31, "game show/quiz/contest" }, { 0x32, "variety show" }, { 0x33, "talk show" }, { 0x3E, "reserved" },
131 { 0x3F, "user defined" }, { 0x40, "sports (general)" }, { 0x41, "special events" }, { 0x42, "sports magazine" }, { 0x43, "football/soccer" }, { 0x44, "tennis/squash" }, { 0x45, "team sports" },
132 { 0x46, "athletics" }, { 0x47, "motor sport" }, { 0x48, "water sport" }, { 0x49, "winter sport" }, { 0x4A, "equestrian" }, { 0x4B, "martial sports" }, { 0x4E, "reserved" }, { 0x4F, "user defined" },
133 { 0x50, "childrens's/youth program (general)" }, { 0x51, "pre-school children's program" }, { 0x52, "entertainment (6-14 year old)" }, { 0x53, "entertainment (10-16 year old)" },
134 { 0x54, "information/education/school program" }, { 0x55, "cartoon/puppets" }, { 0x5E, "reserved" }, { 0x5F, "user defined" }, { 0x60, "music/ballet/dance (general)" }, { 0x61, "rock/pop" },
135 { 0x62, "serious music/classic music" }, { 0x63, "folk/traditional music" }, { 0x64, "jazz" }, { 0x65, "musical/opera" }, { 0x66, "ballet" }, { 0x6E, "reserved" }, { 0x6F, "user defined" },
136 { 0x70, "arts/culture (without music, general)" },{ 0x71, "performing arts" }, { 0x72, "fine arts" }, { 0x73, "religion" }, { 0x74, "popular culture/traditional arts" }, { 0x75, "literature" },
137 { 0x76, "film/cinema" }, { 0x77, "experimental film/video" }, { 0x78, "broadcasting/press" }, { 0x79, "new media" }, { 0x7A, "arts/culture magazine" }, { 0x7B, "fashion" }, { 0x7E, "reserved" },
138 { 0x7F, "user defined" }, { 0x80, "social/political issues/economics (general)" }, { 0x81, "magazines/reports/documentary" }, { 0x82, "economics/social advisory" }, { 0x83, "remarkable people" },
139 { 0x8E, "reserved" }, { 0x8F, "user defined" }, { 0x90, "education/science/factual topics (general)" }, { 0x91, "nature/animals/environment" }, { 0x92, "technology/natural science" },
140 { 0x93, "medicine/physiology/psychology" }, { 0x94, "foreign countries/expeditions" }, { 0x95, "social/spiritual science" }, { 0x96, "further education" }, { 0x97, "languages" },
141 { 0x9E, "reserved" }, { 0x9F, "user defined" }, { 0xA0, "leisure hobbies (general)" }, { 0xA1, "tourism/travel" }, { 0xA2, "handicraft" }, { 0xA3, "motoring" }, { 0xA4, "fitness & health" },
142 { 0xA5, "cooking" }, { 0xA6, "advertisement/shopping" }, { 0xA7, "gardening" }, { 0xAE, "reserved" }, { 0xAF, "user defined" }, { 0xB0, "original language" }, { 0xB1, "black & white" },
143 { 0xB2, "unpublished" }, { 0xB3, "live broadcast" }, { 0xBE, "reserved" }, { 0xBF, "user defined" }, { 0xEF, "reserved" }, { 0xFF, "user defined" }, {0x00, NULL},
144 };
145 struct table *p = t;
146 while(p->name!=NULL)
147 {
148 if(cat==p->cat)
149 return p->name;
150 p++;
151 }
152 return "undefined content";
153
154 }
155
156 // Prints given event to already opened XMLTV file.
EPG_print_event(struct EPG_event * event,uint32_t channel,FILE * f)157 void EPG_print_event(struct EPG_event *event, uint32_t channel, FILE *f)
158 {
159 int i;
160 fprintf(f, " <program ");
161 fprintf(f, "start=\"");
162 fprintf(f, "%s", event->start_time_string);
163 fprintf(f, "\" ");
164 fprintf(f, "stop=\"");
165 fprintf(f, "%s", event->end_time_string);
166 fprintf(f, "\" ");
167 fprintf(f, "channel=\"%i\">\n", channel);
168 if(event->has_simple)
169 {
170 fprintf(f, " <title lang=\"%s\">", event->ISO_639_language_code);
171 EPG_fprintxml(f, event->event_name);
172 fprintf(f, "</title>\n");
173 fprintf(f, " <sub-title lang=\"%s\">", event->ISO_639_language_code);
174 EPG_fprintxml(f, event->text);
175 fprintf(f, "</sub-title>\n");
176 }
177 if(event->extended_text!=NULL)
178 {
179 fprintf(f, " <desc lang=\"%s\">", event->extended_ISO_639_language_code);
180 EPG_fprintxml(f, event->extended_text);
181 fprintf(f, "</desc>\n");
182 }
183 for(i=0; i<event->num_ratings; i++)
184 if(event->ratings[i].age>0 && event->ratings[i].age<0x10)
185 fprintf(f, " <rating system=\"dvb:%s\">%i</rating>\n", event->ratings[i].country_code, event->ratings[i].age+3);
186 for(i=0; i<event->num_categories; i++)
187 {
188 fprintf(f, " <category lang=\"en\">");
189 EPG_fprintxml(f, EPG_DVB_content_type_to_string(event->categories[i]));
190 fprintf(f, "</category>\n");
191 }
192 fprintf(f, " <ts-meta-id>%i</ts-meta-id>\n", event->id);
193 fprintf(f, " </program>\n");
194 }
195
EPG_output_net(struct lib_ccx_ctx * ctx)196 void EPG_output_net(struct lib_ccx_ctx *ctx)
197 {
198 int i;
199 unsigned j;
200 struct EPG_event *event;
201
202 /* TODO: don't remove untill someone fixes segfault with -xmltv 2 */
203 if (ctx->demux_ctx == NULL)
204 return;
205
206 if (ctx->demux_ctx->nb_program == 0)
207 return;
208
209 for (i = 0; i < ctx->demux_ctx->nb_program; i++)
210 {
211 if (ctx->demux_ctx->pinfo[i].program_number == ccx_options.demux_cfg.ts_forced_program)
212 break;
213 }
214
215 if (i == ctx->demux_ctx->nb_program)
216 return;
217
218 for (j = 0; j < ctx->eit_programs[i].array_len; j++)
219 {
220 event = &(ctx->eit_programs[i].epg_events[j]);
221 if (event->live_output == true)
222 continue;
223
224 event->live_output = true;
225
226 char *category = NULL;
227 if (event->num_categories > 0)
228 category = EPG_DVB_content_type_to_string(event->categories[0]);
229
230 net_send_epg(
231 event->start_time_string, event->end_time_string,
232 event->event_name,
233 event->extended_text,
234 event->ISO_639_language_code,
235 category
236 );
237 }
238 }
239
240 // Creates fills and closes a new XMLTV file for live mode output.
241 // File should include only events not previously output.
EPG_output_live(struct lib_ccx_ctx * ctx)242 void EPG_output_live(struct lib_ccx_ctx *ctx)
243 {
244 int c=false, i, j;
245 FILE *f;
246 char *filename, *finalfilename;
247 for(i=0; i < ctx->demux_ctx->nb_program; i++)
248 {
249 for(j=0; j<ctx->eit_programs[i].array_len; j++)
250 if(ctx->eit_programs[i].epg_events[j].live_output==false)
251 {
252 c=true;
253 }
254 }
255 if(!c)
256 return;
257
258 filename = malloc(strlen(ctx->basefilename)+30);
259 sprintf(filename, "%s_%i.xml.part", ctx->basefilename, ctx->epg_last_live_output);
260 f = fopen(filename, "w");
261
262 fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
263 for(i=0; i < ctx->demux_ctx->nb_program; i++)
264 {
265 fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
266 fprintf(f, " <display-name>%i</display-name>\n", ctx->demux_ctx->pinfo[i].program_number);
267 fprintf(f, " </channel>\n");
268 }
269 for(i=0; i < ctx->demux_ctx->nb_program; i++)
270 {
271 for(j=0; j<ctx->eit_programs[i].array_len; j++)
272 if(ctx->eit_programs[i].epg_events[j].live_output==false)
273 {
274 ctx->eit_programs[i].epg_events[j].live_output=true;
275 EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
276 }
277 }
278 fprintf(f, "</tv>");
279 fclose(f);
280 finalfilename = malloc(strlen(filename)+30);
281 memcpy(finalfilename, filename, strlen(filename)-5);
282 finalfilename[strlen(filename)-5]='\0';
283 rename(filename, finalfilename);
284 free(filename);
285 free(finalfilename);
286 }
287
288 // Creates fills and closes a new XMLTV file for full output mode.
289 // File should include all events in memory.
EPG_output(struct lib_ccx_ctx * ctx)290 void EPG_output(struct lib_ccx_ctx *ctx)
291 {
292 FILE *f;
293 char *filename;
294 int i,j, ce;
295
296 filename = malloc(strlen(ctx->basefilename) + 9);
297 if(filename == NULL)
298 return;
299
300 memcpy(filename, ctx->basefilename, strlen(ctx->basefilename)+1);
301 strcat(filename, "_epg.xml");
302 f = fopen(filename, "w");
303 if(!f)
304 {
305 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rUnable to open %s\n", filename);
306 freep(&filename);
307 return;
308 }
309 freep(&filename);
310
311 fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n<tv>\n");
312 for(i=0; i<ctx->demux_ctx->nb_program; i++)
313 {
314 fprintf(f, " <channel id=\"%i\">\n", ctx->demux_ctx->pinfo[i].program_number);
315 fprintf(f, " <display-name>");
316 if(ctx->demux_ctx->pinfo[i].name[0] != '\0')
317 EPG_fprintxml(f, ctx->demux_ctx->pinfo[i].name);
318 else
319 fprintf(f, "%i\n", ctx->demux_ctx->pinfo[i].program_number);
320 fprintf(f, "</display-name>\n");
321 fprintf(f, " </channel>\n");
322 }
323 if(ccx_options.xmltvonlycurrent==0)
324 { // print all events
325 for(i=0; i<ctx->demux_ctx->nb_program; i++)
326 {
327 for(j=0; j<ctx->eit_programs[i].array_len; j++)
328 EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
329 }
330
331 if(ctx->demux_ctx->nb_program==0) //Stream has no PMT, fall back to unordered events
332 for(j=0; j<ctx->eit_programs[TS_PMT_MAP_SIZE].array_len; j++)
333 EPG_print_event(&ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j], ctx->eit_programs[TS_PMT_MAP_SIZE].epg_events[j].service_id, f);
334 }
335 else
336 { // print current events only
337 for(i=0; i<ctx->demux_ctx->nb_program; i++)
338 {
339 ce = ctx->eit_current_events[i];
340 for(j=0; j<ctx->eit_programs[i].array_len; j++)
341 {
342 if(ce==ctx->eit_programs[i].epg_events[j].id)
343 EPG_print_event(&ctx->eit_programs[i].epg_events[j], ctx->demux_ctx->pinfo[i].program_number, f);
344 }
345 }
346 }
347 fprintf(f, "</tv>");
348 fclose(f);
349 }
350
351 // Free all memory allocated for given event
EPG_free_event(struct EPG_event * event)352 void EPG_free_event(struct EPG_event *event)
353 {
354 if(event->has_simple)
355 {
356 free(event->event_name);
357 free(event->text);
358 }
359 if(event->extended_text!=NULL)
360 free(event->extended_text);
361 if(event->num_ratings>0)
362 free(event->ratings);
363 if(event->num_categories>0)
364 free(event->categories);
365 }
366
367 //compare 2 events. Return false if they are different.
EPG_event_cmp(struct EPG_event * e1,struct EPG_event * e2)368 int EPG_event_cmp(struct EPG_event *e1, struct EPG_event *e2)
369 {
370 if(e1->id != e2->id || (strcmp(e1->start_time_string, e2->start_time_string)!=0) || (strcmp(e1->end_time_string, e2->end_time_string)!=0))
371 return false;
372 // could add full checking of strings here if desired.
373 return true;
374 }
375
376 // Add given event to array of events.
377 // Return FALSE if nothing changed, TRUE if this is a new or updated event.
EPG_add_event(struct lib_ccx_ctx * ctx,int32_t pmt_map,struct EPG_event * event)378 int EPG_add_event(struct lib_ccx_ctx *ctx, int32_t pmt_map, struct EPG_event *event)
379 {
380 int isnew=true, j;
381
382 for(j=0; j<ctx->eit_programs[pmt_map].array_len; j++)
383 {
384 if(ctx->eit_programs[pmt_map].epg_events[j].id==event->id)
385 {
386 if(EPG_event_cmp(event, &ctx->eit_programs[pmt_map].epg_events[j]))
387 return false; //event already in array, nothing to do
388 else
389 { //event with this id is already in the array but something has changed. Update it.
390 event->count=ctx->eit_programs[pmt_map].epg_events[j].count;
391 EPG_free_event(&ctx->eit_programs[pmt_map].epg_events[j]);
392 memcpy(&ctx->eit_programs[pmt_map].epg_events[j], event, sizeof(struct EPG_event));
393 return true;
394 }
395 }
396 }
397 // id not in array. Add new event;
398 event->count=0;
399 memcpy(&ctx->eit_programs[pmt_map].epg_events[ctx->eit_programs[pmt_map].array_len], event, sizeof(struct EPG_event));
400 ctx->eit_programs[pmt_map].array_len++;
401 return true;
402 }
403
404 //EN 300 468 V1.3.1 (1998-02)
405 //6.2.4 Content descriptor
EPG_decode_content_descriptor(uint8_t * offset,uint32_t descriptor_length,struct EPG_event * event)406 void EPG_decode_content_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event)
407 {
408 int i;
409 int num_items = descriptor_length/2;
410 if(num_items == 0)
411 {
412 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT content_descriptor length detected.\n");
413 return;
414 }
415 event->categories = malloc(1*num_items);
416 event->num_categories = num_items;
417 for(i=0; i<num_items; i++)
418 {
419 event->categories[i] = offset[0];
420 offset+=2;
421 }
422 }
423
424 //EN 300 468 V1.3.1 (1998-02)
425 //6.2.20 Parental rating descripto
EPG_decode_parental_rating_descriptor(uint8_t * offset,uint32_t descriptor_length,struct EPG_event * event)426 void EPG_decode_parental_rating_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event)
427 {
428 int i;
429 int num_items = descriptor_length/4;
430 struct EPG_rating *ratings;
431
432 if(num_items == 0)
433 {
434 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT parental_rating length detected.\n");
435 return;
436 }
437 event->ratings = malloc(sizeof(struct EPG_rating)*num_items);
438
439 ratings = event->ratings;
440 event->num_ratings = num_items;
441 for(i=0; i<descriptor_length/4; i++)
442 {
443 ratings[i].country_code[0] = offset[0];
444 ratings[i].country_code[1] = offset[1];
445 ratings[i].country_code[2] = offset[2];
446 ratings[i].country_code[3] = '\0';
447 if(offset[3] == 0x00 || offset[3] >=0x10)
448 ratings[i].age = 0;
449 else
450 ratings[i].age = offset[3];
451 offset+=4;
452 }
453 }
454
455 // an ugly function to convert from dvb codepages to UTF-8859-9 using iconv
456 // returns a null terminated UTF8-strings
457 // EN 300 468 V1.7.1 (2006-05)
458 // A.2 Selection of Character table
EPG_DVB_decode_string(uint8_t * in,size_t size)459 char* EPG_DVB_decode_string(uint8_t *in, size_t size)
460 {
461 uint8_t *out;
462 uint16_t decode_buffer_size = (size*4)+1;
463 uint8_t *decode_buffer = malloc(decode_buffer_size);
464 char *dp = &decode_buffer[0];
465 size_t obl=decode_buffer_size;
466 uint16_t osize=0;
467 iconv_t cd=(iconv_t)(-1);
468 int skipiconv = false;
469 int ret=-1;
470 int x;
471 if(size==0)
472 { // 0 length strings are valid
473 decode_buffer[0]='\0';
474 return decode_buffer;
475 }
476
477 if(in[0]>=0x20)
478 {
479 skipiconv=true;
480 }
481 else if(in[0]==0x01)
482 {
483 size--; in++;
484 cd = iconv_open("UTF-8", "ISO8859-5"); //tested
485 }
486 else if(in[0]==0x02)
487 {
488 size--; in++;
489 cd = iconv_open("UTF-8", "ISO8859-6");
490 }
491 else if(in[0]==0x03)
492 {
493 size--; in++;
494 cd = iconv_open("UTF-8", "ISO8859-7");
495 }
496 else if(in[0]==0x04)
497 {
498 size--; in++;
499 cd = iconv_open("UTF-8", "ISO8859-8");
500 }
501 else if(in[0]==0x05)
502 {
503 size--; in++;
504 cd = iconv_open("UTF-8", "ISO8859-9");
505 }
506 else if(in[0]==0x06) {
507 size--; in++;
508 cd = iconv_open("UTF-8", "ISO8859-10");
509 }
510 else if(in[0]==0x07)
511 {
512 size--;
513 in++;
514 cd = iconv_open("UTF-8", "ISO8859-11");
515 }
516 else if(in[0]==0x08)
517 {
518 size--; in++;
519 cd = iconv_open("UTF-8", "ISO8859-12"); //This doesn't even exist?
520 }
521 else if(in[0]==0x09)
522 {
523 size--; in++;
524 cd = iconv_open("UTF-8", "ISO8859-13");
525 }
526 else if(in[0]==0x0a)
527 {
528 size--; in++;
529 cd = iconv_open("UTF-8", "ISO8859-14");
530 }
531 else if(in[0]==0x0b)
532 {
533 size--; in++;
534 cd = iconv_open("UTF-8", "ISO8859-15"); //tested, german
535 }
536 else if(in[0]==0x10)
537 {
538 char from[14];
539 uint16_t cpn = (in[1] << 8) | in[2];
540 size-=3; in+=3;
541 snprintf(from, sizeof(from), "ISO8859-%d", cpn);
542 cd = iconv_open("UTF-8", from);
543 }
544 else if(in[0]==0x11)
545 {
546 size--; in++;
547 cd = iconv_open("UTF-8", "ISO-10646/UTF8");
548 }
549 else if(in[0]==0x12)
550 {
551 size--; in++;
552 cd = iconv_open("UTF-8", "KS_C_5601-1987");
553 }
554 else if(in[0]==0x13)
555 {
556 size--; in++;
557 cd = iconv_open("UTF-8", "GB2312");
558 }
559 else if(in[0]==0x14)
560 {
561 size--; in++;
562 cd = iconv_open("UTF-8", "BIG-5");
563 }
564 else if(in[0]==0x15)
565 {
566 size--; in++;
567 cd = iconv_open("UTF-8", "UTF-8");
568 }
569 else
570 {
571 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: EPG_DVB_decode_string(): Reserved encoding detected: %02x.\n", in[0]);
572 size--; in++;
573 cd = iconv_open("UTF-8", "ISO8859-9");
574 }
575
576 if((long)cd != -1 && !skipiconv)
577 {
578 ret = iconv(cd, (char **)&in, &size, &dp, &obl);
579 obl=decode_buffer_size-obl;
580 decode_buffer[obl]=0x00;
581 }
582 else
583 {
584 uint16_t newsize=0;
585 if(!skipiconv)
586 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: EPG_DVB_decode_string(): Failed to convert codepage.\n");
587 /*
588 http://dvbstreamer.sourcearchive.com/documentation/2.1.0-2/dvbtext_8c_source.html
589 libiconv doesn't support ISO 6937, but glibc does?!
590 so fall back to ISO8859-1 and strip out the non spacing
591 diacritical mark/graphical characters etc.
592 ALSO: http://lists.gnu.org/archive/html/bug-gnu-libiconv/2009-09/msg00000.html
593 */
594 for(x=0; x<size; x++)
595 {
596 if(in[x]<=(uint8_t)127)
597 {
598 decode_buffer[newsize]=in[x];
599 newsize++;
600 }
601 }
602 size=newsize;
603 decode_buffer[size]=0x00;
604 }
605 osize=strlen(decode_buffer);
606 out = malloc(osize+1);
607 memcpy(out, decode_buffer, osize);
608 out[osize]=0x00;
609 free(decode_buffer);
610 if (cd != (iconv_t)-1)
611 iconv_close(cd);
612 return out;
613 }
614
615 //EN 300 468 V1.3.1 (1998-02)
616 //6.2.27 Short event descriptor
EPG_decode_short_event_descriptor(uint8_t * offset,uint32_t descriptor_length,struct EPG_event * event)617 void EPG_decode_short_event_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event)
618 {
619 uint8_t text_length;
620 uint8_t event_name_length;
621 event->has_simple=true;
622 event->ISO_639_language_code[0] = offset[0];
623 event->ISO_639_language_code[1] = offset[1];
624 event->ISO_639_language_code[2] = offset[2];
625 event->ISO_639_language_code[3] = 0x00;
626
627 event_name_length = offset[3];
628 if(event_name_length+4>descriptor_length)
629 {
630 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid short_event_descriptor size detected.\n");
631 return;
632 }
633 event->event_name = EPG_DVB_decode_string(&offset[4], event_name_length);
634
635 text_length = offset[4+event_name_length];
636 if(text_length+event_name_length+4>descriptor_length)
637 {
638 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid short_event_descriptor size detected.\n");
639 return;
640 }
641 event->text = EPG_DVB_decode_string(&offset[5+event_name_length], text_length);
642
643 }
644
645 //EN 300 468 V1.3.1 (1998-02)
646 //6.2.9 Extended event descriptor
EPG_decode_extended_event_descriptor(uint8_t * offset,uint32_t descriptor_length,struct EPG_event * event)647 void EPG_decode_extended_event_descriptor(uint8_t *offset, uint32_t descriptor_length, struct EPG_event *event)
648 {
649 uint8_t descriptor_number=offset[0]>>4;
650 uint8_t last_descriptor_number=(offset[0]&0x0f);
651 uint32_t text_length;
652 uint32_t oldlen=0;
653 uint8_t length_of_items = offset[4];
654 event->extended_ISO_639_language_code[0] = offset[1];
655 event->extended_ISO_639_language_code[1] = offset[2];
656 event->extended_ISO_639_language_code[2] = offset[3];
657 event->extended_ISO_639_language_code[3] = 0x00;
658
659 offset=offset+length_of_items+5;
660 if(length_of_items>descriptor_length-5)
661 {
662 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid extended_event_descriptor size detected.\n");
663 return;
664 }
665
666 text_length = offset[0];
667 if(text_length>descriptor_length-5-length_of_items-1)
668 {
669 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid extended_event_text_length size detected.\n");
670 return;
671 }
672
673 //TODO: can this leak memory with a malformed descriptor?
674 if(descriptor_number>0) {
675 if(offset[1]<0x20) {
676 offset++;
677 text_length--;
678 }
679 uint8_t *net = malloc(strlen(event->extended_text)+text_length+1);
680 oldlen=strlen(event->extended_text);
681 memcpy(net, event->extended_text, strlen(event->extended_text));
682 free(event->extended_text);
683 event->extended_text=net;
684 }
685 else
686 event->extended_text = malloc(text_length+1);
687
688 memcpy(&event->extended_text[oldlen], &offset[1], text_length);
689
690 event->extended_text[oldlen + text_length] = '\0';
691
692 if(descriptor_number==last_descriptor_number) {
693 uint8_t *old = event->extended_text;
694 event->extended_text = EPG_DVB_decode_string(event->extended_text, strlen(event->extended_text));
695 free(old);
696 }
697
698 }
699
700 // decode an ATSC multiple_string
701 // extremely basic implementation
702 // only handles single segment, single language ANSI string!
EPG_ATSC_decode_multiple_string(uint8_t * offset,uint32_t length,struct EPG_event * event)703 void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EPG_event *event)
704 {
705 uint8_t number_strings;
706 int i, j;
707 char ISO_639_language_code[4];
708 uint8_t *offset_end = offset + length;
709 #define CHECK_OFFSET(val) if(offset + val < offset_end) return
710
711 CHECK_OFFSET(1);
712 number_strings = offset[0];
713 offset++;
714
715 for(i=0; i<number_strings; i++)
716 {
717 uint8_t number_segments;
718
719 CHECK_OFFSET(4);
720 number_segments = offset[3];
721 ISO_639_language_code[0] = offset[0];
722 ISO_639_language_code[1] = offset[1];
723 ISO_639_language_code[2] = offset[2];
724 ISO_639_language_code[3] = 0x00;
725 offset+=4;
726 for (j=0; j< number_segments; j++)
727 {
728 uint8_t compression_type;
729 uint8_t mode;
730 uint8_t number_bytes;
731 CHECK_OFFSET(3);
732 compression_type = offset[0];
733 mode = offset[1];
734 number_bytes = offset[2];
735 offset+=3;
736 if(mode==0 && compression_type==0 && j==0)
737 {
738 CHECK_OFFSET(number_bytes);
739 event->has_simple=true;
740 event->ISO_639_language_code[0]=ISO_639_language_code[0];
741 event->ISO_639_language_code[1]=ISO_639_language_code[1];
742 event->ISO_639_language_code[2]=ISO_639_language_code[2];
743 event->ISO_639_language_code[3]=0x00;
744 event->event_name = malloc(number_bytes+1);
745 memcpy(event->event_name, &offset[0], number_bytes);
746 event->event_name[number_bytes]='\0';
747 event->text = malloc(number_bytes+1);
748 memcpy(event->text, &offset[0], number_bytes);
749 event->text[number_bytes]='\0';
750 }
751 else
752 {
753 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Unsupported ATSC multiple_string encoding detected!.\n");
754 }
755 offset+=number_bytes;
756 }
757 }
758 #undef CHECK_OFFSET
759 }
760
761 // decode ATSC EIT table.
EPG_ATSC_decode_EIT(struct lib_ccx_ctx * ctx,uint8_t * payload_start,uint32_t size)762 void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
763 {
764 uint8_t table_id;
765 struct EPG_event event;
766 uint8_t num_events_in_section;
767 uint8_t *offset;
768 int hasnew=false;
769 int i, j;
770 uint16_t source_id;
771 int32_t pmt_map = -1;
772
773 if (size < 11)
774 return;
775
776 table_id = payload_start[0];
777 source_id = ((payload_start[3]) << 8) | payload_start[4];
778
779 event.has_simple=false;
780 event.extended_text=NULL;
781 event.num_ratings=0;
782 event.num_categories=0;
783 event.live_output=false;
784 for (i = 0; i < ctx->demux_ctx->nb_program; i++)
785 {
786 if (ctx->demux_ctx->pinfo[i].program_number == ctx->ATSC_source_pg_map[source_id])
787 pmt_map=i;
788 }
789
790 //Don't know how to store EPG until we know the programs. Ignore it.
791 if(pmt_map==-1)
792 pmt_map=TS_PMT_MAP_SIZE;
793
794 num_events_in_section = payload_start[9];
795
796 #define CHECK_OFFSET(val) if(offset + val < (payload_start + size) ) return
797 offset=&payload_start[10];
798
799 for(j = 0; j < num_events_in_section && offset < payload_start + size; j++)
800 {
801 uint16_t descriptors_loop_length;
802 uint8_t title_length, emt_location;
803 uint32_t length_in_seconds, start_time, full_id;
804 uint16_t event_id;
805
806 CHECK_OFFSET(10);
807
808 event_id = ((offset[0]&0x3F) << 8) | offset[1];
809 full_id = (source_id << 16) | event_id;
810 event.id=full_id;
811 event.service_id=source_id;
812 start_time = (offset[2] << 24) | (offset[3] << 16) | (offset[4] << 8)| (offset[5] << 0);
813 EPG_ATSC_calc_time(event.start_time_string, start_time);
814 emt_location = (offset[6]&0x30)>>4;
815 length_in_seconds = (((offset[6]&0x0F) << 16) | (offset[7] << 8) | (offset[8] << 0));
816 EPG_ATSC_calc_time(event.end_time_string, start_time+length_in_seconds);
817
818 title_length = offset[9];
819 //XXX cant decode data more then size of payload
820 CHECK_OFFSET(11 + title_length);
821
822 EPG_ATSC_decode_multiple_string(&offset[10], title_length, &event);
823
824 descriptors_loop_length = ((offset[10+title_length] & 0x0f) << 8) | offset[10+title_length+1];
825
826 hasnew |= EPG_add_event(ctx, pmt_map, &event);
827 offset += 12 + descriptors_loop_length + title_length;
828 }
829 if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
830 EPG_output(ctx);
831 #undef CHECK_OFFSET
832 }
833
834 // decode ATSC VCT table.
EPG_ATSC_decode_VCT(struct lib_ccx_ctx * ctx,uint8_t * payload_start,uint32_t size)835 void EPG_ATSC_decode_VCT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
836 {
837 uint8_t table_id;
838 uint8_t num_channels_in_section;
839 uint8_t *offset;
840 int i;
841
842 if (size <= 10)
843 return;
844
845 table_id = payload_start[0];
846 num_channels_in_section = payload_start[9];
847 offset = &payload_start[10];
848
849 for (i=0; i< num_channels_in_section; i++)
850 {
851 char short_name[7*2];
852 uint16_t program_number;
853 uint16_t source_id;
854 uint16_t descriptors_loop_length;
855
856 if(offset + 31 > payload_start+size)
857 break;
858
859 program_number = offset[24]<<8 | offset[25];
860 source_id = offset[28]<<8 | offset[29];
861 descriptors_loop_length = ((offset[30] & 0x03) << 8) | offset[31];
862
863 memcpy(short_name, &offset[0], 7*2);
864 offset += 32 + descriptors_loop_length;
865 ctx->ATSC_source_pg_map[source_id]=program_number;
866 }
867 }
868
869
EPG_DVB_decode_EIT(struct lib_ccx_ctx * ctx,uint8_t * payload_start,uint32_t size)870 void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
871 {
872
873 uint8_t table_id;
874 //uint8_t section_syntax_indicator = (0xf1&0x80)>>7;
875 uint16_t section_length;
876 uint16_t service_id;
877 int32_t pmt_map = -1;
878 int i;
879 int hasnew = false;
880 struct EPG_event event;
881 uint8_t section_number;
882 uint8_t last_section_number;
883 uint8_t segment_last_section_number;
884 uint32_t events_length;
885 uint8_t *offset;
886 uint32_t remaining;
887
888
889 if(size < 13)
890 return;
891
892 table_id = payload_start[0];
893 //section_syntax_indicator = (0xf1&0x80)>>7;
894 section_length = (payload_start[1]&0x0F)<<8 | payload_start[2];
895 service_id = (payload_start[3] << 8) | payload_start[4];
896 section_number = payload_start[6];
897 last_section_number = payload_start[7];
898 segment_last_section_number = payload_start[12];
899 events_length = section_length - 11;
900 offset = payload_start;
901 remaining = events_length;
902
903 for (i = 0; i < ctx->demux_ctx->nb_program; i++)
904 {
905 if (ctx->demux_ctx->pinfo[i].program_number == service_id)
906 pmt_map = i;
907 }
908
909 //For any service we don't have an PMT for (yet), store it in the special last array pos.
910 if(pmt_map == -1)
911 pmt_map = TS_PMT_MAP_SIZE;
912
913 if(events_length > size-14)
914 {
915 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n");
916 //XXX hack to override segfault, we should concat packets instead
917 return;
918 }
919
920 while(remaining > 4)
921 {
922 uint16_t descriptors_loop_length;
923 uint8_t *descp;
924 uint32_t duration;
925 uint64_t start_time;
926 event.id = (offset[14] << 8) | offset[15];
927 event.has_simple = false;
928 event.extended_text = NULL;
929 event.num_ratings = 0;
930 event.num_categories = 0;
931 event.live_output = false;
932 event.service_id = service_id;
933
934 //40 bits
935 start_time = ((uint64_t)offset[16] << 32) | ((uint64_t)offset[17] << 24) | ((uint64_t)offset[18] << 16) | ((uint64_t)offset[19] << 8)| ((uint64_t)offset[20] << 0);
936 EPG_DVB_calc_start_time(&event, start_time);
937 //24 bits
938 duration = (offset[21] << 16 ) | (offset[22] << 8 ) | (offset[23] << 0 );
939 EPG_DVB_calc_end_time(&event, start_time, duration);
940 event.running_status = (offset[24] & 0xE0) >> 5;
941 event.free_ca_mode = (offset[24] & 0x10) >> 4;
942 //12 bits
943 descriptors_loop_length = ((offset[24] & 0x0f) << 8) | offset[25];
944 descp = &offset[26];
945 if(descriptors_loop_length > remaining-16)
946 {
947 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptors_loop_length detected.\n");
948 return;
949 }
950 while(descp<&(offset[26])+descriptors_loop_length)
951 {
952 if(descp+descp[1]+2>payload_start+size) {
953 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptor_loop_length detected.\n");
954 EPG_free_event(&event);
955 return;
956 }
957 if(descp[0]==0x4d)
958 EPG_decode_short_event_descriptor(descp+2, descp[1], &event);
959 if(descp[0]==0x4e)
960 EPG_decode_extended_event_descriptor(descp+2, descp[1], &event);
961 if(descp[0]==0x54)
962 EPG_decode_content_descriptor(descp+2, descp[1], &event);
963 if(descp[0]==0x55)
964 EPG_decode_parental_rating_descriptor(descp+2, descp[1], &event);
965 if(descp[1]+2==0)
966 {
967 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT descriptor_length detected.\n");
968 return;
969 }
970 descp=descp+(descp[1]+2);
971 }
972 remaining = remaining - (descriptors_loop_length + 12);
973 offset = offset + descriptors_loop_length + 12;
974 hasnew |= EPG_add_event(ctx, pmt_map, &event);
975
976 if(hasnew && section_number==0 && table_id==0x4e)
977 ctx->eit_current_events[pmt_map]=event.id;
978 }
979
980 if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
981 EPG_output(ctx);
982 }
983 //handle outputing to xml files
EPG_handle_output(struct lib_ccx_ctx * ctx)984 void EPG_handle_output(struct lib_ccx_ctx *ctx)
985 {
986 int cur_sec = (int) ((ctx->demux_ctx->global_timestamp - ctx->demux_ctx->min_global_timestamp) / 1000);
987 if(ccx_options.xmltv==1 || ccx_options.xmltv==3)
988 { //full outout
989 if(ccx_options.xmltvoutputinterval!=0 && cur_sec>ctx->epg_last_output+ccx_options.xmltvliveinterval)
990 {
991 ctx->epg_last_output=cur_sec;
992 EPG_output(ctx);
993 }
994 }
995 if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
996 { //live output
997 if(cur_sec>ctx->epg_last_live_output+ccx_options.xmltvliveinterval)
998 {
999 ctx->epg_last_live_output=cur_sec;
1000 if (ccx_options.send_to_srv)
1001 EPG_output_net(ctx);
1002 else
1003 EPG_output_live(ctx);
1004 }
1005 }
1006 }
1007
1008 //determine table type and call the correct function to handle it
EPG_parse_table(struct lib_ccx_ctx * ctx,uint8_t * b,uint32_t size)1009 void EPG_parse_table(struct lib_ccx_ctx *ctx, uint8_t *b, uint32_t size)
1010 {
1011 uint8_t pointer_field = b[0];
1012 uint8_t *payload_start;
1013 uint8_t table_id;
1014
1015 //XXX hack, should accumulate data
1016 if(pointer_field + 2 > size) {
1017 return;
1018 }
1019 payload_start = &b[pointer_field + 1];
1020 table_id = payload_start[0];
1021 switch (table_id) {
1022 case 0x0cb:
1023 EPG_ATSC_decode_EIT(ctx, payload_start, size - (payload_start - b));
1024 break;
1025 case 0xc8:
1026 EPG_ATSC_decode_VCT(ctx, payload_start, size - (payload_start - b));
1027 break;
1028 default:
1029 if (table_id>=0x4e && table_id<=0x6f)
1030 EPG_DVB_decode_EIT(ctx, payload_start, size - (payload_start - b));
1031 break;
1032 }
1033 EPG_handle_output(ctx);
1034 }
1035
1036 // reconstructs DVB EIT and ATSC tables
parse_EPG_packet(struct lib_ccx_ctx * ctx)1037 void parse_EPG_packet(struct lib_ccx_ctx *ctx)
1038 {
1039 unsigned char *payload_start = tspacket + 4;
1040 unsigned payload_length = 188 - 4;
1041 unsigned transport_error_indicator = (tspacket[1]&0x80)>>7;
1042 unsigned payload_start_indicator = (tspacket[1]&0x40)>>6;
1043 // unsigned transport_priority = (tspacket[1]&0x20)>>5;
1044 unsigned pid = (((tspacket[1] & 0x1F) << 8) | tspacket[2]) & 0x1FFF;
1045 // unsigned transport_scrambling_control = (tspacket[3]&0xC0)>>6;
1046 unsigned adaptation_field_control = (tspacket[3]&0x30)>>4;
1047 unsigned ccounter = tspacket[3] & 0xF;
1048 unsigned adaptation_field_length = 0;
1049 int buffer_map = 0xfff;
1050 if ( adaptation_field_control & 2 )
1051 {
1052 adaptation_field_length = tspacket[4];
1053 payload_start = payload_start + adaptation_field_length + 1;
1054 payload_length = tspacket+188-payload_start;
1055 }
1056
1057 if((pid!=0x12 && pid!=0x1ffb && pid<0x1000) || pid==0x1fff)
1058 return;
1059
1060 if(pid!=0x12)
1061 buffer_map = pid-0x1000;
1062
1063 if(payload_start_indicator)
1064 {
1065 if(ctx->epg_buffers[buffer_map].ccounter>0) {
1066 ctx->epg_buffers[buffer_map].ccounter=0;
1067 EPG_parse_table(ctx, ctx->epg_buffers[buffer_map].buffer, ctx->epg_buffers[buffer_map].buffer_length);
1068 }
1069
1070
1071 ctx->epg_buffers[buffer_map].prev_ccounter = ccounter;
1072
1073 if(ctx->epg_buffers[buffer_map].buffer!=NULL)
1074 free(ctx->epg_buffers[buffer_map].buffer);
1075 else {
1076 // must be first EIT packet
1077 }
1078 ctx->epg_buffers[buffer_map].buffer = (uint8_t *)malloc(payload_length);
1079 memcpy(ctx->epg_buffers[buffer_map].buffer, payload_start, payload_length);
1080 ctx->epg_buffers[buffer_map].buffer_length=payload_length;
1081 ctx->epg_buffers[buffer_map].ccounter++;
1082
1083 }
1084 else if(ccounter==ctx->epg_buffers[buffer_map].prev_ccounter+1 || (ctx->epg_buffers[buffer_map].prev_ccounter==0x0f && ccounter==0))
1085 {
1086 ctx->epg_buffers[buffer_map].prev_ccounter = ccounter;
1087 ctx->epg_buffers[buffer_map].buffer = (uint8_t *)realloc(ctx->epg_buffers[buffer_map].buffer, ctx->epg_buffers[buffer_map].buffer_length+payload_length);
1088 memcpy(ctx->epg_buffers[buffer_map].buffer+ctx->epg_buffers[buffer_map].buffer_length, payload_start, payload_length);
1089 ctx->epg_buffers[buffer_map].ccounter++;
1090 ctx->epg_buffers[buffer_map].buffer_length+=payload_length;
1091 }
1092 else
1093 {
1094 dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Out of order EPG packets detected.\n");
1095 }
1096 }
1097
1098 // Free all memory used for EPG parsing
EPG_free(struct lib_ccx_ctx * ctx)1099 void EPG_free(struct lib_ccx_ctx *ctx)
1100 {
1101 if(ctx->epg_inited)
1102 {
1103 if(ccx_options.xmltv==2 || ccx_options.xmltv==3 || ccx_options.send_to_srv)
1104 {
1105 if (ccx_options.send_to_srv)
1106 EPG_output_net(ctx);
1107 else
1108 EPG_output_live(ctx);
1109 }
1110 }
1111 free(ctx->epg_buffers);
1112 free(ctx->eit_programs);
1113 free(ctx->eit_current_events);
1114 free(ctx->ATSC_source_pg_map);
1115 }
1116