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/cat.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_cat_init(struct dvb_v5_fe_parms * parms,const uint8_t * buf,ssize_t buflen,struct dvb_table_cat ** table)28 ssize_t dvb_table_cat_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
29 		ssize_t buflen, struct dvb_table_cat **table)
30 {
31 	const uint8_t *p = buf, *endbuf = buf + buflen;
32 	struct dvb_table_cat *cat;
33 	struct dvb_desc **head_desc;
34 	size_t size;
35 
36 	size = offsetof(struct dvb_table_cat, descriptor);
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_CAT) {
44 		dvb_logerr("%s: invalid marker 0x%02x, should be 0x%02x",
45 				__func__, buf[0], DVB_TABLE_CAT);
46 		return -2;
47 	}
48 
49 	if (!*table) {
50 		*table = calloc(sizeof(struct dvb_table_cat), 1);
51 		if (!*table) {
52 			dvb_logerr("%s: out of memory", __func__);
53 			return -3;
54 		}
55 	}
56 	cat = *table;
57 	memcpy(cat, p, size);
58 	p += size;
59 	dvb_table_header_init(&cat->header);
60 
61 	/* find end of current lists */
62 	head_desc = &cat->descriptor;
63 	while (*head_desc != NULL)
64 		head_desc = &(*head_desc)->next;
65 
66 	size = cat->header.section_length + 3 - DVB_CRC_SIZE; /* plus header, minus CRC */
67 	if (buf + size > endbuf) {
68 		dvb_logerr("%s: short read %zd/%zd bytes", __func__,
69 			   endbuf - buf, size);
70 		return -4;
71 	}
72 	endbuf = buf + size;
73 
74 	/* parse the descriptors */
75 	if (endbuf > p) {
76 		uint16_t desc_length = endbuf - p;
77 		if (dvb_desc_parse(parms, p, desc_length,
78 				      head_desc) != 0) {
79 			return -5;
80 		}
81 		p += desc_length;
82 	}
83 
84 	if (endbuf - p)
85 		dvb_logwarn("%s: %zu spurious bytes at the end",
86 			   __func__, endbuf - p);
87 
88 	return p - buf;
89 }
90 
dvb_table_cat_free(struct dvb_table_cat * cat)91 void dvb_table_cat_free(struct dvb_table_cat *cat)
92 {
93 	dvb_desc_free((struct dvb_desc **) &cat->descriptor);
94 	free(cat);
95 }
96 
dvb_table_cat_print(struct dvb_v5_fe_parms * parms,struct dvb_table_cat * cat)97 void dvb_table_cat_print(struct dvb_v5_fe_parms *parms, struct dvb_table_cat *cat)
98 {
99 	dvb_loginfo("CAT");
100 	dvb_table_header_print(parms, &cat->header);
101 	dvb_desc_print(parms, cat->descriptor);
102 }
103 
104