Commit 8154e00f authored by Christophe Massiot's avatar Christophe Massiot

* ALL: New *_print() set of functions. * ALL (tables): Check CRC only when...

* ALL: New *_print() set of functions. * ALL (tables): Check CRC only when needed; also check tables coherence. * ALL (descriptors): Add a lot of missing _get_ functions. * ALL (descriptors): Fix off-by-one overflow of structure array. * mpeg/psi.h: Fix off-by-one overflow of PAT program array.
parent 968b0ea0
/*****************************************************************************
* common.h: (Rare) common declarations for all submodules
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id: psi.h 1 2010-08-10 19:42:50Z massiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
#ifndef __BITSTREAM_COMMON_H__
#define __BITSTREAM_COMMON_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef void (*f_print)(void *, const char *, ...);
#ifdef __cplusplus
}
#endif
#endif
......@@ -22,6 +22,7 @@
#ifndef __BITSTREAM_DVB_SI_H__
#define __BITSTREAM_DVB_SI_H__
#include <bitstream/common.h>
#include <bitstream/mpeg/psi.h>
#ifdef __cplusplus
......@@ -55,6 +56,14 @@ static inline void desc40_get_networkname(const uint8_t *p_desc,
psz_network_name[i_length] = '\0';
}
static inline void desc40_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
DESC_DECLARE_STRING1(psz_network_name);
desc40_get_networkname(p_desc, psz_network_name);
pf_print(opaque, " - desc 40 networkname=%s", psz_network_name);
}
/*****************************************************************************
* Descriptor 0x48: Service descriptor
*****************************************************************************/
......@@ -81,6 +90,17 @@ static inline void desc48_get_service(const uint8_t *p_desc,
psz_service[*p] = '\0';
}
static inline void desc48_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
DESC_DECLARE_STRING1(psz_provider);
DESC_DECLARE_STRING1(psz_service);
desc48_get_provider(p_desc, psz_provider);
desc48_get_service(p_desc, psz_service);
pf_print(opaque, " - desc 48 provider=%s service=%s", psz_provider,
psz_service);
}
/*****************************************************************************
* Descriptor 0x56: Teletext descriptor
*****************************************************************************/
......@@ -95,12 +115,14 @@ static inline void desc56_init(uint8_t *p_desc)
static inline uint8_t *desc56_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC56_HEADER_SIZE + n * DESC56_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC56_HEADER_SIZE)
if (p_desc_n + DESC56_LANGUAGE_SIZE - p_desc
> desc_get_length(p_desc) + DESC56_HEADER_SIZE)
return NULL;
return p_desc_n;
}
#define desc56n_set_code desc0an_set_code
#define desc56n_get_code desc0an_get_code
static inline void desc56n_set_teletexttype(uint8_t *p_desc_n, uint8_t i_type)
{
......@@ -108,6 +130,11 @@ static inline void desc56n_set_teletexttype(uint8_t *p_desc_n, uint8_t i_type)
p_desc_n[3] |= (i_type << 3) & 0xfc;
}
static inline uint8_t desc56n_get_teletexttype(const uint8_t *p_desc_n)
{
return p_desc_n[3] >> 3;
}
static inline void desc56n_set_teletextmagazine(uint8_t *p_desc_n,
uint8_t i_magazine)
{
......@@ -115,11 +142,38 @@ static inline void desc56n_set_teletextmagazine(uint8_t *p_desc_n,
p_desc_n[3] |= (i_magazine & 0x3);
}
static inline uint8_t desc56n_get_teletextmagazine(const uint8_t *p_desc_n)
{
return p_desc_n[3] & 0x3;
}
static inline void desc56n_set_teletextpage(uint8_t *p_desc_n, uint8_t i_page)
{
p_desc_n[4] = i_page;
}
static inline uint8_t desc56n_get_teletextpage(const uint8_t *p_desc_n)
{
return p_desc_n[4];
}
static inline void desc56_print(uint8_t *p_desc, f_print pf_print,
void *opaque)
{
uint8_t j = 0;
uint8_t *p_desc_n;
while ((p_desc_n = desc56_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque,
" - desc 56 telx language=%3.3s type=%hhu mag=%hhu page=%hhu",
(const char *)desc56n_get_code(p_desc_n),
desc56n_get_teletexttype(p_desc_n),
desc56n_get_teletextmagazine(p_desc_n),
desc56n_get_teletextpage(p_desc_n));
}
}
/*****************************************************************************
* Descriptor 0x59: Subtitling descriptor
*****************************************************************************/
......@@ -134,18 +188,25 @@ static inline void desc59_init(uint8_t *p_desc)
static inline uint8_t *desc59_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC59_HEADER_SIZE + n * DESC59_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC59_HEADER_SIZE)
if (p_desc_n + DESC59_LANGUAGE_SIZE - p_desc
> desc_get_length(p_desc) + DESC59_HEADER_SIZE)
return NULL;
return p_desc_n;
}
#define desc59n_set_code desc0an_set_code
#define desc59n_get_code desc0an_get_code
static inline void desc59n_set_subtitlingtype(uint8_t *p_desc_n, uint8_t i_type)
{
p_desc_n[3] = i_type;
}
static inline uint8_t desc59n_get_subtitlingtype(const uint8_t *p_desc_n)
{
return p_desc_n[3];
}
static inline void desc59n_set_compositionpage(uint8_t *p_desc_n,
uint16_t i_page)
{
......@@ -153,12 +214,39 @@ static inline void desc59n_set_compositionpage(uint8_t *p_desc_n,
p_desc_n[5] = i_page & 0xff;
}
static inline uint16_t desc59n_get_compositionpage(const uint8_t *p_desc_n)
{
return (p_desc_n[4] << 8) | p_desc_n[5];
}
static inline void desc59n_set_ancillarypage(uint8_t *p_desc_n, uint16_t i_page)
{
p_desc_n[6] = i_page >> 8;
p_desc_n[7] = i_page & 0xff;
}
static inline uint16_t desc59n_get_ancillarypage(const uint8_t *p_desc_n)
{
return (p_desc_n[6] << 8) | p_desc_n[7];
}
static inline void desc59_print(uint8_t *p_desc, f_print pf_print,
void *opaque)
{
uint8_t j = 0;
uint8_t *p_desc_n;
while ((p_desc_n = desc59_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque,
" - desc 59 dvbs language=%3.3s type=%hhu composition=%hu ancillary=%hu",
(const char *)desc59n_get_code(p_desc_n),
desc59n_get_subtitlingtype(p_desc_n),
desc59n_get_compositionpage(p_desc_n),
desc59n_get_ancillarypage(p_desc_n));
}
}
/*****************************************************************************
* Descriptor 0x6a: AC-3 descriptor
*****************************************************************************/
......@@ -174,6 +262,12 @@ static inline void desc6a_clear_flags(uint8_t *p_desc)
p_desc[2] = 0;
}
static inline void desc6a_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
pf_print(opaque, " - desc 6a ac3");
}
/*****************************************************************************
* Network Information Table
*****************************************************************************/
......@@ -337,6 +431,53 @@ static inline bool nit_validate(const uint8_t *p_nit)
return (p_nit_n - p_nit == i_section_size);
}
static inline uint8_t *nit_table_find_ts(uint8_t **pp_sections,
uint16_t i_tsid, uint16_t i_onid)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_ts;
int j = 0;
while ((p_ts = nit_get_ts(p_section, j)) != NULL) {
j++;
if (nitn_get_tsid(p_ts) == i_tsid && nitn_get_onid(p_ts) == i_onid)
return p_ts;
}
}
return NULL;
}
static inline bool nit_table_validate(uint8_t **pp_sections)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_ts;
int j = 0;
if (!psi_check_crc(p_section))
return false;
while ((p_ts = nit_get_ts(p_section, j)) != NULL) {
j++;
/* check that the program number if not already in the table */
if (nit_table_find_ts(pp_sections, nitn_get_tsid(p_ts),
nitn_get_onid(p_ts)) != p_ts)
return false;
}
}
return true;
}
/*****************************************************************************
* Service Description Table
*****************************************************************************/
......@@ -508,6 +649,23 @@ static inline uint8_t *sdt_table_find_service(uint8_t **pp_sections,
return NULL;
}
static inline bool sdt_table_validate(uint8_t **pp_sections)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_ts;
int j = 0;
if (!psi_check_crc(p_section))
return false;
}
return true;
}
/*****************************************************************************
* Event Information Table
*****************************************************************************/
......@@ -569,6 +727,9 @@ static inline bool eit_validate(const uint8_t *p_eit)
&& i_tid <= EIT_TABLE_ID_SCHED_OTHER_LAST)))
return false;
if (!psi_check_crc(p_eit))
return false;
p_eit_n = p_eit + EIT_HEADER_SIZE;
while (p_eit_n + EIT_EVENT_SIZE - p_eit <= i_section_size
......
......@@ -21,6 +21,7 @@
#ifndef __BITSTREAM_MPEG_PSI_H__
#define __BITSTREAM_MPEG_PSI_H__
#include <bitstream/common.h>
#include <bitstream/mpeg/ts.h>
#ifdef __cplusplus
......@@ -58,10 +59,16 @@ static inline uint8_t desc_get_length(const uint8_t *p_desc)
return p_desc[1];
}
static inline void desc_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
pf_print(opaque, " - desc %2.2hhx unknown", desc_get_tag(p_desc));
}
/*****************************************************************************
* Descriptor 0x05: Registration descriptor
*****************************************************************************/
#define DESC05_HEADER_SIZE 6
#define DESC05_HEADER_SIZE (DESC_HEADER_SIZE + 4)
static inline void desc05_init(uint8_t *p_desc)
{
......@@ -77,10 +84,22 @@ static inline void desc05_set_identifier(uint8_t *p_desc, uint8_t p_id[4])
p_desc[5] = p_id[3];
}
static inline const uint8_t *desc05_get_identifier(const uint8_t *p_desc)
{
return p_desc + 2;
}
static inline void desc05_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
pf_print(opaque, " - desc 05 identifier=%4.4s",
desc05_get_identifier(p_desc));
}
/*****************************************************************************
* Descriptor 0x09: Conditional access descriptor
*****************************************************************************/
#define DESC09_HEADER_SIZE 6
#define DESC09_HEADER_SIZE (DESC_HEADER_SIZE + 4)
static inline uint16_t desc09_get_sysid(const uint8_t *p_desc)
{
......@@ -92,6 +111,13 @@ static inline uint16_t desc09_get_pid(const uint8_t *p_desc)
return ((p_desc[4] & 0x1f) << 8) | p_desc[5];
}
static inline void desc09_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
pf_print(opaque, " - desc 09 sysid=%hx pid=%hu",
desc09_get_sysid(p_desc), desc09_get_pid(p_desc));
}
/*****************************************************************************
* Descriptor 0x0a: ISO-639 language descriptor
*****************************************************************************/
......@@ -106,7 +132,8 @@ static inline void desc0a_init(uint8_t *p_desc)
static inline uint8_t *desc0a_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC0A_HEADER_SIZE + n * DESC0A_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC0A_HEADER_SIZE)
if (p_desc_n + DESC0A_LANGUAGE_SIZE - p_desc
> desc_get_length(p_desc) + DESC0A_HEADER_SIZE)
return NULL;
return p_desc_n;
}
......@@ -118,11 +145,35 @@ static inline void desc0an_set_code(uint8_t *p_desc_n, const uint8_t p_code[3])
p_desc_n[2] = p_code[2];
}
static inline const uint8_t *desc0an_get_code(const uint8_t *p_desc_n)
{
return p_desc_n;
}
static inline void desc0an_set_audiotype(uint8_t *p_desc_n, uint8_t i_type)
{
p_desc_n[3] = i_type;
}
static inline uint8_t desc0an_get_audiotype(const uint8_t *p_desc_n)
{
return p_desc_n[3];
}
static inline void desc0a_print(uint8_t *p_desc, f_print pf_print,
void *opaque)
{
uint8_t j = 0;
uint8_t *p_desc_n;
while ((p_desc_n = desc0a_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque, " - desc 0a language=%3.3s audiotype=%hhu",
(const char *)desc0an_get_code(p_desc_n),
desc0an_get_audiotype(p_desc_n));
}
}
/*****************************************************************************
* Descriptors list
*****************************************************************************/
......@@ -344,7 +395,7 @@ static inline void psi_set_version(uint8_t *p_section, uint8_t i_version)
p_section[5] = i_version << 1;
}
static inline uint8_t psi_get_version(uint8_t *p_section)
static inline uint8_t psi_get_version(const uint8_t *p_section)
{
return (p_section[5] & 0x1e) >> 1;
}
......@@ -424,12 +475,20 @@ static inline bool psi_validate(const uint8_t *p_section)
- PSI_HEADER_SIZE + PSI_CRC_SIZE))
return false;
if (psi_get_syntax(p_section) && !psi_check_crc(p_section))
return false;
/* only do the CRC check when it is strictly necessary */
return true;
}
static inline bool psi_compare(const uint8_t *p_section1,
const uint8_t *p_section2)
{
return psi_get_version(p_section1) == psi_get_version(p_section2)
&& psi_get_length(p_section1) == psi_get_length(p_section2)
&& !memcmp(p_section1, p_section2,
psi_get_length(p_section1) + PSI_HEADER_SIZE);
}
/*****************************************************************************
* PSI section gathering
*****************************************************************************/
......@@ -569,7 +628,7 @@ static inline void psi_table_free(uint8_t **pp_sections)
free(pp_sections[i]);
}
static inline bool psi_table_validate(uint8_t **pp_sections)
static inline bool psi_table_validate(uint8_t * const *pp_sections)
{
return pp_sections[0] != NULL;
}
......@@ -579,20 +638,14 @@ static inline void psi_table_copy(uint8_t **pp_dest, uint8_t **pp_src)
memcpy(pp_dest, pp_src, PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
}
static inline uint16_t psi_table_get_tableidext(uint8_t **pp_sections)
{
return psi_get_tableidext(pp_sections[0]);
}
static inline uint8_t psi_table_get_version(uint8_t **pp_sections)
{
return psi_get_version(pp_sections[0]);
}
static inline uint8_t psi_table_get_lastsection(uint8_t **pp_sections)
{
return psi_get_lastsection(pp_sections[0]);
}
#define psi_table_get_tableid(pp_sections) \
psi_get_tableid(pp_sections[0])
#define psi_table_get_version(pp_sections) \
psi_get_version(pp_sections[0])
#define psi_table_get_lastsection(pp_sections) \
psi_get_lastsection(pp_sections[0])
#define psi_table_get_tableidext(pp_sections) \
psi_get_tableidext(pp_sections[0])
static inline bool psi_table_section(uint8_t **pp_sections, uint8_t *p_section)
{
......@@ -628,6 +681,25 @@ static inline uint8_t *psi_table_get_section(uint8_t **pp_sections, uint8_t n)
return pp_sections[n];
}
static inline bool psi_table_compare(uint8_t **pp_sections1,
uint8_t **pp_sections2)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections1);
uint8_t i;
if (i_last_section != psi_table_get_lastsection(pp_sections2))
return false;
for (i = 0; i < i_last_section; i++) {
const uint8_t *p_section1 = psi_table_get_section(pp_sections1, i);
const uint8_t *p_section2 = psi_table_get_section(pp_sections2, i);
if (!psi_compare(p_section1, p_section2))
return false;
}
return true;
}
/*****************************************************************************
* Program Association Table
*****************************************************************************/
......@@ -683,7 +755,8 @@ static inline uint16_t patn_get_pid(const uint8_t *p_pat_n)
static inline uint8_t *pat_get_program(uint8_t *p_pat, uint8_t n)
{
uint8_t *p_pat_n = p_pat + PAT_HEADER_SIZE + n * PAT_PROGRAM_SIZE;
if (p_pat_n - p_pat > psi_get_length(p_pat) + PSI_HEADER_SIZE - PSI_CRC_SIZE)
if (p_pat_n + PAT_PROGRAM_SIZE - p_pat
> psi_get_length(p_pat) + PSI_HEADER_SIZE - PSI_CRC_SIZE)
return NULL;
return p_pat_n;
}
......@@ -710,17 +783,67 @@ static inline uint8_t *pat_table_find_program(uint8_t **pp_sections,
uint8_t *p_program;
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL)
{
while ((p_program = pat_get_program(p_section, j)) != NULL) {
j++;
if (patn_get_program(p_program) == i_program)
return p_program;
j++;
}
}
return NULL;
}
static inline bool pat_table_validate(uint8_t **pp_sections)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_program;
int j = 0;
if (!psi_check_crc(p_section))
return false;
while ((p_program = pat_get_program(p_section, j)) != NULL) {
j++;
/* check that the program number if not already in the table */
if (pat_table_find_program(pp_sections,
patn_get_program(p_program)) != p_program)
return false;
}
}
return true;
}
static inline void pat_table_print(uint8_t **pp_sections, f_print pf_print,
void *opaque)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new PAT tsid=%hu version=%hhu",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections));
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
const uint8_t *p_program;
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL) {
j++;
pf_print(opaque, " * program number=%hu pid=%hu",
patn_get_program(p_program),
patn_get_pid(p_program));
}
}
pf_print(opaque, "end PAT");
}
/*****************************************************************************
* Program Map Table
*****************************************************************************/
......@@ -849,6 +972,9 @@ static inline bool pmt_validate(const uint8_t *p_pmt)
|| psi_get_tableid(p_pmt) != PMT_TABLE_ID)
return false;
if (!psi_check_crc(p_pmt))
return false;
if (i_section_size < PMT_HEADER_SIZE
|| i_section_size < PMT_HEADER_SIZE + pmt_get_desclength(p_pmt))
return false;
......
/*****************************************************************************
* psi_print.h: ISO/IEC 13818-1 Program Stream Information (printing)
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id: psi_print.h -1 $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Placed here for dependancy reasons
*/
#ifndef __BITSTREAM_MPEG_PSI_PRINT_H__
#define __BITSTREAM_MPEG_PSI_PRINT_H__
#include <bitstream/common.h>
#include <bitstream/mpeg/psi.h>
#include <bitstream/dvb/si.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Descriptors list
*****************************************************************************/
static inline void descs_print(uint8_t *p_descs, f_print pf_print, void *opaque)
{
uint16_t j = 0;
uint8_t *p_desc;
while ((p_desc = descs_get_desc(p_descs, j)) != NULL) {
j++;
/* I am not proud of this */
switch (desc_get_tag(p_desc)) {
case 0x05:
desc05_print(p_desc, pf_print, opaque);
break;
case 0x09:
desc09_print(p_desc, pf_print, opaque);
break;
case 0x0a:
desc0a_print(p_desc, pf_print, opaque);
break;
case 0x40:
desc40_print(p_desc, pf_print, opaque);
break;
case 0x48:
desc48_print(p_desc, pf_print, opaque);
break;
case 0x56:
desc56_print(p_desc, pf_print, opaque);
break;
case 0x59:
desc59_print(p_desc, pf_print, opaque);
break;
case 0x6a:
desc6a_print(p_desc, pf_print, opaque);
break;
default:
desc_print(p_desc, pf_print, opaque);
break;
}
}
}
/*****************************************************************************
* Program Map Table
*****************************************************************************/
static inline void pmt_print(uint8_t *p_pmt, f_print pf_print, void *opaque)
{
uint8_t *p_es;
uint8_t j = 0;
pf_print(opaque, "new PMT program=%hu version=%hhu pcrpid=%hu",
pmt_get_program(p_pmt), psi_get_version(p_pmt),
pmt_get_pcrpid(p_pmt));
descs_print(pmt_get_descs(p_pmt), pf_print, opaque);
while ((p_es = pmt_get_es(p_pmt, j)) != NULL) {
j++;
pf_print(opaque, " * ES pid=%hu streamtype=0x%hx", pmtn_get_pid(p_es),
pmtn_get_streamtype(p_es));
descs_print(pmtn_get_descs(p_es), pf_print, opaque);
}
pf_print(opaque, "end PMT");
}
/*****************************************************************************
* Network Information Table
*****************************************************************************/
static inline void nit_table_print(uint8_t **pp_sections, f_print pf_print,
void *opaque)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new NIT %s networkid=%hu version=%hhu",
psi_table_get_tableid(pp_sections) == NIT_TABLE_ID_ACTUAL ?
"actual" : "other",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections));
descs_print(nit_get_descs(psi_table_get_section(pp_sections, 0)),
pf_print, opaque);
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
const uint8_t *p_ts;
int j = 0;
while ((p_ts = nit_get_ts(p_section, j)) != NULL) {
j++;
pf_print(opaque, " * ts tsid=%hu onid=%hu",
nitn_get_tsid(p_ts), nitn_get_onid(p_ts));
descs_print(nitn_get_descs(p_ts), pf_print, opaque);
}
}
pf_print(opaque, "end NIT");
}
/*****************************************************************************
* Service Description Table
*****************************************************************************/
static inline void sdt_table_print(uint8_t **pp_sections, f_print pf_print,
void *opaque)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new SDT %s tsid=%hu version=%hhu onid=%hu",
psi_table_get_tableid(pp_sections) == SDT_TABLE_ID_ACTUAL ?
"actual" : "other",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections),
sdt_get_onid(psi_table_get_section(pp_sections, 0)));
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
const uint8_t *p_service;
int j = 0;
while ((p_service = sdt_get_service(p_section, j)) != NULL) {
j++;
pf_print(opaque, " * service sid=%hu eit%s%s running=%hhu%s",
sdtn_get_sid(p_service),
sdtn_get_eitschedule(p_service) ? " schedule" : "",
sdtn_get_eitpresent(p_service) ? " present" : "",
sdtn_get_running(p_service),
sdtn_get_ca(p_service) ? " scrambled" : "");
descs_print(sdtn_get_descs(p_service), pf_print, opaque);
}
}
pf_print(opaque, "end SDT");
}
#ifdef __cplusplus
}
#endif
#endif