diff --git a/libsi/Makefile b/libsi/Makefile new file mode 100644 index 00000000..cc387aee --- /dev/null +++ b/libsi/Makefile @@ -0,0 +1,57 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile 1.1 2003/11/22 17:56:12 kls Exp $ + +VDRDIR = ../../../.. + +### The C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -O2 -g -Wall -Woverloaded-virtual +AR = ar +ARFLAGS = ru +RANLIB = ranlib + + +### The directory environment: + + +INCLUDES += -I$(VDRDIR)/include -I.. + +DEFINES += + +LIBS += + +### The object files (add further files here): + +OBJS = util.o si.o section.o descriptor.o + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libsi.a + +libsi.a : $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) +# $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@ + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.a *.so *.tgz core* *~ + +dist: + tar cvzf libsi.tar.gz -C .. libsi/util.c libsi/si.c libsi/section.c libsi/descriptor.c \ + libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr.pl diff --git a/libsi/descriptor.c b/libsi/descriptor.c new file mode 100644 index 00000000..eabe0c9e --- /dev/null +++ b/libsi/descriptor.c @@ -0,0 +1,742 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include +#include "descriptor.h" + +namespace SI { + + + +void ShortEventDescriptor::Parse() { + unsigned int offset=0; + const descr_short_event *s; + data.setPointerAndOffset(s, offset); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; + name.setDataAndOffset(data+offset, s->event_name_length, offset); + const descr_short_event_mid *mid; + data.setPointerAndOffset(mid, offset); + text.setData(data+offset, mid->text_length); +} + + + + +int ExtendedEventDescriptor::getDescriptorNumber() { + return s->descriptor_number; +} + +int ExtendedEventDescriptor::getLastDescriptorNumber() { + return s->last_descriptor_number; +} + +void ExtendedEventDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; + itemLoop.setDataAndOffset(data+offset, s->length_of_items, offset); + const descr_extended_event_mid *mid; + data.setPointerAndOffset(mid, offset); + text.setData(data+offset, mid->text_length); +} + + + + +void ExtendedEventDescriptor::Item::Parse() { + unsigned int offset=0; + const item_extended_event *first; + data.setPointerAndOffset(first, offset); + itemDescription.setDataAndOffset(data+offset, first->item_description_length, offset); + const item_extended_event_mid *mid; + data.setPointerAndOffset(mid, offset); + item.setData(data+offset, mid->item_length); +} + + +int ExtendedEventDescriptors::getTextLength() { + int ret=0; + for (int i=0;itext.getLength()+1; //plus a blank + ExtendedEventDescriptor::Item item; + for (Loop::Iterator it; d->itemLoop.hasNext(it); ) { + item=d->itemLoop.getNext(it); + ret+=item.item.getLength(); + ret+=item.itemDescription.getLength(); + ret+=2; //the blanks + } + } + return ret; +} + +//is there a case where this function does not return the same as getTextLength? +int ExtendedEventDescriptors::getMaximumTextLength() { + int ret=0; + for (int i=0;itext.getLength()+1; //plus a blank + ret+=d->itemLoop.getLength(); + } + return ret; +} + +char *ExtendedEventDescriptors::getText() { + char *text=new char[getMaximumTextLength()]; + return getText(text); +} + +//appends the Strings of every Descriptor in the group +char *ExtendedEventDescriptors::getText(char *buffer) { + int index=0, len; + char tempbuf[256]; + for (int i=0;itext.getText(tempbuf); + len=strlen(tempbuf); + if (len) { + memcpy(buffer+index, tempbuf, len); + index+=len; + } + + ExtendedEventDescriptor::Item item; + for (Loop::Iterator it; d->itemLoop.hasNext(it); ) { + item=d->itemLoop.getNext(it); + + item.item.getText(tempbuf); + len=strlen(tempbuf); + if (len) { + memcpy(buffer+index, tempbuf, len); + index+=len; + } + + item.itemDescription.getText(tempbuf); + len=strlen(tempbuf); + if (len) { + memcpy(buffer+index, tempbuf, len); + index+=len; + } + } + } + buffer[index]='\0'; + return buffer; +} + + + + +int TimeShiftedEventDescriptor::getReferenceServiceId() const { + return HILO(s->reference_service_id); +} + +int TimeShiftedEventDescriptor::getReferenceEventId() const { + return HILO(s->reference_event_id); +} + +void TimeShiftedEventDescriptor::Parse() { + s=data.getData(); +} + + + + +void ContentDescriptor::Parse() { + //this descriptor is only a header and a loop + nibbleLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader)); +} + + + + +int ContentDescriptor::Nibble::getContentNibbleLevel1() const { + return s->content_nibble_level_1; +} + +int ContentDescriptor::Nibble::getContentNibbleLevel2() const { + return s->content_nibble_level_2; +} + +int ContentDescriptor::Nibble::getUserNibble1() const { + return s->user_nibble_1; +} + +int ContentDescriptor::Nibble::getUserNibble2() const { + return s->user_nibble_2; +} + +void ContentDescriptor::Nibble::Parse() { + s=data.getData(); +} + + + + +void ParentalRatingDescriptor::Parse() { + //this descriptor is only a header and a loop + ratingLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader)); +} + + +int ParentalRatingDescriptor::Rating::getRating() const { + return s->rating; +} + +void ParentalRatingDescriptor::Rating::Parse() { + s=data.getData(); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; +} + + + + +int CaDescriptor::getCaType() const { + return HILO(s->CA_type); +} + +int CaDescriptor::getCaPid() const { + return HILO(s->CA_PID); +} + +void CaDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + privateData.assign(data.getData(offset), getLength()-offset); +} + + + +int StreamIdentifierDescriptor::getComponentTag() const { + return s->component_tag; +} + +void StreamIdentifierDescriptor::Parse() { + s=data.getData(); +} + + + + +void NetworkNameDescriptor::Parse() { + name.setData(data+sizeof(descr_network_name), getLength()-sizeof(descr_network_name)); +} + + + + +void CaIdentifierDescriptor::Parse() { + identifiers.setData(data+sizeof(descr_ca_identifier), getLength()-sizeof(descr_ca_identifier)); +} + + + + + + +int CarouselIdentifierDescriptor::getCarouselId() const { + return (HILO(s->carousel_id_hi) << 16) | HILO(s->carousel_id_lo); +} + +int CarouselIdentifierDescriptor::getFormatId() const { + return s->FormatId; +} + +void CarouselIdentifierDescriptor::Parse() { + s=data.getData(); +} + + + + +void ServiceListDescriptor::Parse() { + serviceLoop.setData(data+sizeof(descr_service_list), getLength()-sizeof(descr_service_list)); +} + + + + +int ServiceListDescriptor::Service::getServiceId() const { + return HILO(s->service_id); +} + +int ServiceListDescriptor::Service::getServiceType() const { + return s->service_type; +} + +void ServiceListDescriptor::Service::Parse() { + s=data.getData(); +} + + + + +int SatelliteDeliverySystemDescriptor::getFrequency() const { + return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo); +} + +int SatelliteDeliverySystemDescriptor::getOrbitalPosition() const { + return HILO(s->orbital_position); +} + +int SatelliteDeliverySystemDescriptor::getWestEastFlag() const { + return s->west_east_flag; +} + +int SatelliteDeliverySystemDescriptor::getPolarization() const { + return s->polarization; +} + +int SatelliteDeliverySystemDescriptor::getModulation() const { + return s->modulation; +} + +int SatelliteDeliverySystemDescriptor::getSymbolRate() const { + return (HILO(s->symbol_rate_hi) << 12) | (s->symbol_rate_lo_1 << 4) | s->symbol_rate_lo_2; +} + +int SatelliteDeliverySystemDescriptor::getFecInner() const { + return s->fec_inner; +} + +void SatelliteDeliverySystemDescriptor::Parse() { + s=data.getData(); +} + + + + +int CableDeliverySystemDescriptor::getFrequency() const { + return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo); +} + +int CableDeliverySystemDescriptor::getFecOuter() const { + return s->fec_outer; +} + +int CableDeliverySystemDescriptor::getModulation() const { + return s->modulation; +} + +int CableDeliverySystemDescriptor::getSymbolRate() const { + return (HILO(s->symbol_rate_hi) << 12) | (s->symbol_rate_lo_1 << 4) | s->symbol_rate_lo_2; +} + +int CableDeliverySystemDescriptor::getFecInner() const { + return s->fec_inner; +} + +void CableDeliverySystemDescriptor::Parse() { + s=data.getData(); +} + + + + +int TerrestrialDeliverySystemDescriptor::getFrequency() const { + return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo); +} + +int TerrestrialDeliverySystemDescriptor::getBandwidth() const { + return s->bandwidth; +} + +int TerrestrialDeliverySystemDescriptor::getConstellation() const { + return s->constellation; +} + +int TerrestrialDeliverySystemDescriptor::getHierarchy() const { + return s->hierarchy; +} + +int TerrestrialDeliverySystemDescriptor::getCodeRateHP() const { + return s->code_rate_HP; +} + +int TerrestrialDeliverySystemDescriptor::getCodeRateLP() const { + return s->code_rate_LP; +} + +int TerrestrialDeliverySystemDescriptor::getGuardInterval() const { + return s->guard_interval; +} + +int TerrestrialDeliverySystemDescriptor::getTransmissionMode() const { + return s->transmission_mode; +} + +bool TerrestrialDeliverySystemDescriptor::getOtherFrequency() const { + return s->other_frequency_flag; +} + +void TerrestrialDeliverySystemDescriptor::Parse() { + s=data.getData(); +} + + + + +int ServiceDescriptor::getServiceType() const { + return s->service_type; +} + +void ServiceDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + providerName.setDataAndOffset(data+offset, s->provider_name_length, offset); + const descr_service_mid *mid; + data.setPointerAndOffset(mid, offset); + serviceName.setData(data+offset, mid->service_name_length); +} + +void NVODReferenceDescriptor::Parse() { + serviceLoop.setData(data+sizeof(descr_nvod_reference), getLength()-sizeof(descr_nvod_reference)); +} + + + + +int NVODReferenceDescriptor::Service::getTransportStream() const { + return HILO(s->transport_stream_id); +} + +int NVODReferenceDescriptor::Service::getOriginalNetworkId() const { + return HILO(s->original_network_id); +} + +int NVODReferenceDescriptor::Service::getServiceId() const { + return HILO(s->service_id); +} + +void NVODReferenceDescriptor::Service::Parse() { + s=data.getData(); +} + + + + +int TimeShiftedServiceDescriptor::getReferenceServiceId() const { + return HILO(s->reference_service_id); +} + +void TimeShiftedServiceDescriptor::Parse() { + s=data.getData(); +} + + + + +int ComponentDescriptor::getStreamContent() const { + return s->stream_content; +} + +int ComponentDescriptor::getComponentType() const { + return s->component_type; +} + +int ComponentDescriptor::getComponentTag() const { + return s->component_tag; +} + +void ComponentDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; + description.setData(data+offset, getLength()-offset); +} + + + + +void SubtitlingDescriptor::Parse() { + subtitlingLoop.setData(data+sizeof(descr_subtitling), getLength()-sizeof(descr_subtitling)); +} + + + + +int SubtitlingDescriptor::Subtitling::getSubtitlingType() const { + return s->subtitling_type; +} + +int SubtitlingDescriptor::Subtitling::getCompositionPageId() const { + return HILO(s->composition_page_id); +} + +int SubtitlingDescriptor::Subtitling::getAncillaryPageId() const { + return HILO(s->ancillary_page_id); +} + +void SubtitlingDescriptor::Subtitling::Parse() { + s=data.getData(); +} + + + + +int ServiceMoveDescriptor::getNewOriginalNetworkId() const { + return HILO(s->new_original_network_id); +} + +int ServiceMoveDescriptor::getNewTransportStreamId() const { + return HILO(s->new_transport_stream_id); +} + +int ServiceMoveDescriptor::getNewServiceId() const { + return HILO(s->new_service_id); +} + +void ServiceMoveDescriptor::Parse() { + s=data.getData(); +} + + + + +int FrequencyListDescriptor::getCodingType() const { + return s->coding_type; +} + +void FrequencyListDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + frequencies.setData(data+offset, getLength()-offset); +} + + + + +void ServiceIdentifierDescriptor::Parse() { + textualServiceIdentifier.setData(data+sizeof(descr_service_identifier), getLength()-sizeof(descr_service_identifier)); +} + + +void MultilingualNameDescriptor::Parse() { + nameLoop.setData(data+sizeof(descr_multilingual_network_name), getLength()-sizeof(descr_multilingual_network_name)); +} + + +void MultilingualNameDescriptor::Name::Parse() { + unsigned int offset=0; + const entry_multilingual_name *s; + data.setPointerAndOffset(s, offset); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; + name.setData(data+offset, s->text_length); +} + + +int MultilingualComponentDescriptor::getComponentTag() const { + return s->component_tag; +} + +void MultilingualComponentDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + nameLoop.setData(data+sizeof(descr_multilingual_component), getLength()-sizeof(descr_multilingual_component)); +} + + + + +void MultilingualServiceNameDescriptor::Parse() { + nameLoop.setData(data+sizeof(descr_multilingual_network_name), getLength()-sizeof(descr_multilingual_network_name)); +} + + + + +void MultilingualServiceNameDescriptor::Name::Parse() { + unsigned int offset=0; + const entry_multilingual_name *s; + data.setPointerAndOffset(s, offset); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; + providerName.setDataAndOffset(data+offset, s->text_length, offset); + const entry_multilingual_service_name_mid *mid; + data.setPointerAndOffset(mid, offset); + name.setData(data+offset, mid->service_name_length); +} + + + + +void ApplicationSignallingDescriptor::Parse() { + entryLoop.setData(data+sizeof(descr_application_signalling), getLength()-sizeof(descr_application_signalling)); +} + +int ApplicationSignallingDescriptor::ApplicationEntryDescriptor::getApplicationType() const { + return HILO(s->application_type); +} + +int ApplicationSignallingDescriptor::ApplicationEntryDescriptor::getAITVersionNumber() const { + return s->AIT_version_number; +} + +void ApplicationSignallingDescriptor::ApplicationEntryDescriptor::Parse() { + s=data.getData(); +} + + + + + +bool MHP_ApplicationDescriptor::isServiceBound() const { + return s->service_bound_flag; +} + +int MHP_ApplicationDescriptor::getVisibility() const { + return s->visibility; +} + +int MHP_ApplicationDescriptor::getApplicationPriority() const { + return s->application_priority; +} + + +void MHP_ApplicationDescriptor::Parse() { + unsigned int offset=0; + const descr_application *dapp; + data.setPointerAndOffset(dapp, offset); + profileLoop.setDataAndOffset(data+offset, dapp->application_profiles_length, offset); + data.setPointerAndOffset(s, offset); + transportProtocolLabels.setData(data+offset, getLength()-offset); +} + + +int MHP_ApplicationDescriptor::Profile::getApplicationProfile() const { + return HILO(s->application_profile); +} + +int MHP_ApplicationDescriptor::Profile::getVersionMajor() const { + return s->version_major; +} + +int MHP_ApplicationDescriptor::Profile::getVersionMinor() const { + return s->version_minor; +} + +int MHP_ApplicationDescriptor::Profile::getVersionMicro() const { + return s->version_micro; +} + +void MHP_ApplicationDescriptor::Profile::Parse() { + s=data.getData(); +} + + + +void MHP_ApplicationNameDescriptor::Parse() { + nameLoop.setData(data+sizeof(descr_application_name), getLength()-sizeof(descr_application_name)); +} + +void MHP_ApplicationNameDescriptor::NameEntry::Parse() { + const descr_application_name_entry *s; + s=data.getData(); + name.setData(data+sizeof(descr_application_name_entry), s->application_name_length); + languageCode[0]=s->lang_code1; + languageCode[1]=s->lang_code2; + languageCode[2]=s->lang_code3; +} + + + +int MHP_TransportProtocolDescriptor::getProtocolId() const { + return HILO(s->protocol_id); +} + +int MHP_TransportProtocolDescriptor::getProtocolLabel() const { + return s->transport_protocol_label; +} + +bool MHP_TransportProtocolDescriptor::isRemote() const { + return remote; +} + +int MHP_TransportProtocolDescriptor::getComponentTag() const { + return componentTag; +} + +void MHP_TransportProtocolDescriptor::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + if (getProtocolId() == ObjectCarousel) { + const transport_via_oc *oc; + data.setPointerAndOffset(oc, offset); + remote=oc->remote; + if (remote) { + const transport_via_oc_remote_end *rem; + data.setPointerAndOffset(rem, offset); + componentTag=rem->component_tag; + } else { + const transport_via_oc_end *rem; + data.setPointerAndOffset(rem, offset); + componentTag=rem->component_tag; + } + } else { //unimplemented + remote=false; + componentTag=-1; + } +} + + + +void MHP_DVBJApplicationDescriptor::Parse() { + applicationLoop.setData(data+sizeof(descr_dvbj_application), getLength()-sizeof(descr_dvbj_application)); +} + +void MHP_DVBJApplicationDescriptor::ApplicationEntry::Parse() { + const descr_dvbj_application_entry *entry=data.getData(); + parameter.setData(data+sizeof(descr_dvbj_application_entry), entry->parameter_length); +} + + +void MHP_DVBJApplicationLocationDescriptor::Parse() { + unsigned int offset=0; + const descr_dvbj_application_location *first; + data.setPointerAndOffset(first, offset); + baseDirectory.setDataAndOffset(data+offset, first->base_directory_length, offset); + const descr_dvbj_application_location_mid *mid; + data.setPointerAndOffset(mid, offset); + classPath.setDataAndOffset(data+offset, mid->classpath_extension_length, offset); + initialClass.setData(data+offset, getLength()-offset); +} + + +int MHP_ApplicationIconsDescriptor::getIconFlags() const { + return HILO(s->icon_flags); +} + +void MHP_ApplicationIconsDescriptor::Parse() { + unsigned int offset=0; + const descr_application_icons_descriptor *first; + data.setPointerAndOffset(first, offset); + iconLocator.setDataAndOffset(data+offset, first->icon_locator_length, offset); + data.setPointerAndOffset(s, offset); +} + +} //end of namespace + + diff --git a/libsi/descriptor.h b/libsi/descriptor.h new file mode 100644 index 00000000..24d95e8e --- /dev/null +++ b/libsi/descriptor.h @@ -0,0 +1,492 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef LIBSI_DESCRIPTOR_H +#define LIBSI_DESCRIPTOR_H + +#include "si.h" +#include "headers.h" + +namespace SI { + + +class ShortEventDescriptor : public Descriptor { +public: + char languageCode[3]; + String name; //name of the event + String text; //short description +protected: + virtual void Parse(); +}; + +class ExtendedEventDescriptor : public GroupDescriptor { +public: + class Item : public LoopElement { + public: + virtual int getLength() { return sizeof(item_extended_event)+sizeof(item_extended_event_mid)+item.getLength()+itemDescription.getLength(); } + String item; + String itemDescription; + protected: + virtual void Parse(); + }; + char languageCode[3]; + int getDescriptorNumber(); + int getLastDescriptorNumber(); + StructureLoop itemLoop; + String text; +protected: + virtual void Parse(); +private: + const descr_extended_event *s; +}; + +class ExtendedEventDescriptors : public DescriptorGroup { +public: + //don't use + int getTextLength(); + //really fast + int getMaximumTextLength(); + //same semantics as with SI::String + char *getText(); + //buffer must at least be getTextLength(), getMaximumTextLength() is a good choice + char *getText(char *buffer); +}; + + +class TimeShiftedEventDescriptor : public Descriptor { +public: + int getReferenceServiceId() const; + int getReferenceEventId() const; +protected: + virtual void Parse(); +private: + const descr_time_shifted_event *s; +}; + +class ContentDescriptor : public Descriptor { +public: + class Nibble : public LoopElement { + public: + virtual int getLength() { return sizeof(nibble_content); } + int getContentNibbleLevel1() const; + int getContentNibbleLevel2() const; + int getUserNibble1() const; + int getUserNibble2() const; + protected: + virtual void Parse(); + private: + const nibble_content *s; + }; + StructureLoop nibbleLoop; +protected: + virtual void Parse(); +}; + + +class ParentalRatingDescriptor : public Descriptor { +public: + class Rating : public LoopElement { + public: + char languageCode[3]; + int getRating() const; + virtual int getLength() { return sizeof(parental_rating); } + protected: + virtual void Parse(); + private: + const parental_rating *s; + }; + StructureLoop ratingLoop; +protected: + virtual void Parse(); +}; + + +class CaDescriptor : public Descriptor { +public: + int getCaType() const; + int getCaPid() const; + CharArray privateData; +protected: + virtual void Parse(); +private: + const descr_ca *s; +}; + +class StreamIdentifierDescriptor : public Descriptor { +public: + int getComponentTag() const; +protected: + virtual void Parse(); +private: + const descr_stream_identifier *s; +}; + +class NetworkNameDescriptor : public Descriptor { +public: + String name; +protected: + virtual void Parse(); +}; + +class CaIdentifierDescriptor : public Descriptor { +public: + TypeLoop identifiers; +protected: + virtual void Parse(); +}; + +class CarouselIdentifierDescriptor : public Descriptor { +public: + int getCarouselId() const; + int getFormatId() const; +protected: + virtual void Parse(); +private: + const descr_carousel_identifier *s; +}; + +class BouquetNameDescriptor : public NetworkNameDescriptor { +}; + +class ServiceListDescriptor : public Descriptor { +public: + class Service : public LoopElement { + public: + int getServiceId() const; + int getServiceType() const; + virtual int getLength() { return sizeof(descr_service_list_loop); } + protected: + virtual void Parse(); + private: + const descr_service_list_loop *s; + }; + StructureLoop serviceLoop; +protected: + virtual void Parse(); +}; + + +class SatelliteDeliverySystemDescriptor : public Descriptor { +public: + int getFrequency() const; + int getOrbitalPosition() const; + int getWestEastFlag() const; + int getPolarization() const; + int getModulation() const; + int getSymbolRate() const; + int getFecInner() const; +protected: + virtual void Parse(); +private: + const descr_satellite_delivery_system *s; +}; + +class CableDeliverySystemDescriptor : public Descriptor { +public: + int getFrequency() const; + int getFecOuter() const; + int getModulation() const; + int getSymbolRate() const; + int getFecInner() const; +protected: + virtual void Parse(); +private: + const descr_cable_delivery_system *s; +}; + +class TerrestrialDeliverySystemDescriptor : public Descriptor { +public: + int getFrequency() const; + int getBandwidth() const; + int getConstellation() const; + int getHierarchy() const; + int getCodeRateHP() const; + int getCodeRateLP() const; + int getGuardInterval() const; + int getTransmissionMode() const; + bool getOtherFrequency() const; +protected: + virtual void Parse(); +private: + const descr_terrestrial_delivery *s; +}; + +class ServiceDescriptor : public Descriptor { +public: + int getServiceType() const; + String serviceName; + String providerName; +protected: + virtual void Parse(); +private: + const descr_service *s; +}; + +class NVODReferenceDescriptor : public Descriptor { +public: + class Service : public LoopElement { + public: + int getTransportStream() const; + int getOriginalNetworkId() const; + int getServiceId() const; + virtual int getLength() { return sizeof(item_nvod_reference); } + protected: + virtual void Parse(); + private: + const item_nvod_reference *s; + }; + StructureLoop serviceLoop; +protected: + virtual void Parse(); +}; + + +class TimeShiftedServiceDescriptor : public Descriptor { +public: + int getReferenceServiceId() const; +protected: + virtual void Parse(); +private: + const descr_time_shifted_service *s; +}; + +class ComponentDescriptor : public Descriptor { +public: + int getStreamContent() const; + int getComponentType() const; + int getComponentTag() const; + char languageCode[3]; + String description; +protected: + virtual void Parse(); +private: + const descr_component *s; +}; + +class SubtitlingDescriptor : public Descriptor { +public: + class Subtitling : public Descriptor { + public: + int getSubtitlingType() const; + int getCompositionPageId() const; + int getAncillaryPageId() const; + virtual int getLength() { return sizeof(item_nvod_reference); } + protected: + virtual void Parse(); + private: + const item_subtitling *s; + }; + StructureLoop subtitlingLoop; +protected: + virtual void Parse(); +}; + + +class ServiceMoveDescriptor : public Descriptor { +public: + int getNewOriginalNetworkId() const; + int getNewTransportStreamId() const; + int getNewServiceId() const; +protected: + virtual void Parse(); +private: + const descr_service_move *s; +}; + +class FrequencyListDescriptor : public Descriptor { +public: + int getCodingType() const; + TypeLoop frequencies; +protected: + virtual void Parse(); +private: + const descr_frequency_list *s; +}; + +class ServiceIdentifierDescriptor : public Descriptor { +public: + String textualServiceIdentifier; +protected: + virtual void Parse(); +}; + +//abstract base class +class MultilingualNameDescriptor : public Descriptor { +public: + class Name : public LoopElement { + public: + char languageCode[3]; + String name; + virtual int getLength() { return sizeof(entry_multilingual_name)+name.getLength(); } + protected: + virtual void Parse(); + }; + StructureLoop nameLoop; +protected: + virtual void Parse(); +}; + +class MultilingualNetworkNameDescriptor : public MultilingualNameDescriptor { + //inherits nameLoop from MultilingualNameDescriptor +}; + +class MultilingualBouquetNameDescriptor : public MultilingualNameDescriptor { + //inherits nameLoop from MultilingualNameDescriptor +}; + +class MultilingualComponentDescriptor : public MultilingualNameDescriptor { +public: + int getComponentTag() const; + //inherits nameLoop from MultilingualNameDescriptor +protected: + virtual void Parse(); +private: + const descr_multilingual_component *s; +}; + +class MultilingualServiceNameDescriptor : public Descriptor { +public: + class Name : public MultilingualNameDescriptor::Name { + public: + virtual int getLength() { return sizeof(entry_multilingual_name)+providerName.getLength()+sizeof(entry_multilingual_service_name_mid)+name.getLength(); } + String providerName; + //inherits name, meaning: service name; + protected: + virtual void Parse(); + }; + StructureLoop nameLoop; +protected: + virtual void Parse(); +}; + + + + + +//a descriptor currently unimplemented in this library +class UnimplementedDescriptor : public Descriptor { +protected: + virtual void Parse() {} +}; + +class ApplicationSignallingDescriptor : public Descriptor { +public: + class ApplicationEntryDescriptor : public LoopElement { + public: + virtual int getLength() { return sizeof(application_signalling_entry); } + int getApplicationType() const; + int getAITVersionNumber() const; + protected: + virtual void Parse(); + private: + const application_signalling_entry *s; + }; + StructureLoop entryLoop; +protected: + virtual void Parse(); +}; + +class MHP_ApplicationDescriptor : public Descriptor { +public: + class Profile : public LoopElement { + public: + virtual int getLength() { return sizeof(application_profile_entry); } + int getApplicationProfile() const; + int getVersionMajor() const; + int getVersionMinor() const; + int getVersionMicro() const; + private: + const application_profile_entry *s; + protected: + virtual void Parse(); + }; + StructureLoop profileLoop; + bool isServiceBound() const; + int getVisibility() const; + int getApplicationPriority() const; + TypeLoop transportProtocolLabels; +private: + const descr_application_end *s; +protected: + virtual void Parse(); +}; + + +class MHP_ApplicationNameDescriptor : public Descriptor { +public: + class NameEntry : public LoopElement { + public: + virtual int getLength() { return sizeof(descr_application_name_entry)+name.getLength(); } + char languageCode[3]; + String name; + protected: + virtual void Parse(); + }; + StructureLoop nameLoop; +protected: + virtual void Parse(); +}; + + +class MHP_TransportProtocolDescriptor : public Descriptor { +public: + enum Protocol { ObjectCarousel = 0x01, IPviaDVB = 0x02, HTTPoverInteractionChannel = 0x03 }; + int getProtocolId() const; + int getProtocolLabel() const; + bool isRemote() const; + int getComponentTag() const; +protected: + virtual void Parse(); +private: + const descr_transport_protocol *s; + bool remote; + int componentTag; +}; + +class MHP_DVBJApplicationDescriptor : public Descriptor { +public: + class ApplicationEntry : public LoopElement { + public: + virtual int getLength() { return sizeof(descr_dvbj_application_entry)+parameter.getLength(); } + String parameter; + protected: + virtual void Parse(); + }; + StructureLoop applicationLoop; +protected: + virtual void Parse(); +}; + + +class MHP_DVBJApplicationLocationDescriptor : public Descriptor { +public: + String baseDirectory; + String classPath; + String initialClass; +protected: + virtual void Parse(); +}; + +class MHP_ApplicationIconsDescriptor : public Descriptor { +public: + String iconLocator; + int getIconFlags() const; +protected: + virtual void Parse(); +private: + const descr_application_icons_descriptor_end *s; +}; + + + +} //end of namespace + +#endif //LIBSI_TABLE_H + diff --git a/libsi/gendescr.pl b/libsi/gendescr.pl new file mode 100755 index 00000000..901bb834 --- /dev/null +++ b/libsi/gendescr.pl @@ -0,0 +1,82 @@ +#!/usr/bin/perl + +print "Name (ohne ...Descriptor):"; +$name=; +$name =~ s/\n$//; +$inner = ($name =~ s/ä$//); +$name .= "Descriptor" unless ($inner); + +print "Struct:"; +$struct=; +$struct =~ s/\n$//; + + +mm: +$index=0; +$which=1; +print "Variablen:"; +while ( ) { + if (/ä/) { + goto vv; + } elsif (/ü/) { + $which=1; + next; + } + $eingabe=$_; + $eingabe =~ s/(.{75,120} )/\1\n/g; + $eingabe =~ s/\n$//; + if ($which) { + $members[$index]=$eingabe; + } else { + $members_comments[$index]=$eingabe; + $index++; + print "Jep!\n"; + } + $which= (! $which); +} + +vv: +$filename_h="tempdescr.h"; +$filename_c="tempdescr.c"; +schreib(); + +sub schreib { + print "Danke.\n"; + open(OUTPUT_H, ">>".$filename_h) or die "Could not open file!!"; + open(OUTPUT_C, ">>".$filename_c) or die "Could not open file!!"; + + if ($inner) { + $offset=" "; + } else { + $offset=""; + } + print(OUTPUT_H $offset."class ".$name); + if ($inner) { + print(OUTPUT_H " : public LoopElement {\n".$offset."public:"); + } else { + print(OUTPUT_H " : public Descriptor {\n".$offset."public:"); + } + #for ($i=0; $i<=$#vars;$i++) { + # print (OUTPUT "/*\n".$vars_comments[$i]." */\n".$vars[$i].";\n\n\n"); + #} + for ($i=0; $i<=$#members;$i++) { + print (OUTPUT_H "\n".$offset." int get".$members[$i]."() const;"); + } + print(OUTPUT_H "\n".$offset."virtual int getLength() { return sizeof(".$struct."); }") if ($inner); + + print(OUTPUT_H "\n".$offset."protected:\n".$offset." virtual void Parse();"); + print(OUTPUT_H "\n".$offset."private:\n".$offset." const ".$struct." *s;") if ($struct ne ""); + print(OUTPUT_H "\n".$offset."};\n\n"); + for ($i=0; $i<=$#members_comments;$i++) { + print (OUTPUT_C "int ".$name."::get".$members[$i]."() const {\n"); + if ($members_comments[$i] =~ /^(.+)_hi$/) { + $varbase=$1; + print (OUTPUT_C " return HILO(s->".$varbase.");\n}\n\n"); + } else { + print (OUTPUT_C " return s->".$members_comments[$i].";\n}\n\n"); + } + } + print (OUTPUT_C "void ".$name."::Parse() {\n}\n\n"); + print (OUTPUT_C "\n\n\n"); + exit; +} diff --git a/libsi/headers.h b/libsi/headers.h new file mode 100644 index 00000000..e8bef639 --- /dev/null +++ b/libsi/headers.h @@ -0,0 +1,1802 @@ +/*************************************************************************** + * * + * (C) 2001-03 Rolf Hakenes , under the * + * GNU GPL with contribution of Oleg Assovski, * + * www.satmania.com * + * Adapted and extended by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef LIBSI_HEADERS_H +#define LIBSI_HEADERS_H + +#include + +namespace SI { + +typedef unsigned char u_char; + +struct SectionHeader { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; +}; + +struct ExtendedSectionHeader { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char table_id_extension_hi :8; + u_char table_id_extension_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +}; + +struct DescriptorHeader { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + +/* + * + * ETSI ISO/IEC 13818-1 specifies SI which is referred to as PSI. The PSI + * data provides information to enable automatic configuration of the + * receiver to demultiplex and decode the various streams of programs + * within the multiplex. The PSI data is structured as four types of table. + * The tables are transmitted in sections. + * + * 1) Program Association Table (PAT): + * + * - for each service in the multiplex, the PAT indicates the location + * (the Packet Identifier (PID) values of the Transport Stream (TS) + * packets) of the corresponding Program Map Table (PMT). + * It also gives the location of the Network Information Table (NIT). + * + */ + +#define PAT_LEN 8 + +struct pat { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +}; + +#define PAT_PROG_LEN 4 + +struct pat_prog { + u_char program_number_hi :8; + u_char program_number_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char network_pid_hi :5; +#else + u_char network_pid_hi :5; + u_char :3; +#endif + u_char network_pid_lo :8; + /* or program_map_pid (if prog_num=0)*/ +}; + +/* + * + * 2) Conditional Access Table (CAT): + * + * - the CAT provides information on the CA systems used in the + * multiplex; the information is private and dependent on the CA + * system, but includes the location of the EMM stream, when + * applicable. + * + */ +#define CAT_LEN 8 + +struct cat { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char reserved_1 :8; + u_char reserved_2 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +}; + +/* + * + * 3) Program Map Table (PMT): + * + * - the PMT identifies and indicates the locations of the streams that + * make up each service, and the location of the Program Clock + * Reference fields for a service. + * + */ + +#define PMT_LEN 12 + +struct pmt { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char program_number_hi :8; + u_char program_number_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char PCR_PID_hi :5; +#else + u_char PCR_PID_hi :5; + u_char :3; +#endif + u_char PCR_PID_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char program_info_length_hi :4; +#else + u_char program_info_length_hi :4; + u_char :4; +#endif + u_char program_info_length_lo :8; + //descriptors +}; + +#define PMT_INFO_LEN 5 + +struct pmt_info { + u_char stream_type :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char elementary_PID_hi :5; +#else + u_char elementary_PID_hi :5; + u_char :3; +#endif + u_char elementary_PID_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char ES_info_length_hi :4; +#else + u_char ES_info_length_hi :4; + u_char :4; +#endif + u_char ES_info_length_lo :8; + // descriptors +}; + +/* + * + * 4) Network Information Table (NIT): + * + * - the NIT is intended to provide information about the physical + * network. The syntax and semantics of the NIT are defined in + * ETSI EN 300 468. + * + */ + +#define NIT_LEN 10 + +struct nit { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char network_id_hi :8; + u_char network_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char network_descriptor_length_hi :4; +#else + u_char network_descriptor_length_hi :4; + u_char :4; +#endif + u_char network_descriptor_length_lo :8; + /* descriptors */ +}; + +#define SIZE_NIT_MID 2 + +struct nit_mid { // after descriptors +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_stream_loop_length_hi :4; +#else + u_char transport_stream_loop_length_hi :4; + u_char :4; +#endif + u_char transport_stream_loop_length_lo :8; +}; + +#define SIZE_NIT_END 4 + +struct nit_end { + long CRC; +}; + +#define NIT_TS_LEN 6 + +struct ni_ts { + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_descriptors_length_hi :4; +#else + u_char transport_descriptors_length_hi :4; + u_char :4; +#endif + u_char transport_descriptors_length_lo :8; + /* descriptors */ +}; + +/* + * + * In addition to the PSI, data is needed to provide identification of + * services and events for the user. In contrast with the PAT, CAT, and + * PMT of the PSI, which give information only for the multiplex in which + * they are contained (the actual multiplex), the additional information + * defined within the present document can also provide information on + * services and events carried by different multiplexes, and even on other + * networks. This data is structured as nine tables: + * + * 1) Bouquet Association Table (BAT): + * + * - the BAT provides information regarding bouquets. As well as giving + * the name of the bouquet, it provides a list of services for each + * bouquet. + * + */ +/* SEE NIT (It has the same structure but has different allowed descriptors) */ +/* + * + * 2) Service Description Table (SDT): + * + * - the SDT contains data describing the services in the system e.g. + * names of services, the service provider, etc. + * + */ + +#define SDT_LEN 11 + +struct sdt { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char :8; +}; + +#define GetSDTTransportStreamId(x) (HILO(((sdt_t *) x)->transport_stream_id)) +#define GetSDTOriginalNetworkId(x) (HILO(((sdt_t *) x)->original_network_id)) + +#define SDT_DESCR_LEN 5 + +struct sdt_descr { + u_char service_id_hi :8; + u_char service_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :6; + u_char eit_schedule_flag :1; + u_char eit_present_following_flag :1; + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char eit_present_following_flag :1; + u_char eit_schedule_flag :1; + u_char :6; + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo :8; +}; + +/* + * + * 3) Event Information Table (EIT): + * + * - the EIT contains data concerning events or programmes such as event + * name, start time, duration, etc.; - the use of different descriptors + * allows the transmission of different kinds of event information e.g. + * for different service types. + * + */ + +#define EIT_LEN 14 + +struct eit { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char segment_last_section_number :8; + u_char segment_last_table_id :8; +}; + +#define EIT_EVENT_LEN 12 + +struct eit_event { + u_char event_id_hi :8; + u_char event_id_lo :8; + u_char mjd_hi :8; + u_char mjd_lo :8; + u_char start_time_h :8; + u_char start_time_m :8; + u_char start_time_s :8; + u_char duration_h :8; + u_char duration_m :8; + u_char duration_s :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo :8; +}; + +/* + * + * 4) Running Status Table (RST): + * + * - the RST gives the status of an event (running/not running). The RST + * updates this information and allows timely automatic switching to + * events. + * + */ + +struct rst { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; +}; + +struct rst_info { + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; + u_char event_id_hi :8; + u_char event_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :5; + u_char running_status :3; +#else + u_char running_status :3; + u_char :5; +#endif +}; + +/* + * + * 5) Time and Date Table (TDT): + * + * - the TDT gives information relating to the present time and date. + * This information is given in a separate table due to the frequent + * updating of this information. + * + */ + +#define TDT_LEN 8 + +struct tdt { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char utc_mjd_hi :8; + u_char utc_mjd_lo :8; + u_char utc_time_h :8; + u_char utc_time_m :8; + u_char utc_time_s :8; +}; + +/* + * + * 6) Time Offset Table (TOT): + * + * - the TOT gives information relating to the present time and date and + * local time offset. This information is given in a separate table due + * to the frequent updating of the time information. + * + */ +#define TOT_LEN 10 + +struct tot { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char utc_mjd_hi :8; + u_char utc_mjd_lo :8; + u_char utc_time_h :8; + u_char utc_time_m :8; + u_char utc_time_s :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char descriptors_loop_length_hi :4; +#else + u_char descriptors_loop_length_hi :4; + u_char :4; +#endif + u_char descriptors_loop_length_lo :8; +}; + + +/* + * + * 7) Stuffing Table (ST): + * + * - the ST is used to invalidate existing sections, for example at + * delivery system boundaries. + * + */ + /* TO BE DONE */ +/* + * + * 8) Selection Information Table (SIT): + * + * - the SIT is used only in "partial" (i.e. recorded) bitstreams. It + * carries a summary of the SI information required to describe the + * streams in the partial bitstream. + * + */ + /* TO BE DONE */ +/* + * + * 9) Discontinuity Information Table (DIT): + * + * - the DIT is used only in "partial" (i.e. recorded) bitstreams. + * It is inserted where the SI information in the partial bitstream may + * be discontinuous. Where applicable the use of descriptors allows a + * flexible approach to the organization of the tables and allows for + * future compatible extensions. + * + */ + /* TO BE DONE */ + +/* + * + * 3) Application Information Table (AIT): + * + * - the AIT contains data concerning MHP application broadcast by a service. + * + */ + +#define AIT_LEN 10 + +struct ait { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char application_type_hi :8; + u_char application_type_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char common_descriptors_length_hi :4; +#else + u_char common_descriptors_length_hi :4; + u_char :4; +#endif + u_char common_descriptors_length_lo :8; +}; + +#define SIZE_AIT_MID 2 + +struct ait_mid { // after descriptors +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char application_loop_length_hi :4; +#else + u_char application_loop_length_hi :4; + u_char :4; +#endif + u_char application_loop_length_lo :8; +}; + +#define SIZE_AIT_END 4 + +struct ait_end { + long CRC; +}; + +#define AIT_APP_LEN 9 + +struct ait_app { + //how to deal with 32 bit fields? + + u_char organisation_id_hi_hi :8; + u_char organisation_id_hi_lo :8; + u_char organisation_id_lo_hi :8; + u_char organisation_id_lo_lo :8; + + //long organisation_id :32; + u_char application_id_hi :8; + u_char application_id_lo :8; + u_char application_control_code :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char application_descriptors_length_hi :4; +#else + u_char application_descriptors_length_hi :4; + u_char :4; +#endif + u_char application_descriptors_length_lo :8; + /* descriptors */ +}; + + + +/* + * + * The following describes the different descriptors that can be used within + * the SI. + * + * The following semantics apply to all the descriptors defined in this + * subclause: + * + * descriptor_tag: The descriptor tag is an 8-bit field which identifies + * each descriptor. Those values with MPEG-2 normative + * meaning are described in ISO/IEC 13818-1. The values of + * descriptor_tag are defined in 'libsi.h' + * descriptor_length: The descriptor length is an 8-bit field specifying the + * total number of bytes of the data portion of the + * descriptor following the byte defining the value of + * this field. + * + */ + +#define DESCR_GEN_LEN 2 +struct descr_gen { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define GetDescriptorTag(x) (((descr_gen_t *) x)->descriptor_tag) +#define GetDescriptorLength(x) (((descr_gen_t *) x)->descriptor_length+DESCR_GEN_LEN) + + +/* 0x09 ca_descriptor */ + +#define DESCR_CA_LEN 6 +struct descr_ca { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char CA_type_hi :8; + u_char CA_type_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char reserved :3; + u_char CA_PID_hi :5; +#else + u_char CA_PID_hi :5; + u_char reserved :3; +#endif + u_char CA_PID_lo :8; +}; + + +/* 0x0A iso_639_language_descriptor */ + +#define DESCR_ISO_639_LANGUAGE_LEN 5 +struct descr_iso_639_language { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +}; + + + +/* 0x13 carousel_identifier_descriptor */ + +#define DESCR_CAROUSEL_IDENTIFIER_LEN 7 +struct descr_carousel_identifier { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char carousel_id_hi_hi :8; + u_char carousel_id_hi_lo :8; + u_char carousel_id_lo_hi :8; + u_char carousel_id_lo_lo :8; + u_char FormatId :8; + /* FormatSpecifier follows */ +}; + + + +/* 0x40 network_name_descriptor */ + +#define DESCR_NETWORK_NAME_LEN 2 +struct descr_network_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + + +/* 0x41 service_list_descriptor */ + +#define DESCR_SERVICE_LIST_LEN 2 +struct descr_service_list { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define DESCR_SERVICE_LIST_LOOP_LEN 3 +struct descr_service_list_loop { + u_char service_id_hi :8; + u_char service_id_lo :8; + u_char service_type :8; +}; + + + +/* 0x42 stuffing_descriptor */ + +#define DESCR_STUFFING_LEN XX +struct descr_stuffing { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x43 satellite_delivery_system_descriptor */ + +#define DESCR_SATELLITE_DELIVERY_SYSTEM_LEN 13 +struct descr_satellite_delivery_system { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char frequency_hi_hi :8; + u_char frequency_hi_lo :8; + u_char frequency_lo_hi :8; + u_char frequency_lo_lo :8; + u_char orbital_position_hi :8; + u_char orbital_position_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char west_east_flag :1; + u_char polarization :2; + u_char modulation :5; +#else + u_char modulation :5; + u_char polarization :2; + u_char west_east_flag :1; +#endif + u_char symbol_rate_hi_hi :8; + u_char symbol_rate_hi_lo :8; + u_char symbol_rate_lo_1 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate_lo_2 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate_lo_2 :4; +#endif +}; + + + +/* 0x44 cable_delivery_system_descriptor */ + +#define DESCR_CABLE_DELIVERY_SYSTEM_LEN 13 +struct descr_cable_delivery_system { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char frequency_hi_hi :8; + u_char frequency_hi_lo :8; + u_char frequency_lo_hi :8; + u_char frequency_lo_lo :8; + u_char reserved1 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char reserved2 :4; + u_char fec_outer :4; +#else + u_char fec_outer :4; + u_char reserved2 :4; +#endif + u_char modulation :8; + u_char symbol_rate_hi_hi :8; + u_char symbol_rate_hi_lo :8; + u_char symbol_rate_lo_1 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate_lo_2 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate_lo_2 :4; +#endif +}; + + + +/* 0x45 vbi_data_descriptor */ + +#define DESCR_VBI_DATA_LEN XX +struct descr_vbi_data { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x46 vbi_teletext_descriptor */ + +#define DESCR_VBI_TELETEXT_LEN XX +struct descr_vbi_teletext { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x47 bouquet_name_descriptor */ + +#define DESCR_BOUQUET_NAME_LEN 2 +struct descr_bouquet_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + + +/* 0x48 service_descriptor */ + +#define DESCR_SERVICE_LEN 4 +struct descr_service { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char service_type :8; + u_char provider_name_length :8; +}; + +struct descr_service_mid { + u_char service_name_length :8; +}; + + + +/* 0x49 country_availability_descriptor */ + +#define DESCR_COUNTRY_AVAILABILITY_LEN 3 +struct descr_country_availability { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char country_availability_flag :1; + u_char reserved :7; +#else + u_char reserved :7; + u_char country_availability_flag :1; +#endif +}; + + + +/* 0x4A linkage_descriptor */ + +#define DESCR_LINKAGE_LEN 9 +struct descr_linkage { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; + u_char linkage_type :8; +}; + + + +/* 0x4B nvod_reference_descriptor */ + +#define DESCR_NVOD_REFERENCE_LEN 2 +struct descr_nvod_reference { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define ITEM_NVOD_REFERENCE_LEN 6 +struct item_nvod_reference { + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; +}; + + + + +/* 0x4C time_shifted_service_descriptor */ + +#define DESCR_TIME_SHIFTED_SERVICE_LEN 4 +struct descr_time_shifted_service { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char reference_service_id_hi :8; + u_char reference_service_id_lo :8; +}; + + + +/* 0x4D short_event_descriptor */ + +#define DESCR_SHORT_EVENT_LEN 6 +struct descr_short_event { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char event_name_length :8; +}; + +struct descr_short_event_mid { + u_char text_length :8; +}; + + + +/* 0x4E extended_event_descriptor */ + +#define DESCR_EXTENDED_EVENT_LEN 7 +struct descr_extended_event { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +#if BYTE_ORDER == BIG_ENDIAN + u_char descriptor_number :4; + u_char last_descriptor_number :4; +#else + u_char last_descriptor_number :4; + u_char descriptor_number :4; +#endif + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char length_of_items :8; +}; + +struct descr_extended_event_mid { + u_char text_length :8; +}; + + +#define ITEM_EXTENDED_EVENT_LEN 1 +struct item_extended_event { + u_char item_description_length :8; +}; + +struct item_extended_event_mid { + u_char item_length :8; +}; + + + +/* 0x4F time_shifted_event_descriptor */ + +#define DESCR_TIME_SHIFTED_EVENT_LEN 6 +struct descr_time_shifted_event { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char reference_service_id_hi :8; + u_char reference_service_id_lo :8; + u_char reference_event_id_hi :8; + u_char reference_event_id_lo :8; +}; + + + +/* 0x50 component_descriptor */ + +#define DESCR_COMPONENT_LEN 8 +struct descr_component { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char reserved :4; + u_char stream_content :4; +#else + u_char stream_content :4; + u_char reserved :4; +#endif + u_char component_type :8; + u_char component_tag :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +}; + + + +/* 0x51 mosaic_descriptor */ + +#define DESCR_MOSAIC_LEN XX +struct descr_mosaic { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x52 stream_identifier_descriptor */ + +#define DESCR_STREAM_IDENTIFIER_LEN 3 +struct descr_stream_identifier { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char component_tag :8; +}; + + + +/* 0x53 ca_identifier_descriptor */ + +#define DESCR_CA_IDENTIFIER_LEN 2 +struct descr_ca_identifier { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + + +/* 0x54 content_descriptor */ + +#define DESCR_CONTENT_LEN 2 +struct descr_content { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +struct nibble_content { +#if BYTE_ORDER == BIG_ENDIAN + u_char content_nibble_level_1 :4; + u_char content_nibble_level_2 :4; +#else + u_char content_nibble_level_2 :4; + u_char content_nibble_level_1 :4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char user_nibble_1 :4; + u_char user_nibble_2 :4; +#else + u_char user_nibble_2 :4; + u_char user_nibble_1 :4; +#endif +}; + + + +/* 0x55 parental_rating_descriptor */ + +#define DESCR_PARENTAL_RATING_LEN 2 +struct descr_parental_rating { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define PARENTAL_RATING_LEN 4 +struct parental_rating { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char rating :8; +}; + + + +/* 0x56 teletext_descriptor */ + +#define DESCR_TELETEXT_LEN 2 +struct descr_teletext { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define ITEM_TELETEXT_LEN 5 +struct item_teletext { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char type :5; + u_char magazine_number :3; +#else + u_char magazine_number :3; + u_char type :5; +#endif + u_char page_number :8; +}; + + + +/* 0x57 telephone_descriptor */ + +#define DESCR_TELEPHONE_LEN XX +struct descr_telephone { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x58 local_time_offset_descriptor */ + +#define DESCR_LOCAL_TIME_OFFSET_LEN 2 +struct descr_local_time_offset { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define LOCAL_TIME_OFFSET_ENTRY_LEN 15 +struct local_time_offset_entry { + u_char country_code1 :8; + u_char country_code2 :8; + u_char country_code3 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char country_region_id :6; + u_char :1; + u_char local_time_offset_polarity :1; +#else + u_char local_time_offset_polarity :1; + u_char :1; + u_char country_region_id :6; +#endif + u_char local_time_offset_h :8; + u_char local_time_offset_m :8; + u_char time_of_change_mjd_hi :8; + u_char time_of_change_mjd_lo :8; + u_char time_of_change_time_h :8; + u_char time_of_change_time_m :8; + u_char time_of_change_time_s :8; + u_char next_time_offset_h :8; + u_char next_time_offset_m :8; +}; + + + +/* 0x59 subtitling_descriptor */ + +#define DESCR_SUBTITLING_LEN 2 +struct descr_subtitling { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define ITEM_SUBTITLING_LEN 8 +struct item_subtitling { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char subtitling_type :8; + u_char composition_page_id_hi :8; + u_char composition_page_id_lo :8; + u_char ancillary_page_id_hi :8; + u_char ancillary_page_id_lo :8; +}; + + + +/* 0x5A terrestrial_delivery_system_descriptor */ + +#define DESCR_TERRESTRIAL_DELIVERY_SYSTEM_LEN XX +struct descr_terrestrial_delivery { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char frequency_hi_hi :8; + u_char frequency_hi_lo :8; + u_char frequency_lo_hi :8; + u_char frequency_lo_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char bandwidth :3; + u_char reserved1 :5; +#else + u_char reserved1 :5; + u_char bandwidth :3; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char constellation :2; + u_char hierarchy :3; + u_char code_rate_HP :3; +#else + u_char code_rate_HP :3; + u_char hierarchy :3; + u_char constellation :2; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char code_rate_LP :3; + u_char guard_interval :2; + u_char transmission_mode :2; + u_char other_frequency_flag :1; +#else + u_char other_frequency_flag :1; + u_char transmission_mode :2; + u_char guard_interval :2; + u_char code_rate_LP :3; +#endif + u_char reserver2 :8; + u_char reserver3 :8; + u_char reserver4 :8; + u_char reserver5 :8; +}; + + + +/* 0x5B multilingual_network_name_descriptor */ + +#define DESCR_MULTILINGUAL_NETWORK_NAME_LEN XX +struct descr_multilingual_network_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + +struct entry_multilingual_name { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char text_length :8; +}; + + + +/* 0x5C multilingual_bouquet_name_descriptor */ + +#define DESCR_MULTILINGUAL_BOUQUET_NAME_LEN XX +struct descr_multilingual_bouquet_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + + +/* 0x5D multilingual_service_name_descriptor */ + +#define DESCR_MULTILINGUAL_SERVICE_NAME_LEN XX +struct descr_multilingual_service_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + +struct entry_multilingual_service_name_mid { + u_char service_name_length :8; +}; + + +/* 0x5E multilingual_component_descriptor */ + +#define DESCR_MULTILINGUAL_COMPONENT_LEN XX +struct descr_multilingual_component { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char component_tag :8; +}; + + + +/* 0x5F private_data_specifier_descriptor */ + +#define DESCR_PRIVATE_DATA_SPECIFIER_LEN XX +struct descr_private_data_specifier { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x60 service_move_descriptor */ + +#define DESCR_SERVICE_MOVE_LEN XX +struct descr_service_move { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char new_original_network_id_hi :8; + u_char new_original_network_id_lo :8; + u_char new_transport_stream_id_hi :8; + u_char new_transport_stream_id_lo :8; + u_char new_service_id_hi :8; + u_char new_service_id_lo :8; +}; + + + +/* 0x61 short_smoothing_buffer_descriptor */ + +#define DESCR_SHORT_SMOOTHING_BUFFER_LEN XX +struct descr_short_smoothing_buffer { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x62 frequency_list_descriptor */ + +#define DESCR_FREQUENCY_LIST_LEN XX +struct descr_frequency_list { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :6; + u_char coding_type :2; +#else + u_char coding_type :2; + u_char :6; +#endif +}; + + + +/* 0x63 partial_transport_stream_descriptor */ + +#define DESCR_PARTIAL_TRANSPORT_STREAM_LEN XX +struct descr_partial_transport_stream { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x64 data_broadcast_descriptor */ + +#define DESCR_DATA_BROADCAST_LEN XX +struct descr_data_broadcast { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x65 ca_system_descriptor */ + +#define DESCR_CA_SYSTEM_LEN XX +struct descr_ca_system { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x66 data_broadcast_id_descriptor */ + +#define DESCR_DATA_BROADCAST_ID_LEN XX +struct descr_data_broadcast_id { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x67 transport_stream_descriptor */ + +#define DESCR_TRANSPORT_STREAM_LEN XX +struct descr_transport_stream { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x68 dsng_descriptor */ + +#define DESCR_DSNG_LEN XX +struct descr_dsng { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x69 pdc_descriptor */ + +#define DESCR_PDC_LEN XX +struct descr_pdc { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x6A ac3_descriptor */ + +#define DESCR_AC3_LEN 3 +struct descr_ac3 { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char ac3_type_flag :1; + u_char bsid_flag :1; + u_char mainid_flag :1; + u_char asvc_flag :1; + u_char reserved :4; +#else + u_char reserved :4; + u_char asvc_flag :1; + u_char mainid_flag :1; + u_char bsid_flag :1; + u_char ac3_type_flag :1; +#endif + u_char ac3_type :8; + u_char bsid :8; + u_char mainid :8; + u_char asvc :8; +}; + + + +/* 0x6B ancillary_data_descriptor */ + +#define DESCR_ANCILLARY_DATA_LEN 3 +struct descr_ancillary_data { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char ancillary_data_identifier :8; +}; + + + +/* 0x6C cell_list_descriptor */ + +#define DESCR_CELL_LIST_LEN XX +struct descr_cell_list { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x6D cell_frequency_link_descriptor */ + +#define DESCR_CELL_FREQUENCY_LINK_LEN XX +struct descr_cell_frequency_link { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x6E announcement_support_descriptor */ + +#define DESCR_ANNOUNCEMENT_SUPPORT_LEN XX +struct descr_announcement_support { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +}; + + + +/* 0x6F application_signalling_descriptor */ + +#define DESCR_APPLICATION_SIGNALLING_LEN 2 +struct descr_application_signalling { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define APPLICATION_SIGNALLING_ENTRY_LEN 3 +struct application_signalling_entry { + u_char application_type_hi :8; + u_char application_type_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char AIT_version_number :5; +#else + u_char AIT_version_number :5; + u_char :3; +#endif +}; + + + +/* 0x71 service_identifier_descriptor (ETSI TS 102 812, MHP) */ + +struct descr_service_identifier { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +/* MHP 0x00 application_descriptor */ + +#define DESCR_APPLICATION_LEN 3 + +struct descr_application { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char application_profiles_length :8; +}; + + +#define DESCR_APPLICATION_END_LEN 2 + +struct descr_application_end { +#if BYTE_ORDER == BIG_ENDIAN + u_char service_bound_flag :1; + u_char visibility :2; + u_char :5; +#else + u_char :5; + u_char visibility :2; + u_char service_bound_flag :1; +#endif + u_char application_priority :8; +/*now follow 8bit transport_protocol_label fields to the end */ +}; + + +#define APPLICATION_PROFILE_ENTRY_LEN 5 + +struct application_profile_entry { + u_char application_profile_hi :8; + u_char application_profile_lo :8; + u_char version_major :8; + u_char version_minor :8; + u_char version_micro :8; +}; + + +/* MHP 0x01 application_name_desriptor */ + +#define DESCR_APPLICATION_NAME_LEN 2 + +struct descr_application_name { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define APPLICATION_NAME_ENTRY_LEN 4 + +struct descr_application_name_entry { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char application_name_length :8; + /* application name string */ +}; + + +/* MHP 0x02 transport_protocol_descriptor */ + +#define DESCR_TRANSPORT_PROTOCOL_LEN 5 + +struct descr_transport_protocol { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char protocol_id_hi :8; + u_char protocol_id_lo :8; + u_char transport_protocol_label :8; + /* protocol_id-specific selector bytes follow */ +}; + + +#define TRANSPORT_VIA_OC_LEN 1 + +struct transport_via_oc { +#if BYTE_ORDER == BIG_ENDIAN + u_char remote :1; + u_char :7; +#else + u_char :7; + u_char remote :1; +#endif +}; + + +//if remote is true, transport_via_oc_remote_end_t follows, +// else transport_via_oc_end_t. + +#define TRANSPORT_VIA_OC_REMOTE_END_LEN 7 + +struct transport_via_oc_remote_end { + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; + u_char component_tag :8; +}; + + +#define TRANSPORT_VIA_OC_END_LEN 1 + +struct transport_via_oc_end { + u_char component_tag :8; +}; + + +/* 0x03 dvb_j_application_descriptor() */ + +#define DESCR_DVBJ_APPLICATION_LEN 2 + +struct descr_dvbj_application { + u_char descriptor_tag :8; + u_char descriptor_length :8; +}; + + +#define DESCR_DVBJ_APPLICATION_ENTRY_LEN 1 + +struct descr_dvbj_application_entry { + u_char parameter_length :8; + /* parameter string */ +}; + + +/* 0x04 dvb_j_application_location_descriptor */ + +#define DESCR_DVBJ_APPLICATION_LOCATION_LEN 3 + +struct descr_dvbj_application_location { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char base_directory_length :8; + /* base directory string */ +}; + + +#define DESCR_DVBJ_APPLICATION_LOCATION_MID_LEN 1 + +struct descr_dvbj_application_location_mid { + u_char classpath_extension_length :8; +}; + + +/* 0x0B application_icons_descriptor */ + +#define DESCR_APPLICATION_ICONS_LEN 3 + +struct descr_application_icons_descriptor { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char icon_locator_length :8; + /* icon locator */ +}; + + +#define DESCR_APPLICATION_ICONS_END_LEN 2 + +struct descr_application_icons_descriptor_end { + u_char icon_flags_hi :8; + u_char icon_flags_lo :8; +}; + + + + + +} //end of namespace + +#endif //LIBSI_HEADERS_H + diff --git a/libsi/section.c b/libsi/section.c new file mode 100644 index 00000000..6abbb232 --- /dev/null +++ b/libsi/section.c @@ -0,0 +1,346 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "section.h" +#include + +namespace SI { + +/*********************** PAT ***********************/ + +void PAT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + associationLoop.setData(data+offset, getLength()-offset-4); +} + +int PAT::getTransportStreamId() const { + return HILO(s->transport_stream_id); +} + +int PAT::Association::getServiceId() const { + return HILO(s->program_number); +} + +int PAT::Association::getPid() const { + return HILO(s->network_pid); +} + +void PAT::Association::Parse() { + s=data.getData(); +} + +/*********************** CAT ***********************/ + +void CAT::Parse() { + loop.setData(data+sizeof(cat), getLength()-sizeof(cat)-4); +} + +/*********************** PMT ***********************/ + +void PMT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + commonDescriptors.setDataAndOffset(data+offset, HILO(s->program_info_length), offset); + streamLoop.setData(data+offset, getLength()-offset-4); +} + +int PMT::getServiceId() const { + return HILO(s->program_number); +} + +int PMT::getPCRPid() const { + return HILO(s->PCR_PID); +} + +int PMT::Stream::getPid() const { + return HILO(s->elementary_PID); +} + +int PMT::Stream::getStreamType() const { + return s->stream_type; +} + +void PMT::Stream::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + streamDescriptors.setData(data+offset, HILO(s->ES_info_length)); +} + + + +/*********************** NIT ***********************/ + +int NIT::getNetworkId() const { + return HILO(s->network_id); +} + +void NIT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + commonDescriptors.setDataAndOffset(data+offset, HILO(s->network_descriptor_length), offset); + const nit_mid *mid; + data.setPointerAndOffset(mid, offset); + transportStreamLoop.setData(data+offset, HILO(mid->transport_stream_loop_length)); +} + +int NIT::TransportStream::getTransportStreamId() const { + return HILO(s->transport_stream_id); +} + +int NIT::TransportStream::getOriginalNetworkId() const { + return HILO(s->original_network_id); +} + +void NIT::TransportStream::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + transportStreamDescriptors.setData(data+offset, HILO(s->transport_descriptors_length)); +} + + + +/*********************** SDT ***********************/ + + +void SDT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + serviceLoop.setData(data+offset, getLength()-offset-4); //4 is for CRC +} + +int SDT::getTransportStreamId() const { + return HILO(s->transport_stream_id); +} + +int SDT::getOriginalNetworkId() const { + return HILO(s->original_network_id); +} + +int SDT::Service::getServiceId() const { + return HILO(s->service_id); +} + +int SDT::Service::getEITscheduleFlag() const { + return s->eit_schedule_flag; +} + +int SDT::Service::getEITpresentFollowingFlag() const { + return s->eit_present_following_flag; +} + +RunningStatus SDT::Service::getRunningStatus() const { + return (RunningStatus)s->running_status; +} + +int SDT::Service::getFreeCaMode() const { + return s->free_ca_mode; +} + +void SDT::Service::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + serviceDescriptors.setData(data+offset, HILO(s->descriptors_loop_length)); +} + + + +/*********************** EIT ***********************/ + +int EIT::getServiceId() const { + return HILO(s->service_id); +} + +int EIT::getTransportStreamId() const { + return HILO(s->transport_stream_id); +} + +int EIT::getOriginalNetworkId() const { + return HILO(s->original_network_id); +} + +bool EIT::isPresentFollowing() const { + return getTableId() == TableIdEIT_presentFollowing || getTableId() == TableIdEIT_presentFollowing_other; +} + +bool EIT::isActualTS() const { + return + (getTableId() ==TableIdEIT_presentFollowing) + || (TableIdEIT_schedule_first <= getTableId() && getTableId() <= TableIdEIT_schedule_last); +} + +void EIT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + //printf("%d %d %d %d %d\n", getServiceId(), getTransportStreamId(), getOriginalNetworkId(), isPresentFollowing(), isActualTS()); + eventLoop.setData(data+offset, getLength()-offset-4); //4 is for CRC +} + + +time_t EIT::Event::getStartTime() const { + return DVBTime::getTime(s->mjd_hi, s->mjd_lo, s->start_time_h, s->start_time_m, s->start_time_s); +} + +time_t EIT::Event::getDuration() const { + return DVBTime::getDuration(s->duration_h, s->duration_m, s->duration_s); +} + +int EIT::Event::getEventId() const { + return HILO(s->event_id); +} + +int EIT::Event::getMJD() const { + return HILO(s->mjd); +} + +int EIT::Event::getStartTimeHour() const { + return DVBTime::bcdToDec(s->start_time_h); +} + +int EIT::Event::getStartTimeMinute() const { + return DVBTime::bcdToDec(s->start_time_m); +} + +int EIT::Event::getStartTimeSecond() const { + return DVBTime::bcdToDec(s->start_time_s); +} + +int EIT::Event::getDurationHour() const { + return DVBTime::bcdToDec(s->duration_h); +} + +int EIT::Event::getDurationMinute() const { + return DVBTime::bcdToDec(s->duration_m); +} + +int EIT::Event::getDurationSecond() const { + return DVBTime::bcdToDec(s->duration_s); +} + +RunningStatus EIT::Event::getRunningStatus() const { + return (RunningStatus)s->running_status; +} + +int EIT::Event::getFreeCaMode() const { + return s->free_ca_mode; +} + +void EIT::Event::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + //printf("%d %d %d\n", getStartTime(), getDuration(), getRunningStatus()); + eventDescriptors.setData(data+offset, HILO(s->descriptors_loop_length)); +} + + +/*********************** TDT ***********************/ + +time_t TDT::getTime() const { + return DVBTime::getTime(s->utc_mjd_hi, s->utc_mjd_lo, s->utc_time_h, s->utc_time_m, s->utc_time_s); +} + +void TDT::Parse() { + s=data.getData(); +} + + +/*********************** TOT ***********************/ + +time_t TOT::getTime() const { + return DVBTime::getTime(s->utc_mjd_hi, s->utc_mjd_lo, s->utc_time_h, s->utc_time_m, s->utc_time_s); +} + +void TOT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + descriptorLoop.setData(data+offset, getLength()-offset-4); +} + + + + +/*********************** RST ***********************/ + +void RST::Parse() { + unsigned int offset=0; + const rst *s; + data.setPointerAndOffset(s, offset); + infoLoop.setData(data+offset, getLength()-offset); +} + +int RST::RunningInfo::getTransportStreamId() const { + return HILO(s->transport_stream_id); +} + +int RST::RunningInfo::getOriginalNetworkId() const { + return HILO(s->original_network_id); +} + +int RST::RunningInfo::getServiceId() const { + return HILO(s->service_id); +} + +int RST::RunningInfo::getEventId() const { + return HILO(s->event_id); +} + +RunningStatus RST::RunningInfo::getRunningStatus() const { + return (RunningStatus)s->running_status; +} + +void RST::RunningInfo::Parse() { + s=data.getData(); +} + + + +/*********************** AIT ***********************/ + + +int AIT::getApplicationType() const { + return HILO(first->application_type); +} + +int AIT::getAITVersion() const { + return first->version_number; +} + +void AIT::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(first, offset); + commonDescriptors.setDataAndOffset(data+offset, HILO(first->common_descriptors_length), offset); + const ait_mid *mid; + data.setPointerAndOffset(mid, offset); + applicationLoop.setData(data+offset, HILO(mid->application_loop_length)); +} + + +long AIT::Application::getOrganisationId() const { + return data.FourBytes(0); +} + +int AIT::Application::getApplicationId() const { + return HILO(s->application_id); +} + +int AIT::Application::getControlCode() const { + return s->application_control_code; +} + +void AIT::Application::Parse() { + unsigned int offset=0; + data.setPointerAndOffset(s, offset); + applicationDescriptors.setData(data+offset, HILO(s->application_descriptors_length)); +} + + + +} //end of namespace + diff --git a/libsi/section.h b/libsi/section.h new file mode 100644 index 00000000..55fc1bab --- /dev/null +++ b/libsi/section.h @@ -0,0 +1,259 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef LIBSI_SECTION_H +#define LIBSI_SECTION_H + +#include + +#include "si.h" +#include "headers.h" + +namespace SI { + +class PAT : public NumberedSection { +public: + PAT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + PAT() {} + class Association : public LoopElement { + public: + int getServiceId() const; + int getPid() const; + bool isNITPid() const { return getServiceId()==0; } + virtual int getLength() { return sizeof(pat_prog); } + protected: + virtual void Parse(); + private: + const pat_prog *s; + }; + int getTransportStreamId() const; + StructureLoop associationLoop; +protected: + virtual void Parse(); +private: + const pat *s; +}; + +class CAT : public NumberedSection { +public: + CAT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + CAT() {} + DescriptorLoop loop; +protected: + virtual void Parse(); +}; + + +class PMT : public NumberedSection { +public: + PMT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + PMT() {} + class Stream : public LoopElement { + public: + int getPid() const; + int getStreamType() const; + DescriptorLoop streamDescriptors; + virtual int getLength() { return sizeof(pmt_info)+streamDescriptors.getLength(); } + protected: + virtual void Parse(); + private: + const pmt_info *s; + }; + DescriptorLoop commonDescriptors; + StructureLoop streamLoop; + int getServiceId() const; + int getPCRPid() const; +protected: + virtual void Parse(); +private: + const pmt *s; +}; + +class NIT : public NumberedSection { +public: + NIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + NIT() {} + class TransportStream : public LoopElement { + public: + int getTransportStreamId() const; + int getOriginalNetworkId() const; + virtual int getLength() { return sizeof(ni_ts)+transportStreamDescriptors.getLength(); } + DescriptorLoop transportStreamDescriptors; + protected: + virtual void Parse(); + private: + const ni_ts *s; + }; + DescriptorLoop commonDescriptors; + StructureLoop transportStreamLoop; + int getNetworkId() const; +protected: + virtual void Parse(); +private: + const nit *s; +}; + +//BAT has the same structure as NIT but different allowed descriptors +class BAT : public NIT { +public: + BAT(const unsigned char *data, bool doCopy=true) : NIT(data, doCopy) {} + BAT() {} + int getBouquetId() const { return getNetworkId(); } +}; + + +class SDT : public NumberedSection { +public: + SDT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + SDT() {} + class Service : public LoopElement { + public: + int getServiceId() const; + int getEITscheduleFlag() const; + int getEITpresentFollowingFlag() const; + RunningStatus getRunningStatus() const; + int getFreeCaMode() const; + virtual int getLength() { return sizeof(sdt_descr)+serviceDescriptors.getLength(); } + DescriptorLoop serviceDescriptors; + protected: + virtual void Parse(); + private: + const sdt_descr *s; + }; + int getTransportStreamId() const; + int getOriginalNetworkId() const; + StructureLoop serviceLoop; +protected: + virtual void Parse(); +private: + const sdt *s; +}; + + +class EIT : public NumberedSection { +public: + EIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + EIT() {} + class Event : public LoopElement { + public: + int getEventId() const; + time_t getStartTime() const; //UTC + time_t getDuration() const; + + int getMJD() const; + int getStartTimeHour() const; //UTC + int getStartTimeMinute() const; //UTC + int getStartTimeSecond() const; //UTC + int getDurationHour() const; + int getDurationMinute() const; + int getDurationSecond() const; + RunningStatus getRunningStatus() const; + int getFreeCaMode() const; + + DescriptorLoop eventDescriptors; + virtual int getLength() { return sizeof(eit_event)+eventDescriptors.getLength(); } + protected: + virtual void Parse(); + private: + const eit_event *s; + }; + int getServiceId() const; + int getTransportStreamId() const; + int getOriginalNetworkId() const; + StructureLoop eventLoop; + + //true if table conveys present/following information, false if it conveys schedule information + bool isPresentFollowing() const; + //true if table describes TS on which it is broadcast, false if it describes other TS + bool isActualTS() const; +protected: + virtual void Parse(); +private: + const eit *s; +}; + + +class TDT : public Section { +public: + TDT(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {} + TDT() {} + time_t getTime() const; //UTC +protected: + virtual void Parse(); +private: + const tdt *s; +}; + + +class TOT : public CRCSection { +public: + TOT(const unsigned char *data, bool doCopy=true) : CRCSection(data, doCopy) {} + TOT() {} + time_t getTime() const; + DescriptorLoop descriptorLoop; +protected: + virtual void Parse(); +private: + const tot *s; +}; + + +class RST : public Section { +public: + RST(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {} + RST() {} + class RunningInfo : public LoopElement { + public: + int getTransportStreamId() const; + int getOriginalNetworkId() const; + int getServiceId() const; + int getEventId() const; + RunningStatus getRunningStatus() const; + virtual int getLength() { return sizeof(rst_info); } + protected: + virtual void Parse(); + private: + const rst_info *s; + }; + StructureLoop infoLoop; +protected: + virtual void Parse(); +}; + + +class AIT : public NumberedSection { +public: + AIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} + AIT() {} + class Application : public LoopElement { + public: + virtual int getLength() { return sizeof(ait_app)+applicationDescriptors.getLength(); } + long getOrganisationId() const; + int getApplicationId() const; + int getControlCode() const; + MHP_DescriptorLoop applicationDescriptors; + protected: + virtual void Parse(); + const ait_app *s; + }; + MHP_DescriptorLoop commonDescriptors; + StructureLoop applicationLoop; + int getApplicationType() const; + int getAITVersion() const; +protected: + const ait *first; + virtual void Parse(); +}; + + + +} //end of namespace + +#endif //LIBSI_TABLE_H diff --git a/libsi/si.c b/libsi/si.c new file mode 100644 index 00000000..013fdf13 --- /dev/null +++ b/libsi/si.c @@ -0,0 +1,431 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include "si.h" +#include "descriptor.h" + +namespace SI { + +Object::Object() { +} + +Object::Object(CharArray &d) : data(d) { +} + +void Object::setData(const unsigned char*d, unsigned int size, bool doCopy) { + data.assign(d, size, doCopy); +} + +void Object::setData(CharArray &d) { + data=d; +} + + + +Section::Section(const unsigned char *data, bool doCopy) { + setData(data, getLength(data), doCopy); +} + +TableId Section::getTableId() const { + return getTableId(data.getData()); +} + +int Section::getLength() { + return getLength(data.getData()); +} + +TableId Section::getTableId(const unsigned char *d) { + return (TableId)((const SectionHeader *)d)->table_id; +} + +int Section::getLength(const unsigned char *d) { + return HILO(((const SectionHeader *)d)->section_length)+sizeof(SectionHeader); +} + +bool CRCSection::isValid() { + return CRC32::isValid((const char *)data.getData(), getLength()/*, data.FourBytes(getLength()-4)*/); +} + +bool CRCSection::CheckCRCAndParse() { + if (!isValid()) + return false; + CheckParse(); + return true; +} + + + +bool NumberedSection::getCurrentNextIndicator() const { + return data.getData()->current_next_indicator; +} + +int NumberedSection::getVersionNumber() const { + return data.getData()->version_number; +} + +int NumberedSection::getSectionNumber() const { + return data.getData()->section_number; +} + +int NumberedSection::getLastSectionNumber() const { + return data.getData()->last_section_number; +} + + + + + +int Descriptor::getLength() { + return getLength(data.getData()); +} + +DescriptorTag Descriptor::getDescriptorTag() const { + return getDescriptorTag(data.getData()); +} + +int Descriptor::getLength(const unsigned char *d) { + return ((const DescriptorHeader*)d)->descriptor_length+sizeof(DescriptorHeader); +} + +DescriptorTag Descriptor::getDescriptorTag(const unsigned char *d) { + return (DescriptorTag)((const DescriptorHeader*)d)->descriptor_tag; +} + + +Descriptor *DescriptorLoop::getNext(Iterator &it) { + if (it.igetDescriptorTag()==UnimplementedDescriptorTag) + return returnUnimplemetedDescriptor ? d : 0; + return d; +} + +Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor) { + Descriptor *d=0; + if (it.igetDescriptorTag()==UnimplementedDescriptorTag) + return returnUnimplemetedDescriptor ? d : 0; + return d; +} + +Descriptor *DescriptorLoop::createDescriptor(int &i) { + Descriptor *d=Descriptor::getDescriptor(data+i, domain); + i+=d->getLength(); + d->CheckParse(); + return d; +} + +DescriptorGroup::DescriptorGroup(bool del) { + array=0; + length=0; + deleteOnDesctruction=del; +} + +DescriptorGroup::~DescriptorGroup() { + if (deleteOnDesctruction) + Delete(); + delete[] array; +} + +void DescriptorGroup::Delete() { + for (int i=0;igetLastDescriptorNumber()+1; + array=new GroupDescriptor*[length]; //numbering is zero-based + for (int i=0;igetLastDescriptorNumber()+1) + return; //avoid crash in case of misuse + array[d->getDescriptorNumber()]=d; +} + +bool DescriptorGroup::isComplete() { + for (int i=0;i4095) + return "text error"; + char *data=new char(getLength()+1); + decodeText(data); + return data; +} + +char *String::getText(char *buffer) { + if (getLength() < 0 || getLength() >4095) { + strncpy(buffer, "text error", getLength()+1); + return buffer; + } + decodeText(buffer); + return buffer; +} + +//taken from libdtv, Copyright Rolf Hakenes +void String::decodeText(char *buffer) { + const unsigned char *from=data.getData(0); + char *to=buffer; + + /* Disable detection of coding tables - libdtv doesn't do it either + if ( (0x01 <= *from) && (*from <= 0x1f) ) { + codeTable=*from + } + */ + + for (int i = 0; i < getLength(); i++) { + if (*from == 0) + break; + if ( ((' ' <= *from) && (*from <= '~')) + || (*from == '\n') + || ((0xA0 <= *from) && (*from <= 0xFF)) + ) + *to++ = *from; + else if (*from == 0x8A) + *to++ = '\n'; + else if (*from == 0x86 || *from == 0x87) //&& !(GDT_NAME_DESCRIPTOR & type)) + *to++ = ' '; + from++; + } + *to = '\0'; +} + +Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain) { + Descriptor *d=0; + switch (domain) { + case SI: + switch ((DescriptorTag)da.getData()->descriptor_tag) { + case CaDescriptorTag: + d=new CaDescriptor(); + break; + case CarouselIdentifierDescriptorTag: + d=new CarouselIdentifierDescriptor(); + break; + case NetworkNameDescriptorTag: + d=new NetworkNameDescriptor(); + break; + case ServiceListDescriptorTag: + d=new ServiceListDescriptor(); + break; + case SatelliteDeliverySystemDescriptorTag: + d=new SatelliteDeliverySystemDescriptor(); + break; + case CableDeliverySystemDescriptorTag: + d=new CableDeliverySystemDescriptor(); + break; + case TerrestrialDeliverySystemDescriptorTag: + d=new TerrestrialDeliverySystemDescriptor(); + break; + case BouquetNameDescriptorTag: + d=new BouquetNameDescriptor(); + break; + case ServiceDescriptorTag: + d=new ServiceDescriptor(); + break; + case NVODReferenceDescriptorTag: + d=new NVODReferenceDescriptor(); + break; + case TimeShiftedServiceDescriptorTag: + d=new TimeShiftedServiceDescriptor(); + break; + case ComponentDescriptorTag: + d=new ComponentDescriptor(); + break; + case StreamIdentifierDescriptorTag: + d=new StreamIdentifierDescriptor(); + break; + case SubtitlingDescriptorTag: + d=new SubtitlingDescriptor(); + break; + case MultilingualNetworkNameDescriptorTag: + d=new MultilingualNetworkNameDescriptor(); + break; + case MultilingualBouquetNameDescriptorTag: + d=new MultilingualBouquetNameDescriptor(); + break; + case MultilingualServiceNameDescriptorTag: + d=new MultilingualServiceNameDescriptor(); + break; + case MultilingualComponentDescriptorTag: + d=new MultilingualComponentDescriptor(); + break; + case ServiceMoveDescriptorTag: + d=new ServiceMoveDescriptor(); + break; + case FrequencyListDescriptorTag: + d=new FrequencyListDescriptor(); + break; + case ServiceIdentifierDescriptorTag: + d=new ServiceIdentifierDescriptor(); + break; + case CaIdentifierDescriptorTag: + d=new CaIdentifierDescriptor(); + break; + case ShortEventDescriptorTag: + d=new ShortEventDescriptor(); + break; + case ExtendedEventDescriptorTag: + d=new ExtendedEventDescriptor(); + break; + case TimeShiftedEventDescriptorTag: + d=new TimeShiftedEventDescriptor(); + break; + case ContentDescriptorTag: + d=new ContentDescriptor(); + break; + case ParentalRatingDescriptorTag: + d=new ParentalRatingDescriptor(); + break; + case ApplicationSignallingDescriptorTag: + d=new ApplicationSignallingDescriptor(); + break; + + //note that it is no problem to implement one + //of the unimplemented descriptors. + + //defined in ISO-13818-1 + case VideoStreamDescriptorTag: + case AudioStreamDescriptorTag: + case HierarchyDescriptorTag: + case RegistrationDescriptorTag: + case DataStreamAlignmentDescriptorTag: + case TargetBackgroundGridDescriptorTag: + case VideoWindowDescriptorTag: + case ISO639LanguageDescriptorTag: + case SystemClockDescriptorTag: + case MultiplexBufferUtilizationDescriptorTag: + case CopyrightDescriptorTag: + case MaximumBitrateDescriptorTag: + case PrivateDataIndicatorDescriptorTag: + case SmoothingBufferDescriptorTag: + case STDDescriptorTag: + case IBPDescriptorTag: + + //defined in ETSI EN 300 468 + case StuffingDescriptorTag: + case VBIDataDescriptorTag: + case VBITeletextDescriptorTag: + case CountryAvailabilityDescriptorTag: + case MocaicDescriptorTag: + case LinkageDescriptorTag: + case TeletextDescriptorTag: + case TelephoneDescriptorTag: + case LocalTimeOffsetDescriptorTag: + case PrivateDataSpecifierDescriptorTag: + case CellListDescriptorTag: + case CellFrequencyLinkDescriptorTag: + case ServiceAvailabilityDescriptorTag: + case ShortSmoothingBufferDescriptorTag: + case PartialTransportStreamDescriptorTag: + case DataBroadcastDescriptorTag: + case DataBroadcastIdDescriptorTag: + case CaSystemDescriptorTag: + case AC3DescriptorTag: + case DSNGDescriptorTag: + case PDCDescriptorTag: + case AncillaryDataDescriptorTag: + case AnnouncementSupportDescriptorTag: + case AdaptationFieldDataDescriptorTag: + case TransportStreamDescriptorTag: + default: + d=new UnimplementedDescriptor(); + break; + } + break; + case MHP: + switch ((DescriptorTag)da.getData()->descriptor_tag) { + // They once again start with 0x00 (see page 234, MHP specification) + case MHP_ApplicationDescriptorTag: + d=new MHP_ApplicationDescriptor(); + break; + case MHP_ApplicationNameDescriptorTag: + d=new MHP_ApplicationNameDescriptor(); + break; + case MHP_TransportProtocolDescriptorTag: + d=new MHP_TransportProtocolDescriptor(); + break; + case MHP_DVBJApplicationDescriptorTag: + d=new MHP_DVBJApplicationDescriptor(); + break; + case MHP_DVBJApplicationLocationDescriptorTag: + d=new MHP_DVBJApplicationLocationDescriptor(); + break; + // 0x05 - 0x0A is unimplemented this library + case MHP_ExternalApplicationAuthorisationDescriptorTag: + case MHP_IPv4RoutingDescriptorTag: + case MHP_IPv6RoutingDescriptorTag: + case MHP_DVBHTMLApplicationDescriptorTag: + case MHP_DVBHTMLApplicationLocationDescriptorTag: + case MHP_DVBHTMLApplicationBoundaryDescriptorTag: + case MHP_ApplicationIconsDescriptorTag: + case MHP_PrefetchDescriptorTag: + case MHP_DelegatedApplicationDescriptorTag: + case MHP_ApplicationStorageDescriptorTag: + default: + d=new UnimplementedDescriptor(); + break; + } + break; + } + d->setData(da); + return d; +} + + + + + + +} //end of namespace + + diff --git a/libsi/si.h b/libsi/si.h new file mode 100644 index 00000000..89b438df --- /dev/null +++ b/libsi/si.h @@ -0,0 +1,405 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef LIBSI_SI_H +#define LIBSI_SI_H + +#include + +#include "util.h" +#include "headers.h" + +namespace SI { + +enum TableId { TableIdPAT = 0x00, //program association section + TableIdCAT = 0x01, //conditional access section + TableIdPMT = 0x02, //program map section + TableIdTSDT = 0x03,//transport stream description section + TableIdNIT = 0x40, //network information, actual network section + TableIdNIT_other = 0x41, //network information section, other network + TableIdSDT = 0x42, //service description section + TableIdSDT_other = 0x46, + TableIdBAT = 0x46, //bouquet association section + TableIdEIT_presentFollowing = 0x4E, //event information section + TableIdEIT_presentFollowing_other = 0x4F, + //range from 0x50 to 0x5F + TableIdEIT_schedule_first = 0x50, + TableIdEIT_schedule_last = 0x5F, + //range from 0x60 to 0x6F + TableIdEIT_schedule_Other_first = 0x60, + TableIdEIT_schedule_Other_fast = 0x6F, + TableIdTDT = 0x70, //time date section + TableIdRST = 0x71, //running status section + TableIdST = 0x72, //stuffing section + TableIdTOT = 0x73, //time offset section + TableIdDIT = 0x7E, //discontinuity information section + TableIdSIT = 0x7F, //service information section + TableIdAIT = 0x74 //application information section + }; + + +enum DescriptorTag { + // defined by ISO/IEC 13818-1 + VideoStreamDescriptorTag = 0x02, + AudioStreamDescriptorTag = 0x03, + HierarchyDescriptorTag = 0x04, + RegistrationDescriptorTag = 0x05, + DataStreamAlignmentDescriptorTag = 0x06, + TargetBackgroundGridDescriptorTag = 0x07, + VideoWindowDescriptorTag = 0x08, + CaDescriptorTag = 0x09, + ISO639LanguageDescriptorTag = 0x0A, + SystemClockDescriptorTag = 0x0B, + MultiplexBufferUtilizationDescriptorTag = 0x0C, + CopyrightDescriptorTag = 0x0D, + MaximumBitrateDescriptorTag = 0x0E, + PrivateDataIndicatorDescriptorTag = 0x0F, + SmoothingBufferDescriptorTag = 0x10, + STDDescriptorTag = 0x11, + IBPDescriptorTag = 0x12, + // defined by ISO-13818-6 (DSM-CC) + CarouselIdentifierDescriptorTag = 0x13, + // 0x14 - 0x3F Reserved + // defined by ETSI (EN 300 468) + NetworkNameDescriptorTag = 0x40, + ServiceListDescriptorTag = 0x41, + StuffingDescriptorTag = 0x42, + SatelliteDeliverySystemDescriptorTag = 0x43, + CableDeliverySystemDescriptorTag = 0x44, + VBIDataDescriptorTag = 0x45, + VBITeletextDescriptorTag = 0x46, + BouquetNameDescriptorTag = 0x47, + ServiceDescriptorTag = 0x48, + CountryAvailabilityDescriptorTag = 0x49, + LinkageDescriptorTag = 0x4A, + NVODReferenceDescriptorTag = 0x4B, + TimeShiftedServiceDescriptorTag = 0x4C, + ShortEventDescriptorTag = 0x4D, + ExtendedEventDescriptorTag = 0x4E, + TimeShiftedEventDescriptorTag = 0x4F, + ComponentDescriptorTag = 0x50, + MocaicDescriptorTag = 0x51, + StreamIdentifierDescriptorTag = 0x52, + CaIdentifierDescriptorTag = 0x53, + ContentDescriptorTag = 0x54, + ParentalRatingDescriptorTag = 0x55, + TeletextDescriptorTag = 0x56, + TelephoneDescriptorTag = 0x57, + LocalTimeOffsetDescriptorTag = 0x58, + SubtitlingDescriptorTag = 0x59, + TerrestrialDeliverySystemDescriptorTag = 0x5A, + MultilingualNetworkNameDescriptorTag = 0x5B, + MultilingualBouquetNameDescriptorTag = 0x5C, + MultilingualServiceNameDescriptorTag = 0x5D, + MultilingualComponentDescriptorTag = 0x5E, + PrivateDataSpecifierDescriptorTag = 0x5F, + ServiceMoveDescriptorTag = 0x60, + ShortSmoothingBufferDescriptorTag = 0x61, + FrequencyListDescriptorTag = 0x62, + PartialTransportStreamDescriptorTag = 0x63, + DataBroadcastDescriptorTag = 0x64, + CaSystemDescriptorTag = 0x65, + DataBroadcastIdDescriptorTag = 0x66, + TransportStreamDescriptorTag = 0x67, + DSNGDescriptorTag = 0x68, + PDCDescriptorTag = 0x69, + AC3DescriptorTag = 0x6A, + AncillaryDataDescriptorTag = 0x6B, + CellListDescriptorTag = 0x6C, + CellFrequencyLinkDescriptorTag = 0x6D, + AnnouncementSupportDescriptorTag = 0x6E, + ApplicationSignallingDescriptorTag = 0x6F, + AdaptationFieldDataDescriptorTag = 0x70, + ServiceIdentifierDescriptorTag = 0x71, + ServiceAvailabilityDescriptorTag = 0x72, + // Defined by ETSI TS 102 812 (MHP) + // They once again start with 0x00 (see page 234, MHP specification) + MHP_ApplicationDescriptorTag = 0x00, + MHP_ApplicationNameDescriptorTag = 0x01, + MHP_TransportProtocolDescriptorTag = 0x02, + MHP_DVBJApplicationDescriptorTag = 0x03, + MHP_DVBJApplicationLocationDescriptorTag = 0x04, + // 0x05 - 0x0A is unimplemented this library + MHP_ExternalApplicationAuthorisationDescriptorTag = 0x05, + MHP_IPv4RoutingDescriptorTag = 0x06, + MHP_IPv6RoutingDescriptorTag = 0x07, + MHP_DVBHTMLApplicationDescriptorTag = 0x08, + MHP_DVBHTMLApplicationLocationDescriptorTag = 0x09, + MHP_DVBHTMLApplicationBoundaryDescriptorTag = 0x0A, + MHP_ApplicationIconsDescriptorTag = 0x0B, + MHP_PrefetchDescriptorTag = 0x0C, + MHP_DelegatedApplicationDescriptorTag = 0x0E, + MHP_ApplicationStorageDescriptorTag = 0x10, + + //a descriptor currently unimplemented in this library + //the actual value 0xFF is "forbidden" according to the spec. + UnimplementedDescriptorTag = 0xFF +}; + +enum DescriptorTagDomain { SI, MHP }; + +enum RunningStatus { RunningStatusUndefined = 0, + RunningStatusNotRunning = 1, + RunningStatusStartsInAFewSeconds = 2, + RunningStatusPausing = 3, + RunningStatusRunning = 4 + }; + + +/* Some principles: + - Objects that return references to other objects contained in their data must make sure + that the returned objects have been parsed. + (the Loop subclasses take care of that.) + Note that this does not apply to Loops and Strings (their are never returned by reference, BTW). +*/ + + +class Object : public Parsable { +public: + Object(); + Object(CharArray &d); + //can only be called once since data is immutable + void setData(const unsigned char*data, unsigned int size, bool doCopy=true); + virtual int getLength() = 0; +protected: + CharArray data; + //is protected - not used for sections + template friend class StructureLoop; + void setData(CharArray &d); +}; + +class Section : public Object { +public: + //convenience: sets data and parses if doParse + Section(const unsigned char *data, bool doCopy=true); + Section() {} + TableId getTableId() const; + virtual int getLength(); + + static int getLength(const unsigned char *d); + static TableId getTableId(const unsigned char *d); +}; + +class CRCSection : public Section { +public: + //convenience: sets data and parses if doParse + CRCSection(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {} + CRCSection() {} + bool isValid(); + //convenience: isValid+CheckParse + bool CheckCRCAndParse(); +}; + +/* A section which has the ExtendedSectionHeader + (section_syntax_indicator==1) */ +class NumberedSection : public CRCSection { +public: + NumberedSection(const unsigned char *data, bool doCopy=true) : CRCSection(data, doCopy) {} + NumberedSection() {} + bool getCurrentNextIndicator() const; + int getVersionNumber() const; + int getSectionNumber() const; + int getLastSectionNumber() const; + bool moreThanOneSection() const { return getLastSectionNumber()>1; } +}; + + + + +class VariableLengthPart : public Object { +public: + //never forget to call this + void setData(CharArray d, int l) { Object::setData(d); length=l; } + //convenience method + void setDataAndOffset(CharArray d, int l, unsigned int &offset) { Object::setData(d); length=l; offset+=l; } + virtual int getLength() { return length; } +private: + int length; +}; + + + +class LoopElement : public Object { +}; + + +class SubStructure : public LoopElement { +}; + +class Descriptor : public LoopElement { +public: + virtual int getLength(); + DescriptorTag getDescriptorTag() const; + + static int getLength(const unsigned char *d); + static DescriptorTag getDescriptorTag(const unsigned char *d); +protected: + friend class DescriptorLoop; + //returns a subclass of descriptor according to the data given. + //The object is allocated with new and must be delete'd. + //setData() will have been called, CheckParse() not. + //Never returns null - maybe the UnimplementedDescriptor. + static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain); +}; + + + +class Loop : public VariableLengthPart { +public: + class Iterator { + public: + Iterator() { i=0; } + void reset() { i=0; } + private: + template friend class StructureLoop; + friend class DescriptorLoop; + int i; + }; +protected: + virtual void Parse() {} +}; + +//contains LoopElements of one type only +template class StructureLoop : public Loop { +public: + //currently you must use a while-loop testing for hasNext() + //i must be 0 to get the first descriptor (with the first call) + T getNext(Iterator &it) + { + CharArray d=data; + d.addOffset(it.i); + T ret; + ret.setData(d); + ret.CheckParse(); + it.i+=ret.getLength(); + return ret; + } + T* getNextAsPointer(Iterator &it) + { + if (getLength() <= it.i) + return 0; + CharArray d=data; + d.addOffset(it.i); + T *ret=new T(); + ret->setData(d); + ret->CheckParse(); + it.i+=ret->getLength(); + return ret; + } + bool hasNext(Iterator &it) { return getLength() > it.i; } +}; + +//contains descriptors of different types +class DescriptorLoop : public Loop { +public: + DescriptorLoop() { domain=SI; } + //i must be 0 to get the first descriptor (with the first call) + //All returned descriptors must be delete'd. + //returns null if no more descriptors available + Descriptor *getNext(Iterator &it); + //return the next descriptor with given tag, or 0 if not available. + //if the descriptor found is not implemented, + // an UnimplementedDescriptor will be returned if returnUnimplemetedDescriptor==true, + // 0 will be returned if returnUnimplemetedDescriptor==false + Descriptor *getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor=false); + //return the next descriptor with one of the given tags, or 0 if not available. + Descriptor *getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor=false); +protected: + Descriptor *createDescriptor(int &i); + DescriptorTagDomain domain; +}; + +typedef uint8_t EightBit; +typedef uint16_t SixteenBit; +typedef uint32_t ThirtyTwoBit; +typedef uint64_t SixtyFourBit; + +template class TypeLoop : public Loop { +public: + int getCount() const { return getLength()/sizeof(T); } + T operator[](const unsigned int index) const + { + switch (sizeof(T)) { + case 1: + return data[index]; + case 2: + return data.TwoBytes(index); + case 4: + return data.FourBytes(index); + case 8: + return (data.FourBytes(index) << 32) | data.FourBytes(index+4); + } + } + T getNext(Iterator &it) const + { + T ret=operator[](it.i); + it.i+=sizeof(T); + return ret; + } + bool hasNext() const { return getLength() > it.i; } +}; + +class MHP_DescriptorLoop : public DescriptorLoop { +public: + MHP_DescriptorLoop() { domain=MHP; } +}; + + +//The content of the ExtendedEventDescriptor may be split over several +//descriptors if the text is longer than 256 bytes. +//The following classes provide base functionality to handle this case. +class GroupDescriptor : public Descriptor { +public: + virtual int getDescriptorNumber() = 0; + virtual int getLastDescriptorNumber() = 0; +}; + +class DescriptorGroup { +public: + DescriptorGroup(bool deleteOnDesctruction=true); + ~DescriptorGroup(); + void Add(GroupDescriptor *d); + void Delete(); + int getLength() { return length; } + GroupDescriptor **getDescriptors() { return array; } + bool isComplete(); //if all descriptors have been added +protected: + int length; + GroupDescriptor **array; + bool deleteOnDesctruction; +}; + + + +class String : public VariableLengthPart { +public: + //A note to the length: getLength() returns the length of the raw data. + //The text may be shorter. Its length can be obtained with one of the + //above functions and strlen. + + //returns text. Data is allocated with new and must be delete'd by the user. + char *getText(); + //copies text into given buffer. + //a buffer of size getLength()+1 is guaranteed to be sufficiently large. + //In most descriptors the string length is an 8-bit field, + //so the maximum there is 256. + //returns the given buffer for convenience. + char * getText(char *buffer); +protected: + virtual void Parse() {} + void decodeText(char *buffer); +}; + + +} //end of namespace + +#endif //LIBSI_SI_H + diff --git a/libsi/util.c b/libsi/util.c new file mode 100644 index 00000000..872a3e48 --- /dev/null +++ b/libsi/util.c @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg, Rolf Hakenes * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include "util.h" + +namespace SI { + + +/*---------------------------- CharArray ----------------------------*/ + +CharArray::CharArray() : data_(0), off(0) { +} + +CharArray::~CharArray() { + if (!data_) + return; + if (--data_->count_ == 0) + delete data_; +} + +CharArray::CharArray(const CharArray &f) : data_(f.data_), off(f.off) { + if (data_) + ++ data_->count_; +} + +CharArray& CharArray::operator=(const CharArray &f) { + // DO NOT CHANGE THE ORDER OF THESE STATEMENTS! + // (This order properly handles self-assignment) + if (f.data_) { + ++ f.data_->count_; + } + if (data_) { + if (--data_->count_ == 0) + delete data_; + } + data_ = f.data_; + off = f.off; + return *this; +} + +void CharArray::assign(const unsigned char*data, unsigned int size, bool doCopy) { + //immutable + if (!data_) + data_= doCopy ? (Data*)new DataOwnData() : (Data*)new DataForeignData(); + // This method might need to change things in *data_ + // Thus it first checks if this is the only pointer to *data_ + if (data_->count_ > 1) { + Data* d = doCopy ? (Data*)new DataOwnData() : (Data*)new DataForeignData(); + -- data_->count_; + data_ = d; + } + data_->assign(data, size); +} + +bool CharArray::operator==(const char *string) const { + //here we can use strcmp, string is null-terminated. + if (!data_) + return false; + return data_->size ? (!strcmp((const char*)data_->data, string)) : string[0]==0; +} + +bool CharArray::operator==(const CharArray &other) const { + if (!data_ || !other.data_) + return !(data_ || other.data_); //true if both empty + + if (data_->size != other.data_->size) + return false; + + //do _not_ use strcmp! Data is not necessarily null-terminated. + for (unsigned int i=0;isize;i++) + if (data_->data[i] != other.data_->data[i]) + return false; + return true; +} + +CharArray CharArray::operator+(const unsigned int offset) const { + CharArray f(*this); + f.off+=offset; + return f; +} + +CharArray::Data::Data() : count_(1) { + size=0; + data=0; + /* + lockingPid = 0; + locked = 0; + pthread_mutex_init(&mutex, NULL); + */ +} + +CharArray::Data::~Data() { + /* + if (locked) + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&mutex); + */ +} + +/*CharArray::Data::Data(const Data& d) : count_(1) { + size=0; + data=0; + + lockingPid = 0; + locked = 0; + pthread_mutex_init(&mutex, NULL); +}*/ + +CharArray::DataOwnData::~DataOwnData() { + Delete(); +} + +void CharArray::DataOwnData::assign(const unsigned char*d, unsigned int s) { + Delete(); + size=s; + unsigned char *newdata=new unsigned char[size]; + memcpy(newdata, d, size); + data=newdata; +} + +void CharArray::DataOwnData::Delete() { + delete[] data; +} + +CharArray::DataForeignData::~DataForeignData() { + Delete(); +} + +void CharArray::DataForeignData::assign(const unsigned char*d, unsigned int s) { + size=s; + data=d; +} + +void CharArray::DataForeignData::Delete() { + //do not delete! +} + + +/* +void CharArray::Data::assign(unsigned int s) { + if (data) + delete[] data; + size=s; + if (size) { //new assignment may be zero length + data=new unsigned char[size]; + memset(data, 0, size); + } +} + +void CharArray::Data::Lock(void) +{ + if ( !pthread_equal(pthread_self(), lockingPid) || !locked) { + pthread_mutex_lock(&mutex); + lockingPid = pthread_self(); + } + locked++; +} + +void CharArray::Data::Unlock(void) +{ + if (!--locked) { + lockingPid = 0; + pthread_mutex_unlock(&mutex); + } +} +*/ + +Parsable::Parsable() { + parsed=false; +} + +void Parsable::CheckParse() { + if (!parsed) { + parsed=true; + Parse(); + } +} + + +//taken and adapted from libdtv, (c) Rolf Hakenes and VDR, (c) Klaus Schmidinger +time_t DVBTime::getTime(unsigned char date_hi, unsigned char date_lo, unsigned char time_hour, unsigned char time_minute, unsigned char time_second) { + unsigned short mjd = date_hi << 8 | date_lo; + struct tm t; + + t.tm_sec = bcdToDec(time_second); + t.tm_min = bcdToDec(time_minute); + t.tm_hour = bcdToDec(time_hour); + + int k; + t.tm_year = (int) ((mjd - 15078.2) / 365.25); + t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); + t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); + k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; + t.tm_year = t.tm_year + k; + t.tm_mon = t.tm_mon - 1 - k * 12; + t.tm_mon--; + + t.tm_isdst = -1; + t.tm_gmtoff = 0; + + return timegm(&t); +} + +time_t DVBTime::getDuration(unsigned char time_hour, unsigned char time_minute, unsigned char time_second) { + return + bcdToDec(time_second) + + bcdToDec(time_minute) * 60 + + bcdToDec(time_hour) *3600; +} + +//taken and adapted from libdtv, (c) Rolf Hakenes +// CRC32 lookup table for polynomial 0x04c11db7 +unsigned long CRC32::crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; + +unsigned long CRC32::crc32 (const char *d, int len, unsigned long crc) +{ + register int i; + + for (i=0; i> 24) ^ *d++) & 0xff]; + + return crc; +} + +CRC32::CRC32(const char *d, int len, unsigned long CRCvalue) { + data=d; + length=len; + value=CRCvalue; +} + + + + + + +} //end of namespace + + + diff --git a/libsi/util.h b/libsi/util.h new file mode 100644 index 00000000..8df82c4d --- /dev/null +++ b/libsi/util.h @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef LIBSI_UTIL_H +#define LIBSI_UTIL_H + +#include +#include +#include + +#define HILO(x) (x##_hi << 8 | x##_lo) +#define BCD_TIME_TO_SECONDS(x) ((3600 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \ + (60 * ((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))) + \ + ((10*((x##_s & 0xF0)>>4)) + (x##_s & 0xF))) + +namespace SI { + + +//Holds an array of unsigned char which is deleted +//when the last object pointing to it is deleted. +//Optimized for use in libsi. +class CharArray { +public: + CharArray(); + + CharArray(const CharArray &source); + CharArray& operator=(const CharArray &source); + ~CharArray(); + + //can be called exactly once + void assign(const unsigned char*data, unsigned int size, bool doCopy=true); + //compares to a null-terminated string + bool operator==(const char *string) const; + //compares to another CharArray (data not necessarily null-terminated) + bool operator==(const CharArray &other) const; + + //returns another CharArray with its offset incremented by offset + CharArray operator+(const unsigned int offset) const; + + //access and convenience methods + const unsigned char* getData() const { return data_->data+off; } + const unsigned char* getData(int offset) const { return data_->data+offset+off; } + template const T* getData() const { return (T*)(data_->data+off); } + template const T* getData(int offset) const { return (T*)(data_->data+offset+off); } + //sets p to point to data+offset, increments offset + template void setPointerAndOffset(const T* &p, unsigned int &offset) const { p=(T*)getData(offset); offset+=sizeof(T); } + unsigned char operator[](const unsigned int index) const { return data_->data ? data_->data[off+index] : 0; } + int getLength() const { return data_->size; } + unsigned short TwoBytes(const unsigned int index) const { return data_->data ? data_->TwoBytes(off+index) : 0; } + unsigned long FourBytes(const unsigned int index) const { return data_->data ? data_->FourBytes(off+index) : 0; } + + void addOffset(unsigned int offset) { off+=offset; } +private: + class Data { + public: + Data(); + virtual ~Data(); + + virtual void assign(const unsigned char*data, unsigned int size) = 0; + virtual void Delete() = 0; + + unsigned short TwoBytes(const unsigned int index) const + { return (data[index] << 8) | data[index+1]; } + unsigned long FourBytes(const unsigned int index) const + { return (data[index] << 24) | (data[index+1] << 16) | (data[index+2] << 8) | data[index+3]; } + /*#ifdef CHARARRAY_THREADSAFE + void Lock(); + void Unlock(); + #else + void Lock() {} + void Unlock() {} + #endif + Data(const Data& d); + void assign(unsigned int size); + */ + + const unsigned char*data; + unsigned int size; + + unsigned count_; + // count_ is the number of CharArray objects that point at this + // count_ must be initialized to 1 by all constructors + // (it starts as 1 since it is pointed to by the CharArray object that created it) + + /* + pthread_mutex_t mutex; + pid_t lockingPid; + pthread_t locked; + */ + }; + class DataOwnData : public Data { + public: + DataOwnData() {} + virtual ~DataOwnData(); + virtual void assign(const unsigned char*data, unsigned int size); + virtual void Delete(); + }; + class DataForeignData : public Data { + public: + DataForeignData() {} + virtual ~DataForeignData(); + virtual void assign(const unsigned char*data, unsigned int size); + virtual void Delete(); + }; + Data* data_; + unsigned int off; +}; + + + +//abstract base class +class Parsable { +public: + void CheckParse(); +protected: + Parsable(); + virtual ~Parsable() {} + //actually parses given data. + virtual void Parse() = 0; +private: + bool parsed; +}; + +//taken and adapted from libdtv, (c) Rolf Hakenes and VDR, (c) Klaus Schmidinger +namespace DVBTime { +time_t getTime(unsigned char date_hi, unsigned char date_lo, unsigned char timehr, unsigned char timemi, unsigned char timese); +time_t getDuration(unsigned char timehr, unsigned char timemi, unsigned char timese); +inline unsigned char bcdToDec(unsigned char b) { return ((b >> 4) & 0x0F) * 10 + (b & 0x0F); } +}; + +//taken and adapted from libdtv, (c) Rolf Hakenes +class CRC32 { +public: + CRC32(const char *d, int len, unsigned long CRCvalue=0xFFFFFFFF); + bool isValid() { return crc32(data, length, value) == 0; } + static bool isValid(const char *d, int len, unsigned long CRCvalue=0xFFFFFFFF) { return crc32(d, len, CRCvalue) == 0; } +protected: + static unsigned long crc_table[256]; + static unsigned long crc32 (const char *d, int len, unsigned long CRCvalue); + + const char *data; + int length; + unsigned long value; +}; + + + +} //end of namespace + + +#endif +