1 /*****************************************************************************
2  * cat.c: CAT decoder/generator
3  *----------------------------------------------------------------------------
4  * Copyright (C) 2001-2011 VideoLAN
5  * $Id$
6  *
7  * Authors: Johann Hanne
8  *          heavily based on pmt.c which was written by
9  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
10  *          Jean-Paul Saman <jpsaman@videolan.org>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  *----------------------------------------------------------------------------
27  *
28  *****************************************************************************/
29 
30 #include "config.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdbool.h>
35 #include <string.h>
36 
37 #if defined(HAVE_INTTYPES_H)
38 #include <inttypes.h>
39 #elif defined(HAVE_STDINT_H)
40 #include <stdint.h>
41 #endif
42 
43 #include <assert.h>
44 
45 #include "../dvbpsi.h"
46 #include "../dvbpsi_private.h"
47 #include "../psi.h"
48 #include "../descriptor.h"
49 #include "cat.h"
50 #include "cat_private.h"
51 
52 /*****************************************************************************
53  * dvbpsi_cat_attach
54  *****************************************************************************
55  * Initialize a CAT decoder and return a handle on it.
56  *****************************************************************************/
dvbpsi_cat_attach(dvbpsi_t * p_dvbpsi,dvbpsi_cat_callback pf_callback,void * p_cb_data)57 bool dvbpsi_cat_attach(dvbpsi_t *p_dvbpsi, dvbpsi_cat_callback pf_callback,
58                       void* p_cb_data)
59 {
60     assert(p_dvbpsi);
61     assert(p_dvbpsi->p_decoder == NULL);
62 
63     dvbpsi_cat_decoder_t* p_cat_decoder;
64     p_cat_decoder = (dvbpsi_cat_decoder_t*) dvbpsi_decoder_new(&dvbpsi_cat_sections_gather,
65                                                 1024, true, sizeof(dvbpsi_cat_decoder_t));
66     if (p_cat_decoder == NULL)
67         return false;
68 
69     /* CAT decoder configuration */
70     p_cat_decoder->pf_cat_callback = pf_callback;
71     p_cat_decoder->p_cb_data = p_cb_data;
72     p_cat_decoder->p_building_cat = NULL;
73 
74     p_dvbpsi->p_decoder = DVBPSI_DECODER(p_cat_decoder);
75     return true;
76 }
77 
78 /*****************************************************************************
79  * dvbpsi_cat_detach
80  *****************************************************************************
81  * Close a CAT decoder. The handle isn't valid any more.
82  *****************************************************************************/
dvbpsi_cat_detach(dvbpsi_t * p_dvbpsi)83 void dvbpsi_cat_detach(dvbpsi_t *p_dvbpsi)
84 {
85     assert(p_dvbpsi);
86     assert(p_dvbpsi->p_decoder);
87 
88     dvbpsi_cat_decoder_t* p_cat_decoder
89                         = (dvbpsi_cat_decoder_t*)p_dvbpsi->p_decoder;
90     if (p_cat_decoder->p_building_cat)
91         dvbpsi_cat_delete(p_cat_decoder->p_building_cat);
92     p_cat_decoder->p_building_cat = NULL;
93 
94     dvbpsi_decoder_delete(p_dvbpsi->p_decoder);
95     p_dvbpsi->p_decoder = NULL;
96 }
97 
98 /*****************************************************************************
99  * dvbpsi_cat_init
100  *****************************************************************************
101  * Initialize a pre-allocated dvbpsi_cat_t structure.
102  *****************************************************************************/
dvbpsi_cat_init(dvbpsi_cat_t * p_cat,uint8_t i_version,bool b_current_next)103 void dvbpsi_cat_init(dvbpsi_cat_t* p_cat, uint8_t i_version, bool b_current_next)
104 {
105     assert(p_cat);
106 
107     p_cat->i_version = i_version;
108     p_cat->b_current_next = b_current_next;
109     p_cat->p_first_descriptor = NULL;
110 }
111 
112 /*****************************************************************************
113  * dvbpsi_cat_new
114  *****************************************************************************
115  * Allocate and Initialize a dvbpsi_cat_t structure.
116  *****************************************************************************/
dvbpsi_cat_new(uint8_t i_version,bool b_current_next)117 dvbpsi_cat_t *dvbpsi_cat_new(uint8_t i_version, bool b_current_next)
118 {
119     dvbpsi_cat_t *p_cat = (dvbpsi_cat_t*)malloc(sizeof(dvbpsi_cat_t));
120     if (p_cat != NULL)
121         dvbpsi_cat_init(p_cat, i_version, b_current_next);
122     return p_cat;
123 }
124 
125 /*****************************************************************************
126  * dvbpsi_cat_empty
127  *****************************************************************************
128  * Clean a dvbpsi_cat_t structure.
129  *****************************************************************************/
dvbpsi_cat_empty(dvbpsi_cat_t * p_cat)130 void dvbpsi_cat_empty(dvbpsi_cat_t* p_cat)
131 {
132     dvbpsi_DeleteDescriptors(p_cat->p_first_descriptor);
133     p_cat->p_first_descriptor = NULL;
134 }
135 
136 /*****************************************************************************
137  * dvbpsi_cat_delete
138  *****************************************************************************
139  * Clean a dvbpsi_cat_t structure.
140  *****************************************************************************/
dvbpsi_cat_delete(dvbpsi_cat_t * p_cat)141 void dvbpsi_cat_delete(dvbpsi_cat_t *p_cat)
142 {
143     if (p_cat)
144         dvbpsi_cat_empty(p_cat);
145     free(p_cat);
146 }
147 
148 /*****************************************************************************
149  * dvbpsi_cat_descriptor_add
150  *****************************************************************************
151  * Add a descriptor in the CAT.
152  *****************************************************************************/
dvbpsi_cat_descriptor_add(dvbpsi_cat_t * p_cat,uint8_t i_tag,uint8_t i_length,uint8_t * p_data)153 dvbpsi_descriptor_t* dvbpsi_cat_descriptor_add(dvbpsi_cat_t* p_cat,
154                                              uint8_t i_tag, uint8_t i_length,
155                                              uint8_t* p_data)
156 {
157     dvbpsi_descriptor_t* p_descriptor
158                         = dvbpsi_NewDescriptor(i_tag, i_length, p_data);
159     if (p_descriptor == NULL)
160         return NULL;
161 
162     p_cat->p_first_descriptor = dvbpsi_AddDescriptor(p_cat->p_first_descriptor,
163                                                      p_descriptor);
164     assert(p_cat->p_first_descriptor);
165     if (p_cat->p_first_descriptor == NULL)
166         return NULL;
167 
168     return p_descriptor;
169 }
170 
171 /* */
dvbpsi_ReInitCAT(dvbpsi_cat_decoder_t * p_decoder,const bool b_force)172 static void dvbpsi_ReInitCAT(dvbpsi_cat_decoder_t* p_decoder, const bool b_force)
173 {
174     assert(p_decoder);
175 
176     dvbpsi_decoder_reset(DVBPSI_DECODER(p_decoder), b_force);
177 
178     /* Force redecoding */
179     if (b_force)
180     {
181         /* Free structures */
182         if (p_decoder->p_building_cat)
183             dvbpsi_cat_delete(p_decoder->p_building_cat);
184     }
185     p_decoder->p_building_cat = NULL;
186 }
187 
dvbpsi_CheckCAT(dvbpsi_t * p_dvbpsi,dvbpsi_psi_section_t * p_section)188 static bool dvbpsi_CheckCAT(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t *p_section)
189 {
190     bool b_reinit = false;
191     assert(p_dvbpsi->p_decoder);
192 
193     dvbpsi_cat_decoder_t* p_cat_decoder;
194     p_cat_decoder = (dvbpsi_cat_decoder_t *)p_dvbpsi->p_decoder;
195 
196     /* Perform a few sanity checks */
197 #if 0
198     if (p_pat_decoder->p_building_pat->i_ts_id != p_section->i_extension)
199     {
200         /* transport_stream_id */
201         dvbpsi_error(p_dvbpsi, "PAT decoder",
202                         "'transport_stream_id' differs"
203                         " whereas no TS discontinuity has occured");
204         b_reinit = true;
205     }
206     else
207 #endif
208     if (p_cat_decoder->p_building_cat->i_version != p_section->i_version)
209     {
210         /* version_number */
211         dvbpsi_error(p_dvbpsi, "CAT decoder",
212                         "'version_number' differs"
213                         " whereas no discontinuity has occured");
214         b_reinit = true;
215     }
216     else if (p_cat_decoder->i_last_section_number != p_section->i_last_number)
217     {
218          /* last_section_number */
219          dvbpsi_error(p_dvbpsi, "CAT decoder",
220                         "'last_section_number' differs"
221                         " whereas no discontinuity has occured");
222          b_reinit = true;
223     }
224 
225     return b_reinit;
226 }
227 
dvbpsi_AddSectionCAT(dvbpsi_t * p_dvbpsi,dvbpsi_cat_decoder_t * p_decoder,dvbpsi_psi_section_t * p_section)228 static bool dvbpsi_AddSectionCAT(dvbpsi_t *p_dvbpsi, dvbpsi_cat_decoder_t *p_decoder,
229                                  dvbpsi_psi_section_t* p_section)
230 {
231     assert(p_dvbpsi);
232     assert(p_decoder);
233     assert(p_section);
234 
235     /* Initialize the structures if it's the first section received */
236     if (p_decoder->p_building_cat == NULL)
237     {
238         p_decoder->p_building_cat = dvbpsi_cat_new(p_section->i_version,
239                                                    p_section->b_current_next);
240         if (p_decoder->p_building_cat == NULL)
241             return false;
242 
243         p_decoder->i_last_section_number = p_section->i_last_number;
244     }
245 
246     /* Add to linked list of sections */
247     if (dvbpsi_decoder_psi_section_add(DVBPSI_DECODER(p_decoder), p_section))
248         dvbpsi_debug(p_dvbpsi, "CAT decoder", "overwrite section number %d",
249                      p_section->i_number);
250 
251     return true;
252 }
253 
254 /*****************************************************************************
255  * dvbpsi_cat_sections_gather
256  *****************************************************************************
257  * Callback for the PSI decoder.
258  *****************************************************************************/
dvbpsi_cat_sections_gather(dvbpsi_t * p_dvbpsi,dvbpsi_psi_section_t * p_section)259 void dvbpsi_cat_sections_gather(dvbpsi_t *p_dvbpsi,
260                               dvbpsi_psi_section_t* p_section)
261 {
262     assert(p_dvbpsi);
263     assert(p_dvbpsi->p_decoder);
264 
265     if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x01, "CAT decoder"))
266     {
267         dvbpsi_DeletePSISections(p_section);
268         return;
269     }
270 
271     /* */
272     dvbpsi_cat_decoder_t* p_cat_decoder
273                           = (dvbpsi_cat_decoder_t*)p_dvbpsi->p_decoder;
274 
275     /* TS discontinuity check */
276     if (p_cat_decoder->b_discontinuity)
277     {
278         dvbpsi_ReInitCAT(p_cat_decoder, true);
279         p_cat_decoder->b_discontinuity = false;
280     }
281     else
282     {
283         /* Perform some few sanity checks */
284         if (p_cat_decoder->p_building_cat)
285         {
286             if (dvbpsi_CheckCAT(p_dvbpsi, p_section))
287                 dvbpsi_ReInitCAT(p_cat_decoder, true);
288         }
289         else
290         {
291              if (   (p_cat_decoder->b_current_valid)
292                  && (p_cat_decoder->current_cat.i_version == p_section->i_version)
293                  && (p_cat_decoder->current_cat.b_current_next ==
294                                                    p_section->b_current_next))
295              {
296                  /* Don't decode since this version is already decoded */
297                  dvbpsi_debug(p_dvbpsi, "CAT decoder",
298                               "ignoring already decoded section %d",
299                               p_section->i_number);
300                  dvbpsi_DeletePSISections(p_section);
301                  return;
302              }
303         }
304     }
305 
306     /* Add section to CAT */
307     if (!dvbpsi_AddSectionCAT(p_dvbpsi, p_cat_decoder, p_section))
308     {
309         dvbpsi_error(p_dvbpsi, "CAT decoder", "failed decoding section %d",
310                      p_section->i_number);
311         dvbpsi_DeletePSISections(p_section);
312         return;
313     }
314 
315     /* Check if we have all the sections */
316     if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_cat_decoder)))
317     {
318         assert(p_cat_decoder->pf_cat_callback);
319 
320         /* Save the current information */
321         p_cat_decoder->current_cat = *p_cat_decoder->p_building_cat;
322         p_cat_decoder->b_current_valid = true;
323         /* Decode the sections */
324         dvbpsi_cat_sections_decode(p_cat_decoder->p_building_cat,
325                                    p_cat_decoder->p_sections);
326         /* signal the new CAT */
327         p_cat_decoder->pf_cat_callback(p_cat_decoder->p_cb_data,
328                                        p_cat_decoder->p_building_cat);
329         /* Delete sections and Reinitialize the structures */
330         dvbpsi_ReInitCAT(p_cat_decoder, false);
331         assert(p_cat_decoder->p_sections == NULL);
332     }
333 }
334 
335 /*****************************************************************************
336  * dvbpsi_cat_sections_decode
337  *****************************************************************************
338  * CAT decoder.
339  *****************************************************************************/
dvbpsi_cat_sections_decode(dvbpsi_cat_t * p_cat,dvbpsi_psi_section_t * p_section)340 void dvbpsi_cat_sections_decode(dvbpsi_cat_t* p_cat, dvbpsi_psi_section_t* p_section)
341 {
342     uint8_t* p_byte;
343 
344     while (p_section)
345     {
346         /* CAT descriptors */
347         p_byte = p_section->p_payload_start;
348         while (p_byte <= p_section->p_payload_end)
349         {
350             uint8_t i_tag = p_byte[0];
351             uint8_t i_length = p_byte[1];
352             if (i_length + 2 <= p_section->p_payload_end - p_byte)
353                 dvbpsi_cat_descriptor_add(p_cat, i_tag, i_length, p_byte + 2);
354             p_byte += 2 + i_length;
355         }
356         p_section = p_section->p_next;
357     }
358 }
359 
360 /*****************************************************************************
361  * dvbpsi_cat_sections_generate
362  *****************************************************************************
363  * Generate CAT sections based on the dvbpsi_cat_t structure.
364  *****************************************************************************/
dvbpsi_cat_sections_generate(dvbpsi_t * p_dvbpsi,dvbpsi_cat_t * p_cat)365 dvbpsi_psi_section_t* dvbpsi_cat_sections_generate(dvbpsi_t* p_dvbpsi, dvbpsi_cat_t* p_cat)
366 {
367     dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024);
368     dvbpsi_psi_section_t* p_current = p_result;
369     dvbpsi_psi_section_t* p_prev;
370     dvbpsi_descriptor_t* p_descriptor = p_cat->p_first_descriptor;
371 
372     p_current->i_table_id = 0x01;
373     p_current->b_syntax_indicator = true;
374     p_current->b_private_indicator = false;
375     p_current->i_length = 9;                      /* header + CRC_32 */
376     p_current->i_extension = 0;                   /* Not used in the CAT */
377     p_current->i_version = p_cat->i_version;
378     p_current->b_current_next = p_cat->b_current_next;
379     p_current->i_number = 0;
380     p_current->p_payload_end += 8;                /* just after the header */
381     p_current->p_payload_start = p_current->p_data + 8;
382 
383     /* CAT descriptors */
384     while (p_descriptor != NULL)
385     {
386         /* New section if needed */
387         /* written_data_length + descriptor_length + 2 > 1024 - CRC_32_length */
388         if(   (p_current->p_payload_end - p_current->p_data)
389                                 + p_descriptor->i_length > 1018)
390         {
391             p_prev = p_current;
392             p_current = dvbpsi_NewPSISection(1024);
393             p_prev->p_next = p_current;
394 
395             p_current->i_table_id = 0x01;
396             p_current->b_syntax_indicator = true;
397             p_current->b_private_indicator = false;
398             p_current->i_length = 9;                  /* header + CRC_32 */
399             p_current->i_extension = 0;               /* Not used in the CAT */
400             p_current->i_version = p_cat->i_version;
401             p_current->b_current_next = p_cat->b_current_next;
402             p_current->i_number = p_prev->i_number + 1;
403             p_current->p_payload_end += 8;            /* just after the header */
404             p_current->p_payload_start = p_current->p_data + 8;
405         }
406 
407         /* p_payload_end is where the descriptor begins */
408         p_current->p_payload_end[0] = p_descriptor->i_tag;
409         p_current->p_payload_end[1] = p_descriptor->i_length;
410         memcpy(p_current->p_payload_end + 2,
411                 p_descriptor->p_data, p_descriptor->i_length);
412 
413         /* Increase length by descriptor_length + 2 */
414         p_current->p_payload_end += p_descriptor->i_length + 2;
415         p_current->i_length += p_descriptor->i_length + 2;
416 
417         p_descriptor = p_descriptor->p_next;
418     }
419 
420     /* Finalization */
421     p_prev = p_result;
422     while (p_prev != NULL)
423     {
424         p_prev->i_last_number = p_current->i_number;
425         dvbpsi_BuildPSISection(p_dvbpsi, p_prev);
426         p_prev = p_prev->p_next;
427     }
428     return p_result;
429 }
430