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