aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libucsi/section.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libucsi/section.h')
-rw-r--r--lib/libucsi/section.h253
1 files changed, 253 insertions, 0 deletions
diff --git a/lib/libucsi/section.h b/lib/libucsi/section.h
new file mode 100644
index 0000000..53ad07f
--- /dev/null
+++ b/lib/libucsi/section.h
@@ -0,0 +1,253 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_SECTION_H
+#define _UCSI_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/endianops.h>
+#include <libucsi/descriptor.h>
+#include <libucsi/crc32.h>
+#include <stdint.h>
+#include <string.h>
+
+#define CRC_SIZE 4
+
+
+/**
+ * Generic section header.
+ */
+struct section {
+ uint8_t table_id;
+ EBIT4(uint16_t syntax_indicator : 1; ,
+ uint16_t private_indicator : 1; , /* 2.4.4.10 */
+ uint16_t reserved : 2; ,
+ uint16_t length :12; );
+} __ucsi_packed;
+
+/**
+ * Generic extended section header structure.
+ */
+struct section_ext {
+ uint8_t table_id;
+ EBIT4(uint16_t syntax_indicator : 1; ,
+ uint16_t private_indicator : 1; , /* 2.4.4.10 */
+ uint16_t reserved : 2; ,
+ uint16_t length :12; );
+
+ uint16_t table_id_ext;
+ EBIT3(uint8_t reserved1 : 2; ,
+ uint8_t version_number : 5; ,
+ uint8_t current_next_indicator : 1; );
+ uint8_t section_number;
+ uint8_t last_section_number;
+} __ucsi_packed;
+
+/**
+ * Structure for keeping track of sections of a PSI table.
+ */
+struct psi_table_state {
+ uint8_t version_number;
+ uint16_t next_section_number;
+ uint8_t complete:1;
+ uint8_t new_table:1;
+} __ucsi_packed;
+
+
+/**
+ * Determine the total length of a section, including the header.
+ *
+ * @param section The parsed section structure.
+ * @return The length.
+ */
+static inline size_t section_length(struct section *section)
+{
+ return section->length + sizeof(struct section);
+}
+
+/**
+ * Determine the total length of an extended section, including the header,
+ * but omitting the CRC.
+ *
+ * @param section The parsed section_ext structure.
+ * @return The length.
+ */
+static inline size_t section_ext_length(struct section_ext * section)
+{
+ return section->length + sizeof(struct section) - CRC_SIZE;
+}
+
+/**
+ * Process a section structure in-place.
+ *
+ * @param buf Pointer to the data.
+ * @param len Length of data.
+ * @return Pointer to the section structure, or NULL if invalid.
+ */
+static inline struct section * section_codec(uint8_t * buf, size_t len)
+{
+ struct section * ret = (struct section *)buf;
+
+ if (len < 3)
+ return NULL;
+
+ bswap16(buf+1);
+
+ if (len != ret->length + 3U)
+ return NULL;
+
+ return ret;
+}
+
+/**
+ * Some sections have a CRC even though they are not section_exts.
+ * This function is to allow checking of them.
+ *
+ * @param section Pointer to the processed section structure.
+ * @return Nonzero on error, or 0 if the CRC was correct.
+ */
+static inline int section_check_crc(struct section *section)
+{
+ uint8_t * buf = (uint8_t *) section;
+ size_t len = section_length(section);
+ uint32_t crc;
+
+ /* the crc check has to be performed on the unswapped data */
+ bswap16(buf+1);
+ crc = crc32(CRC32_INIT, buf, len);
+ bswap16(buf+1);
+
+ /* the crc check includes the crc value,
+ * the result should therefore be zero.
+ */
+ if (crc)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * Decode an extended section structure.
+ *
+ * @param section Pointer to the processed section structure.
+ * @param check_crc If 1, the CRC of the section will also be checked.
+ * @return Pointer to the parsed section_ext structure, or NULL if invalid.
+ */
+static inline struct section_ext * section_ext_decode(struct section * section,
+ int check_crc)
+{
+ if (section->syntax_indicator == 0)
+ return NULL;
+
+ if (check_crc) {
+ if (section_check_crc(section))
+ return NULL;
+ }
+
+ bswap16((uint8_t *)section + sizeof(struct section));
+
+ return (struct section_ext *)section;
+}
+
+/**
+ * Encode an extended section structure for transmission.
+ *
+ * @param section Pointer to the section_ext structure.
+ * @param update_crc If 1, the CRC of the section will also be updated.
+ * @return Pointer to the encoded section_ext structure, or NULL if invalid.
+ */
+static inline struct section_ext * section_ext_encode(struct section_ext* section,
+ int update_crc)
+{
+ if (section->syntax_indicator == 0)
+ return NULL;
+
+ bswap16((uint8_t *)section + sizeof(struct section));
+
+ if (update_crc) {
+ uint8_t * buf = (uint8_t *) section;
+ int len = sizeof(struct section) + section->length;
+ uint32_t crc;
+
+ /* the crc has to be performed on the swapped data */
+ bswap16(buf+1);
+ crc = crc32(CRC32_INIT, buf, len-4);
+ bswap16(buf+1);
+
+ /* update the CRC */
+ *((uint32_t*) (buf+len-4)) = crc;
+ bswap32(buf+len-4);
+ }
+
+ return (struct section_ext *)section;
+}
+
+/**
+ * Reset a psi_table_state structure.
+ *
+ * @param tstate The structure to reset.
+ */
+static inline void psi_table_state_reset(struct psi_table_state *tstate)
+{
+ tstate->version_number = 0xff;
+}
+
+/**
+ * Check if a supplied section_ext is something we want to process.
+ *
+ * @param section The parsed section_ext structure.
+ * @param tstate The state structure for this PSI table.
+ * @return 0=> not useful. nonzero => useful.
+ */
+static inline int section_ext_useful(struct section_ext *section, struct psi_table_state *tstate)
+{
+ if ((section->version_number == tstate->version_number) && tstate->complete)
+ return 0;
+ if (section->version_number != tstate->version_number) {
+ if (section->section_number != 0)
+ return 0;
+
+ tstate->next_section_number = 0;
+ tstate->complete = 0;
+ tstate->version_number = section->version_number;
+ tstate->new_table = 1;
+ } else if (section->section_number == tstate->next_section_number) {
+ tstate->new_table = 0;
+ } else {
+ return 0;
+ }
+
+ tstate->next_section_number++;
+ if (section->last_section_number < tstate->next_section_number) {
+ tstate->complete = 1;
+ }
+
+ return 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif