• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013 - Mauro Carvalho Chehab <mchehab@kernel.org>
3  * Copyright (c) 2013-2014 - Andre Roth <neolynx@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation version 2.1 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18  *
19  */
20 
21 #include <libdvbv5/vct.h>
22 #include <libdvbv5/descriptors.h>
23 #include <libdvbv5/dvb-fe.h>
24 #include <parse_string.h>
25 
26 #if __GNUC__ >= 9
27 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
28 #endif
29 
atsc_table_vct_init(struct dvb_v5_fe_parms * parms,const uint8_t * buf,ssize_t buflen,struct atsc_table_vct ** table)30 ssize_t atsc_table_vct_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
31 			ssize_t buflen, struct atsc_table_vct **table)
32 {
33 	const uint8_t *p = buf, *endbuf = buf + buflen;
34 	struct atsc_table_vct *vct;
35 	struct atsc_table_vct_channel **head;
36 	size_t size;
37 	int i, n;
38 
39 	size = offsetof(struct atsc_table_vct, channel);
40 	if (p + size > endbuf) {
41 		dvb_logerr("%s: short read %zd/%zd bytes", __func__,
42 			   endbuf - p, size);
43 		return -1;
44 	}
45 
46 	if (buf[0] != ATSC_TABLE_TVCT && buf[0] != ATSC_TABLE_CVCT) {
47 		dvb_logerr("%s: invalid marker 0x%02x, should be 0x%02x or 0x%02x",
48 				__func__, buf[0], ATSC_TABLE_TVCT, ATSC_TABLE_CVCT);
49 		return -2;
50 	}
51 
52 	if (!*table) {
53 		*table = calloc(sizeof(struct atsc_table_vct), 1);
54 		if (!*table) {
55 			dvb_logerr("%s: out of memory", __func__);
56 			return -3;
57 		}
58 	}
59 	vct = *table;
60 	memcpy(vct, p, size);
61 	p += size;
62 	dvb_table_header_init(&vct->header);
63 
64 	/* find end of curent list */
65 	head = &vct->channel;
66 	while (*head != NULL)
67 		head = &(*head)->next;
68 
69 	size = offsetof(struct atsc_table_vct_channel, descriptor);
70 	for (n = 0; n < vct->num_channels_in_section; n++) {
71 		struct atsc_table_vct_channel *channel;
72 
73 		if (p + size > endbuf) {
74 			dvb_logerr("%s: channel table is missing %d elements",
75 				   __func__, vct->num_channels_in_section - n + 1);
76 			vct->num_channels_in_section = n;
77 			break;
78 		}
79 
80 		channel = malloc(sizeof(struct atsc_table_vct_channel));
81 		if (!channel) {
82 			dvb_logerr("%s: out of memory", __func__);
83 			return -4;
84 		}
85 
86 		memcpy(channel, p, size);
87 		p += size;
88 
89 		/* Fix endiannes of the copied fields */
90 		for (i = 0; i < ARRAY_SIZE(channel->__short_name); i++)
91 			bswap16(channel->__short_name[i]);
92 
93 		bswap32(channel->carrier_frequency);
94 		bswap16(channel->channel_tsid);
95 		bswap16(channel->program_number);
96 		bswap32(channel->bitfield1);
97 		bswap16(channel->bitfield2);
98 		bswap16(channel->source_id);
99 		bswap16(channel->bitfield3);
100 
101 		/* Short name is always UTF-16 */
102 		dvb_iconv_to_charset(parms, channel->short_name,
103 				     sizeof(channel->short_name),
104 				     (const unsigned char *)channel->__short_name,
105 				     sizeof(channel->__short_name),
106 				     "UTF-16",
107 				     parms->output_charset);
108 
109 		/* Fill descriptors */
110 
111 		channel->descriptor = NULL;
112 		channel->next = NULL;
113 
114 		*head = channel;
115 		head = &(*head)->next;
116 
117 		if (endbuf - p < channel->descriptors_length) {
118 			dvb_logerr("%s: short read %d/%zd bytes", __func__,
119 				   channel->descriptors_length, endbuf - p);
120 			return -5;
121 		}
122 
123 		/* get the descriptors for each program */
124 		if (dvb_desc_parse(parms, p, channel->descriptors_length,
125 				      &channel->descriptor) != 0) {
126 			return -6;
127 		}
128 
129 		p += channel->descriptors_length;
130 	}
131 
132 	/* Get extra descriptors */
133 	size = sizeof(union atsc_table_vct_descriptor_length);
134 	while (p + size <= endbuf) {
135 		union atsc_table_vct_descriptor_length *d = (void *)p;
136 		bswap16(d->descriptor_length);
137 		p += size;
138 		if (endbuf - p < d->descriptor_length) {
139 			dvb_logerr("%s: short read %d/%zd bytes", __func__,
140 				   d->descriptor_length, endbuf - p);
141 			return -7;
142 		}
143 		if (dvb_desc_parse(parms, p, d->descriptor_length,
144 				      &vct->descriptor) != 0) {
145 			return -8;
146 		}
147 	}
148 	if (endbuf - p)
149 		dvb_logwarn("%s: %zu spurious bytes at the end",
150 			   __func__, endbuf - p);
151 	return p - buf;
152 }
153 
atsc_table_vct_free(struct atsc_table_vct * vct)154 void atsc_table_vct_free(struct atsc_table_vct *vct)
155 {
156 	struct atsc_table_vct_channel *channel = vct->channel;
157 	while (channel) {
158 		dvb_desc_free((struct dvb_desc **) &channel->descriptor);
159 		struct atsc_table_vct_channel *tmp = channel;
160 		channel = channel->next;
161 		free(tmp);
162 	}
163 	dvb_desc_free(&vct->descriptor);
164 
165 	free(vct);
166 }
167 
atsc_table_vct_print(struct dvb_v5_fe_parms * parms,struct atsc_table_vct * vct)168 void atsc_table_vct_print(struct dvb_v5_fe_parms *parms, struct atsc_table_vct *vct)
169 {
170 	const struct atsc_table_vct_channel *channel = vct->channel;
171 	uint16_t channels = 0;
172 
173 	if (vct->header.table_id == ATSC_TABLE_CVCT)
174 		dvb_loginfo("CVCT");
175 	else
176 		dvb_loginfo("TVCT");
177 
178 	ATSC_TABLE_HEADER_PRINT(parms, vct);
179 
180 	dvb_loginfo("|- #channels        %d", vct->num_channels_in_section);
181 	dvb_loginfo("|\\  channel_id");
182 	while (channel) {
183 		dvb_loginfo("|- Channel                %d.%d: %s",
184 			channel->major_channel_number,
185 			channel->minor_channel_number,
186 			channel->short_name);
187 		dvb_loginfo("|   modulation mode       %d", channel->modulation_mode);
188 		dvb_loginfo("|   carrier frequency     %d", channel->carrier_frequency);
189 		dvb_loginfo("|   TS ID                 %d", channel->channel_tsid);
190 		dvb_loginfo("|   program number        %d", channel->program_number);
191 
192 		dvb_loginfo("|   ETM location          %d", channel->ETM_location);
193 		dvb_loginfo("|   access controlled     %d", channel->access_controlled);
194 		dvb_loginfo("|   hidden                %d", channel->hidden);
195 
196 		if (vct->header.table_id == ATSC_TABLE_CVCT) {
197 			dvb_loginfo("|   path select           %d", channel->path_select);
198 			dvb_loginfo("|   out of band           %d", channel->out_of_band);
199 		}
200 		dvb_loginfo("|   hide guide            %d", channel->hide_guide);
201 		dvb_loginfo("|   service type          %d", channel->service_type);
202 		dvb_loginfo("|   source id            %d", channel->source_id);
203 
204 		dvb_desc_print(parms, channel->descriptor);
205 		channel = channel->next;
206 		channels++;
207 	}
208 	dvb_loginfo("|_  %d channels", channels);
209 }
210