2019-01-25 15:58:24 +00:00
|
|
|
/*
|
|
|
|
* Humax EPG Tool
|
|
|
|
* by af123, 2011
|
|
|
|
*/
|
|
|
|
|
2011-06-01 23:34:35 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <strings.h>
|
|
|
|
|
|
|
|
#include "lint.h"
|
|
|
|
|
2011-06-02 11:14:43 +00:00
|
|
|
struct section *
|
|
|
|
read_section(struct epg *epg)
|
2011-06-01 23:34:35 +00:00
|
|
|
{
|
2011-06-02 11:14:43 +00:00
|
|
|
static struct section h;
|
2011-06-01 23:34:35 +00:00
|
|
|
|
|
|
|
if (epg->binsize - epg->offset < sizeof(h))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(&h, epg->bin + epg->offset, sizeof(h));
|
2011-06-02 11:14:43 +00:00
|
|
|
if (memcmp(h.magic, SECTION_MAGIC, sizeof(h.magic)))
|
2011-06-01 23:34:35 +00:00
|
|
|
{
|
|
|
|
printf("Section header magic mismatch.\n");
|
2011-06-03 10:27:40 +00:00
|
|
|
hexdump(epg->bin + epg->offset, 64, 0);
|
2011-06-01 23:34:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-02 01:32:55 +00:00
|
|
|
h.total_length = _swap16(h.total_length);
|
|
|
|
h.service_id = _swap16(h.service_id);
|
|
|
|
h.transport_stream_id = _swap16(h.transport_stream_id);
|
|
|
|
h.original_network_id = _swap16(h.original_network_id);
|
|
|
|
|
|
|
|
h.u1.comp = _swap16(h.u1.comp);
|
|
|
|
|
2011-06-01 23:34:35 +00:00
|
|
|
epg->offset += sizeof(h);
|
|
|
|
|
|
|
|
return &h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-06-02 11:14:43 +00:00
|
|
|
dump_section(struct section *h)
|
2011-06-01 23:34:35 +00:00
|
|
|
{
|
|
|
|
printf("Section header:\n");
|
|
|
|
DUMPINT(h, total_length);
|
|
|
|
DUMPINT(h, table_id);
|
2011-06-02 01:32:55 +00:00
|
|
|
DUMPINT(h, u1.u.syntax_indicator);
|
|
|
|
DUMPINT(h, u1.u.reserved);
|
|
|
|
DUMPINT(h, u1.u.length);
|
2011-06-01 23:34:35 +00:00
|
|
|
DUMPINT(h, service_id);
|
|
|
|
DUMPINT(h, reserved2);
|
|
|
|
DUMPINT(h, version_number);
|
|
|
|
DUMPINT(h, current_next_indicator);
|
|
|
|
DUMPINT(h, section_number);
|
|
|
|
DUMPINT(h, last_section_number);
|
|
|
|
DUMPINT(h, transport_stream_id);
|
|
|
|
DUMPINT(h, original_network_id);
|
|
|
|
DUMPINT(h, segment_last_section_number);
|
|
|
|
DUMPINT(h, last_table_id);
|
|
|
|
}
|
|
|
|
|
2011-06-02 11:14:43 +00:00
|
|
|
struct data *
|
|
|
|
read_data(struct epg *epg)
|
|
|
|
{
|
|
|
|
static struct data d;
|
|
|
|
|
|
|
|
if (epg->binsize - epg->offset < sizeof(d))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(&d, epg->bin + epg->offset, sizeof(d));
|
|
|
|
|
|
|
|
d.event_id = _swap16(d.event_id);
|
|
|
|
d.start_date = _swap16(d.start_date);
|
|
|
|
d.u1.comp = _swap16(d.u1.comp);
|
|
|
|
|
2011-06-02 23:51:14 +00:00
|
|
|
d.start_hour = bcd(d.start_hour);
|
|
|
|
d.start_min = bcd(d.start_min);
|
|
|
|
d.start_sec = bcd(d.start_sec);
|
|
|
|
|
|
|
|
d.dur_hour = bcd(d.dur_hour);
|
|
|
|
d.dur_min = bcd(d.dur_min);
|
|
|
|
d.dur_sec = bcd(d.dur_sec);
|
|
|
|
|
2011-06-02 11:14:43 +00:00
|
|
|
epg->offset += sizeof(d);
|
|
|
|
|
|
|
|
return &d;
|
|
|
|
}
|
|
|
|
|
2011-06-01 23:34:35 +00:00
|
|
|
void
|
|
|
|
dump_data(struct data *d)
|
|
|
|
{
|
|
|
|
time_t tm;
|
|
|
|
|
|
|
|
printf("Data:\n");
|
|
|
|
DUMPINT(d, event_id);
|
|
|
|
|
2011-06-02 23:51:14 +00:00
|
|
|
tm = mjd(d->start_date, d->start_hour, d->start_min, d->start_sec);
|
2011-06-04 21:45:40 +00:00
|
|
|
printf(" %30s: %#x %d:%02d:%02d (%s) [%ld]\n", "start_date",
|
2011-06-02 23:51:14 +00:00
|
|
|
d->start_date, d->start_hour, d->start_min, d->start_sec,
|
2011-06-04 21:45:40 +00:00
|
|
|
ctime_nl(&tm), tm);
|
2011-06-02 01:32:55 +00:00
|
|
|
|
|
|
|
printf(" %30s: %d:%02d:%02d\n", "duration",
|
|
|
|
d->dur_hour, d->dur_min, d->dur_sec);
|
|
|
|
|
|
|
|
DUMPINT(d, u1.u.running_status);
|
|
|
|
DUMPINT(d, u1.u.free_CA_mode);
|
|
|
|
DUMPINT(d, u1.u.descriptors_loop_length);
|
|
|
|
}
|
2011-06-01 23:34:35 +00:00
|
|
|
|
2011-09-29 18:23:24 +00:00
|
|
|
static inline int
|
|
|
|
check_filter_timerange(struct epgfilter *f, enum epgfiltertype type,
|
|
|
|
unsigned long idl, unsigned long idh)
|
|
|
|
{
|
|
|
|
if (!f)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (; f; f = f->next)
|
|
|
|
{
|
|
|
|
if (f->type != type)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(
|
|
|
|
(idl > f->num && idl < f->num2) ||
|
|
|
|
(idh > f->num && idh < f->num2) ||
|
|
|
|
(idl < f->num && idh > f->num))
|
|
|
|
)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-06-04 21:45:40 +00:00
|
|
|
static inline int
|
|
|
|
check_filter_range(struct epgfilter *f, enum epgfiltertype type,
|
|
|
|
unsigned long idl, unsigned long idh)
|
|
|
|
{
|
|
|
|
if (!f)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (; f; f = f->next)
|
|
|
|
{
|
2011-08-25 19:51:00 +00:00
|
|
|
if (f->type != type)
|
|
|
|
continue;
|
|
|
|
if (f->match == FT_RANGE)
|
|
|
|
{
|
|
|
|
if (idl < f->num || idl > f->num2)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (f->num < idl || f->num > idh)
|
2011-06-04 21:45:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-06-03 10:27:40 +00:00
|
|
|
static inline int
|
|
|
|
check_filter(struct epgfilter *f, enum epgfiltertype type,
|
2011-06-06 11:58:16 +00:00
|
|
|
unsigned long id, char *str)
|
2011-06-03 10:27:40 +00:00
|
|
|
{
|
|
|
|
if (!f)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (; f; f = f->next)
|
2011-06-04 21:45:40 +00:00
|
|
|
{
|
2011-06-06 11:58:16 +00:00
|
|
|
if (f->type == type)
|
|
|
|
{
|
2011-06-08 20:56:01 +00:00
|
|
|
if (type == FILTER_CRID || type == FILTER_SCRID)
|
2011-06-06 11:58:16 +00:00
|
|
|
{
|
|
|
|
if (strcmp(str, f->str))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (f->num != id)
|
|
|
|
return 0;
|
|
|
|
}
|
2011-06-04 21:45:40 +00:00
|
|
|
}
|
2011-06-03 10:27:40 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-06-02 23:51:14 +00:00
|
|
|
void
|
|
|
|
parse(char *epgpath,
|
|
|
|
void (*callback)(struct epg *, struct section *, struct data *,
|
2011-06-03 10:27:40 +00:00
|
|
|
struct descriptor **, void *), void *val, struct epgfilter *filter)
|
2011-06-02 23:51:14 +00:00
|
|
|
{
|
2011-06-06 13:48:49 +00:00
|
|
|
struct descriptor *dslist[PARSER_MAX];
|
2011-06-02 23:51:14 +00:00
|
|
|
struct epg *epg;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!(epg = open_file(epgpath)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (epg->offset < epg->binsize)
|
|
|
|
{
|
|
|
|
struct section *s;
|
|
|
|
uint32_t send;
|
|
|
|
|
|
|
|
if (!(s = read_section(epg)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
send = epg->offset - 11 + s->u1.u.length - 4;
|
|
|
|
|
2011-06-08 20:56:01 +00:00
|
|
|
if ((filterflags & FILTER_SERVICE) &&
|
|
|
|
!check_filter(filter, FILTER_SERVICE, s->service_id, NULL))
|
2011-06-03 10:27:40 +00:00
|
|
|
{
|
|
|
|
/* Skip this service. */
|
|
|
|
epg->offset += s->total_length - 14;
|
|
|
|
/* Skip padding bytes... */
|
|
|
|
while (epg->bin[epg->offset] == 'U')
|
|
|
|
epg->offset++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-06-02 23:51:14 +00:00
|
|
|
while (epg->offset < send)
|
|
|
|
{
|
|
|
|
struct data *d;
|
2011-06-06 12:14:05 +00:00
|
|
|
uint32_t dstart, dend;
|
|
|
|
|
|
|
|
dstart = epg->offset;
|
2011-06-02 23:51:14 +00:00
|
|
|
|
|
|
|
if (!(d = read_data(epg)))
|
|
|
|
break;
|
|
|
|
|
2011-06-03 10:27:40 +00:00
|
|
|
dend = epg->offset + d->u1.u.descriptors_loop_length;
|
|
|
|
|
2011-06-08 20:56:01 +00:00
|
|
|
if ((filterflags & FILTER_EVENT) &&
|
|
|
|
!check_filter(filter, FILTER_EVENT, d->event_id,
|
2011-06-03 10:27:40 +00:00
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
/* Skip this event. */
|
|
|
|
epg->offset = dend;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-09-29 18:23:24 +00:00
|
|
|
if ((filterflags &
|
|
|
|
(FILTER_TIMESTAMP | FILTER_TIMERANGE)))
|
2011-06-04 21:45:40 +00:00
|
|
|
{
|
|
|
|
time_t tm;
|
|
|
|
int dur;
|
|
|
|
|
|
|
|
tm = mjd(d->start_date, d->start_hour,
|
|
|
|
d->start_min, d->start_sec);
|
|
|
|
|
|
|
|
dur = d->dur_hour * 3600 + d->dur_min * 60 +
|
|
|
|
d->dur_sec;
|
|
|
|
|
2011-09-29 18:23:24 +00:00
|
|
|
if ((filterflags & FILTER_TIMESTAMP))
|
2011-06-04 21:45:40 +00:00
|
|
|
{
|
2011-09-29 18:23:24 +00:00
|
|
|
if (!check_filter_range(filter,
|
|
|
|
FILTER_TIMESTAMP, tm, tm + dur))
|
|
|
|
{
|
|
|
|
/* Skip this event. */
|
|
|
|
epg->offset = dend;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((filterflags & FILTER_TIMERANGE))
|
|
|
|
{
|
|
|
|
if (!check_filter_timerange(filter,
|
|
|
|
FILTER_TIMERANGE, tm, tm + dur))
|
|
|
|
{
|
|
|
|
/* Skip this event. */
|
|
|
|
epg->offset = dend;
|
|
|
|
continue;
|
|
|
|
}
|
2011-06-04 21:45:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-06 12:14:05 +00:00
|
|
|
if (debug)
|
|
|
|
hexdump(epg->bin + dstart, dend - dstart,
|
|
|
|
dstart);
|
|
|
|
|
2011-06-06 13:48:49 +00:00
|
|
|
for (i = 0; i < PARSER_MAX; i++)
|
2011-06-06 11:58:16 +00:00
|
|
|
dslist[i] = NULL;
|
2011-06-02 23:51:14 +00:00
|
|
|
|
|
|
|
while (epg->offset < dend)
|
|
|
|
{
|
2011-06-08 20:56:01 +00:00
|
|
|
unsigned int dstag = epg->bin[epg->offset];
|
|
|
|
unsigned int dslen = epg->bin[epg->offset + 1];
|
2011-06-02 23:51:14 +00:00
|
|
|
struct descriptor *ds;
|
|
|
|
|
2011-06-08 20:56:01 +00:00
|
|
|
if ((filterflags & FILTER_DESCRIPTOR) &&
|
|
|
|
!check_filter(filter, FILTER_DESCRIPTOR,
|
|
|
|
dstag, NULL))
|
2011-06-03 10:27:40 +00:00
|
|
|
{
|
2011-06-08 20:56:01 +00:00
|
|
|
epg->offset += dslen + 2;
|
2011-06-03 10:27:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-06-08 20:56:01 +00:00
|
|
|
switch (dstag)
|
2011-06-02 23:51:14 +00:00
|
|
|
{
|
|
|
|
case DS_SHORT_EVENT:
|
2011-06-08 20:56:01 +00:00
|
|
|
if (!(ds = read_descriptor_header(epg)))
|
|
|
|
break;
|
2011-06-02 23:51:14 +00:00
|
|
|
read_descriptor(epg, ds);
|
|
|
|
dslist[PARSER_SHORT_EVENT] = ds;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DS_CONTENT_IDENTIFIER:
|
2011-06-08 20:56:01 +00:00
|
|
|
if (!(ds = read_descriptor_header(epg)))
|
|
|
|
break;
|
2011-06-02 23:51:14 +00:00
|
|
|
read_descriptor(epg, ds);
|
2011-06-06 11:58:16 +00:00
|
|
|
switch (ds->content.d118.crids[0].type)
|
|
|
|
{
|
|
|
|
case CRIDT_EVENT:
|
|
|
|
dslist[PARSER_CRID_EVENT] = ds;
|
|
|
|
break;
|
|
|
|
case CRIDT_SERIES:
|
|
|
|
dslist[PARSER_CRID_SERIES] = ds;
|
|
|
|
break;
|
|
|
|
case CRIDT_REC:
|
|
|
|
dslist[PARSER_CRID_REC] = ds;
|
|
|
|
break;
|
|
|
|
}
|
2011-06-02 23:51:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DS_USER_DEFINED:
|
2011-06-08 20:56:01 +00:00
|
|
|
if (!(ds = read_descriptor_header(epg)))
|
|
|
|
break;
|
2011-06-02 23:51:14 +00:00
|
|
|
read_descriptor(epg, ds);
|
|
|
|
dslist[PARSER_USER_DEFINED] = ds;
|
|
|
|
break;
|
|
|
|
|
2011-06-06 13:48:49 +00:00
|
|
|
case DS_CONTENT:
|
2011-06-08 20:56:01 +00:00
|
|
|
if (!(ds = read_descriptor_header(epg)))
|
|
|
|
break;
|
2011-06-06 13:48:49 +00:00
|
|
|
read_descriptor(epg, ds);
|
|
|
|
dslist[PARSER_CONTENT] = ds;
|
|
|
|
break;
|
|
|
|
|
2011-06-06 14:43:58 +00:00
|
|
|
/*
|
|
|
|
case DS_FTA_CONTENT_MGMT:
|
|
|
|
read_descriptor(epg, ds);
|
|
|
|
dump_descriptor(ds, 1);
|
|
|
|
free_descriptor(ds);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DS_LINKAGE:
|
|
|
|
read_descriptor(epg, ds);
|
|
|
|
dump_descriptor(ds, 1);
|
|
|
|
free_descriptor(ds);
|
|
|
|
break;
|
|
|
|
*/
|
|
|
|
|
2011-06-02 23:51:14 +00:00
|
|
|
default:
|
2011-06-08 20:56:01 +00:00
|
|
|
epg->offset += dslen + 2;
|
2011-06-02 23:51:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-06 13:56:53 +00:00
|
|
|
if (
|
|
|
|
(
|
2011-06-08 20:56:01 +00:00
|
|
|
!(filterflags & FILTER_CRID) ||
|
2011-06-06 13:56:53 +00:00
|
|
|
(dslist[PARSER_CRID_EVENT] &&
|
|
|
|
check_filter(filter, FILTER_CRID, 0,
|
|
|
|
dslist[PARSER_CRID_EVENT]->content.d118.
|
|
|
|
crids[0].crid))
|
2011-06-06 14:11:09 +00:00
|
|
|
) && (
|
2011-06-08 20:56:01 +00:00
|
|
|
!(filterflags & FILTER_SCRID) ||
|
|
|
|
(dslist[PARSER_CRID_SERIES] &&
|
|
|
|
check_filter(filter, FILTER_SCRID, 0,
|
|
|
|
dslist[PARSER_CRID_SERIES]->content.d118.
|
|
|
|
crids[0].crid))
|
|
|
|
) && (
|
|
|
|
!(filterflags & FILTER_CONTENT) ||
|
2011-06-06 13:56:53 +00:00
|
|
|
(dslist[PARSER_CONTENT] &&
|
|
|
|
check_filter(filter, FILTER_CONTENT,
|
|
|
|
dslist[PARSER_CONTENT]->content.d84.level1,
|
|
|
|
NULL))
|
|
|
|
)
|
|
|
|
)
|
2011-06-06 11:58:16 +00:00
|
|
|
callback(epg, s, d, dslist, val);
|
2011-06-02 23:51:14 +00:00
|
|
|
|
2011-06-06 13:48:49 +00:00
|
|
|
for (i = 0; i < PARSER_MAX; i++)
|
2011-06-02 23:51:14 +00:00
|
|
|
if (dslist[i])
|
|
|
|
free_descriptor(dslist[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip CRC */
|
|
|
|
epg->offset += 4;
|
|
|
|
|
|
|
|
/* Skip padding bytes... */
|
2011-09-01 14:39:56 +00:00
|
|
|
while (epg->offset < epg->binsize &&
|
|
|
|
epg->bin[epg->offset] == 'U')
|
2011-06-02 23:51:14 +00:00
|
|
|
epg->offset++;
|
|
|
|
}
|
|
|
|
|
|
|
|
close_file(epg);
|
|
|
|
}
|
|
|
|
|
2011-06-03 10:27:40 +00:00
|
|
|
void
|
|
|
|
add_epgfilter(struct epgfilter **filter, enum epgfiltertype type,
|
2011-06-04 21:45:40 +00:00
|
|
|
unsigned long num, unsigned long num2, char *str, enum matchtype match)
|
2011-06-03 10:27:40 +00:00
|
|
|
{
|
|
|
|
struct epgfilter *f = malloc(sizeof(struct epgfilter));
|
|
|
|
|
|
|
|
f->type = type;
|
|
|
|
f->num = num;
|
2011-06-04 21:45:40 +00:00
|
|
|
f->num2 = num2;
|
2011-06-03 10:27:40 +00:00
|
|
|
f->str = str;
|
2011-06-04 21:45:40 +00:00
|
|
|
f->match = match;
|
|
|
|
|
2011-06-08 20:56:01 +00:00
|
|
|
filterflags |= type;
|
|
|
|
|
2011-06-03 10:27:40 +00:00
|
|
|
f->next = *filter;
|
|
|
|
*filter = f;
|
|
|
|
}
|
|
|
|
|