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