1 /*
2  * Copyright (c) 2013-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/atsc_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 
atsc_table_eit_init(struct dvb_v5_fe_parms * parms,const uint8_t * buf,ssize_t buflen,struct atsc_table_eit ** table)28 ssize_t atsc_table_eit_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
29 		ssize_t buflen, struct atsc_table_eit **table)
30 {
31 	const uint8_t *p = buf, *endbuf = buf + buflen;
32 	struct atsc_table_eit *eit;
33 	struct atsc_table_eit_event **head;
34 	size_t size;
35 	int i = 0;
36 
37 	size = offsetof(struct atsc_table_eit, event);
38 	if (p + size > endbuf) {
39 		dvb_logerr("%s: short read %zd/%zd bytes", __func__,
40 			   endbuf - p, size);
41 		return -1;
42 	}
43 
44 	if (buf[0] != ATSC_TABLE_EIT) {
45 		dvb_logerr("%s: invalid marker 0x%02x, should be 0x%02x",
46 				__func__, buf[0], ATSC_TABLE_EIT);
47 		return -2;
48 	}
49 
50 	if (!*table) {
51 		*table = calloc(sizeof(struct atsc_table_eit), 1);
52 		if (!*table) {
53 			dvb_logerr("%s: out of memory", __func__);
54 			return -3;
55 		}
56 	}
57 	eit = *table;
58 	memcpy(eit, p, size);
59 	p += size;
60 	dvb_table_header_init(&eit->header);
61 
62 	/* find end of curent list */
63 	head = &eit->event;
64 	while (*head != NULL)
65 		head = &(*head)->next;
66 
67 	while (i++ < eit->events && p < endbuf) {
68 		struct atsc_table_eit_event *event;
69                 union atsc_table_eit_desc_length dl;
70 
71 		size = offsetof(struct atsc_table_eit_event, descriptor);
72 		if (p + size > endbuf) {
73 			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
74 				   endbuf - p, size);
75 			return -4;
76 		}
77 		event = (struct atsc_table_eit_event *) malloc(sizeof(struct atsc_table_eit_event));
78 		if (!event) {
79 			dvb_logerr("%s: out of memory", __func__);
80 			return -5;
81 		}
82 		memcpy(event, p, size);
83 		p += size;
84 
85 		bswap16(event->bitfield);
86 		bswap32(event->start_time);
87 		bswap32(event->bitfield2);
88 		event->descriptor = NULL;
89 		event->next = NULL;
90                 atsc_time(event->start_time, &event->start);
91 		event->source_id = eit->header.id;
92 
93 		*head = event;
94 		head = &(*head)->next;
95 
96 		size = event->title_length - 1;
97 		if (p + size > endbuf) {
98 			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
99 				   endbuf - p, size);
100 			return -6;
101 		}
102                 /* TODO: parse title */
103                 p += size;
104 
105 		/* get the descriptors for each program */
106 		size = sizeof(union atsc_table_eit_desc_length);
107 		if (p + size > endbuf) {
108 			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
109 				   endbuf - p, size);
110 			return -7;
111 		}
112 		memcpy(&dl, p, size);
113                 p += size;
114                 bswap16(dl.bitfield);
115 
116 		size = dl.desc_length;
117 		if (p + size > endbuf) {
118 			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
119 				   endbuf - p, size);
120 			return -8;
121 		}
122 		if (dvb_desc_parse(parms, p, size,
123 					&event->descriptor) != 0 ) {
124 			return -9;
125 		}
126 
127 		p += size;
128 	}
129 
130 	return p - buf;
131 }
132 
atsc_table_eit_free(struct atsc_table_eit * eit)133 void atsc_table_eit_free(struct atsc_table_eit *eit)
134 {
135 	struct atsc_table_eit_event *event = eit->event;
136 
137 	while (event) {
138 		struct atsc_table_eit_event *tmp = event;
139 
140 		dvb_desc_free((struct dvb_desc **) &event->descriptor);
141 		event = event->next;
142 		free(tmp);
143 	}
144 	free(eit);
145 }
146 
atsc_table_eit_print(struct dvb_v5_fe_parms * parms,struct atsc_table_eit * eit)147 void atsc_table_eit_print(struct dvb_v5_fe_parms *parms, struct atsc_table_eit *eit)
148 {
149 	dvb_loginfo("EIT");
150 	ATSC_TABLE_HEADER_PRINT(parms, eit);
151 	const struct atsc_table_eit_event *event = eit->event;
152 	uint16_t events = 0;
153 
154 	while (event) {
155 		char start[255];
156 
157 		strftime(start, sizeof(start), "%F %T", &event->start);
158 		dvb_loginfo("|-  event %7d", event->event_id);
159 		dvb_loginfo("|   Source                %d", event->source_id);
160 		dvb_loginfo("|   Starttime             %d", event->start_time);
161 		dvb_loginfo("|   Start                 %s UTC", start);
162 		dvb_loginfo("|   Duration              %dh %dm %ds", event->duration / 3600, (event->duration % 3600) / 60, event->duration % 60);
163 		dvb_loginfo("|   ETM                   %d", event->etm);
164 		dvb_loginfo("|   title length          %d", event->title_length);
165 		dvb_desc_print(parms, event->descriptor);
166 		event = event->next;
167 		events++;
168 	}
169 	dvb_loginfo("|_  %d events", events);
170 }
171 
atsc_time(const uint32_t start_time,struct tm * tm)172 void atsc_time(const uint32_t start_time, struct tm *tm)
173 {
174   tm->tm_sec   = 0;
175   tm->tm_min   = 0;
176   tm->tm_hour  = 0;
177   tm->tm_mday  = 6;
178   tm->tm_mon   = 0;
179   tm->tm_year  = 80;
180   tm->tm_isdst = -1;
181   tm->tm_wday  = 0;
182   tm->tm_yday  = 0;
183   mktime(tm);
184   tm->tm_sec += start_time;
185   mktime(tm);
186 }
187 
188 
189