1 /*
2 * Copyright (c) 2012-2014 - Andre Roth <neolynx@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17 *
18 */
19
20 #include <libdvbv5/eit.h>
21 #include <libdvbv5/descriptors.h>
22 #include <libdvbv5/dvb-fe.h>
23
24 #if __GNUC__ >= 9
25 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
26 #endif
27
dvb_table_eit_init(struct dvb_v5_fe_parms * parms,const uint8_t * buf,ssize_t buflen,struct dvb_table_eit ** table)28 ssize_t dvb_table_eit_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
29 ssize_t buflen, struct dvb_table_eit **table)
30 {
31 const uint8_t *p = buf, *endbuf = buf + buflen;
32 struct dvb_table_eit *eit;
33 struct dvb_table_eit_event **head;
34 size_t size;
35
36 size = offsetof(struct dvb_table_eit, event);
37 if (p + size > endbuf) {
38 dvb_logerr("%s: short read %zd/%zd bytes", __func__,
39 endbuf - p, size);
40 return -1;
41 }
42
43 if ((buf[0] != DVB_TABLE_EIT && buf[0] != DVB_TABLE_EIT_OTHER) &&
44 !(buf[0] >= DVB_TABLE_EIT_SCHEDULE && buf[0] <= DVB_TABLE_EIT_SCHEDULE + 0xF) &&
45 !(buf[0] >= DVB_TABLE_EIT_SCHEDULE_OTHER && buf[0] <= DVB_TABLE_EIT_SCHEDULE_OTHER + 0xF)) {
46 dvb_logerr("%s: invalid marker 0x%02x, should be 0x%02x, 0x%02x or between 0x%02x and 0x%02x or 0x%02x and 0x%02x",
47 __func__, buf[0], DVB_TABLE_EIT, DVB_TABLE_EIT_OTHER,
48 DVB_TABLE_EIT_SCHEDULE, DVB_TABLE_EIT_SCHEDULE + 0xF,
49 DVB_TABLE_EIT_SCHEDULE_OTHER, DVB_TABLE_EIT_SCHEDULE_OTHER + 0xF);
50 return -2;
51 }
52
53 if (!*table) {
54 *table = calloc(sizeof(struct dvb_table_eit), 1);
55 if (!*table) {
56 dvb_logerr("%s: out of memory", __func__);
57 return -3;
58 }
59 }
60 eit = *table;
61 memcpy(eit, p, size);
62 p += size;
63 dvb_table_header_init(&eit->header);
64
65 bswap16(eit->transport_id);
66 bswap16(eit->network_id);
67
68 /* find end of curent list */
69 head = &eit->event;
70 while (*head != NULL)
71 head = &(*head)->next;
72
73 /* get the event entries */
74 size = offsetof(struct dvb_table_eit_event, descriptor);
75 while (p + size <= endbuf) {
76 struct dvb_table_eit_event *event;
77
78 event = malloc(sizeof(struct dvb_table_eit_event));
79 if (!event) {
80 dvb_logerr("%s: out of memory", __func__);
81 return -4;
82 }
83 memcpy(event, p, size);
84 p += size;
85
86 bswap16(event->event_id);
87 bswap16(event->bitfield1);
88 bswap16(event->bitfield2);
89 event->descriptor = NULL;
90 event->next = NULL;
91 dvb_time(event->dvbstart, &event->start);
92 event->duration = dvb_bcd((uint32_t) event->dvbduration[0]) * 3600 +
93 dvb_bcd((uint32_t) event->dvbduration[1]) * 60 +
94 dvb_bcd((uint32_t) event->dvbduration[2]);
95
96 event->service_id = eit->header.id;
97
98 *head = event;
99 head = &(*head)->next;
100
101 /* parse the descriptors */
102 if (event->desc_length > 0) {
103 uint16_t desc_length = event->desc_length;
104 if (p + desc_length > endbuf) {
105 dvb_logwarn("%s: descriptors short read %zd/%d bytes", __func__,
106 endbuf - p, desc_length);
107 desc_length = endbuf - p;
108 }
109 if (dvb_desc_parse(parms, p, desc_length,
110 &event->descriptor) != 0) {
111 return -5;
112 }
113 p += desc_length;
114 }
115 }
116 if (p < endbuf)
117 dvb_logwarn("%s: %zu spurious bytes at the end",
118 __func__, endbuf - p);
119 return p - buf;
120 }
121
dvb_table_eit_free(struct dvb_table_eit * eit)122 void dvb_table_eit_free(struct dvb_table_eit *eit)
123 {
124 struct dvb_table_eit_event *event = eit->event;
125 while (event) {
126 dvb_desc_free((struct dvb_desc **) &event->descriptor);
127 struct dvb_table_eit_event *tmp = event;
128 event = event->next;
129 free(tmp);
130 }
131 free(eit);
132 }
133
dvb_table_eit_print(struct dvb_v5_fe_parms * parms,struct dvb_table_eit * eit)134 void dvb_table_eit_print(struct dvb_v5_fe_parms *parms, struct dvb_table_eit *eit)
135 {
136 dvb_loginfo("EIT");
137 dvb_table_header_print(parms, &eit->header);
138 dvb_loginfo("|- transport_id %d", eit->transport_id);
139 dvb_loginfo("|- network_id %d", eit->network_id);
140 dvb_loginfo("|- last segment %d", eit->last_segment);
141 dvb_loginfo("|- last table %d", eit->last_table_id);
142 dvb_loginfo("|\\ event_id");
143 const struct dvb_table_eit_event *event = eit->event;
144 uint16_t events = 0;
145 while (event) {
146 char start[255];
147 strftime(start, sizeof(start), "%F %T", &event->start);
148 dvb_loginfo("|- %7d", event->event_id);
149 dvb_loginfo("| Service %d", event->service_id);
150 dvb_loginfo("| Start %s UTC", start);
151 dvb_loginfo("| Duration %dh %dm %ds", event->duration / 3600, (event->duration % 3600) / 60, event->duration % 60);
152 dvb_loginfo("| free CA mode %d", event->free_CA_mode);
153 dvb_loginfo("| running status %d: %s", event->running_status, dvb_eit_running_status_name[event->running_status] );
154 dvb_desc_print(parms, event->descriptor);
155 event = event->next;
156 events++;
157 }
158 dvb_loginfo("|_ %d events", events);
159 }
160
dvb_time(const uint8_t data[5],struct tm * tm)161 void dvb_time(const uint8_t data[5], struct tm *tm)
162 {
163 /* ETSI EN 300 468 V1.4.1 */
164 int year, month, day, hour, min, sec;
165 int k = 0;
166 uint16_t mjd;
167
168 mjd = *(uint16_t *) data;
169 hour = dvb_bcd(data[2]);
170 min = dvb_bcd(data[3]);
171 sec = dvb_bcd(data[4]);
172 year = ((mjd - 15078.2) / 365.25);
173 month = ((mjd - 14956.1 - (int) (year * 365.25)) / 30.6001);
174 day = mjd - 14956 - (int) (year * 365.25) - (int) (month * 30.6001);
175 if (month == 14 || month == 15) k = 1;
176 year += k;
177 month = month - 1 - k * 12;
178
179 tm->tm_sec = sec;
180 tm->tm_min = min;
181 tm->tm_hour = hour;
182 tm->tm_mday = day;
183 tm->tm_mon = month - 1;
184 tm->tm_year = year;
185 tm->tm_isdst = -1; /* do not adjust */
186 mktime( tm );
187 }
188
189 const char *dvb_eit_running_status_name[8] = {
190 [0] = "Undefined",
191 [1] = "Not running",
192 [2] = "Starts in a few seconds",
193 [3] = "Pausing",
194 [4] = "Running",
195 [5 ... 7] = "Reserved"
196 };
197