Copy sectionsd code to new eitd directory, to cleanup and leave original code for reference

This commit is contained in:
[CST] Focus
2012-02-01 16:09:49 +04:00
parent dae48e5b9a
commit 3ea0c375ea
19 changed files with 19576 additions and 1 deletions

View File

@@ -174,7 +174,7 @@ data/lcd/clock/Makefile
data/locale/Makefile
data/scripts/Makefile
data/themes/Makefile
src/sectionsd/Makefile
src/eitd/Makefile
src/timerd/Makefile
src/zapit/Makefile
src/zapit/lib/Makefile

3052
src/eitd/FreesatTables.hpp Normal file

File diff suppressed because it is too large Load Diff

20
src/eitd/Makefile.am Normal file
View File

@@ -0,0 +1,20 @@
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src/zapit/include \
-I$(top_srcdir)/lib/libconfigfile \
-I$(top_srcdir)/lib/connection \
-I$(top_srcdir)/lib/libeventserver \
-I$(top_srcdir)/lib/xmltree
if BOXTYPE_COOL
INCLUDES += -I$(top_srcdir)/lib/libcoolstream
endif
if BOXTYPE_TRIPLE
INCLUDES += -I$(top_srcdir)/lib/libtriple
endif
AM_CPPFLAGS = -D DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
noinst_LIBRARIES = libsectionsd.a
libsectionsd_a_SOURCES = sectionsd.cpp dmxapi.cpp debug.cpp dmx.cpp SIsections.cpp SIevents.cpp SIutils.cpp SIlanguage.cpp edvbstring.cpp

141
src/eitd/SIbouquets.hpp Normal file
View File

@@ -0,0 +1,141 @@
#ifndef SIBOUQUETS_HPP
#define SIBOUQUETS_HPP
//
// $Id: SIbouquets.hpp,v 1.2 2006/02/08 21:15:50 houdini Exp $
//
// classes SIservices and SIservices (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de),
// 2002 thegoodguy (thegoodguy@berlios.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <algorithm>
#include <endian.h>
#include <sectionsdclient/sectionsdMsg.h>
// forward references
class SIservice;
class SIevent;
class SIbouquet;
struct loop_len {
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 4;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned descriptors_loop_length_hi : 4;
unsigned reserved_future_use : 4;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ; // 2 Bytes
struct bat_service {
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 4;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned descriptors_loop_length_hi : 4;
unsigned reserved_future_use : 4;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ; // 6 Bytes
class SIbouquet {
public:
SIbouquet(const t_bouquet_id _bouquet_id) {
bouquet_id = _bouquet_id;
transport_stream_id = 0;
original_network_id = 0;
service_id = 0;
serviceTyp = 0;
// position = 0;
bouquetName = "";
}
// Um einen service zum Suchen zu erstellen
SIbouquet(const t_bouquet_id _bouquet_id, const t_service_id _service_id, const t_original_network_id _original_network_id, const t_transport_stream_id _transport_stream_id)
{
service_id = _service_id;
original_network_id = _original_network_id;
transport_stream_id = _transport_stream_id;
serviceTyp = 0;
// position = 0;
}
// Std-Copy
SIbouquet(const SIbouquet &s) {
service_id = s.service_id;
original_network_id = s.original_network_id;
transport_stream_id = s.transport_stream_id;
bouquet_id = s.bouquet_id;
bouquetName = s.bouquetName;
serviceTyp = s.serviceTyp;
position = s.position;
}
t_bouquet_id bouquet_id; // This is because of wrong design of sectionsd. Normally we would parse only tables instead of sections...
std::string bouquetName; // This is because of wrong design of sectionsd. Normally we would parse only tables instead of sections...
t_original_network_id original_network_id;
t_transport_stream_id transport_stream_id;
t_service_id service_id;
uint16_t position;
unsigned char serviceTyp;
bool operator < (const SIbouquet& s) const {
return uniqueKey() < s.uniqueKey();
}
t_bouquetentry_id uniqueKey(void) const {
return CREATE_BOUQUETENTRY_ID(bouquet_id, (uint16_t) serviceTyp, position, service_id);
}
void dump(void) const {
printf("Bouquet-ID: %hu\n", bouquet_id);
printf("Original-Network-ID: %hu\n", original_network_id);
printf("Transport-Stream-ID: %hu\n", transport_stream_id);
printf("Service-ID: %hu\n", service_id);
printf("Service-Typ: %hhu\n", serviceTyp);
if(bouquetName.length())
printf("Bouquet-Name: %s\n", bouquetName.c_str());
}
};
// Fuer for_each
struct printSIbouquet : public std::unary_function<SIbouquet, void>
{
void operator() (const SIbouquet &s) { s.dump();}
};
// Als Klasse, da ich nicht weiss, wie man eine Forward-Referenz auf ein typedef macht
class SIbouquets : public std::set <SIbouquet, std::less<SIbouquet> >
{
};
#endif // SIBOUQUETS_HPP

593
src/eitd/SIevents.cpp Normal file
View File

@@ -0,0 +1,593 @@
//
// $Id: SIevents.cpp,v 1.35 2008/08/16 19:23:18 seife Exp $
//
// classes SIevent and SIevents (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/poll.h> // fuer poll()
#include <set>
#include <algorithm>
#include <string>
#include "SIlanguage.hpp"
#include "SIutils.hpp"
#include "SIservices.hpp"
#include "SIevents.hpp"
#ifdef UPDATE_NETWORKS
#include "SIbouquets.hpp"
#include "SInetworks.hpp"
#endif
#include "SIsections.hpp"
#include <dmxapi.h>
const std::string languangeOFF = "OFF";
SIevent::SIevent(const struct eit_event *e)
{
eventID = (e->event_id_hi << 8) | e->event_id_lo;
time_t start_time = changeUTCtoCtime(((const unsigned char *)e) + 2);
unsigned long duration = 0;
if (!((e->duration_hi == 0xff) && (e->duration_mid == 0xff) && (e->duration_lo == 0xff)))
duration = ((e->duration_hi)>>4)*10*3600L + ((e->duration_hi)&0x0f)*3600L +
((e->duration_mid)>>4)*10*60L + ((e->duration_mid)&0x0f)*60L +
((e->duration_lo)>>4)*10 + ((e->duration_lo)&0x0f);
if (start_time && duration)
times.insert(SItime(start_time, duration));
running = (int)e->running_status;
table_id = 0xFF; /* not set */
version = 0xFF;
service_id = 0;
original_network_id = 0;
transport_stream_id = 0;
}
SIevent::SIevent(const t_original_network_id _original_network_id, const t_transport_stream_id _transport_stream_id, const t_service_id _service_id,
const unsigned short _event_id)
{
original_network_id = _original_network_id;
transport_stream_id = _transport_stream_id;
service_id = _service_id;
eventID = _event_id;
table_id = 0xFF; /* not set */
version = 0xFF;
/* contentClassification = "";
userClassification = "";
itemDescription = "";
item = "";
extendedText = "";*/
}
// Std-Copy
SIevent::SIevent(const SIevent &e)
{
eventID=e.eventID;
langName=e.langName;
langText=e.langText;
// startzeit=e.startzeit;
// dauer=e.dauer;
times=e.times;
service_id = e.service_id;
original_network_id = e.original_network_id;
transport_stream_id = e.transport_stream_id;
itemDescription=e.itemDescription;
item=e.item;
langExtendedText=e.langExtendedText;
contentClassification=e.contentClassification;
userClassification=e.userClassification;
components=e.components;
ratings=e.ratings;
linkage_descs=e.linkage_descs;
running=e.running;
vps = e.vps;
table_id = e.table_id;
version = e.version;
}
int SIevent::saveXML(FILE *file, const char *serviceName) const
{
if(saveXML0(file))
return 1;
if(serviceName) {
if(fprintf(file, " <service_name>")<0)
return 2;
saveStringToXMLfile(file, serviceName);
if(fprintf(file, "</service_name>\n")<0)
return 3;
}
return saveXML2(file);
}
char SIevent::getFSK() const
{
for (SIparentalRatings::iterator it = ratings.begin(); it != ratings.end(); ++it)
{
if (it->countryCode == "DEU")
{
if ((it->rating >= 0x01) && (it->rating <= 0x0F))
return (it->rating + 3); // 0x01 to 0x0F minimum age = rating + 3 years
else
return (it->rating == 0 ? 0 : 18); // return FSK 18 for : 0x10 to 0xFF defined by the broadcaster
}
}
if (!ratings.empty())
{
if ((ratings.begin()->rating >= 0x01) && (ratings.begin()->rating <= 0x0F))
return (ratings.begin()->rating + 3);
else
return (ratings.begin()->rating == 0 ? 0 : 18);
}
return 0x00; // 0x00 undefined
}
int SIevent::saveXML0(FILE *file) const
{
if(fprintf(file, "\t\t<event id=\"%04x\">\n", eventID)<0)
return 1;
return 0;
}
int SIevent::saveXML2(FILE *file) const
{
for (std::map<std::string, std::string>::const_iterator
i = langName.begin() ;
i != langName.end() ;
i++) {
if (i->second.length()) {
fprintf(file, "\t\t\t<name lang=\"%s\" string=\"", i->first.c_str());
saveStringToXMLfile(file, i->second.c_str());
fprintf(file, "\"/>\n");
}
}
for (std::map<std::string, std::string>::const_iterator
i = langText.begin() ;
i != langText.end() ;
i++) {
if (i->second.length()) {
fprintf(file, "\t\t\t<text lang=\"%s\" string=\"", i->first.c_str());
saveStringToXMLfile(file, i->second.c_str());
fprintf(file, "\"/>\n");
}
}
if(item.length()) {
fprintf(file, "\t\t\t<item string=\"");
saveStringToXMLfile(file, item.c_str());
fprintf(file, "\"/>\n");
}
if(itemDescription.length()) {
fprintf(file, "\t\t\t<item_description string=\"");
saveStringToXMLfile(file, itemDescription.c_str());
fprintf(file, "\"/>\n");
}
for (std::map<std::string, std::string>::const_iterator
i = langExtendedText.begin() ;
i != langExtendedText.end() ;
i++) {
if (i->second.length()) {
fprintf(file, "\t\t\t<extended_text lang=\"%s\" string=\"", i->first.c_str());
saveStringToXMLfile(file, i->second.c_str());
fprintf(file, "\"/>\n");
}
}
for_each(times.begin(), times.end(), saveSItimeXML(file));
for(unsigned i=0; i<contentClassification.length(); i++)
fprintf(file, "\t\t\t<content class=\"%02x\" user=\"%02x\"/>\n", contentClassification[i], userClassification[i]);
for_each(components.begin(), components.end(), saveSIcomponentXML(file));
for_each(ratings.begin(), ratings.end(), saveSIparentalRatingXML(file));
for_each(linkage_descs.begin(), linkage_descs.end(), saveSIlinkageXML(file));
fprintf(file, "\t\t</event>\n");
return 0;
}
std::string SIevent::getName() const
{
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
std::map<std::string, std::string>::const_iterator it = langName.begin() ;
if (it != langName.end()) return it->second;
else return("");
} else {
std::string retval;
SIlanguage::filter(langName, 1, retval);
return retval;
}
}
void SIevent::setName(const std::string &lang, const std::string &name)
{
std::string tmp = name;
std::replace(tmp.begin(), tmp.end(), '\n', ' ');
//printf("setName: lang %s text %s\n", lang.c_str(), name.c_str());
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
langName[languangeOFF] = tmp; //name;
} else {
langName[lang] = tmp; //name;
}
}
std::string SIevent::getText() const
{
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
std::map<std::string, std::string>::const_iterator it = langText.begin() ;
if (it != langText.end()) return it->second;
else return("");
} else {
std::string retval;
SIlanguage::filter(langText, 0, retval);
return retval;
}
}
void SIevent::setText(const std::string &lang, const std::string &text)
{
//printf("setText: lang %s text %s\n", lang.c_str(), text.c_str());
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
langText[languangeOFF] = text;
} else {
langText[lang] = text;
}
}
std::string SIevent::getExtendedText() const
{
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
std::map<std::string, std::string>::const_iterator it = langExtendedText.begin() ;
if (it != langExtendedText.end()) return it->second;
else return("");
} else {
std::string retval;
SIlanguage::filter(langExtendedText, 0, retval);
return retval;
}
}
void SIevent::appendExtendedText(const std::string &lang, const std::string &text)
{
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
langExtendedText[languangeOFF] += text;
} else {
langExtendedText[lang] += text;
}
}
void SIevent::setExtendedText(const std::string &lang, const std::string &text)
{
//printf("setExtendedText: lang %s text %s\n", lang.c_str(), text.c_str());
if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) {
langExtendedText[languangeOFF] = text;
} else {
langExtendedText[lang] = text;
}
}
void SIevent::dump(void) const
{
printf("Unique key: %llx\n", uniqueKey());
if(original_network_id)
printf("Original-Network-ID: %hu\n", original_network_id);
if (service_id)
printf("Service-ID: %hu\n", service_id);
printf("Event-ID: %hu\n", eventID);
if(item.length())
printf("Item: %s\n", item.c_str());
if(itemDescription.length())
printf("Item-Description: %s\n", itemDescription.c_str());
for (std::map<std::string, std::string>::const_iterator it = langName.begin() ;
it != langName.end() ; ++it)
printf("Name (%s): %s\n", it->first.c_str(), it->second.c_str());
for (std::map<std::string, std::string>::const_iterator it = langText.begin() ;
it != langText.end() ; ++it)
printf("Text (%s): %s\n", it->first.c_str(), it->second.c_str());
for (std::map<std::string, std::string>::const_iterator it = langExtendedText.begin() ;
it != langExtendedText.end() ; ++it)
printf("Extended-Text (%s): %s\n", it->first.c_str(), it->second.c_str());
if(contentClassification.length()) {
printf("Content classification:");
for(unsigned i=0; i<contentClassification.length(); i++)
printf(" 0x%02hhx", contentClassification[i]);
printf("\n");
}
if(userClassification.length()) {
printf("User classification:");
for(unsigned i=0; i<userClassification.length(); i++)
printf(" 0x%02hhx", userClassification[i]);
printf("\n");
}
/*
if(startzeit)
printf("Startzeit: %s", ctime(&startzeit));
if(dauer)
printf("Dauer: %02u:%02u:%02u (%umin, %us)\n", dauer/3600, (dauer%3600)/60, dauer%60, dauer/60, dauer);
*/
for_each(times.begin(), times.end(), printSItime());
for_each(components.begin(), components.end(), printSIcomponent());
for_each(ratings.begin(), ratings.end(), printSIparentalRating());
for_each(linkage_descs.begin(), linkage_descs.end(), printSIlinkage());
}
void SIevent::dumpSmall(void) const
{
for (std::map<std::string, std::string>::const_iterator it = langName.begin() ;
it != langName.end() ; ++it)
printf("Name (%s): %s\n", it->first.c_str(), it->second.c_str());
for (std::map<std::string, std::string>::const_iterator it = langText.begin() ;
it != langText.end() ; ++it)
printf("Text (%s): %s\n", it->first.c_str(), it->second.c_str());
for (std::map<std::string, std::string>::const_iterator it = langExtendedText.begin() ;
it != langExtendedText.end() ; ++it)
printf("Extended-Text (%s): %s\n", it->first.c_str(), it->second.c_str());
/*
if(startzeit)
printf("Startzeit: %s", ctime(&startzeit));
if(dauer)
printf("Dauer: %02u:%02u:%02u (%umin, %us)\n", dauer/3600, (dauer%3600)/60, dauer%60, dauer/60, dauer);
*/
for_each(times.begin(), times.end(), printSItime());
for_each(ratings.begin(), ratings.end(), printSIparentalRating());
for_each(linkage_descs.begin(), linkage_descs.end(), printSIlinkage());
}
/*
// Liest n Bytes aus einem Socket per read
inline int readNbytes(int fd, char *buf, int n)
{
int j;
for(j=0; j<n;) {
int r=read (fd, buf, n-j);
if(r<=0) {
perror ("read");
return -1;
}
j+=r;
buf+=r;
}
return j;
}
*/
#ifndef DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
// Liest n Bytes aus einem Socket per read
// Liefert 0 bei timeout
// und -1 bei Fehler
// ansonsten die Anzahl gelesener Bytes
inline int readNbytes(int fd, char *buf, int n, unsigned timeoutInSeconds)
{
int j;
for(j=0; j<n;) {
struct pollfd ufds;
// memset(&ufds, 0, sizeof(ufds));
ufds.fd=fd;
ufds.events=POLLIN|POLLPRI;
ufds.revents=0;
int rc=poll(&ufds, 1, timeoutInSeconds*1000);
if(!rc)
return 0; // timeout
else if(rc<0) {
perror ("poll");
return -1;
}
int r=read (fd, buf, n-j);
if(r<=0) {
perror ("read");
return -1;
}
j+=r;
buf+=r;
}
return j;
}
SIevent SIevent::readActualEvent(t_service_id serviceID, unsigned timeoutInSeconds)
{
int fd;
SIevent evt; // Std-Event das bei Fehler zurueckgeliefert wird
struct SI_section_header header;
char *buf;
unsigned short section_length;
if ((fd = open(DEMUX_DEVICE, O_RDWR)) == -1) {
perror(DEMUX_DEVICE);
return evt;
}
if (!setfilter(fd, 0x12, 0x4e, 0xff, DMX_IMMEDIATE_START | DMX_CHECK_CRC)) {
close(fd);
return evt;
}
time_t szeit = time(NULL);
// Segment mit Event fuer sid suchen
do {
int rc = readNbytes(fd, (char *)&header, sizeof(header), timeoutInSeconds);
if(!rc)
break; // timeout
else if(rc<0) {
close(fd);
perror ("read header");
return evt;
}
section_length = (header.section_length_hi << 8) | header.section_length_lo;
buf = new char[sizeof(header) + section_length - 5];
if (!buf) {
close(fd);
printf("Not enough memory!\n");
return evt;
}
// Den Header kopieren
memmove(buf, &header, sizeof(header));
rc = readNbytes(fd, &buf[sizeof(header)], section_length - 5, timeoutInSeconds);
if(!rc) {
delete[] buf;
break; // timeout
}
if (rc < 0) {
close(fd);
delete[] buf;
perror ("read section");
return evt;
}
if (header.current_next_indicator) {
// Wir wollen nur aktuelle sections
SIsectionEIT e(SIsection(sizeof(header) + section_length - 5, buf));
time_t zeit = time(NULL);
for (SIevents::iterator k = e.events().begin(); k != e.events().end(); ++k)
if (k->service_id == serviceID)
for (SItimes::iterator t = k->times.begin(); t != k->times.end(); ++t)
if ((t->startzeit <= zeit) && (zeit <= (long)(t->startzeit+t->dauer))) {
close(fd);
return SIevent(*k);
}
}
else {
delete[] buf;
}
} while (time(NULL) < szeit + (long)timeoutInSeconds);
close(fd);
return evt;
}
void SIevents::removeOldEvents(long seconds)
{
time_t current_time = time(NULL);
for(SIevents::iterator it = begin(); it != end(); )
{
// "it->times.erase(kt);":
// passing `const SItimes' as `this' argument of `void set<SItime,less<SItime>,allocator<SItime> >::erase(_Rb_tree_iterator<SItime,const SItime &,const SItime *>)' discards qualifiers
// hence we have to modify a copy
SIevent copy_of_event(*it);
bool copy_has_changed = false;
for (SItimes::iterator jt = copy_of_event.times.begin(); jt != copy_of_event.times.end(); )
{
if ((jt->startzeit) + (int)(jt->dauer) < current_time - seconds)
{
copy_of_event.times.erase(jt++);
copy_has_changed = true;
}
else
++jt;
}
if (copy_has_changed)
{
erase(it++);
// Set has the important property that inserting a new element into a set does not
// invalidate iterators that point to existing elements.
if (copy_of_event.times.size() != 0)
#ifdef DEBUG
assert((++insert(it, copy_of_event)) == it);
#else
insert(it, copy_of_event); // it is the hint where to insert (I hope that doesn't invalidate it)
// insert(copy_of_event); // alternative method without hint
#endif
}
else
++it;
}
}
// Entfernt anhand der Services alle time shifted events (ohne Text,
// mit service-id welcher im nvod steht)
// und sortiert deren Zeiten in die Events mit dem Text ein.
void SIevents::mergeAndRemoveTimeShiftedEvents(const SIservices &services)
{
// Wir gehen alle services durch, suchen uns die services mit nvods raus
// und fuegen dann die Zeiten der Events mit der service-id eines nvods
// in das entsprechende Event mit der service-id das die nvods hat ein.
// die 'nvod-events' werden auch geloescht
// SIevents eventsToDelete; // Hier rein kommen Events die geloescht werden sollen
for(SIservices::iterator k=services.begin(); k!=services.end(); ++k)
if(k->nvods.size()) {
// NVOD-Referenzen gefunden
// Zuerst mal das Event mit dem Text holen
iterator e;
for(e=begin(); e!=end(); ++e)
if(e->service_id == k->service_id)
break;
if(e!=end()) {
// *e == event mit dem Text
SIevent newEvent(*e); // Kopie des Events
// Jetzt die nvods druchgehen und deren Uhrzeiten in obiges Event einfuegen
for(SInvodReferences::iterator n=k->nvods.begin(); n!=k->nvods.end(); ++n) {
// Alle druchgehen und deren Events suchen
for(iterator en=begin(); en!=end(); en++) {
if(en->service_id==n->getServiceID()) {
newEvent.times.insert(en->times.begin(), en->times.end());
// newEvent.times.insert(SItime(en->startzeit, en->dauer));
// eventsToDelete.insert(SIevent(*en));
}
}
}
erase(e); // Altes Event loeschen -> iterator (e) ung<6E>ltig
insert(newEvent); // und das erweiterte Event wieder einfuegen
}
}
//
// delete all events with serviceID that have a service type 0
//
for (iterator it = begin(); it != end(); )
{
SIservices::iterator s = services.find(SIservice(it->service_id, it->original_network_id, it->transport_stream_id));
if ((s != services.end()) && (s->serviceTyp == 0))
{
// Set is a Sorted Associative Container
// Erasing an element from a set also does not invalidate any iterators,
// except, of course, for iterators that actually point to the element
// that is being erased.
erase(it++);
}
else
++it;
}
}
#endif

488
src/eitd/SIevents.hpp Normal file
View File

@@ -0,0 +1,488 @@
#ifndef SIEVENTS_HPP
#define SIEVENTS_HPP
//
// $Id: SIevents.hpp,v 1.29 2008/08/16 19:23:18 seife Exp $
//
// classes SIevent and SIevents (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <endian.h>
#include <vector>
#include <map>
#include <sectionsdclient/sectionsdtypes.h>
#include "edvbstring.h"
//#include "SIutils.hpp"
// forward references
class SIservice;
class SIservices;
class SIbouquets;
struct eit_event {
unsigned event_id_hi : 8;
unsigned event_id_lo : 8;
unsigned start_time_hi : 8;
unsigned start_time_hi2 : 8;
unsigned start_time_mid : 8;
unsigned start_time_lo2 : 8;
unsigned start_time_lo : 8;
unsigned duration_hi : 8;
unsigned duration_mid : 8;
unsigned duration_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned running_status : 3;
unsigned free_CA_mode : 1;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned descriptors_loop_length_hi : 4;
unsigned free_CA_mode : 1;
unsigned running_status : 3;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ;
struct descr_component_header {
unsigned descriptor_tag : 8;
unsigned descriptor_length : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 4;
unsigned stream_content : 4;
#else
unsigned stream_content : 4;
unsigned reserved_future_use : 4;
#endif
unsigned component_type : 8;
unsigned component_tag : 8;
unsigned iso_639_2_language_code_hi : 8;
unsigned iso_639_2_language_code_mid : 8;
unsigned iso_639_2_language_code_lo : 8;
} __attribute__ ((packed)) ;
struct descr_linkage_header {
unsigned descriptor_tag : 8;
unsigned descriptor_length : 8;
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
unsigned service_id_hi : 8;
unsigned service_id_lo : 8;
unsigned linkage_type : 8;
} __attribute__ ((packed)) ;
struct descr_pdc_header {
unsigned descriptor_tag : 8;
unsigned descriptor_length : 8;
unsigned pil0 : 8;
unsigned pil1 : 8;
unsigned pil2 : 8;
} __attribute__ ((packed)) ;
class SIlinkage {
public:
SIlinkage(const struct descr_linkage_header *link) {
linkageType = link->linkage_type;
transportStreamId = (link->transport_stream_id_hi << 8) | link->transport_stream_id_lo;
originalNetworkId = (link->original_network_id_hi << 8) | link->original_network_id_lo;
serviceId = (link->service_id_hi << 8) | link->service_id_lo;
if (link->descriptor_length > sizeof(struct descr_linkage_header) - 2)
//name = std::string(((const char *)link) + sizeof(struct descr_linkage_header), link->descriptor_length - (sizeof(struct descr_linkage_header) - 2));
name = convertDVBUTF8(((const char *)link)+sizeof(struct descr_linkage_header), link->descriptor_length-(sizeof(struct descr_linkage_header)-2), 0, 0);
}
// Std-copy
SIlinkage(const SIlinkage &l) {
linkageType = l.linkageType;
transportStreamId = l.transportStreamId;
originalNetworkId = l.originalNetworkId;
serviceId = l.serviceId;
name = l.name;
}
// default
SIlinkage(void) {
linkageType = 0;
transportStreamId = 0;
originalNetworkId = 0;
serviceId = 0;
// name = ;
}
// Der Operator zum sortieren
bool operator < (const SIlinkage& l) const {
return name < l.name;
}
void dump(void) const {
printf("Linakge Type: 0x%02hhx\n", linkageType);
if (name.length())
printf("Name: %s\n", name.c_str());
printf("Transport Stream Id: 0x%04hhx\n", transportStreamId);
printf("Original Network Id: 0x%04hhx\n", originalNetworkId);
printf("Service Id: 0x%04hhx\n", serviceId);
}
int saveXML(FILE *file) const {
fprintf(file, "\t\t\t<linkage type=\"%02x\" linkage_descriptor=\"", linkageType);
saveStringToXMLfile(file, name.c_str());
fprintf(file, "\" transport_stream_id=\"%04x\" original_network_id=\"%04x\" service_id=\"%04x\" />\n", transportStreamId, originalNetworkId, serviceId);
// %s, , name.c_str())<0)
// return 1;
return 0;
}
unsigned char linkageType; // Linkage Descriptor
std::string name; // Text aus dem Linkage Descriptor
t_transport_stream_id transportStreamId; // Linkage Descriptor
t_original_network_id originalNetworkId; // Linkage Descriptor
t_service_id serviceId; // Linkage Descriptor
};
// Fuer for_each
struct printSIlinkage : public std::unary_function<class SIlinkage, void>
{
void operator() (const SIlinkage &l) { l.dump();}
};
// Fuer for_each
struct saveSIlinkageXML : public std::unary_function<class SIlinkage, void>
{
FILE *f;
saveSIlinkageXML(FILE *fi) { f=fi;}
void operator() (const SIlinkage &l) { l.saveXML(f);}
};
//typedef std::multiset <SIlinkage, std::less<SIlinkage> > SIlinkage_descs;
typedef std::vector<class SIlinkage> SIlinkage_descs;
class SIcomponent {
public:
SIcomponent(const struct descr_component_header *comp) {
streamContent=comp->stream_content;
componentType=comp->component_type;
componentTag=comp->component_tag;
if(comp->descriptor_length>sizeof(struct descr_component_header)-2)
//component=std::string(((const char *)comp)+sizeof(struct descr_component_header), comp->descriptor_length-(sizeof(struct descr_component_header)-2));
component=convertDVBUTF8(((const char *)comp)+sizeof(struct descr_component_header), comp->descriptor_length-(sizeof(struct descr_component_header)-2), 0, 0);
}
// Std-copy
SIcomponent(const SIcomponent &c) {
streamContent=c.streamContent;
componentType=c.componentType;
componentTag=c.componentTag;
component=c.component;
}
SIcomponent(void) {
streamContent=0;
componentType=0;
componentTag=0;
}
// Der Operator zum sortieren
bool operator < (const SIcomponent& c) const {
return streamContent < c.streamContent;
// return component < c.component;
}
void dump(void) const {
if(component.length())
printf("Component: %s\n", component.c_str());
printf("Stream Content: 0x%02hhx\n", streamContent);
printf("Component type: 0x%02hhx\n", componentType);
printf("Component tag: 0x%02hhx\n", componentTag);
}
int saveXML(FILE *file) const {
fprintf(file, "\t\t\t<component tag=\"%02x\" type=\"%02x\" stream_content=\"%02x\" text=\"", componentTag, componentType, streamContent);
saveStringToXMLfile(file,component.c_str());
fprintf(file, "\"/>\n");
// %s
// return 1;
// saveStringToXMLfile(file, component.c_str());
// fprintf(file, "\"/>\n");
return 0;
}
std::string component; // Text aus dem Component Descriptor
unsigned char componentType; // Component Descriptor
unsigned char componentTag; // Component Descriptor
unsigned char streamContent; // Component Descriptor
};
// Fuer for_each
struct printSIcomponent : public std::unary_function<class SIcomponent, void>
{
void operator() (const SIcomponent &c) { c.dump();}
};
// Fuer for_each
struct saveSIcomponentXML : public std::unary_function<class SIcomponent, void>
{
FILE *f;
saveSIcomponentXML(FILE *fi) { f=fi;}
void operator() (const SIcomponent &c) { c.saveXML(f);}
};
typedef std::multiset <SIcomponent, std::less<SIcomponent> > SIcomponents;
class SIparentalRating {
public:
SIparentalRating(const std::string &cc, unsigned char rate) {
rating=rate;
countryCode=cc;
}
// Std-Copy
SIparentalRating(const SIparentalRating &r) {
rating=r.rating;
countryCode=r.countryCode;
}
// Der Operator zum sortieren
bool operator < (const SIparentalRating& c) const {
return countryCode < c.countryCode;
}
void dump(void) const {
printf("Rating: %s %hhu (+3)\n", countryCode.c_str(), rating);
}
int saveXML(FILE *file) const {
if(fprintf(file, "\t\t\t<parental_rating country=\"%s\" rating=\"%hhu\"/>\n", countryCode.c_str(), rating)<0)
return 1;
return 0;
}
std::string countryCode;
unsigned char rating; // Bei 1-16 -> Minumim Alter = rating +3
};
// Fuer for_each
struct printSIparentalRating : public std::unary_function<SIparentalRating, void>
{
void operator() (const SIparentalRating &r) { r.dump();}
};
// Fuer for_each
struct saveSIparentalRatingXML : public std::unary_function<SIparentalRating, void>
{
FILE *f;
saveSIparentalRatingXML(FILE *fi) { f=fi;}
void operator() (const SIparentalRating &r) { r.saveXML(f);}
};
typedef std::set <SIparentalRating, std::less<SIparentalRating> > SIparentalRatings;
class SItime {
public:
SItime(time_t s, unsigned d) {
startzeit=s;
dauer=d; // in Sekunden, 0 -> time shifted (cinedoms)
}
// Std-Copy
SItime(const SItime &t) {
startzeit=t.startzeit;
dauer=t.dauer;
}
// Der Operator zum sortieren
bool operator < (const SItime& t) const {
return startzeit < t.startzeit;
}
void dump(void) const {
printf("Startzeit: %s", ctime(&startzeit));
printf("Dauer: %02u:%02u:%02u (%umin, %us)\n", dauer/3600, (dauer%3600)/60, dauer%60, dauer/60, dauer);
}
int saveXML(FILE *file) const { // saves the time
// Ist so noch nicht in Ordnung, das sollte untergliedert werden,
// da sonst evtl. time,date,duration,time,date,... auftritt
// und eine rein sequentielle Ordnung finde ich nicht ok.
/*
struct tm *zeit=localtime(&startzeit);
fprintf(file, "\t\t\t\t\t<time>%02d:%02d:%02d</time>\n", zeit->tm_hour, zeit->tm_min, zeit->tm_sec);
fprintf(file, "\t\t\t\t\t<date>%02d.%02d.%04d</date>\n", zeit->tm_mday, zeit->tm_mon+1, zeit->tm_year+1900);
fprintf(file, "\t\t\t\t\t<duration>%u</duration>\n", dauer);
*/
fprintf(file, "\t\t\t<time start_time=\"%u\" duration=\"%u\"/>\n", (unsigned int) startzeit, dauer);
return 0;
}
time_t startzeit; // lokale Zeit, 0 -> time shifted (cinedoms)
unsigned dauer; // in Sekunden, 0 -> time shifted (cinedoms)
};
typedef std::set <SItime, std::less<SItime> > SItimes;
// Fuer for_each
struct printSItime : public std::unary_function<SItime, void>
{
void operator() (const SItime &t) { t.dump();}
};
// Fuer for_each
struct saveSItimeXML : public std::unary_function<SItime, void>
{
FILE *f;
saveSItimeXML(FILE *fi) { f=fi;}
void operator() (const SItime &t) { t.saveXML(f);}
};
class SIevent {
public:
t_service_id service_id;
t_original_network_id original_network_id;
t_transport_stream_id transport_stream_id;
SIevent(const struct eit_event *);
// Std-Copy
SIevent(const SIevent &);
SIevent(const t_original_network_id, const t_transport_stream_id, const t_service_id, const unsigned short);
SIevent(void) {
service_id = 0;
original_network_id = 0;
transport_stream_id = 0;
eventID = 0;
vps = 0;
table_id = 0xFF; /* 0xFF means "not set" */
version = 0xFF;
// dauer=0;
// startzeit=0;
}
unsigned short eventID;
// Name aus dem Short-Event-Descriptor
std::string getName() const;
void setName(const std::string &lang, const std::string &name);
// Text aus dem Short-Event-Descriptor
std::string getText() const;
void setText(const std::string &lang, const std::string &text);
std::string itemDescription; // Aus dem Extended Descriptor
std::string item; // Aus dem Extended Descriptor
// Aus dem Extended Descriptor
std::string getExtendedText() const;
void appendExtendedText(const std::string &lang, const std::string &text);
void setExtendedText(const std::string &lang, const std::string &text);
std::string contentClassification; // Aus dem Content Descriptor, als String, da mehrere vorkommen koennen
std::string userClassification; // Aus dem Content Descriptor, als String, da mehrere vorkommen koennen
// time_t startzeit; // lokale Zeit, 0 -> time shifted (cinedoms)
// unsigned dauer; // in Sekunden, 0 -> time shifted (cinedoms)
t_channel_id get_channel_id(void) const {
return CREATE_CHANNEL_ID;
}
event_id_t uniqueKey(void) const {
return CREATE_EVENT_ID(CREATE_CHANNEL_ID, eventID);
}
int runningStatus(void) const {
return running;
}
SIcomponents components;
SIparentalRatings ratings;
SIlinkage_descs linkage_descs;
SItimes times;
time_t vps;
unsigned char table_id;
unsigned char version;
// Der Operator zum sortieren
bool operator < (const SIevent& e) const {
return uniqueKey()<e.uniqueKey();
}
int saveXML(FILE *file) const { // saves the event
return saveXML0(file) || saveXML2(file);
}
int saveXML(FILE *file, const char *serviceName) const; // saves the event
void dump(void) const; // dumps the event to stdout
void dumpSmall(void) const; // dumps the event to stdout (not all information)
#ifndef DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
// Liefert das aktuelle EPG des senders mit der uebergebenen serviceID,
// bei Fehler ist die serviceID des zurueckgelieferten Events 0
static SIevent readActualEvent(t_service_id serviceID, unsigned timeoutInSeconds=2);
#endif
char getFSK() const;
protected:
int saveXML0(FILE *f) const;
int saveXML2(FILE *f) const;
private:
std::map<std::string, std::string> langName;
std::map<std::string, std::string> langText;
std::map<std::string, std::string> langExtendedText;
int running;
};
// Fuer for_each
struct printSIevent : public std::unary_function<SIevent, void>
{
void operator() (const SIevent &e) { e.dump();}
};
// Fuer for_each
struct saveSIeventXML : public std::unary_function<SIevent, void>
{
FILE *f;
saveSIeventXML(FILE *fi) { f=fi;}
void operator() (const SIevent &e) { e.saveXML(f);}
};
// Fuer for_each
struct saveSIeventXMLwithServiceName : public std::unary_function<SIevent, void>
{
FILE *f;
const SIservices *s;
saveSIeventXMLwithServiceName(FILE *fi, const SIservices &svs) {f=fi; s=&svs;}
void operator() (const SIevent &e) {
SIservices::iterator k=s->find(SIservice(e.service_id, e.original_network_id, e.transport_stream_id));
if(k!=s->end()) {
if(k->serviceName.length())
e.saveXML(f, k->serviceName.c_str());
}
else
e.saveXML(f);
}
};
// Fuer for_each
struct printSIeventWithService : public std::unary_function<SIevent, void>
{
printSIeventWithService(const SIservices &svs) { s=&svs;}
void operator() (const SIevent &e) {
SIservices::iterator k=s->find(SIservice(e.service_id, e.original_network_id, e.transport_stream_id));
if(k!=s->end()) {
char servicename[50];
strncpy(servicename, k->serviceName.c_str(), sizeof(servicename)-1);
servicename[sizeof(servicename)-1]=0;
removeControlCodes(servicename);
printf("Service-Name: %s\n", servicename);
// printf("Provider-Name: %s\n", k->providerName.c_str());
}
e.dump();
// e.dumpSmall();
printf("\n");
}
const SIservices *s;
};
class SIevents : public std::set <SIevent, std::less<SIevent> >
{
public:
// Entfernt anhand der Services alle time shifted events (Service-Typ 0)
// und sortiert deren Zeiten in die Events mit dem Text ein.
void mergeAndRemoveTimeShiftedEvents(const SIservices &);
// Loescht alte Events (aufgrund aktueller Zeit - seconds und Zeit im Event)
void removeOldEvents(long seconds);
};
#endif // SIEVENTS_HPP

220
src/eitd/SIlanguage.cpp Normal file
View File

@@ -0,0 +1,220 @@
//
// $Id: SIlanguage.cpp,v 1.4 2006/04/21 20:40:13 houdini Exp $
//
// Class for filtering preferred language
//
// Copyright (C) 2001 arzka (dbox2@oh3mqu.pp.hyper.fi)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Log: SIlanguage.cpp,v $
// Revision 1.4 2006/04/21 20:40:13 houdini
// improvments when not using the MultiLanguageEPG feature
//
// Revision 1.3 2006/04/13 19:10:54 mws
// bugfix returned wrong value for error while saving;
// preincrement iterators;
//
// Revision 1.2 2006/04/12 21:23:58 Arzka
// Optimization.
// Removed unnecessary copying of std:map and
// removed few avoidable std::string creation
//
// Revision 1.1 2006/03/26 20:13:49 Arzka
// Added support for selecting EPG language
//
//
//
#include "SIlanguage.hpp"
#include <string>
#include <vector>
#include <map>
#include <pthread.h>
#include <fstream>
#include <sectionsdclient/sectionsdclient.h>
#define LANGUAGEFILE "/var/tuxbox/config/epglanguages.conf"
std::vector<std::string> SIlanguage::languages;
pthread_mutex_t SIlanguage::languages_lock = PTHREAD_MUTEX_INITIALIZER;
/*
ALL = Show all available languages
FIRST_FIRST = Show first found language from list. If not found show first of available language
FIRST_ALL = Show first found language from list. If not found show all available languages.
ALL_FIRST = Show all wanted languages if possible. If not found show first of av ailable language
ALL_ALL = Show all wanted languages if possible. If not found show all available languages.
*/
//CSectionsdClient::SIlanguageMode_t SIlanguage::mode = CSectionsdClient::ALL;
CSectionsdClient::SIlanguageMode_t SIlanguage::mode = CSectionsdClient::FIRST_ALL;
void SIlanguage::filter(const std::map<std::string, std::string>& s, int max, std::string& retval)
{
pthread_mutex_lock(&languages_lock);
// languages cannot get iterated through
// if another thread is updating it simultaneously
int count = max;
if (mode != CSectionsdClient::ALL) {
for (std::vector<std::string>::const_iterator it = languages.begin() ;
it != languages.end() ; ++it) {
std::map<std::string,std::string>::const_iterator text;
if ((text = s.find(*it)) != s.end()) {
if (count != max) {
retval.append(" \n");
}
retval.append(text->second);
if (--count == 0) break;
if (mode == CSectionsdClient::FIRST_FIRST ||
mode == CSectionsdClient::FIRST_ALL) {
break;
}
}
}
}
if (retval.length() == 0) {
// return all available languages
if (s.begin() != s.end()) {
for (std::map<std::string, std::string>::const_iterator it = s.begin() ;
it != s.end() ; ++it) {
if (it != s.begin()) {
retval.append(" \n");
}
retval.append(it->second);
if (--max == 0) break;
if (mode == CSectionsdClient::FIRST_FIRST ||
mode == CSectionsdClient::ALL_FIRST) {
break;
}
}
}
}
pthread_mutex_unlock(&languages_lock);
}
bool SIlanguage::loadLanguages()
{
pthread_mutex_lock(&languages_lock);
std::ifstream file(LANGUAGEFILE);
std::string word;
CSectionsdClient::SIlanguageMode_t tmpMode = CSectionsdClient::FIRST_ALL;
std::vector<std::string> tmpLang;
if (!(file >> word)) goto error;
if (word == "FIRST_FIRST") {
tmpMode = CSectionsdClient::FIRST_FIRST;
} else if (word == "FIRST_ALL") {
tmpMode = CSectionsdClient::FIRST_ALL;
} else if (word == "ALL_FIRST") {
tmpMode = CSectionsdClient::ALL_FIRST;
} else if (word == "ALL_ALL") {
tmpMode = CSectionsdClient::ALL_ALL;
} else if (word == "OFF") {
tmpMode = CSectionsdClient::LANGUAGE_MODE_OFF;
}
while (!file.eof()) {
if ((file >> word)) {
tmpLang.push_back(word);
}
}
if (tmpLang.empty()) tmpLang.push_back("OFF");
languages = tmpLang;
mode = tmpMode;
pthread_mutex_unlock(&languages_lock);
return true;
error:
tmpLang.push_back("OFF");
languages = tmpLang;
mode = tmpMode;
pthread_mutex_unlock(&languages_lock);
return false;
}
bool SIlanguage::saveLanguages()
{
pthread_mutex_lock(&languages_lock);
std::ofstream file(LANGUAGEFILE);
switch(mode) {
case CSectionsdClient::ALL:
file << "ALL\n";
break;
case CSectionsdClient::FIRST_FIRST:
file << "FIRST_FIRST\n";
break;
case CSectionsdClient::FIRST_ALL:
file << "FIRST_ALL\n";
break;
case CSectionsdClient::ALL_FIRST:
file << "ALL_FIRST\n";
break;
case CSectionsdClient::ALL_ALL:
file << "ALL_ALL\n";
break;
case CSectionsdClient::LANGUAGE_MODE_OFF:
file << "OFF\n";
break;
}
for (std::vector<std::string>::iterator it = languages.begin() ;
it != languages.end() ; ++it) {
file << *it;
file << "\n";
if (file.fail()) goto error;
}
file.close();
if (file.fail()) goto error;
pthread_mutex_unlock(&languages_lock);
return true;
error:
pthread_mutex_unlock(&languages_lock);
return false;
}
void SIlanguage::setLanguages(const std::vector<std::string>& newLanguages)
{
pthread_mutex_lock(&languages_lock);
languages = newLanguages;
pthread_mutex_unlock(&languages_lock);
}
std::vector<std::string> SIlanguage::getLanguages()
{
pthread_mutex_lock(&languages_lock);
std::vector<std::string> retval(languages); // Store it before unlock
pthread_mutex_unlock(&languages_lock);
return retval;
}
void SIlanguage::setMode(CSectionsdClient::SIlanguageMode_t newMode)
{
mode = newMode;
}
CSectionsdClient::SIlanguageMode_t SIlanguage::getMode()
{
return mode;
}

62
src/eitd/SIlanguage.hpp Normal file
View File

@@ -0,0 +1,62 @@
#ifndef SILANGUAGES_HPP
#define SILANGUAGES_HPP
//
// $Id: SIlanguage.hpp,v 1.2 2006/04/12 21:23:58 Arzka Exp $
//
// Class for filtering preferred language
//
// Copyright (C) 2001 arzka (dbox2@oh3mqu.pp.hyper.fi)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Log: SIlanguage.hpp,v $
// Revision 1.2 2006/04/12 21:23:58 Arzka
// Optimization.
// Removed unnecessary copying of std:map and
// removed few avoidable std::string creation
//
// Revision 1.1 2006/03/26 20:13:49 Arzka
// Added support for selecting EPG language
//
//
//
#include <string>
#include <vector>
#include <map>
#include <sectionsdclient/sectionsdclient.h>
#define LANGUAGEFILE "/var/tuxbox/config/epglanguages.conf"
class SIlanguage {
public:
static void filter(const std::map<std::string, std::string>& s, int max, std::string& retval);
static bool loadLanguages();
static bool saveLanguages();
static void setLanguages(const std::vector<std::string>& newLanguages);
static std::vector<std::string> getLanguages();
static void setMode(CSectionsdClient::SIlanguageMode_t newMode);
static CSectionsdClient::SIlanguageMode_t getMode();
private:
SIlanguage();
~SIlanguage();
static std::vector<std::string> languages;
static pthread_mutex_t languages_lock;
static CSectionsdClient::SIlanguageMode_t mode;
};
#endif

183
src/eitd/SInetworks.hpp Normal file
View File

@@ -0,0 +1,183 @@
#ifndef SINETWORKS_HPP
#define SINETWORKS_HPP
//
// $Id: SInetworks.hpp,v 1.3 2006/02/08 21:15:50 houdini Exp $
//
// classes SIservices and SIservices (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de),
// 2002 thegoodguy (thegoodguy@berlios.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <algorithm>
#include <endian.h>
#include <sectionsdclient/sectionsdMsg.h>
// forward references
class SIservice;
class SIevent;
class SInetwork;
/*
struct loop_len {
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 4;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned descriptors_loop_length_hi : 4;
unsigned reserved_future_use : 4;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ; // 2 Bytes
*/
struct nit_transponder {
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 4;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned descriptors_loop_length_hi : 4;
unsigned reserved_future_use : 4;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ; // 6 Bytes
struct satellite_delivery_descriptor {
unsigned frequency_1 : 8;
unsigned frequency_2 : 8;
unsigned frequency_3 : 8;
unsigned frequency_4 : 8;
unsigned orbital_pos_hi : 8;
unsigned orbital_pos_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned west_east_flag : 1;
unsigned polarization : 2;
unsigned modulation : 5;
#else
unsigned modulation : 5;
unsigned polarization : 2;
unsigned west_east_flag : 1;
#endif
unsigned symbol_rate_1 : 8;
unsigned symbol_rate_2 : 8;
unsigned symbol_rate_3 : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned symbol_rate_4 : 4;
unsigned fec_inner : 4;
#else
unsigned fec_inner : 4;
unsigned symbol_rate_4 : 4;
#endif
} __attribute__ ((packed)) ; // 11 Bytes
struct cable_delivery_descriptor {
unsigned frequency_1 : 8;
unsigned frequency_2 : 8;
unsigned frequency_3 : 8;
unsigned frequency_4 : 8;
unsigned reserved_hi : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_lo : 4;
unsigned fec_outer : 4;
#else
unsigned fec_outer : 4;
unsigned reserved_lo : 4;
#endif
unsigned modulation : 8;
unsigned symbol_rate_1 : 8;
unsigned symbol_rate_2 : 8;
unsigned symbol_rate_3 : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned symbol_rate_4 : 4;
unsigned fec_inner : 4;
#else
unsigned fec_inner : 4;
unsigned symbol_rate_4 : 4;
#endif
} __attribute__ ((packed)) ; // 11 Bytes
class SInetwork {
public:
SInetwork(const struct nit_transponder *s) {
network_id = 0;
transport_stream_id = 0;
original_network_id = 0;
delivery_type = 0;
is_actual = false;
}
// Um einen service zum Suchen zu erstellen
SInetwork(const t_network_id _network_id, const t_original_network_id _original_network_id, const t_transport_stream_id _transport_stream_id)
{
network_id = _network_id;
original_network_id = _original_network_id;
transport_stream_id = _transport_stream_id;
}
// Std-Copy
SInetwork(const SInetwork &s) {
network_id = s.network_id;
original_network_id = s.original_network_id;
transport_stream_id = s.transport_stream_id;
delivery_type = s.delivery_type;
is_actual = s.is_actual;
memmove(delivery_descriptor, s.delivery_descriptor, sizeof(struct satellite_delivery_descriptor));
}
t_network_id network_id;
t_original_network_id original_network_id;
t_transport_stream_id transport_stream_id;
unsigned short delivery_type;
bool is_actual;
char delivery_descriptor[sizeof(struct satellite_delivery_descriptor)];
bool operator < (const SInetwork& s) const {
return uniqueKey() < s.uniqueKey();
}
t_transponder_id uniqueKey(void) const {
return CREATE_TRANSPONDER_ID_FROM_ORIGINALNETWORK_TRANSPORTSTREAM_ID(original_network_id, transport_stream_id);
}
void dump(void) const {
printf("Original-Network-ID: %hu\n", original_network_id);
printf("Transport-Stream-ID: %hu\n", transport_stream_id);
}
};
// Fuer for_each
struct printSInetwork : public std::unary_function<SInetwork, void>
{
void operator() (const SInetwork &s) { s.dump();}
};
// Als Klasse, da ich nicht weiss, wie man eine Forward-Referenz auf ein typedef macht
class SInetworks : public std::set <SInetwork, std::less<SInetwork> >
{
};
#endif // SINETWORKS_HPP

1636
src/eitd/SIsections.cpp Normal file

File diff suppressed because it is too large Load Diff

984
src/eitd/SIsections.hpp Normal file
View File

@@ -0,0 +1,984 @@
#ifndef SISECTIONS_HPP
#define SISECTIONS_HPP
//
// $Id: SIsections.hpp,v 1.28 2009/07/26 17:02:46 rhabarber1848 Exp $
//
// classes for SI sections (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de)
// Copyright (C) 2003 Andreas Oberritter <obi@tuxbox.org>
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <endian.h>
#ifdef UPDATE_NETWORKS
#include "SInetworks.hpp"
#include "SIbouquets.hpp"
#endif
struct SI_section_SDT_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
unsigned reserved_future_use2 : 8;
} __attribute__ ((packed)) ; // 11 bytes
struct SI_section_NIT_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned network_id_hi : 8;
unsigned network_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use2 : 4;
unsigned network_descriptors_length_hi : 4;
#else
unsigned network_descriptors_length_hi : 4;
unsigned reserved_future_use2 : 4;
#endif
unsigned network_descriptors_length_lo : 8;
} __attribute__ ((packed)) ; // 10 bytes
struct SI_section_BAT_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned bouquet_id_hi : 8;
unsigned bouquet_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use2 : 4;
unsigned bouquet_descriptors_length_hi : 4;
#else
unsigned bouquet_descriptors_length_hi : 4;
unsigned reserved_future_use2 : 4;
#endif
unsigned bouquet_descriptors_length_lo : 8;
} __attribute__ ((packed)) ; // 10 bytes
struct SI_section_EIT_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned service_id_hi : 8;
unsigned service_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
unsigned segment_last_section_number : 8;
unsigned last_table_id : 8;
} __attribute__ ((packed)) ; // 14 bytes
// Muss evtl. angepasst werden falls damit RST, TDT und TOT gelesen werden sollen
// ^^^
// RST usw. haben section_syntax_indicator == 0, andere == 1 (obi)
struct SI_section_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned table_id_extension_hi : 8;
unsigned table_id_extension_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
} __attribute__ ((packed)) ; // 8 bytes
#ifdef ENABLE_PPT
struct SI_section_PPT_header { // Premiere Private Table
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
unsigned table_id_extension_hi : 8;
unsigned table_id_extension_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved2 : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
unsigned content_id_32_25 : 8;
unsigned content_id_24_17 : 8;
unsigned content_id_16_9 : 8;
unsigned content_id_8_0 : 8;
unsigned duration_hi : 8;
unsigned duration_mid : 8;
unsigned duration_lo : 8;
unsigned reserved3 : 4;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned descriptor_section_length_hi : 4;
unsigned descriptor_section_length_lo : 8;
#else
unsigned descriptor_section_length_lo : 8;
unsigned descriptor_section_length_hi : 4;
#endif
} __attribute__ ((packed)) ; // 8 bytes
#endif
class SIsection
{
public:
SIsection(void) { buffer = 0; bufferLength = 0;}
#if 0
// Kopierte den Puffer in eigenen Puffer
SIsection(const char *buf, unsigned bufLength) {
buffer = 0; bufferLength = 0;
if ((buf) && (bufLength >= sizeof(struct SI_section_header))) {
buffer = new char[bufLength];
if (buffer) {
bufferLength = bufLength;
memmove(buffer, buf, bufLength);
}
}
}
#endif
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsection(unsigned bufLength, char *buf) {
buffer = 0; bufferLength = 0;
if ((buf) && (bufLength >= sizeof(struct SI_section_header))) {
buffer = buf;
bufferLength = bufLength;
}
}
#if 0
// Konstruktor um eine (leere) SIsection mit den fuer Vergleiche
// noetigen Inhalte (s. key) zu erstellen
SIsection(const struct SI_section_header *header) {
bufferLength = 0;
buffer = new char[sizeof(struct SI_section_header)];
if (buffer) {
memmove(buffer, header, sizeof(struct SI_section_header));
bufferLength = sizeof(struct SI_section_header);
}
}
// Std-Copy
SIsection(const SIsection &s) {
buffer = 0; bufferLength = 0;
if (s.buffer) {
buffer = new char[s.bufferLength];
if (buffer) {
bufferLength = s.bufferLength;
memmove(buffer, s.buffer, bufferLength);
}
}
}
#endif
// Destruktor
virtual ~SIsection(void) {
bufferLength = 0;
}
unsigned char tableID(void) const {
return buffer ? ((struct SI_section_header *)buffer)->table_id : (unsigned char) -1;
}
unsigned short tableIDextension(void) const {
return buffer ? ((((struct SI_section_header *)buffer)->table_id_extension_hi << 8) |
((struct SI_section_header *)buffer)->table_id_extension_lo) : (unsigned short) -1;
}
unsigned char sectionNumber(void) const {
return buffer ? ((struct SI_section_header *)buffer)->section_number : (unsigned char) -1;
}
unsigned char versionNumber(void) const {
return buffer ? ((struct SI_section_header *)buffer)->version_number : (unsigned char) -1;
}
unsigned char currentNextIndicator(void) const {
return buffer ? ((struct SI_section_header *)buffer)->current_next_indicator : (unsigned char) -1;
}
unsigned char lastSectionNumber(void) const {
return buffer ? ((struct SI_section_header *)buffer)->last_section_number : (unsigned char) -1;
}
struct SI_section_header const *header(void) const {
return (struct SI_section_header *)buffer;
}
static uint64_t key(const struct SI_section_header *header) {
// Der eindeutige Key einer SIsection besteht aus 1 Byte Table-ID,
// 2 Byte Table-ID-extension, 1 Byte Section number
// 1 Byte Version number und 1 Byte current_next_indicator
if (!header)
return (uint64_t) -1;
return (((uint64_t)header->table_id) << 40) +
(((uint64_t)header->table_id_extension_hi) << 32) +
(((uint64_t)header->table_id_extension_lo) << 24) +
(((uint64_t)header->section_number) << 16) +
(((uint64_t)header->version_number) << 8) +
(((uint64_t)header->current_next_indicator));
}
uint64_t key(void) const {
return buffer ? key(header()) : (uint64_t) -1;
}
// Der Operator zum sortieren
bool operator < (const SIsection& s) const {
return key() < s.key();
}
static void dumpSmallSectionHeader(const struct SI_section_header *header) {
if (!header)
return;
printf("\ntable_id: 0x%02x ", header->table_id);
printf("table_id_extension: 0x%02x%02x", header->table_id_extension_hi, header->table_id_extension_lo);
printf("section_number: 0x%02x\n", header->section_number);
}
static void dumpSmallSectionHeader(const SIsection &s) {
dumpSmallSectionHeader((struct SI_section_header *)s.buffer);
}
void dumpSmallSectionHeader(void) const {
dumpSmallSectionHeader((struct SI_section_header *)buffer);
}
int saveBufferToFile(FILE *file) const {
if (!file)
return 1;
return (fwrite(buffer, bufferLength, 1, file) != 1);
}
int saveBufferToFile(const char *filename) const {
if (!filename)
return 2;
FILE *file = fopen(filename, "wb");
if (file) {
int rc = saveBufferToFile(file);
fclose(file);
return rc;
}
return 2;
}
static void dump1(const struct SI_section_header *header) {
if (!header)
return;
printf("\ntable_id: 0x%02x\n", header->table_id);
printf("section_syntax_indicator: 0x%02x\n", header->section_syntax_indicator);
printf("section_length: %hu\n", (header->section_length_hi << 8) | header->section_length_lo);
}
static void dump2(const struct SI_section_header *header) {
if (!header)
return;
printf("version_number: 0x%02x\n", header->version_number);
printf("current_next_indicator: 0x%02x\n", header->current_next_indicator);
printf("section_number: 0x%02x\n", header->section_number);
printf("last_section_number: 0x%02x\n", header->last_section_number);
}
static void dump(const struct SI_section_header *header) {
if (!header)
return;
dump1(header);
printf("table_id_extension: 0x%02x%02x\n", header->table_id_extension_hi, header->table_id_extension_lo);
dump2(header);
}
static void dump(const SIsection &s) {
dump((struct SI_section_header *)s.buffer);
}
void dump(void) const {
dump((struct SI_section_header *)buffer);
}
protected:
char *buffer;
unsigned bufferLength;
};
// Fuer for_each
struct printSIsection : public std::unary_function<SIsection, void>
{
void operator() (const SIsection &s) { s.dump();}
};
// Fuer for_each
struct printSmallSIsectionHeader : public std::unary_function<SIsection, void>
{
void operator() (const SIsection &s) { s.dumpSmallSectionHeader();}
};
class SIsections : public std::set <SIsection, std::less<SIsection> >
{
public:
// Liefert 0 falls kein Fehler
// Algo:
// (1) Segment lesen (wird zum ersten Segment deklariert)
// (2) Falls Segmentnummer = letze Segmentnummer = 0 dann fertig, sonst
// (3) alle Segment lesen bis erstes wieder kommt
// (4) fehlende Segmente (s. last_section_number) versuchen zu lesen
// Der Timeout gilt fuer jeden der 3 Abschnitte, d.h. maximal dauert
// es 3 x timeout.
// Mit readNext=0 werden nur aktuelle Sections gelesen (current_next_indicator = 1)
int readSections(unsigned short pid, unsigned char filter, unsigned char mask, int readNext=0, unsigned timeoutInSeconds=10);
};
class SIsectionEIT : public SIsection
{
public:
SIsectionEIT(const SIsection &s) : SIsection(s) {
parsed = 0;
parse();
}
// Std-Copy
SIsectionEIT(const SIsectionEIT &s) : SIsection(s) {
evts = s.evts;
parsed = s.parsed;
}
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsectionEIT(unsigned bufLength, char *buf) : SIsection(bufLength, buf) {
parsed = 0;
parse();
}
t_service_id service_id(void) const {
return buffer ? ((((struct SI_section_EIT_header *)buffer)->service_id_hi << 8) |
((struct SI_section_EIT_header *)buffer)->service_id_lo): 0;
}
t_original_network_id original_network_id(void) const {
return buffer ? ((((struct SI_section_EIT_header *)buffer)->original_network_id_hi << 8) |
((struct SI_section_EIT_header *)buffer)->original_network_id_lo) : 0;
}
t_transport_stream_id transport_stream_id(void) const {
return buffer ? ((((struct SI_section_EIT_header *)buffer)->transport_stream_id_hi << 8) |
((struct SI_section_EIT_header *)buffer)->transport_stream_id_lo) : 0;
}
struct SI_section_EIT_header const *header(void) const {
return (struct SI_section_EIT_header *)buffer;
}
static void dump(const struct SI_section_EIT_header *header) {
if (!header)
return;
SIsection::dump1((const struct SI_section_header *)header);
printf("service_id: 0x%02x%02x\n", header->service_id_hi, header->service_id_lo);
SIsection::dump2((const struct SI_section_header *)header);
printf("transport_stream_id 0x%02x%02x\n", header->transport_stream_id_hi, header->transport_stream_id_lo);
printf("original_network_id 0x%02x%02x\n", header->original_network_id_hi, header->original_network_id_lo);
printf("segment_last_section_number: 0x%02x\n", header->segment_last_section_number);
printf("last_table_id 0x%02x\n", header->last_table_id);
}
static void dump(const SIsectionEIT &s) {
dump((struct SI_section_EIT_header *)s.buffer);
for_each(s.evts.begin(), s.evts.end(), printSIevent());
}
void dump(void) const {
dump((struct SI_section_EIT_header *)buffer);
for_each(evts.begin(), evts.end(), printSIevent());
}
const SIevents &events(void) const {
//if(!parsed)
// parse(); -> nicht const
return evts;
}
int is_parsed(void) const {
return parsed;
}
protected:
SIevents evts;
int parsed;
void parse(void);
void parseDescriptors(const char *desc, unsigned len, SIevent &e);
void parseShortEventDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseExtendedEventDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseContentDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseComponentDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseParentalRatingDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseLinkageDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parsePDCDescriptor(const char *buf, SIevent &e, unsigned maxlen);
#ifdef ENABLE_FREESATEPG
std::string freesatHuffmanDecode(std::string input);
#endif
};
#ifdef ENABLE_PPT
class SIsectionPPT : public SIsection
{
public:
SIsectionPPT(const SIsection &s) : SIsection(s) {
parsed = 0;
parse();
}
// Std-Copy
SIsectionPPT(const SIsectionPPT &s) : SIsection(s) {
evts = s.evts;
parsed = s.parsed;
}
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsectionPPT(unsigned bufLength, char *buf) : SIsection(bufLength, buf) {
parsed = 0;
parse();
}
long content_id(void) const {
return buffer ? ((((struct SI_section_PPT_header *)buffer)->content_id_32_25<< 24) |
(((struct SI_section_PPT_header *)buffer)->content_id_24_17<< 16) |
(((struct SI_section_PPT_header *)buffer)->content_id_16_9<< 8) |
((struct SI_section_PPT_header *)buffer)->content_id_8_0): 0;
}
long duration(void) const {
if (!buffer) return(0);
if (!((((struct SI_section_PPT_header *)buffer)->duration_hi == 0xff) &&
(((struct SI_section_PPT_header *)buffer)->duration_mid == 0xff) &&
(((struct SI_section_PPT_header *)buffer)->duration_lo == 0xff)))
return ((((struct SI_section_PPT_header *)buffer)->duration_hi)>>4)*10*3600L + ((((struct SI_section_PPT_header *)buffer)->duration_hi)&0x0f)*3600L +
((((struct SI_section_PPT_header *)buffer)->duration_mid)>>4)*10*60L + ((((struct SI_section_PPT_header *)buffer)->duration_mid)&0x0f)*60L +
((((struct SI_section_PPT_header *)buffer)->duration_lo)>>4)*10 + ((((struct SI_section_PPT_header *)buffer)->duration_lo)&0x0f);
return(0);
}
short int descriptor_section_length(void) const {
return buffer ? ((((struct SI_section_PPT_header *)buffer)->descriptor_section_length_hi << 8) |
((struct SI_section_PPT_header *)buffer)->descriptor_section_length_lo) : 0;
}
struct SI_section_PPT_header const *header(void) const {
return (struct SI_section_PPT_header *)buffer;
}
static void dump(const struct SI_section_PPT_header *header) {
if (!header)
return;
SIsection::dump1((const struct SI_section_header *)header);
printf("table_id_extension: 0x%02x%02x\n", header->table_id_extension_hi, header->table_id_extension_lo);
SIsection::dump1((const struct SI_section_header *)header);
printf("content id 0x%02x%02x%02x%02x\n", header->content_id_32_25, header->content_id_24_17, header->content_id_16_9, header->content_id_8_0);
printf("duration 0x%02x%02x%02x\n", header->duration_hi, header->duration_mid, header->duration_lo);
printf("reserved3 0x%02x\n", header->reserved3);
printf("descriptor section length 0x%02x%02x\n", header->descriptor_section_length_hi, header->descriptor_section_length_lo);
}
static void dump(const SIsectionPPT &s) {
dump((struct SI_section_PPT_header *)s.buffer);
for_each(s.evts.begin(), s.evts.end(), printSIevent());
}
void dump(void) const {
dump((struct SI_section_PPT_header *)buffer);
for_each(evts.begin(), evts.end(), printSIevent());
}
const SIevents &events(void) const {
//if(!parsed)
// parse(); -> nicht const
return evts;
}
int is_parsed(void) const {
return parsed;
}
protected:
SIevents evts;
int parsed;
void parse(void);
void parseDescriptors(const char *desc, unsigned len, SIevent &e);
void parseShortEventDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseExtendedEventDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseContentDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseComponentDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseParentalRatingDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parseLinkageDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parsePrivateContentOrderDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parsePrivateParentalInformationDescriptor(const char *buf, SIevent &e, unsigned maxlen);
void parsePrivateContentTransmissionDescriptor(const char *buf, SIevent &e, unsigned maxlen);
};
#endif
#ifndef DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
// Fuer for_each
struct printSIsectionEIT : public std::unary_function<SIsectionEIT, void>
{
void operator() (const SIsectionEIT &s) { s.dump();}
};
#ifdef ENABLE_PPT
// Fuer for_each
struct printSIsectionPPT : public std::unary_function<SIsectionPPT, void>
{
void operator() (const SIsectionPPT &s) { s.dump();}
};
#endif
/*
// Fuer for_each
struct parseSIsectionEIT : public std::unary_function<SIsectionEIT, void>
{
void operator() (const SIsectionEIT &s) { s.parse();}
};
*/
// Menge aller present/following EITs (actual TS)
class SIsectionsEIT : public std::set <SIsectionEIT, std::less<SIsectionEIT> >
{
public:
int readSections(void) {
SIsections sections;
int rc=sections.readSections(0x12, 0x4e, 0xff);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
#ifdef ENABLE_PPT
// Menge aller present/following PPTs (actual TS)
class SIsectionsPPT : public std::set <SIsectionPPT, std::less<SIsectionPPT> >
{
public:
int readSections(int pid) {
// int readSections(void) {
SIsections sections;
int rc=sections.readSections(pid, 0xa1, 0xfe);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
#endif
// Menge aller schedule EITs (actual TS)
class SIsectionsEITschedule : public std::set <SIsectionEIT, std::less<SIsectionEIT> >
{
public:
int readSections(void) {
SIsections sections;
int rc=sections.readSections(0x12, 0x50, 0xf0);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
#endif
class SIsectionSDT : public SIsection
{
public:
SIsectionSDT(const SIsection &s) : SIsection(s) {
parsed = 0;
parse();
}
// Std-Copy
SIsectionSDT(const SIsectionSDT &s) : SIsection(s) {
svs = s.svs;
parsed = s.parsed;
}
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsectionSDT(unsigned bufLength, char *buf) : SIsection(bufLength, buf) {
parsed = 0;
parse();
}
t_transport_stream_id transport_stream_id(void) const {
return buffer ? ((((struct SI_section_SDT_header *)buffer)->transport_stream_id_hi << 8) |
((struct SI_section_SDT_header *)buffer)->transport_stream_id_lo) : 0;
}
struct SI_section_SDT_header const *header(void) const {
return (struct SI_section_SDT_header *)buffer;
}
t_original_network_id original_network_id(void) const {
return buffer ? ((((struct SI_section_SDT_header *)buffer)->original_network_id_hi << 8) |
((struct SI_section_SDT_header *)buffer)->original_network_id_lo) : 0;
}
static void dump(const struct SI_section_SDT_header *header) {
if (!header)
return;
SIsection::dump1((const struct SI_section_header *)header);
printf("transport_stream_id: 0x%02x%02x\n", header->transport_stream_id_hi, header->transport_stream_id_lo);
SIsection::dump2((const struct SI_section_header *)header);
printf("original_network_id: 0x%02x%02x\n", header->original_network_id_hi, header->original_network_id_lo);
}
static void dump(const SIsectionSDT &s) {
dump((struct SI_section_SDT_header *)s.buffer);
for_each(s.svs.begin(), s.svs.end(), printSIservice());
}
void dump(void) const {
dump((struct SI_section_SDT_header *)buffer);
for_each(svs.begin(), svs.end(), printSIservice());
}
const SIservices &services(void) const {
//if(!parsed)
// parse(); -> nicht const
return svs;
}
private:
SIservices svs;
int parsed;
void parse(void);
void parseDescriptors(const char *desc, unsigned len, SIservice &s);
void parseServiceDescriptor(const char *buf, SIservice &s);
void parsePrivateDataDescriptor(const char *buf, SIservice &s);
void parseNVODreferenceDescriptor(const char *buf, SIservice &s);
};
#ifdef UPDATE_NETWORKS
class SIsectionBAT : public SIsection
{
public:
SIsectionBAT(const SIsection &s) : SIsection(s) {
parsed = 0;
parse();
}
// Std-Copy
SIsectionBAT(const SIsectionBAT &s) : SIsection(s) {
bsv = s.bsv;
parsed = s.parsed;
}
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsectionBAT(unsigned bufLength, char *buf) : SIsection(bufLength, buf) {
parsed = 0;
parse();
}
unsigned short bouquetID(void) const {
return buffer ? ((((struct SI_section_BAT_header *)buffer)->bouquet_id_hi << 8) |
((struct SI_section_BAT_header *)buffer)->bouquet_id_lo) : (unsigned short) -1;
}
struct SI_section_BAT_header const *header(void) const {
return (struct SI_section_BAT_header *)buffer;
}
static void dump(const struct SI_section_BAT_header *header) {
if (!header)
return;
SIsection::dump1((const struct SI_section_header *)header);
printf("bouquet_id: 0x%02x%02x\n", header->bouquet_id_hi, header->bouquet_id_lo);
SIsection::dump2((const struct SI_section_header *)header);
printf("bouquet_descriptors_length %hu\n",
(header->bouquet_descriptors_length_hi << 8) | header->bouquet_descriptors_length_lo);
}
static void dump(const SIsectionBAT &s) {
dump((struct SI_section_BAT_header *)s.buffer);
}
void dump(void) const {
dump((struct SI_section_BAT_header *)buffer);
}
const SIbouquets &bouquets(void) const {
//if(!parsed)
// parse(); -> nicht const
return bsv;
}
protected:
SIbouquets bsv;
int parsed;
void parse(void);
// int parseDescriptors(const char *desc, unsigned len, SIbouquet &s, int section_no, int count, const char *bouquetName);
// void parseBouquetNameDescriptor(const char *buf, SIbouquet &s);
// int parseServiceListDescriptor(const char *buf, SIbouquet &s, int section_no, int count);
};
class SIsectionNIT : public SIsection
{
public:
SIsectionNIT(const SIsection &s) : SIsection(s) {
parsed = 0;
parse();
}
// Std-Copy
SIsectionNIT(const SIsectionNIT &s) : SIsection(s) {
ntw = s.ntw;
parsed = s.parsed;
}
// Benutzt den uebergebenen Puffer (sollte mit new char[n] allokiert sein)
SIsectionNIT(unsigned bufLength, char *buf) : SIsection(bufLength, buf) {
parsed = 0;
parse();
}
unsigned short networkID(void) const {
return buffer ? ((((struct SI_section_NIT_header *)buffer)->network_id_hi << 8) |
((struct SI_section_NIT_header *)buffer)->network_id_lo) : (unsigned short) -1;
}
struct SI_section_NIT_header const *header(void) const {
return (struct SI_section_NIT_header *)buffer;
}
static void dump(const struct SI_section_NIT_header *header) {
if (!header)
return;
SIsection::dump1((const struct SI_section_header *)header);
printf("network_id: 0x%02x%02x\n", header->network_id_hi, header->network_id_lo);
SIsection::dump2((const struct SI_section_header *)header);
printf("network_descriptors_length %hu\n",
(header->network_descriptors_length_hi << 8) | header->network_descriptors_length_lo);
}
static void dump(const SIsectionNIT &s) {
dump((struct SI_section_NIT_header *)s.buffer);
}
void dump(void) const {
dump((struct SI_section_NIT_header *)buffer);
}
const SInetworks &networks(void) const {
//if(!parsed)
// parse(); -> nicht const
return ntw;
}
protected:
SInetworks ntw;
int parsed;
void parse(void);
void parseDescriptors(const char *desc, unsigned len, SInetwork &s);
void copyDeliveryDescriptor(const char *buf, SInetwork &s);
};
#endif
#ifndef DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
// Fuer for_each
struct printSIsectionSDT : public std::unary_function<SIsectionSDT, void>
{
void operator() (const SIsectionSDT &s) { s.dump();}
};
// Menge aller SDTs (actual TS)
class SIsectionsSDT : public std::set <SIsectionSDT, std::less<SIsectionSDT> >
{
public:
int readSections(void) {
SIsections sections;
int rc=sections.readSections(0x11, 0x42, 0xff);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
// Fuer for_each
struct printSIsectionBAT : public std::unary_function<SIsectionBAT, void>
{
void operator() (const SIsectionBAT &s) { s.dump();}
};
// Menge aller BATs
class SIsectionsBAT : public std::set <SIsectionBAT, std::less<SIsectionBAT> >
{
public:
int readSections(void) {
SIsections sections;
int rc=sections.readSections(0x11, 0x4a, 0xff);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
// Fuer for_each
struct printSIsectionNIT : public std::unary_function<SIsectionNIT, void>
{
void operator() (const SIsectionNIT &s) { s.dump();}
};
// Menge aller NITs (actual network)
class SIsectionsNIT : public std::set <SIsectionNIT, std::less<SIsectionNIT> >
{
public:
int readSections(void) {
SIsections sections;
int rc=sections.readSections(0x10, 0x40, 0xff);
for (SIsections::iterator k=sections.begin(); k!=sections.end(); k++)
insert(*k);
return rc;
}
};
#endif
#endif // SISECTIONS_HPP

208
src/eitd/SIservices.hpp Normal file
View File

@@ -0,0 +1,208 @@
#ifndef SISERVICES_HPP
#define SISERVICES_HPP
//
// $Id: SIservices.hpp,v 1.15 2009/02/24 19:09:10 seife Exp $
//
// classes SIservices and SIservices (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de),
// 2002 thegoodguy (thegoodguy@berlios.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <algorithm>
#include <cstring> // memset
#include <endian.h>
#include <sectionsdclient/sectionsdMsg.h>
// forward references
class SIservice;
class SIevent;
struct sdt_service {
unsigned service_id_hi : 8;
unsigned service_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved_future_use : 6;
unsigned EIT_schedule_flag : 1;
unsigned EIT_present_following_flag : 1;
unsigned running_status : 3;
unsigned free_CA_mode : 1;
unsigned descriptors_loop_length_hi : 4;
#else
unsigned EIT_present_following_flag : 1;
unsigned EIT_schedule_flag : 1;
unsigned reserved_future_use : 6;
unsigned descriptors_loop_length_hi : 4;
unsigned free_CA_mode : 1;
unsigned running_status : 3;
#endif
unsigned descriptors_loop_length_lo : 8;
} __attribute__ ((packed)) ; // 5 Bytes
class SInvodReference
{
public:
t_service_id service_id;
t_original_network_id original_network_id;
t_transport_stream_id transport_stream_id;
SInvodReference(const t_transport_stream_id new_transport_stream_id, const t_original_network_id new_original_network_id, const t_service_id new_service_id)
{
service_id = new_service_id;
original_network_id = new_original_network_id;
transport_stream_id = new_transport_stream_id;
}
SInvodReference(const SInvodReference &ref)
{
service_id = ref.service_id;
original_network_id = ref.original_network_id;
transport_stream_id = ref.transport_stream_id;
}
bool operator < (const SInvodReference& ref) const
{
return uniqueKey() < ref.uniqueKey();
}
void dump(void) const
{
printf("NVOD Ref. Service-ID: %hu\n", service_id);
printf("NVOD Ref. Original-Network-ID: %hu\n", original_network_id);
printf("NVOD Ref. Transport-Stream-ID: %hu\n", transport_stream_id);
}
void toStream(char * &p) const
{
*(t_service_id *)p = service_id; p += sizeof(t_service_id);
*(t_original_network_id *)p = original_network_id; p += sizeof(t_original_network_id);
*(t_transport_stream_id *)p = transport_stream_id; p += sizeof(t_transport_stream_id);
}
t_service_id getServiceID() const
{
return service_id;
}
t_channel_id uniqueKey(void) const {
return CREATE_CHANNEL_ID; // cf. zapittypes.h
}
};
// Fuer for_each
struct printSInvodReference : public std::unary_function<class SInvodReference, void>
{
void operator() (const SInvodReference &ref) { ref.dump();}
};
typedef std::set <SInvodReference, std::less<SInvodReference> > SInvodReferences;
class SIservice {
public:
SIservice(const struct sdt_service *s) {
service_id = (s->service_id_hi << 8) | s->service_id_lo;
original_network_id = 0;
transport_stream_id = 0;
serviceTyp = 0;
flags.EIT_schedule_flag = s->EIT_schedule_flag;
flags.EIT_present_following_flag = s->EIT_present_following_flag;
flags.running_status = s->running_status;
flags.free_CA_mode = s->free_CA_mode;
is_actual = false;
}
// Um einen service zum Suchen zu erstellen
SIservice(const t_service_id _service_id, const t_original_network_id _original_network_id, const t_transport_stream_id _transport_stream_id)
{
service_id = _service_id;
original_network_id = _original_network_id;
transport_stream_id = _transport_stream_id;
serviceTyp=0;
memset(&flags, 0, sizeof(flags));
}
// Std-Copy
SIservice(const SIservice &s) {
service_id = s.service_id;
original_network_id = s.original_network_id;
transport_stream_id = s.transport_stream_id;
serviceTyp=s.serviceTyp;
providerName=s.providerName;
serviceName=s.serviceName;
flags=s.flags;
nvods=s.nvods;
is_actual=s.is_actual;
}
t_service_id service_id;
t_original_network_id original_network_id; // Ist innerhalb einer section unnoetig
t_transport_stream_id transport_stream_id;
unsigned char serviceTyp;
int is_actual;
SInvodReferences nvods;
std::string serviceName; // Name aus dem Service-Descriptor
std::string providerName; // Name aus dem Service-Descriptor
int eitScheduleFlag(void) {return (int)flags.EIT_schedule_flag;}
int eitPresentFollowingFlag(void) {return (int)flags.EIT_present_following_flag;}
int runningStatus(void) {return (int)flags.running_status;}
int freeCAmode(void) {return (int)flags.free_CA_mode;}
bool operator < (const SIservice& s) const {
return uniqueKey() < s.uniqueKey();
}
t_channel_id uniqueKey(void) const {
//return CREATE_CHANNEL_ID;
//notice that tsid & onid were changed for compatibility sake - order should be onid tsid when being sorted
return CREATE_CHANNEL_ID_FROM_SERVICE_ORIGINALNETWORK_TRANSPORTSTREAM_ID(service_id, transport_stream_id, original_network_id);
}
void dump(void) const {
printf("Original-Network-ID: %hu\n", original_network_id);
printf("Service-ID: %hu\n", service_id);
printf("Service-Typ: %hhu\n", serviceTyp);
if(providerName.length())
printf("Provider-Name: %s\n", providerName.c_str());
if(serviceName.length())
printf("Service-Name: %s\n", serviceName.c_str());
for_each(nvods.begin(), nvods.end(), printSInvodReference());
printf("\n");
}
protected:
struct {
unsigned char EIT_schedule_flag : 1;
unsigned char EIT_present_following_flag : 1;
unsigned char running_status : 3;
unsigned char free_CA_mode : 1;
} flags;
};
// Fuer for_each
struct printSIservice : public std::unary_function<SIservice, void>
{
void operator() (const SIservice &s) { s.dump();}
};
// Als Klasse, da ich nicht weiss, wie man eine Forward-Referenz auf ein typedef macht
class SIservices : public std::set <SIservice, std::less<SIservice> >
{
};
#endif // SISERVICES_HPP

300
src/eitd/SIutils.cpp Normal file
View File

@@ -0,0 +1,300 @@
//
// $Id: SIutils.cpp,v 1.15 2005/11/03 21:08:52 mogway Exp $
//
// utility functions for the SI-classes (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Log: SIutils.cpp,v $
// Revision 1.15 2005/11/03 21:08:52 mogway
// sectionsd update by Houdini
//
// Changes:
// - EIT und SDT DMX buffer verändert
// -> keine(weniger) POLLER, kostet Speicher beim EITDMX, spart Speicher beim SDTDMX
//
// - vor dem Parsen der Sections werden die Buffer nicht mehr (unnötig) ein zweites mal allokiert und umkopiert -> mehr Performance, weniger Speicherfragmentierung
//
// - unnötige/unbenutze Funktionen auskommentiert -> das gestrippte sectionsd binary wird 23kB kleiner, Test-/Beispielprogramme wie sdt, epg, nit, ... können dann nicht mehr kompiliert werden.
//
// Revision 1.14 2003/03/03 13:38:33 obi
// - cleaned up changeUTCtoCtime a bit
// - finish pthreads using pthread_exit(NULL) instead of return 0
// - use settimeofday() instead of stime()
//
// Revision 1.13 2002/11/03 22:26:54 thegoodguy
// Use more frequently types defined in zapittypes.h(not complete), fix some warnings, some code cleanup
//
// Revision 1.12 2001/07/17 14:15:52 fnbrd
// Kleine Aenderung damit auch static geht.
//
// Revision 1.11 2001/07/14 16:38:46 fnbrd
// Mit workaround fuer defektes mktime der glibc
//
// Revision 1.10 2001/07/12 22:55:51 fnbrd
// Fehler behoben
//
// Revision 1.9 2001/07/12 22:51:25 fnbrd
// Time-Thread im sectionsd (noch disabled, da prob mit mktime)
//
// Revision 1.8 2001/07/06 11:09:56 fnbrd
// Noch ne Kleinigkeit gefixt.
//
// Revision 1.7 2001/07/06 09:46:01 fnbrd
// Kleiner Fehler behoben
//
// Revision 1.6 2001/07/06 09:27:40 fnbrd
// Kleine Anpassung
//
// Revision 1.5 2001/06/10 14:55:51 fnbrd
// Kleiner Aenderungen und Ergaenzungen (epgMini).
//
// Revision 1.4 2001/05/19 22:46:50 fnbrd
// Jetzt wellformed xml.
//
// Revision 1.3 2001/05/18 13:11:46 fnbrd
// Fast komplett, fehlt nur noch die Auswertung der time-shifted events
// (Startzeit und Dauer der Cinedoms).
//
// Revision 1.2 2001/05/17 01:53:35 fnbrd
// Jetzt mit lokaler Zeit.
//
// Revision 1.1 2001/05/16 15:23:47 fnbrd
// Alles neu macht der Mai.
//
//
#include <stdio.h>
#include <time.h>
#include <string.h>
// Houdini: not used in the code at the moment, found in SIsections.cpp
#if 0
static const char descr_tbl[][50] = {
// defined by ISO/IEC 13818-1 P64
"Reserved",
"Reserved",
"Video Stream",
"Audio Stream",
"Hierarchy",
"Registration",
"Data Stream Alignment",
"Target Background Grid",
"Video Window",
"CA",
"ISO 639 Language",
"System Clock",
"Multiplex Buffer Utilization",
"Copyright",
"Maximum Bitrate",
"Private Data Indicator",
"Smoothing Buffer",
"STD",
"IBP",
"ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved",
// defined by ETSI
"Network Name",
"Service List",
"Stuffing",
"Satellite Delivery System",
"Cable Delivery System",
"Reserved for future use",
"Reserved for future use",
"Bouquet Name",
"Service",
"Country Availability",
"Linkage",
"NVOD Reference",
"Time Shifted Service",
"Short Event",
"Extended Event",
"Time Shifted Event",
"Component",
"Mosaic",
"Stream Identifier",
"CA Identifier",
"Content",
"Parental Rating",
"Teletext",
"Telephone",
"Local Time Offset",
"Subtitling",
"Terrestrial Delivery System",
"Multilingual Network Name",
"Multilingual Bouquet Name",
"Multilingual Service Name",
"Multilingual Component",
"Private Data Specifier",
"Service Move",
"Short Smoothing Buffer",
"Reserved for future use",
"User defined",
"FORBIDDEN"
};
// Thanks to tmbinc
const char *decode_descr (unsigned char _index) {
int index = _index;
if (_index>=0x13 && _index<=0x3F)
index = 0x13;
if (_index>=0x40)
index -= (0x3F - 0x13);
if (_index>=0x62 && _index<=0x7F)
index = 0x62 - (_index - index);
if (_index>=0x80)
index -= (0x7F - 0x62);
if (_index>=0x80 && _index<=0xFE)
index = 0x80 - (_index - index);
if (_index == 0xFF)
index = 0xFF - (_index - index) - (0xFE - 0x80);
return descr_tbl[index];
}
#endif
// Thanks to kwon
time_t changeUTCtoCtime(const unsigned char *buffer, int local_time)
{
int year, month, day, y_, m_, k, hour, minutes, seconds, mjd;
if (!memcmp(buffer, "\xff\xff\xff\xff\xff", 5))
return 0; // keine Uhrzeit
mjd = (buffer[0] << 8) | buffer[1];
hour = buffer[2];
minutes = buffer[3];
seconds = buffer[4];
y_ = (int) ((mjd - 15078.2) / 365.25);
m_ = (int) ((mjd - 14956.1 - (int) (y_ * 365.25)) / 30.6001);
day = mjd - 14956 - (int) (y_ * 365.25) - (int) (m_ * 30.60001);
k = !!((m_ == 14) || (m_ == 15));
year = y_ + k + 1900;
month = m_ - 1 - k * 12;
struct tm time;
memset(&time, 0, sizeof(struct tm));
time.tm_mday = day;
time.tm_mon = month - 1;
time.tm_year = year - 1900;
time.tm_hour = (hour >> 4) * 10 + (hour & 0x0f);
time.tm_min = (minutes >> 4) * 10 + (minutes & 0x0f);
time.tm_sec = (seconds >> 4) * 10 + (seconds & 0x0f);
#if 0
printf ("Startzeit: GMT: %.2d.%.2d.%.4d %.2x:%.2x:%.2x\n",
day, month, year, hour, minutes, seconds);
printf ("Startzeit: GMT: %.2d.%.2d.%.4d %.2d:%.2d:%.2d\n",
time.tm_mday, time.tm_mon + 1, time.tm_year + 1900,
time.tm_hour, time.tm_min, time.tm_sec);
#endif
return mktime(&time) + (local_time ? -timezone : 0);
}
// Thanks to tmbinc
int saveStringToXMLfile(FILE *out, const char *c, int /*withControlCodes*/)
{
if(!c)
return 1;
// Die Umlaute sind ISO-8859-9 [5]
/*
char buf[6000];
int inlen=strlen(c);
int outlen=sizeof(buf);
// UTF8Toisolat1((unsigned char *)buf, &outlen, (const unsigned char *)c, &inlen);
isolat1ToUTF8((unsigned char *)buf, &outlen, (const unsigned char *)c, &inlen);
buf[outlen]=0;
c=buf;
*/
for(; *c; c++) {
switch ((unsigned char)*c) {
case '<':
fprintf(out, "&lt;");
break;
case '>':
fprintf(out, "&gt;");
break;
case '&':
fprintf(out, "&amp;");
break;
case '\"':
fprintf(out, "&quot;");
break;
case '\'':
fprintf(out, "&apos;");
break;
#if 0
case 0x81:
case 0x82:
break;
case 0x86:
if(withControlCodes)
fprintf(out, "<b>");
break;
case 0x87:
if(withControlCodes)
fprintf(out, "</b>");
break;
case 0x8a:
if(withControlCodes)
fprintf(out, "<br/>");
break;
default:
if (*c<32)
break;
if ((*c>=32) && (((unsigned char)*c)<128))
fprintf(out, "%c", *c);
else
fprintf(out, "&#%d;", *c);
#else
default:
if ((unsigned char)*c<32)
break;
fprintf(out, "%c", *c);
#endif
} // case
} // for
return 0;
}
// Entfernt die ControlCodes aus dem String (-> String wird evtl. kuerzer)
void removeControlCodes(char *string)
{
if(!string)
return;
for(; *string; )
if (!((*string>=32) && (((unsigned char)*string)<128)))
memmove(string, string+1, strlen(string+1)+1);
else
string++;
return ;
}

57
src/eitd/SIutils.hpp Normal file
View File

@@ -0,0 +1,57 @@
#ifndef SIUTILS_HPP
#define SIUTILS_HPP
//
// $Id: SIutils.hpp,v 1.5 2006/05/19 21:28:08 houdini Exp $
//
// utility functions for the SI-classes (dbox-II-project)
//
// Homepage: http://dbox2.elxsi.de
//
// Copyright (C) 2001 fnbrd (fnbrd@gmx.de)
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Log: SIutils.hpp,v $
// Revision 1.5 2006/05/19 21:28:08 houdini
// - Nirvanas save/restore EPG patch #g
// - automatic update of subchannels for Premiere (disable with <sectionsd -nu>)
// - Fix for ZDF audio option "mono/H<>rfilm"
// - improved navigation speed in bouquet/channel list
// - zapit/pzapit new option (-sbo) save bouquets.xml including Bouquet "Andere" which saves me a lot of time :-)
//
// Revision 1.4 2001/07/14 16:38:46 fnbrd
// Mit workaround fuer defektes mktime der glibc
//
// Revision 1.3 2001/06/10 14:55:51 fnbrd
// Kleiner Aenderungen und Ergaenzungen (epgMini).
//
// Revision 1.2 2001/05/19 22:46:50 fnbrd
// Jetzt wellformed xml.
//
// Revision 1.1 2001/05/16 15:23:47 fnbrd
// Alles neu macht der Mai.
//
//
time_t changeUTCtoCtime(const unsigned char *buffer, int local_time=1);
// returns the descriptor type as readable text
const char *decode_descr (unsigned char tag_value);
int saveStringToXMLfile(FILE *out, const char *string, int withControlCodes=0);
// Entfernt die ControlCodes aus dem String (-> String wird evtl. kuerzer)
void removeControlCodes(char *string);
#endif // SIUTILS_HPP

35
src/eitd/debug.cpp Normal file
View File

@@ -0,0 +1,35 @@
/*
* $Header: /cvs/tuxbox/apps/tuxbox/neutrino/daemons/sectionsd/debug.cpp,v 1.3 2008/06/15 10:19:38 seife Exp $
*
* Debug tools (sectionsd) - d-box2 linux project
*
* (C) 2003 by thegoodguy <thegoodguy@berlios.de>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
bool sections_debug;
void printdate_ms(FILE *f) {
timeval now;
gettimeofday(&now, NULL);
struct tm *tm = localtime(&now.tv_sec);
/* use strftime for that? */
fprintf(f, "%02d:%02d:%02d.%03ld ", tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec/1000);
}

862
src/eitd/dmx.cpp Normal file
View File

@@ -0,0 +1,862 @@
/*
* $Header: /cvs/tuxbox/apps/tuxbox/neutrino/daemons/sectionsd/dmx.cpp,v 1.51 2009/06/14 21:46:03 rhabarber1848 Exp $
*
* DMX class (sectionsd) - d-box2 linux project
*
* (C) 2001 by fnbrd,
* 2003 by thegoodguy <thegoodguy@berlios.de>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <dmx.h>
#include <dmxapi.h>
#include <debug.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <string>
#include <cstring>
#include <map>
#include <driver/abstime.h>
/*
#define DEBUG_MUTEX 1
#define DEBUG_CACHED_SECTIONS 1
*/
typedef std::map<sections_id_t, version_number_t, std::less<sections_id_t> > MyDMXOrderUniqueKey;
static MyDMXOrderUniqueKey myDMXOrderUniqueKey;
extern void showProfiling(std::string text);
DMX::DMX(const unsigned short p, const unsigned short bufferSizeInKB, const bool c, int dmx_source)
{
dmx_num = dmx_source;
fd = -1;
lastChanged = time_monotonic();
filter_index = 0;
pID = p;
dmxBufferSizeInKB = bufferSizeInKB;
#if HAVE_TRIPLEDRAGON
/* hack, to keep the TD changes in one place. */
dmxBufferSizeInKB = 128; /* 128kB is enough on TD */
dmx_num = 0; /* always use demux 0 */
#endif
pthread_mutex_init(&pauselock, NULL); // default = fast mutex
#ifdef DEBUG_MUTEX
pthread_mutexattr_t start_stop_mutex_attr;
pthread_mutexattr_init(&start_stop_mutex_attr);
pthread_mutexattr_settype(&start_stop_mutex_attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&start_stop_mutex, &start_stop_mutex_attr);
#else
pthread_mutex_init(&start_stop_mutex, NULL); // default = fast mutex
#endif
pthread_cond_init (&change_cond, NULL);
real_pauseCounter = 0;
current_service = 0;
first_skipped = 0;
cache = c;
}
DMX::~DMX()
{
first_skipped = 0;
myDMXOrderUniqueKey.clear();
pthread_mutex_destroy(&pauselock);
pthread_mutex_destroy(&start_stop_mutex);
pthread_cond_destroy (&change_cond);
closefd();
}
ssize_t DMX::read(char * const /*buf*/, const size_t /*buflength*/, const unsigned /*timeoutMInSeconds*/)
{
//FIXME is this used ??
printf("[sectionsd] ******************************* DMX::read called *******************************\n");
return 0;
//return readNbytes(fd, buf, buflength, timeoutMInSeconds);
}
void DMX::close(void)
{
if(dmx)
delete dmx;
dmx = NULL;
}
void DMX::closefd(void)
{
if (isOpen())
{
//close(fd);
#if HAVE_TRIPLEDRAGON
dmx->Close();
#else
dmx->Stop();
#endif
fd = -1;
}
}
void DMX::addfilter(const unsigned char filter, const unsigned char mask)
{
s_filters tmp;
tmp.filter = filter;
tmp.mask = mask;
filters.push_back(tmp);
}
int DMX::immediate_stop(void)
{
if (!isOpen())
return 1;
closefd();
return 0;
}
int DMX::stop(void)
{
int rc;
lock();
rc = immediate_stop();
unlock();
return rc;
}
void DMX::lock(void)
{
//dprintf("DMX::lock, thread %lu\n", pthread_self());
#ifdef DEBUG_MUTEX
int rc = pthread_mutex_lock(&start_stop_mutex);
if (rc != 0)
{
fprintf(stderr, "[sectionsd] mutex_lock: %d %d %d\n", rc, EINVAL, EDEADLK);
fflush(stderr);
fprintf(stderr, "[sectionsd] pid: %d\n", getpid());
fflush(stderr);
}
#else
pthread_mutex_lock(&start_stop_mutex);
#endif
}
void DMX::unlock(void)
{
//dprintf("DMX::unlock, thread %lu\n", pthread_self());
#ifdef DEBUG_MUTEX
int rc = pthread_mutex_unlock(&start_stop_mutex);
if (rc != 0)
{
fprintf(stderr, "[sectionsd] mutex_unlock: %d %d %d\n", rc, EINVAL, EPERM);
fflush(stderr);
fprintf(stderr, "[sectionsd] pid: %d\n", getpid());
fflush(stderr);
}
#else
pthread_mutex_unlock(&start_stop_mutex);
#endif
sched_yield();
}
sections_id_t DMX::create_sections_id(const unsigned char table_id, const unsigned short extension_id, const unsigned char section_number, const unsigned short onid, const unsigned short tsid)
{
return (sections_id_t) ( ((sections_id_t) table_id << 56) |
((sections_id_t) extension_id << 40) |
((sections_id_t) section_number << 32) |
((sections_id_t) onid << 16) |
((sections_id_t) tsid));
}
bool DMX::check_complete(const unsigned char table_id, const unsigned short extension_id, const unsigned short onid, const unsigned short tsid, const unsigned char last)
{
int current_section_number = 0;
if (((table_id == 0x4e) || (table_id == 0x50)) && (current_service == extension_id)) {
if (last == 0)
return true;
MyDMXOrderUniqueKey::iterator di = myDMXOrderUniqueKey.find(create_sections_id(
table_id,
extension_id,
current_section_number,
onid,
tsid));
if (di != myDMXOrderUniqueKey.end()) {
di++;
}
while ((di != myDMXOrderUniqueKey.end()) && ((uint8_t) ((di->first >> 56) & 0xff) == table_id) &&
((uint16_t) ((di->first >> 40) & 0xffff) == extension_id) &&
(((uint8_t) ((di->first >> 32) & 0xff) == current_section_number + 1) ||
((uint8_t) ((di->first >> 32) & 0xff) == current_section_number + 8)) &&
((uint16_t) ((di->first >> 16) & 0xffff) == onid) &&
((uint16_t) (di->first & 0xffff) == tsid))
{
if ((uint8_t) ((di->first >> 32) & 0xff) == last) {
return true;
}
else {
current_section_number = (uint8_t) (di->first >> 32) & 0xff;
di++;
}
}
}
return false;
}
int DMX::getSection(char *buf, const unsigned timeoutInMSeconds, int &timeouts)
{
struct minimal_section_header {
unsigned table_id : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned section_syntax_indicator : 1;
unsigned reserved_future_use : 1;
unsigned reserved1 : 2;
unsigned section_length_hi : 4;
#else
unsigned section_length_hi : 4;
unsigned reserved1 : 2;
unsigned reserved_future_use : 1;
unsigned section_syntax_indicator : 1;
#endif
unsigned section_length_lo : 8;
} __attribute__ ((packed)); // 3 bytes total
struct extended_section_header {
unsigned table_extension_id_hi : 8;
unsigned table_extension_id_lo : 8;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned reserved : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
#else
unsigned current_next_indicator : 1;
unsigned version_number : 5;
unsigned reserved : 2;
#endif
unsigned section_number : 8;
unsigned last_section_number : 8;
} __attribute__ ((packed)); // 5 bytes total
struct eit_extended_section_header {
unsigned transport_stream_id_hi : 8;
unsigned transport_stream_id_lo : 8;
unsigned original_network_id_hi : 8;
unsigned original_network_id_lo : 8;
unsigned segment_last_section_number : 8;
unsigned last_table_id : 8;
} __attribute__ ((packed)); // 6 bytes total
minimal_section_header *initial_header;
extended_section_header *extended_header;
eit_extended_section_header *eit_extended_header;
int rc;
unsigned short section_length;
unsigned short current_onid = 0;
unsigned short current_tsid = 0;
/* filter == 0 && maks == 0 => EIT dummy filter to slow down EIT thread startup */
if (pID == 0x12 && filters[filter_index].filter == 0 && filters[filter_index].mask == 0)
{
//dprintf("dmx: dummy filter, sleeping for %d ms\n", timeoutInMSeconds);
usleep(timeoutInMSeconds * 1000);
timeouts++;
return -1;
}
lock();
//rc = read(buf, 4098, timeoutInMSeconds);
rc = dmx->Read((unsigned char *) buf, 4098, timeoutInMSeconds);
if (rc < 3)
{
unlock();
if (rc <= 0)
{
dprintf("dmx.read timeout - filter: %x - timeout# %d\n", filters[filter_index].filter, timeouts);
timeouts++;
}
else
{
dprintf("dmx.read rc: %d - filter: %x\n", rc, filters[filter_index].filter);
// restart DMX
real_pause();
real_unpause();
}
return -1;
}
initial_header = (minimal_section_header*)buf;
section_length = (initial_header->section_length_hi * 256) | initial_header->section_length_lo;
if (section_length <= 0)
{
unlock();
fprintf(stderr, "[sectionsd] section_length <= 0: %d [%s:%s:%d] please report!\n", section_length, __FILE__,__FUNCTION__,__LINE__);
return -1;
}
timeouts = 0;
if (rc != section_length + 3)
{
xprintf("rc != section_length + 3 (%d != %d + 3)\n", rc, section_length);
unlock();
// DMX restart required? This should never happen anyway.
real_pause();
real_unpause();
return -1;
}
// check if the filter worked correctly
if (((initial_header->table_id ^ filters[filter_index].filter) & filters[filter_index].mask) != 0)
{
printf("[sectionsd] filter 0x%x mask 0x%x -> skip sections for table 0x%x\n", filters[filter_index].filter, filters[filter_index].mask, initial_header->table_id);
unlock();
real_pause();
real_unpause();
return -1;
}
unlock();
// skip sections which are too short
if ((section_length < 5) ||
(initial_header->table_id >= 0x4e && initial_header->table_id <= 0x6f && section_length < 14))
{
dprintf("section too short: table %x, length: %d\n", initial_header->table_id, section_length);
return -1;
}
// check if it's extended syntax, e.g. NIT, BAT, SDT, EIT
if (initial_header->section_syntax_indicator != 0)
{
extended_header = (extended_section_header *)(buf+3);
// only current sections
if (extended_header->current_next_indicator != 0) {
// if ((initial_header.table_id >= 0x4e) && (initial_header.table_id <= 0x6f))
if (pID == 0x12) {
eit_extended_header = (eit_extended_section_header *)(buf+8);
current_onid = eit_extended_header->original_network_id_hi * 256 +
eit_extended_header->original_network_id_lo;
current_tsid = eit_extended_header->transport_stream_id_hi * 256 +
eit_extended_header->transport_stream_id_lo;
}
else {
current_onid = 0;
current_tsid = 0;
}
int eh_tbl_extension_id = extended_header->table_extension_id_hi * 256
+ extended_header->table_extension_id_lo;
/* if we are not caching the already read sections (CN-thread), check EIT version and get out */
if (!cache)
{
if (initial_header->table_id == 0x4e &&
eh_tbl_extension_id == current_service &&
extended_header->version_number != eit_version) {
dprintf("EIT old: %d new version: %d\n",eit_version,extended_header->version_number);
eit_version = extended_header->version_number;
}
return rc;
}
// the current section
sections_id_t s_id = create_sections_id(initial_header->table_id,
eh_tbl_extension_id,
extended_header->section_number,
current_onid,
current_tsid);
//find current section in list
MyDMXOrderUniqueKey::iterator di = myDMXOrderUniqueKey.find(s_id);
if (di != myDMXOrderUniqueKey.end())
{
//the current section was read before
if (di->second == extended_header->version_number) {
#ifdef DEBUG_CACHED_SECTIONS
dprintf("[sectionsd] skipped duplicate section for table 0x%02x table_extension 0x%04x section 0x%02x\n",
initial_header->table_id,
eh_tbl_extension_id,
extended_header->section_number);
#endif
//the version number is still up2date
if (first_skipped == 0) {
//the last section was new - this is the 1st dup
first_skipped = s_id;
}
else {
//this is not the 1st new - check if it's the last
//or to be more precise only dups occured since
if (first_skipped == s_id)
timeouts = -1;
}
//since version is still up2date, check if table complete
if (check_complete(initial_header->table_id,
eh_tbl_extension_id,
current_onid,
current_tsid,
extended_header->last_section_number))
timeouts = -2;
return -1;
}
else {
#ifdef DEBUG_CACHED_SECTIONS
dprintf("[sectionsd] version update from 0x%02x to 0x%02x for table 0x%02x table_extension 0x%04x section 0x%02x\n",
di->second,
extended_header->version_number,
initial_header->table_id,
eh_tbl_extension_id,
extended_header->section_number);
#endif
//update version number
di->second = extended_header->version_number;
}
}
else
{
#ifdef DEBUG_CACHED_SECTIONS
dprintf("[sectionsd] new section for table 0x%02x table_extension 0x%04x section 0x%02x\n",
initial_header->table_id,
eh_tbl_extension_id,
extended_header->section_number);
#endif
//section was not read before - insert in list
myDMXOrderUniqueKey.insert(std::make_pair(s_id, extended_header->version_number));
//check if table is now complete
if (check_complete(initial_header->table_id,
eh_tbl_extension_id,
current_onid,
current_tsid,
extended_header->last_section_number))
timeouts = -2;
}
//if control comes to here the sections skipped counter must be restarted
first_skipped = 0;
}
}
return rc;
}
int DMX::immediate_start(void)
{
if (isOpen())
{
xprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>DMX::imediate_start: isOpen()<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
closefd();
}
if (real_pauseCounter != 0) {
dprintf("DMX::immediate_start: realPausecounter !=0 (%d)!\n", real_pauseCounter);
return 0;
}
#if 0
if ((fd = open(DEMUX_DEVICE, O_RDWR|O_NONBLOCK)) == -1)
{
perror("[sectionsd] open dmx");
return 2;
}
if (ioctl(fd, DMX_SET_BUFFER_SIZE, (unsigned long)(dmxBufferSizeInKB*1024UL)) == -1)
{
closefd();
perror("[sectionsd] DMX: DMX_SET_BUFFER_SIZE");
return 3;
}
#endif
if(dmx == NULL) {
dmx = new cDemux(dmx_num);
#if !HAVE_TRIPLEDRAGON
dmx->Open(DMX_PSI_CHANNEL, NULL, dmxBufferSizeInKB*1024UL);
#endif
}
#if HAVE_TRIPLEDRAGON
dmx->Open(DMX_PSI_CHANNEL, NULL, dmxBufferSizeInKB*1024UL);
#endif
fd = 1;
/* setfilter() only if this is no dummy filter... */
#if 0
if (filters[filter_index].filter && filters[filter_index].mask &&
!setfilter(fd, pID, filters[filter_index].filter, filters[filter_index].mask, DMX_IMMEDIATE_START | DMX_CHECK_CRC))
#endif
if (filters[filter_index].filter && filters[filter_index].mask)
{
unsigned char filter[DMX_FILTER_SIZE];
unsigned char mask[DMX_FILTER_SIZE];
filter[0] = filters[filter_index].filter;
mask[0] = filters[filter_index].mask;
dmx->sectionFilter(pID, filter, mask, 1);
//FIXME error check
//closefd();
//return 4;
}
/* this is for dmxCN only... */
eit_version = 0xff;
return 0;
}
int DMX::start(void)
{
int rc;
lock();
rc = immediate_start();
unlock();
return rc;
}
int DMX::real_pause(void)
{
if (!isOpen()) {
dprintf("DMX::real_pause: (!isOpen())\n");
return 1;
}
lock();
if (real_pauseCounter == 0)
{
immediate_stop();
}
//else
// dprintf("real_pause: counter %d\n", real_pauseCounter);
unlock();
return 0;
}
int DMX::real_unpause(void)
{
lock();
if (real_pauseCounter == 0)
{
immediate_start();
//dprintf("real_unpause DONE: %d\n", real_pauseCounter);
}
//else
// dprintf("real_unpause NOT DONE: %d\n", real_pauseCounter);
unlock();
return 0;
}
int DMX::request_pause(void)
{
real_pause(); // unlocked
lock();
//dprintf("request_pause: %d\n", real_pauseCounter);
real_pauseCounter++;
unlock();
return 0;
}
int DMX::request_unpause(void)
{
lock();
//dprintf("request_unpause: %d\n", real_pauseCounter);
--real_pauseCounter;
unlock();
real_unpause(); // unlocked
return 0;
}
#if 0
to be removed....
int DMX::pause(void)
{
pthread_mutex_lock(&pauselock);
//dprintf("lock from pc: %d\n", pauseCounter);
pauseCounter++;
pthread_mutex_unlock(&pauselock);
return 0;
}
int DMX::unpause(void)
{
pthread_mutex_lock(&pauselock);
//dprintf("unlock from pc: %d\n", pauseCounter);
--pauseCounter;
pthread_mutex_unlock(&pauselock);
return 0;
}
#endif
const char *dmx_filter_types [] = {
"dummy filter",
"actual transport stream, scheduled",
"other transport stream, now/next",
"other transport stream, scheduled 1",
"other transport stream, scheduled 2"
};
int DMX::change(const int new_filter_index, const int new_current_service)
{
if (sections_debug)
showProfiling("changeDMX: before pthread_mutex_lock(&start_stop_mutex)");
lock();
if (sections_debug)
showProfiling("changeDMX: after pthread_mutex_lock(&start_stop_mutex)");
filter_index = new_filter_index;
first_skipped = 0;
#if 0
/* i have to think about this. This #if 0 now makes .change() automatically unpause the
* demux. No idea if there are negative side effects - we will find out :) -- seife
*/
if (!isOpen())
{
pthread_cond_signal(&change_cond);
unlock();
dprintf("DMX::change(%d): not open!\n",new_filter_index);
return 1;
}
#endif
if (new_current_service != -1)
current_service = new_current_service;
if (real_pauseCounter > 0)
{
printf("changeDMX: for 0x%x not ignored! even though real_pauseCounter> 0 (%d)\n",
filters[new_filter_index].filter, real_pauseCounter);
/* immediate_start() checks for real_pauseCounter again (and
does nothing in that case), so we can just continue here. */
}
if (sections_debug) { // friendly debug output...
if(pID==0x12 && filters[0].filter != 0x4e) { // Only EIT
printdate_ms(stderr);
fprintf(stderr, "changeDMX [EIT]-> %d (0x%x/0x%x) %s (%ld seconds)\n",
new_filter_index, filters[new_filter_index].filter,
filters[new_filter_index].mask, dmx_filter_types[new_filter_index],
time_monotonic()-lastChanged);
} else {
printdate_ms(stderr);
fprintf(stderr, "changeDMX [%x]-> %d (0x%x/0x%x) (%ld seconds)\n", pID,
new_filter_index, filters[new_filter_index].filter,
filters[new_filter_index].mask, time_monotonic()-lastChanged);
}
}
closefd();
int rc = immediate_start();
if (rc != 0)
{
unlock();
return rc;
}
if (sections_debug)
showProfiling("after DMX_SET_FILTER");
pthread_cond_signal(&change_cond);
lastChanged = time_monotonic();
unlock();
return 0;
}
// Liest n Bytes aus einem Socket per read
// Liefert 0 bei timeout
// und -1 bei Fehler
// ansonsten die Anzahl gelesener Bytes
/* inline */
ssize_t DMX::readNbytes(int _fd, char *buf, const size_t n, unsigned timeoutInMSeconds)
{
int rc;
struct pollfd ufds;
ufds.fd = _fd;
ufds.events = POLLIN;
ufds.revents = 0;
rc = ::poll(&ufds, 1, timeoutInMSeconds);
if (!rc)
return 0; // timeout
else if (rc < 0)
{
/* we consciously ignore EINTR, since it does not happen in practice */
perror ("[sectionsd] DMX::readNbytes poll");
return -1;
}
if ((ufds.revents & POLLERR) != 0) /* POLLERR means buffer error, i.e. buffer overflow */
{
printdate_ms(stderr);
fprintf(stderr, "[sectionsd] DMX::readNbytes received POLLERR, pid 0x%x, filter[%d] "
"filter 0x%02x mask 0x%02x\n", pID, filter_index,
filters[filter_index].filter, filters[filter_index].mask);
return -1;
}
if (!(ufds.revents&POLLIN))
{
xprintf("%s: not ufds.revents&POLLIN, please report!\n", __FUNCTION__);
// POLLHUP, beim dmx bedeutet das DMXDEV_STATE_TIMEDOUT
// kommt wenn ein Timeout im Filter gesetzt wurde
// dprintf("revents: 0x%hx\n", ufds.revents);
// usleep(100*1000UL); // wir warten 100 Millisekunden bevor wir es nochmal probieren
// if (timeoutInMSeconds <= 200000)
return 0; // timeout
// timeoutInMSeconds -= 200000;
// goto retry;
}
int r = ::read(_fd, buf, n);
if (r >= 0)
return r;
perror ("[sectionsd] DMX::readNbytes read");
return -1;
}
int DMX::setPid(const unsigned short new_pid)
{
lock();
if (!isOpen())
{
pthread_cond_signal(&change_cond);
unlock();
return 1;
}
if (real_pauseCounter > 0)
{
dprintf("changeDMX: for 0x%x ignored! because of real_pauseCounter> 0 (%d)\n", new_pid, real_pauseCounter);
unlock();
return 0; // not running (e.g. streaming)
}
closefd();
pID = new_pid;
int rc = immediate_start();
if (rc != 0)
{
unlock();
return rc;
}
pthread_cond_signal(&change_cond);
lastChanged = time_monotonic();
unlock();
return 0;
}
int DMX::setCurrentService(int new_current_service)
{
return change(0, new_current_service);
}
int DMX::dropCachedSectionIDs()
{
lock();
/* i think that those checks are wrong for dropCachedSectionIDs(), since
this is called from the housekeeping thread while sectionsd might be
idle waiting for the EIT update filter to trigger -- seife
*/
#if 0
if (!isOpen())
{
pthread_cond_signal(&change_cond);
unlock();
return 1;
}
if (real_pauseCounter > 0)
{
unlock();
return 0; // not running (e.g. streaming)
}
closefd();
#endif
myDMXOrderUniqueKey.clear();
#if 0
int rc = immediate_start();
if (rc != 0)
{
unlock();
return rc;
}
#endif
pthread_cond_signal(&change_cond);
unlock();
return 0;
}
unsigned char DMX::get_eit_version()
{
return eit_version;
}
unsigned int DMX::get_current_service()
{
return current_service;
}

208
src/eitd/dmxapi.cpp Normal file
View File

@@ -0,0 +1,208 @@
/*
* $Header: /cvs/tuxbox/apps/tuxbox/neutrino/daemons/sectionsd/dmxapi.cpp,v 1.5 2005/01/13 10:48:02 diemade Exp $
*
* DMX low level functions (sectionsd) - d-box2 linux project
*
* (C) 2003 by thegoodguy <thegoodguy@berlios.de>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdio.h> /* perror */
#include <string.h> /* memset */
#include <sys/ioctl.h> /* ioctl */
#include <fcntl.h> /* open */
#include <unistd.h> /* close, read */
#include <arpa/inet.h> /* htons */
#include <time.h> /* ctime */
#include <dmxapi.h>
#if HAVE_TRIPLEDRAGON
#include <dmx_td.h>
#else
#include <dmx_cs.h>
#endif
#include "SIutils.hpp"
#include "debug.h"
#ifndef DO_NOT_INCLUDE_STUFF_NOT_NEEDED_FOR_SECTIONSD
bool setfilter(const int fd, const uint16_t pid, const uint8_t filter, const uint8_t mask, const uint32_t flags)
{
struct dmx_sct_filter_params flt;
memset(&flt, 0, sizeof(struct dmx_sct_filter_params));
flt.pid = pid;
flt.filter.filter[0] = filter;
flt.filter.mask [0] = mask;
flt.timeout = 0;
flt.flags = flags;
if (::ioctl(fd, DMX_SET_FILTER, &flt) == -1)
{
perror("[sectionsd] DMX: DMX_SET_FILTER");
return false;
}
return true;
}
#endif
struct SI_section_TOT_header
{
unsigned char table_id : 8;
unsigned char section_syntax_indicator : 1;
unsigned char reserved_future_use : 1;
unsigned char reserved1 : 2;
unsigned short section_length : 12;
UTC_t UTC_time; /* :40 */
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned char reserved2 : 4;
unsigned char descr_loop_length_hi : 4;
#else
unsigned char descr_loop_length_hi : 4;
unsigned char reserved2 : 4;
#endif
unsigned short descr_loop_length_lo : 8;
}
__attribute__ ((packed)); /* 10 bytes */
struct SI_section_TDT_header
{
unsigned char table_id : 8;
unsigned char section_syntax_indicator : 1;
unsigned char reserved_future_use : 1;
unsigned char reserved1 : 2;
unsigned short section_length : 12;
/* uint64_t UTC_time : 40;*/
UTC_t UTC_time;
}
__attribute__ ((packed)); /* 8 bytes */
struct descrLocalTimeOffset
{
unsigned char country_code[3];
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned char country_region_id : 6;
unsigned char reserved_1 : 1;
unsigned char local_time_offset_polarity : 1;
#else
unsigned char local_time_offset_polarity : 1;
unsigned char reserved_1 : 1;
unsigned char country_region_id : 6;
#endif
unsigned int local_time_offset : 16;
unsigned int time_of_change_MJD : 16;
unsigned int time_of_change_UTC : 24;
unsigned int next_time_offset : 16;
} __attribute__ ((packed)); /* 13 bytes */;
cDemux * dmxUTC;
bool getUTC(UTC_t * const UTC, const bool TDT)
{
unsigned char filter[DMX_FILTER_SIZE];
unsigned char mask[DMX_FILTER_SIZE];
int timeout;
struct SI_section_TOT_header tdt_tot_header;
char cUTC[5];
bool ret = true;
unsigned char buf[1023+3];
if(dmxUTC == NULL) {
dmxUTC = new cDemux();
dmxUTC->Open(DMX_PSI_CHANNEL);
}
memset(&filter, 0, DMX_FILTER_SIZE);
memset(&mask, 0, DMX_FILTER_SIZE);
filter[0] = TDT ? 0x70 : 0x73;
mask [0] = 0xFF;
timeout = 31000;
// flags = TDT ? (DMX_ONESHOT | DMX_IMMEDIATE_START) : (DMX_ONESHOT | DMX_CHECK_CRC | DMX_IMMEDIATE_START);
dmxUTC->sectionFilter(0x0014, filter, mask, 5, timeout);
int size = TDT ? sizeof(struct SI_section_TDT_header) : sizeof(tdt_tot_header);
int r = dmxUTC->Read(buf, TDT ? size : sizeof(buf));
if (r < size) {
if (TDT || sections_debug) /* not having TOT is common, no need to log */
perror("[sectionsd] getUTC: read");
dmxUTC->Stop();
return false;
}
memset(&tdt_tot_header, 0, sizeof(tdt_tot_header));
memmove(&tdt_tot_header, buf, size);
int64_t tmp = tdt_tot_header.UTC_time.time;
memmove(cUTC, (&tdt_tot_header.UTC_time), 5);
if ((cUTC[2] > 0x23) || (cUTC[3] > 0x59) || (cUTC[4] > 0x59)) // no valid time
{
printf("[sectionsd] getUTC: invalid %s section received: %02x %02x %02x %02x %02x\n",
TDT ? "TDT" : "TOT", cUTC[0], cUTC[1], cUTC[2], cUTC[3], cUTC[4]);
ret = false;
}
(*UTC).time = tmp;
#if 1
short loop_length = tdt_tot_header.descr_loop_length_hi << 8 | tdt_tot_header.descr_loop_length_lo;
if (loop_length >= 15) {
int off = sizeof(tdt_tot_header);
int rem = loop_length;
while (rem >= 15)
{
unsigned char *b2 = &buf[off];
if (b2[0] == 0x58) {
struct descrLocalTimeOffset *to;
to = (struct descrLocalTimeOffset *)&b2[2];
unsigned char cc[4];
cc[3] = 0;
memmove(cc, to->country_code, 3);
time_t t = changeUTCtoCtime(&b2[2+6],0);
xprintf("getUTC(TOT): len=%d cc=%s reg_id=%d "
"pol=%d offs=%04x new=%04x when=%s",
b2[1], cc, to->country_region_id,
to->local_time_offset_polarity, htons(to->local_time_offset),
htons(to->next_time_offset), ctime(&t));
} else {
xprintf("getUTC(TOT): descriptor != 0x58: 0x%02x\n", b2[0]);
}
off += b2[1] + 2;
rem -= b2[1] + 2;
if (off + rem > (int)sizeof(buf))
{
xprintf("getUTC(TOT): not enough buffer space? (%d/%d)\n", off+rem, sizeof(buf));
break;
}
}
}
#endif
/* TOT without descriptors seems to be not better than a plain TDT, such TOT's are */
/* found on transponders which also have wrong time in TDT etc, so don't trust it. */
if (loop_length < 15 && !TDT)
ret = false;
//delete dmxUTC;
dmxUTC->Stop();
return ret;
}

886
src/eitd/edvbstring.cpp Normal file
View File

@@ -0,0 +1,886 @@
#include <string>
#include <ctype.h>
#include <limits.h>
#include <debug.h>
#include <map>
#include <set>
std::map<std::string, int> CountryCodeDefaultMapping;
std::map<int, int> TransponderDefaultMapping;
std::set<int> TransponderUseTwoCharMapping;
int readEncodingFile()
{
FILE *f = fopen("/var/tuxbox/config/encoding.conf", "rt");
if (f) {
CountryCodeDefaultMapping.clear();
TransponderDefaultMapping.clear();
TransponderUseTwoCharMapping.clear();
char line[256];
size_t bufsize=256;
char countrycode[256];
while(fgets(line, bufsize, f)) {
if ( line[0] == '#' )
continue;
int tsid, onid, encoding;
if ( sscanf( line, "%s ISO8859-%d", countrycode, &encoding ) == 2 )
CountryCodeDefaultMapping[countrycode]=encoding;
else if ( (sscanf( line, "0x%x 0x%x ISO8859-%d", &tsid, &onid, &encoding ) == 3 )
||(sscanf( line, "%d %d ISO8859-%d", &tsid, &onid, &encoding ) == 3 ) )
TransponderDefaultMapping[(tsid<<16)|onid]=encoding;
else if ( (sscanf( line, "0x%x 0x%x ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6937 )
||(sscanf( line, "%d %d ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6937 ) )
TransponderDefaultMapping[(tsid<<16)|onid]=64;
else if ( (sscanf( line, "0x%x 0x%x", &tsid, &onid ) == 2 )
||(sscanf( line, "%d %d", &tsid, &onid ) == 2 ) )
TransponderUseTwoCharMapping.insert((tsid<<16)|onid);
}
fclose(f);
return 0;
}
return -1;
}
// 8859-x to ucs-16 coding tables. taken from www.unicode.org/Public/MAPPINGS/ISO8859/
static unsigned long c88592[96]= {
0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0142, /*0x0159,*/ 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
};
static unsigned long c88593[96]= {
0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0000, 0x0124, 0x00A7, 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x0000, 0x017B,
0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x0000, 0x017C,
0x00C0, 0x00C1, 0x00C2, 0x0000, 0x00C4, 0x010A, 0x0108, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x0000, 0x00E4, 0x010B, 0x0109, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x0000, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9
};
static unsigned long c88594[96]= {
0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9
};
static unsigned long c88595[96]= {
0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F
};
static unsigned long c88596[96]= {
0x00A0, 0x0000, 0x0000, 0x0000, 0x00A4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x060C, 0x00AD, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061B, 0x0000, 0x0000, 0x0000, 0x061F,
0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
static unsigned long c88597[96]= {
0x00A0, 0x2018, 0x2019, 0x00A3, 0x20AC, 0x20AF, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x037A, 0x00AB, 0x00AC, 0x00AD, 0x0000, 0x2015,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
};
static unsigned long c88598[96]= {
0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017,
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
};
static unsigned long c88599[96]= {
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
};
static unsigned long c885910[96]= {
0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A,
0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B,
0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF,
0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF,
0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138
};
static unsigned long c885911[96]= {
0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
};
static unsigned long c885913[96]= {
0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019
};
static unsigned long c885914[96]= {
0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61,
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF
};
static unsigned long c885915[96]= {
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
};
static unsigned long c885916[96]= {
0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7, 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B,
0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7, 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C,
0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A, 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF
};
static unsigned long iso6937[96]={
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0000, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x0000, 0xE002, 0xE003, 0xE004, 0xE005, 0xE006, 0xE007, 0xE008, 0xE009, 0xE00C, 0xE00A, 0xE00B, 0x0000, 0xE00D, 0xE00E, 0xE00F,
0x2015, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x00AC, 0x00A6, 0x0000, 0x0000, 0x0000, 0x0000, 0x215B, 0x215C, 0x215D, 0x215E,
0x2126, 0x00C6, 0x0110, 0x00AA, 0x0126, 0x0000, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x00AD
};
// Two Char Mapping ( many polish services and UPC Direct/HBO services)
// get from http://mitglied.lycos.de/buran/charsets/videotex-suppl.html
//static inline unsigned int doVideoTexSuppl(int c1, int c2)
static inline unsigned int doVideoTexSuppl(char c1, char c2)
{
switch (c1)
{
case 0xC1: // grave
switch (c2)
{
case 0x61:
return 224;
case 0x41:
return 192;
case 0x65:
return 232;
case 0x45:
return 200;
case 0x69:
return 236;
case 0x49:
return 204;
case 0x6f:
return 242;
case 0x4f:
return 210;
case 0x75:
return 249;
case 0x55:
return 217;
default:
return 0;
}
case 0xC2: // acute
switch (c2)
{
case 0x61:
return 225;
case 0x41:
return 193;
case 0x65:
return 233;
case 0x45:
return 201;
case 0x69:
return 237;
case 0x49:
return 205;
case 0x6f:
return 243;
case 0x4f:
return 211;
case 0x75:
return 250;
case 0x55:
return 218;
case 0x79:
return 253;
case 0x59:
return 221;
case 0x63:
return 263;
case 0x43:
return 262;
case 0x6c:
return 314;
case 0x4c:
return 313;
case 0x6e:
return 324;
case 0x4e:
return 323;
case 0x72:
return 341;
case 0x52:
return 340;
case 0x73:
return 347;
case 0x53:
return 346;
case 0x7a:
return 378;
case 0x5a:
return 377;
default:
return 0;
}
case 0xC3: // cedilla
switch (c2)
{
case 0x61:
return 226;
case 0x41:
return 194;
case 0x65:
return 234;
case 0x45:
return 202;
case 0x69:
return 238;
case 0x49:
return 206;
case 0x6f:
return 244;
case 0x4f:
return 212;
case 0x75:
return 251;
case 0x55:
return 219;
case 0x79:
return 375;
case 0x59:
return 374;
case 0x63:
return 265;
case 0x43:
return 264;
case 0x67:
return 285;
case 0x47:
return 284;
case 0x68:
return 293;
case 0x48:
return 292;
case 0x6a:
return 309;
case 0x4a:
return 308;
case 0x73:
return 349;
case 0x53:
return 348;
case 0x77:
return 373;
case 0x57:
return 372;
default:
return 0;
}
case 0xC4: // tilde
switch (c2)
{
case 0x61:
return 227;
case 0x41:
return 195;
case 0x6e:
return 241;
case 0x4e:
return 209;
case 0x69:
return 297;
case 0x49:
return 296;
case 0x6f:
return 245;
case 0x4f:
return 213;
case 0x75:
return 361;
case 0x55:
return 360;
default:
return 0;
}
case 0xC6: // breve
switch (c2)
{
case 0x61:
return 259;
case 0x41:
return 258;
case 0x67:
return 287;
case 0x47:
return 286;
case 0x75:
return 365;
case 0x55:
return 364;
default:
return 0;
}
case 0xC7: // dot above
switch (c2)
{
case 0x63:
return 267;
case 0x43:
return 266;
case 0x65:
return 279;
case 0x45:
return 278;
case 0x67:
return 289;
case 0x47:
return 288;
case 0x49:
return 304;
case 0x7a:
return 380;
case 0x5a:
return 379;
default:
return 0;
}
case 0xC8: // diaeresis
switch (c2)
{
case 0x61:
return 228;
case 0x41:
return 196;
case 0x65:
return 235;
case 0x45:
return 203;
case 0x69:
return 239;
case 0x49:
return 207;
case 0x6f:
return 246;
case 0x4f:
return 214;
case 0x75:
return 252;
case 0x55:
return 220;
case 0x79:
return 255;
case 0x59:
return 376;
default:
return 0;
}
case 0xCA: // ring above
switch (c2)
{
case 0x61:
return 229;
case 0x41:
return 197;
case 0x75:
return 367;
case 0x55:
return 366;
default:
return 0;
}
case 0xCB: // cedilla
switch (c2)
{
case 0x63:
return 231;
case 0x43:
return 199;
case 0x67:
return 291;
case 0x47:
return 290;
case 0x6b:
return 311;
case 0x4b:
return 310;
case 0x6c:
return 316;
case 0x4c:
return 315;
case 0x6e:
return 326;
case 0x4e:
return 325;
case 0x72:
return 343;
case 0x52:
return 342;
case 0x73:
return 351;
case 0x53:
return 350;
case 0x74:
return 355;
case 0x54:
return 354;
default:
return 0;
}
case 0xCD: // double acute accent
switch (c2)
{
case 0x6f:
return 337;
case 0x4f:
return 336;
case 0x75:
return 369;
case 0x55:
return 368;
default:
return 0;
}
case 0xCE: // ogonek
switch (c2)
{
case 0x61:
return 261;
case 0x41:
return 260;
case 0x65:
return 281;
case 0x45:
return 280;
case 0x69:
return 303;
case 0x49:
return 302;
case 0x75:
return 371;
case 0x55:
return 370;
default:
return 0;
}
case 0xCF: // caron
switch (c2)
{
case 0x63:
return 269;
case 0x43:
return 268;
case 0x64:
return 271;
case 0x44:
return 270;
case 0x65:
return 283;
case 0x45:
return 282;
case 0x6c:
return 318;
case 0x4c:
return 317;
case 0x6e:
return 328;
case 0x4e:
return 327;
case 0x72:
return 345;
case 0x52:
return 344;
case 0x73:
return 353;
case 0x53:
return 352;
case 0x74:
return 357;
case 0x54:
return 356;
case 0x7a:
return 382;
case 0x5a:
return 381;
default:
return 0;
}
}
return 0;
}
static inline unsigned int recode(unsigned char d, int cp)
{
if (d < 0xA0)
return d;
switch (cp)
{
case 0: // Latin1 <-> unicode mapping
case 1: // 8859-1 <-> unicode mapping
return d;
case 2: // 8859-2 -> unicode mapping
return c88592[d-0xA0];
case 3: // 8859-3 -> unicode mapping
return c88593[d-0xA0];
case 4: // 8859-2 -> unicode mapping
return c88594[d-0xA0];
case 5: // 8859-5 -> unicode mapping
return c88595[d-0xA0];
case 6: // 8859-6 -> unicode mapping
return c88596[d-0xA0];
case 7: // 8859-7 -> unicode mapping
return c88597[d-0xA0];
case 8: // 8859-8 -> unicode mapping
return c88598[d-0xA0];
case 9: // 8859-9 -> unicode mapping
return c88599[d-0xA0];
case 10:// 8859-10 -> unicode mapping
return c885910[d-0xA0];
case 11:// 8859-11 -> unicode mapping
return c885911[d-0xA0];
/* case 12:// 8859-12 -> unicode mapping // reserved for indian use..
return c885912[d-0xA0];*/
case 13:// 8859-13 -> unicode mapping
return c885913[d-0xA0];
case 14:// 8859-14 -> unicode mapping
return c885914[d-0xA0];
case 15:// 8859-15 -> unicode mapping
return c885915[d-0xA0];
case 16:// 8859-16 -> unicode mapping
return c885916[d-0xA0];
case 64:// ISO6937
return iso6937[d-0xA0];
default:
return d;
}
}
std::string convertDVBUTF8(const char *data, int len, int table, int tsidonid)
{
int newtable = 0;
bool twochar = false;
if (!len)
return "";
int i=0, t=0;
if ( tsidonid )
{
std::map<int, int>::iterator it =
TransponderDefaultMapping.find(tsidonid);
if ( it != TransponderDefaultMapping.end() )
table = it->second;
twochar = TransponderUseTwoCharMapping.find(tsidonid) != TransponderUseTwoCharMapping.end();
}
//printf("table %d tsidonid %04x twochar %d : %20s\n", table, tsidonid, twochar, data);
switch(data[0])
{
case 1 ... 12:
newtable=data[i++]+4;
// eDebug("(1..12)text encoded in ISO-8859-%d",table);
break;
case 0x10:
{
// eDebug("(0x10)text encoded in ISO-8859-%d",n);
int n=(data[i+1]<<8)|(data[i+2]);
i += 3;
switch(n)
{
case 12:
{} //eDebug("unsup. ISO8859-12 enc.", n);
default:
newtable=n;
break;
}
break;
}
case 0x11:// Basic Multilingual Plane of ISO/IEC 10646-1 enc (UTF-16... Unicode)
table = 65;
tsidonid = 0;
++i;
break;
case 0x12:
++i;
{} //eDebug("unsup. KSC 5601 enc.");
break;
case 0x13:
++i;
{} //eDebug("unsup. GB-2312-1980 enc.");
break;
case 0x14:
++i;
{} //eDebug("unsup. Big5 subset of ISO/IEC 10646-1 enc.");
break;
case 0x0:
case 0xD ... 0xF:
case 0x15 ... 0x1F:
{} //eDebug("reserved %d", data[0]);
++i;
break;
}
//printf("convertDVBUTF8: table %d new table %d\n", table, newtable);
if(!table)
table = newtable;
if(table == 64 && (newtable !=0 )){//for ISO6937
table = newtable;
}
//dprintf("recode:::: tsidonid %X table %d two-char %d len %d\n", tsidonid, table, twochar, len);
unsigned char res[2048];
while (i < len)
{
unsigned long code=0;
if ( i+1 < len && twochar && (code=doVideoTexSuppl(data[i], data[i+1])) ) {
i+=2;
//dprintf("recode:::: doVideoTexSuppl code %lX\n", code);
}
if (!code) {
if (table == 65) { // unicode
if (i+1 < len) {
code=(data[i] << 8) | data[i+1];
i += 2;
}
}
else
code=recode(data[i++], table);
}
if (!code)
continue;
// Unicode->UTF8 encoding
if (code < 0x80) // identity ascii <-> utf8 mapping
res[t++]=char(code);
else if((table == 5) && (code == 0x8A))
res[t++]= 0x20;
else if ((code == 0x8A))
res[t++]= '\n'; // 0x8a is vertical tab. Just use newline for now.
else if((code >= 0x80) && (code <= 0x9F))
continue;
else if (code < 0x800) // two byte mapping
{
res[t++]=(code>>6)|0xC0;
res[t++]=(code&0x3F)|0x80;
} else if (code < 0x10000) // three bytes mapping
{
res[t++]=(code>>12)|0xE0;
res[t++]=((code>>6)&0x3F)|0x80;
res[t++]=(code&0x3F)|0x80;
} else
{
res[t++]=(code>>18)|0xF0;
res[t++]=((code>>12)&0x3F)|0x80;
res[t++]=((code>>6)&0x3F)|0x80;
res[t++]=(code&0x3F)|0x80;
}
if (t+4 > 2047)
{
{} //eDebug("convertDVBUTF8 buffer to small.. break now");
break;
}
}
return std::string((char*)res, t);
}
#if 0
eString convertUTF8DVB(const eString &string, int table)
{
unsigned long *coding_table=0;
int len=string.length(), t=0;
unsigned char buf[len];
for(int i=0; i<len; i++)
{
unsigned char c1=string[i];
unsigned int c;
if(c1<0x80)
c=c1;
else
{
i++;
unsigned char c2=string[i];
c=((c1&0x3F)<<6) + (c2&0x3F);
if (table==0||table==1||c1<0xA0)
;
else
{
if (!coding_table)
{
switch(table)
{
case 2:
coding_table = c88592;
break;
case 3:
coding_table = c88593;
break;
case 4:
coding_table = c88594;
break;
case 5:
coding_table = c88595;
break;
case 6:
coding_table = c88596;
break;
case 7:
coding_table = c88597;
break;
case 8:
coding_table = c88598;
break;
case 9:
coding_table = c88599;
break;
case 10:
coding_table = c885910;
break;
case 11:
coding_table = c885911;
break;
/* case 12: // reserved.. for indian use
coding_table = c885912;
break;*/
case 13:
coding_table = c885913;
break;
case 14:
coding_table = c885914;
break;
case 15:
coding_table = c885915;
break;
case 16:
coding_table = c885916;
break;
default:
//eFatal("unknown coding table %d", table);
break;
}
}
for(unsigned int j=0; j<96; j++)
{
if(coding_table[j]==c)
{
c=0xA0+j;
break;
}
}
}
}
buf[t++]=(unsigned char)c;
}
return eString((char*)buf,t);
}
#endif
const std::string convertLatin1UTF8(const std::string &string)
{
unsigned int t=0, i=0, len=string.size();
unsigned char res[2048];
while (i < len)
{
unsigned long code=string[i++];
// Unicode->UTF8 encoding
if (code < 0x80) // identity latin <-> utf8 mapping
res[t++]=char(code);
else if (code < 0x800) // two byte mapping
{
res[t++]=(code>>6)|0xC0;
res[t++]=(code&0x3F)|0x80;
} else if (code < 0x10000) // three bytes mapping
{
res[t++]=(code>>12)|0xE0;
res[t++]=((code>>6)&0x3F)|0x80;
res[t++]=(code&0x3F)|0x80;
} else
{
res[t++]=(code>>18)|0xF0;
res[t++]=((code>>12)&0x3F)|0x80;
res[t++]=((code>>6)&0x3F)|0x80;
res[t++]=(code&0x3F)|0x80;
}
if (t+4 > 2047)
{
{} //eDebug("convertLatin1UTF8 buffer to small.. break now");
break;
}
}
return std::string((char*)res, t);
}
int isUTF8(const std::string &string)
{
unsigned int len=string.size();
for (unsigned int i=0; i < len; ++i)
{
if (!(string[i]&0x80)) // normal ASCII
continue;
if ((string[i] & 0xE0) == 0xC0) // one char following.
{
// first, length check:
if (i+1 >= len)
return 0; // certainly NOT utf-8
i++;
if ((string[i]&0xC0) != 0x80)
return 0; // no, not UTF-8.
} else if ((string[i] & 0xF0) == 0xE0)
{
if ((i+1) >= len)
return 0;
i++;
if ((string[i]&0xC0) != 0x80)
return 0;
i++;
if ((string[i]&0xC0) != 0x80)
return 0;
}
}
return 1; // can be UTF8 (or pure ASCII, at least no non-UTF-8 8bit characters)
}

9640
src/eitd/sectionsd.cpp Normal file

File diff suppressed because it is too large Load Diff