diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | eepg.c | 743 | ||||
-rw-r--r-- | eepg.h | 15 | ||||
-rw-r--r-- | eit2.c | 643 | ||||
-rw-r--r-- | eit2.h | 50 | ||||
-rw-r--r-- | epghandler.c | 27 | ||||
-rw-r--r-- | epghandler.h | 2 | ||||
-rw-r--r-- | equivhandler.c | 2 | ||||
-rw-r--r-- | log.h | 3 | ||||
-rw-r--r-- | setupeepg.c | 1 | ||||
-rw-r--r-- | util.c | 169 | ||||
-rw-r--r-- | util.h | 67 |
12 files changed, 989 insertions, 735 deletions
@@ -65,7 +65,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o +OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o eit2.o ifdef DBG CXXFLAGS += -g @@ -45,6 +45,7 @@ #include "setupeepg.h" #include "equivhandler.h" #include "util.h" +#include "eit2.h" #include <map> #include <string> @@ -64,14 +65,6 @@ static const char *VERSION = "0.0.6pre"; static const char *DESCRIPTION = trNOOP ("Parses Extended EPG data"); -template <class T> T REALLOC(T Var, size_t Size) -{ - T p = (T)realloc(Var, Size); - if (!p) - free(Var); - return p; -} - using namespace std; using namespace util; @@ -100,7 +93,6 @@ char *cs_hexdump (int m, const uchar * buf, int n) } cSetupEEPG* SetupPE = cSetupEEPG::getInstance(); -cEquivHandler* EquivHandler; // --- cMenuSetupPremiereEpg ------------------------------------------------------------ @@ -150,7 +142,7 @@ void cMenuSetupPremiereEpg::Store (void) #endif } -#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() ) +//#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() ) // --- CRC16 ------------------------------------------------------------------- @@ -173,27 +165,6 @@ unsigned int crc16 (unsigned int crc, unsigned char const *p, int len) static int LastVersionNagra = -1; //currently only used for Nagra, should be stored per transponder, per system - -#ifdef USE_NOEPG -bool allowedEPG (tChannelID kanalID) -{ - bool rc; - - if (Setup.noEPGMode == 1) { - rc = false; - if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) - rc = true; - } else { - rc = true; - if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) - rc = false; - } - - return rc; -} -#endif /* NOEPG */ - - class cFilterEEPG:public cFilter { private: @@ -267,6 +238,8 @@ public: cFilterEEPG::cFilterEEPG (void) { + nSummaries = 0; + nTitles = 0; Trigger (); //Set (0x00, 0x00); } @@ -333,21 +306,21 @@ void syslog_with_tid (int priority, const char *format, ...) __attribute__ ((for -struct hufftab { - unsigned int value; - short bits; - char next; -}; +//struct hufftab { +// unsigned int value; +// short bits; +// char next; +//}; +// +//#define START '\0' +//#define STOP '\0' +//#define ESCAPE '\1' -#define START '\0' -#define STOP '\0' -#define ESCAPE '\1' +//int freesat_decode_error = 0; /* If set an error has occurred during decoding */ -int freesat_decode_error = 0; /* If set an error has occurred during decoding */ - -static struct hufftab *tables[2][128]; -static int table_size[2][128]; +//static struct hufftab *tables[2][128]; +//static int table_size[2][128]; static sNodeH* sky_tables[2]; /** \brief Convert a textual character description into a value @@ -589,7 +562,7 @@ static bool load_sky_file (const char *filename) char *freesat_huffman_decode (const unsigned char *src, size_t size) { int tableid; - freesat_decode_error = 0; +// freesat_decode_error = 0; if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) { int uncompressed_len = 30; @@ -859,44 +832,28 @@ bool cFilterEEPG::InitDictionary (void) return true; } -void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize) -{ - if (from[0] == 0x1f) { - char *temp = freesat_huffman_decode (from, len); - if (temp) { - len = strlen (temp); - len = len < buffsize - 1 ? len : buffsize - 1; - strncpy (buffer, temp, len); - buffer[len] = 0; - free (temp); - return; - } - } - - SI::String convStr; - SI::CharArray charArray; - charArray.assign(from, len); - convStr.setData(charArray, len); - //LogE(5, prep("decodeText2 from %s - length %d"), from, len); - convStr.getText(buffer, buffsize); - //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize); -} - -void sortSchedules(cSchedules * Schedules, tChannelID channelID){ - - LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString()); - - cChannel *pChannel = GetChannelByID (channelID, false); - cSchedule *pSchedule; - if (pChannel) { - pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true)); - pSchedule->Sort(); - Schedules->SetModified(pSchedule); - } - if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0) - EquivHandler->sortEquivalents(channelID, Schedules); -} - +//void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize) +//{ +// if (from[0] == 0x1f) { +// char *temp = freesat_huffman_decode (from, len); +// if (temp) { +// len = strlen (temp); +// len = len < buffsize - 1 ? len : buffsize - 1; +// strncpy (buffer, temp, len); +// buffer[len] = 0; +// free (temp); +// return; +// } +// } +// +// SI::String convStr; +// SI::CharArray charArray; +// charArray.assign(from, len); +// convStr.setData(charArray, len); +// //LogE(5, prep("decodeText2 from %s - length %d"), from, len); +// convStr.getText(buffer, buffsize); +// //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize); +//} /** * \brief Get MHW channels @@ -2662,628 +2619,6 @@ void cFilterEEPG::AddFilter (u_short Pid, u_char Tid, unsigned char Mask) } } -namespace SI -{ - enum DescriptorTagExt { - DishRatingDescriptorTag = 0x89, - DishShortEventDescriptorTag = 0x91, - DishExtendedEventDescriptorTag = 0x92, - DishSeriesDescriptorTag = 0x96, - }; - -// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag; - -/*extern const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL); -extern bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode); -extern bool SystemCharacterTableIsSingleByte;*/ -class cEIT2:public SI::EIT -{ -public: - cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false, bool OnlyRunningStatus = false); -//protected: -// void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent); -}; - - -cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus) -: SI::EIT (Data, false) -{ - //LogD(2, prep("cEIT2::cEIT2")); - if (Tid > 0 && (Format == DISH_BEV || (SetupPE->ProcessEIT && isEITPid))) Tid--; - - if (!CheckCRCAndParse ()) { - LogD(2, prep("!CheckCRCAndParse ()")); - return; - } - - bool searchOtherSatPositions = Format == DISH_BEV; - - tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ()); - cChannel *channel = GetChannelByID (channelID, searchOtherSatPositions); - if (!channel) { - LogD(3, prep("!channel channelID: %s"), *channelID.ToString()); - return; // only collect data for known channels - } - - //LogD(5, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format); - -#ifdef USE_NOEPG - // only use epg from channels not blocked by noEPG-patch - tChannelID kanalID; - kanalID = channel->GetChannelID (); - if (!allowedEPG (kanalID)) - return; -#endif /* NOEPG */ - - cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true); - - bool Empty = true; - bool Modified = false; - bool HasExternalData = false; - time_t SegmentStart = 0; - time_t SegmentEnd = 0; - - SI::EIT::Event SiEitEvent; - for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) { - bool ExternalData = false; - // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. - if (SiEitEvent.getStartTime () == 0 || (SiEitEvent.getStartTime () > 0 && SiEitEvent.getDuration () == 0)) - continue; - Empty = false; - if (!SegmentStart) - SegmentStart = SiEitEvent.getStartTime (); - SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration (); - int versionNumber = getVersionNumber(); - - cEvent *newEvent = NULL; - cEvent *rEvent = NULL; - cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ()); - if (!pEvent) { - if (OnlyRunningStatus) - continue; - // If we don't have that event yet, we create a new one. - // Otherwise we copy the information into the existing event anyway, because the data might have changed. - pEvent = newEvent = new cEvent (SiEitEvent.getEventId ()); - if (!pEvent) - continue; - } else { - //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber); - // We have found an existing event, either through its event ID or its start time. - pEvent->SetSeen (); - - // If the existing event has a zero table ID it was defined externally and shall - // not be overwritten. - if (pEvent->TableID () == 0x00) { -#ifdef USE_DDEPGENTRY - if (pEvent->Version () == getVersionNumber ()) { - if (Setup.MixEpgAction == 0) - continue; - //printf("in"); - //printf("%s", pEvent->GetTimeString()); - // to use the info of the original epg, update the extern one, - // if it has less info - SI::Descriptor * d; - SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; - //SI::ExtendedEventDescriptor *eed = NULL; - SI::ShortEventDescriptor * ShortEventDescriptor = NULL; - //SI::ShortEventDescriptor *sed = NULL; - //SI::TimeShiftedEventDescriptor *tsed = NULL; - //cLinkChannels *LinkChannels = NULL; - for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) { - if (d->getDescriptorTag () == SI::ShortEventDescriptorTag) { - int LanguagePreferenceShort = -1; - SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d; - if (I18nIsPreferredLanguage (Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) - || !ShortEventDescriptor) { - delete ShortEventDescriptor; - ShortEventDescriptor = sed; - d = NULL; // so that it is not deleted - } - } else if (d->getDescriptorTag () == SI::ExtendedEventDescriptorTag) { - int LanguagePreferenceExt = -1; - bool UseExtendedEventDescriptor = false; - SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d; - if (I18nIsPreferredLanguage (Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) - || !ExtendedEventDescriptors) { - delete ExtendedEventDescriptors; - ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; - UseExtendedEventDescriptor = true; - } - if (UseExtendedEventDescriptor) { - ExtendedEventDescriptors->Add (eed); - d = NULL; // so that it is not deleted - } - if (eed->getDescriptorNumber () == eed->getLastDescriptorNumber ()) - UseExtendedEventDescriptor = false; - } - delete d; - } - if (pEvent) { - if (ShortEventDescriptor) { - char buffer[256]; - if (ShortEventDescriptor->text.getText (buffer, sizeof (buffer)) && pEvent->ShortText () - && (strlen (ShortEventDescriptor->text.getText (buffer, sizeof (buffer))) > - strlen (pEvent->ShortText ()))) { - pEvent->SetShortText (ShortEventDescriptor->text.getText (buffer, sizeof (buffer))); - pEvent->FixEpgBugs (); - } - } - if (ExtendedEventDescriptors) { - char buffer[ExtendedEventDescriptors->getMaximumTextLength (": ") + 1]; - //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); - if (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ") - && pEvent->Description () - && (strlen (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")) > - strlen (pEvent->Description ()))) { - pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")); - pEvent->FixEpgBugs (); - } - } - } - delete ExtendedEventDescriptors; - delete ShortEventDescriptor; - continue; - } -#else - if (pEvent->Version () == versionNumber) - continue; -#endif /* DDEPGENTRY */ - HasExternalData = ExternalData = true; - } - // If the new event has a higher table ID, let's skip it. - // The lower the table ID, the more "current" the information. - else if (Tid > pEvent->TableID()) - continue; - // If the new event comes from the same table and has the same version number - // as the existing one, let's skip it to avoid unnecessary work. - // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like - // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on - // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned - // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. - else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber) - continue; - } - if (!ExternalData) { - pEvent->SetEventID (SiEitEvent.getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-( - pEvent->SetTableID (Tid); - pEvent->SetStartTime (SiEitEvent.getStartTime ()); - pEvent->SetDuration (SiEitEvent.getDuration ()); - } - if (newEvent) - pSchedule->AddEvent (newEvent); - if (Tid == 0x4E) { // we trust only the present/following info on the actual TS -#ifdef USE_DDEPGENTRY - if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning) -#else - if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning) -#endif /* DDEPGENTRY */ - pSchedule->SetRunningStatus (pEvent, SiEitEvent.getRunningStatus (), channel); - } - if (OnlyRunningStatus) - continue; // do this before setting the version, so that the full update can be done later - pEvent->SetVersion (versionNumber); - - int LanguagePreferenceShort = -1; - int LanguagePreferenceExt = -1; - unsigned char nDescriptorTag; - bool UseExtendedEventDescriptor = false; - SI::Descriptor * d; - SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; - SI::ShortEventDescriptor * ShortEventDescriptor = NULL; - //SI::DishDescriptor *DishExtendedEventDescriptor = NULL; - SI::DishDescriptor *DishEventDescriptor = NULL; - //uchar DishTheme = 0, DishCategory = 0; - - - cLinkChannels *LinkChannels = NULL; - cComponents *Components = NULL; - for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) { - if (ExternalData && d->getDescriptorTag () != SI::ComponentDescriptorTag) { - delete d; - LogD(2, prep("continue:d->getDescriptorTAG():%x)"), d->getDescriptorTag ()); - continue; - } - - //LogD(2, prep("EEPGDEBUG:d->getDescriptorTAG():%x)"), d->getDescriptorTag ()); - nDescriptorTag = d->getDescriptorTag (); - switch (nDescriptorTag) { - case SI::ExtendedEventDescriptorTag: { - SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d; - if (I18nIsPreferredLanguage (Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) - || !ExtendedEventDescriptors) { - delete ExtendedEventDescriptors; - ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; - UseExtendedEventDescriptor = true; - } - if (UseExtendedEventDescriptor) { - ExtendedEventDescriptors->Add (eed); - d = NULL; // so that it is not deleted - } - if (eed->getDescriptorNumber () == eed->getLastDescriptorNumber ()) - UseExtendedEventDescriptor = false; - } - break; - case SI::ShortEventDescriptorTag: { - SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d; - if (I18nIsPreferredLanguage (Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) - || !ShortEventDescriptor) { - delete ShortEventDescriptor; - ShortEventDescriptor = sed; - d = NULL; // so that it is not deleted - } - } - break; -#if APIVERSNUM > 10711 - case SI::ContentDescriptorTag: { - SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; - SI::ContentDescriptor::Nibble Nibble; - int NumContents = 0; - uchar Contents[MaxEventContents] = { 0 }; - for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { - if (NumContents < MaxEventContents) { - Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); - NumContents++; - } - if (DishEventDescriptor && NumContents == 1) { - DishEventDescriptor->setContent(Nibble); - } -// LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2() -// , Nibble.getUserNibble1(), Nibble.getUserNibble2()); - - } - pEvent->SetContents(Contents); - } - break; -#endif - case SI::ParentalRatingDescriptorTag: { - int LanguagePreferenceRating = -1; - SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; - SI::ParentalRatingDescriptor::Rating Rating; - for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { - if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { - int ParentalRating = (Rating.getRating() & 0xFF); - switch (ParentalRating) { - // values defined by the DVB standard (minimum age = rating + 3 years): - case 0x01 ... 0x0F: - ParentalRating += 3; - break; - // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?): - case 0x11: - ParentalRating = 10; - break; - case 0x12: - ParentalRating = 12; - break; - case 0x13: - ParentalRating = 16; - break; - default: - ParentalRating = 0; - } - pEvent->SetParentalRating(ParentalRating); - } - } - } - break; - case SI::PDCDescriptorTag: { - SI::PDCDescriptor * pd = (SI::PDCDescriptor *) d; - time_t now = time (NULL); - struct tm tm_r; - struct tm t = *localtime_r (&now, &tm_r); // this initializes the time zone in 't' - t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting - int month = t.tm_mon; - t.tm_mon = pd->getMonth () - 1; - t.tm_mday = pd->getDay (); - t.tm_hour = pd->getHour (); - t.tm_min = pd->getMinute (); - t.tm_sec = 0; - if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan - t.tm_year++; - else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec - t.tm_year--; - time_t vps = mktime (&t); - pEvent->SetVps (vps); - } - break; - case SI::TimeShiftedEventDescriptorTag: { - SI::TimeShiftedEventDescriptor * tsed = (SI::TimeShiftedEventDescriptor *) d; - cSchedule *rSchedule = - (cSchedule *) Schedules-> - GetSchedule (tChannelID (Source, channel->Nid (), channel->Tid (), tsed->getReferenceServiceId ())); - if (!rSchedule) - break; - rEvent = (cEvent *) rSchedule->GetEvent (tsed->getReferenceEventId ()); - if (!rEvent) - break; - pEvent->SetTitle (rEvent->Title ()); - pEvent->SetShortText (rEvent->ShortText ()); - pEvent->SetDescription (rEvent->Description ()); - } - break; - case SI::LinkageDescriptorTag: { - SI::LinkageDescriptor * ld = (SI::LinkageDescriptor *) d; - tChannelID linkID (Source, ld->getOriginalNetworkId (), ld->getTransportStreamId (), ld->getServiceId ()); - if (ld->getLinkageType () == 0xB0) { // Premiere World - time_t now = time (NULL); - bool hit = SiEitEvent.getStartTime () <= now - && now < SiEitEvent.getStartTime () + SiEitEvent.getDuration (); - if (hit) { - char linkName[ld->privateData.getLength () + 1]; - strn0cpy (linkName, (const char *) ld->privateData.getData (), sizeof (linkName)); - // TODO is there a standard way to determine the character set of this string? - cChannel *link = Channels.GetByChannelID (linkID); - if (link != channel) { // only link to other channels, not the same one - //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX - if (link) { - if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) - link->SetName (linkName, "", ""); - } else if (Setup.UpdateChannels >= 4) { - cChannel *transponder = channel; - if (channel->Tid () != ld->getTransportStreamId ()) - transponder = Channels.GetByTransponderID (linkID); - link = - Channels.NewChannel (transponder, linkName, "", "", ld->getOriginalNetworkId (), - ld->getTransportStreamId (), ld->getServiceId ()); - } - if (link) { - if (!LinkChannels) - LinkChannels = new cLinkChannels; - LinkChannels->Add (new cLinkChannel (link)); - } - } else - channel->SetPortalName (linkName); - } - } - } - break; - case SI::ComponentDescriptorTag: { - SI::ComponentDescriptor * cd = (SI::ComponentDescriptor *) d; - uchar Stream = cd->getStreamContent (); - uchar Type = cd->getComponentType (); - //if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles - if (1 <= Stream && Stream <= 6 && Type != 0) { // 1=MPEG2-video, 2=MPEG1-audio, 3=subtitles, 4=AC3-audio, 5=H.264-video, 6=HEAAC-audio - if (!Components) - Components = new cComponents; - char buffer[Utf8BufSize (256)]; - Components->SetComponent (Components->NumComponents (), Stream, Type, - I18nNormalizeLanguageCode (cd->languageCode), - cd->description.getText (buffer, sizeof (buffer))); - } - } - break; - case SI::DishExtendedEventDescriptorTag: { - SI::UnimplementedDescriptor *deed = (SI::UnimplementedDescriptor *)d; - if (!DishEventDescriptor) { - DishEventDescriptor = new SI::DishDescriptor(); - } - DishEventDescriptor->setExtendedtData(Tid+1, deed->getData()); - HasExternalData = true; - } - break; - case SI::DishShortEventDescriptorTag: { - SI::UnimplementedDescriptor *dsed = (SI::UnimplementedDescriptor *)d; - if (!DishEventDescriptor) { - DishEventDescriptor = new SI::DishDescriptor(); - } - DishEventDescriptor->setShortData(Tid+1, dsed->getData()); - HasExternalData = true; - } - break; - case SI::DishRatingDescriptorTag: { - if (d->getLength() == 4) { - if (!DishEventDescriptor) { - DishEventDescriptor = new SI::DishDescriptor(); - } - uint16_t rating = d->getData().TwoBytes(2); - DishEventDescriptor->setRating(rating); - } - } - break; - case SI::DishSeriesDescriptorTag: { - if (d->getLength() == 10) { - //LogD(2, prep("DishSeriesDescriptorTag: %s)"), (const char*) d->getData().getData()); - if (!DishEventDescriptor) { - DishEventDescriptor = new SI::DishDescriptor(); - } - DishEventDescriptor->setEpisodeInfo(d->getData()); - } -// else { -// LogD(2, prep("DishSeriesDescriptorTag length: %d)"), d->getLength()); -// } - } - break; - default: - break; - } - delete d; - } - - if (!rEvent) { - if (ShortEventDescriptor) { - char buffer[Utf8BufSize (256)]; - unsigned char *f; - int l = ShortEventDescriptor->name.getLength(); - f = (unsigned char *) ShortEventDescriptor->name.getData().getData(); - decodeText2 (f, l, buffer, sizeof (buffer)); - //ShortEventDescriptor->name.getText(buffer, sizeof(buffer)); - LogD(2, prep("Title: %s Decoded: %s"), f, buffer); - pEvent->SetTitle (buffer); - LogD(3, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title()); - l = ShortEventDescriptor->text.getLength(); - if (l > 0) { //Set the Short Text only if there is data so that we do not overwrite valid data - f = (unsigned char *) ShortEventDescriptor->text.getData().getData(); - decodeText2 (f, l, buffer, sizeof (buffer)); - //ShortEventDescriptor->text.getText(buffer, sizeof(buffer)); - pEvent->SetShortText (buffer); - } - LogD(3, prep("ShortText: %s"), pEvent->ShortText()); - LogD(2, prep("ShortText: %s Decoded: %s"), f, buffer); - } else if (!HasExternalData) { - pEvent->SetTitle (NULL); - pEvent->SetShortText (NULL); - LogD(3, prep("SetTitle (NULL)")); - } - if (ExtendedEventDescriptors) { - char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1]; - pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")); - LogD(3, prep("Description: %s"), pEvent->Description()); - } else if (!HasExternalData) - pEvent->SetDescription (NULL); - - if (DishEventDescriptor) { - if (DishEventDescriptor->getName()) - pEvent->SetTitle(DishEventDescriptor->getName()); - //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName()); - pEvent->SetShortText(DishEventDescriptor->getShortText()); - char *tmp; - string fmt; - - const char * description = DishEventDescriptor->getDescription(); - //BEV sets the description previously with ExtendedEventDescriptor - if (0 == strcmp(DishEventDescriptor->getDescription(),"") && pEvent->Description()) - description = pEvent->Description(); - - - fmt = "%s"; - if (DishEventDescriptor->hasTheme()) { - fmt += "\nTheme: "; - } - fmt += "%s"; - if (DishEventDescriptor->hasCategory()) { - fmt += "\nCategory: "; - } - fmt += "%s"; - - if ((0 != strcmp(DishEventDescriptor->getRating(),"") - || 0 != strcmp(DishEventDescriptor->getStarRating(),""))) { - fmt += "\n\nRating: "; - } - fmt += "%s %s"; - if (0 != strcmp(DishEventDescriptor->getProgramId(),"")) { - fmt += "\n\nProgram ID: "; - } - fmt += "%s %s%s"; - time_t orgAirDate = DishEventDescriptor->getOriginalAirDate(); - char datestr [80]; - bool dateok = false; - if (orgAirDate == 0) { - dateok = strftime (datestr,80," Original Air Date: %a %b %d %Y",gmtime(&orgAirDate)) > 0; - } - - Asprintf (&tmp, fmt.c_str(), description - , DishEventDescriptor->getTheme(), DishEventDescriptor->getCategory() - , DishEventDescriptor->getRating(), DishEventDescriptor->getStarRating() - , DishEventDescriptor->getProgramId(), DishEventDescriptor->getSeriesId() - , orgAirDate == 0 || !dateok ? "" : datestr); - pEvent->SetDescription(tmp); - free(tmp); - - - //LogD(2, prep("DishDescription: %s"), DishEventDescriptor->getDescription()); - //LogD(2, prep("DishShortText: %s"), DishEventDescriptor->getShortText()); - } - - } - delete ExtendedEventDescriptors; - delete ShortEventDescriptor; - delete DishEventDescriptor; - - pEvent->SetComponents (Components); - -// LogD(2, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title()); - -// if (pEvent->ChannelID() == tChannelID::FromString("S119.0W-4100-6-110-110")) { -// LogD(2, prep("ID: %d Title: %s Time: %d Tid: 0x%x"), pEvent->EventID(), pEvent->Title(), pEvent->StartTime(), pEvent->TableID()); -// } - - if (!HasExternalData) - pEvent->FixEpgBugs (); - if (LinkChannels) - channel->SetLinkChannels (LinkChannels); - Modified = true; -#ifdef USE_DDEPGENTRY - //to avoid double epg-entrys from ext and int epg sources :EW - if (pEvent && pEvent->TableID () != 0x00) { - cEvent *pPreviousEvent = (cEvent *) pSchedule->GetPreviousEvent (pEvent); - if (pPreviousEvent) { - if (Setup.DoubleEpgAction == 0) { - pPreviousEvent->SetStartTime (pEvent->StartTime ()); - pPreviousEvent->SetDuration (pEvent->Duration ()); - if (Setup.DisableVPS == 0) { - if (channel) - pPreviousEvent->SetRunningStatus (pEvent->RunningStatus (), channel); - else - pPreviousEvent->SetRunningStatus (pEvent->RunningStatus ()); - } - // to use the info of the original epg, update the extern one, - // if it has less info - char buffer_short_intern[256]; - char buffer_short_extern[256]; - int len_short_intern = 0; - int len_short_extern = 0; - if (pEvent->ShortText ()) - len_short_intern = - snprintf (buffer_short_intern, sizeof (buffer_short_intern) - 1, "%s", pEvent->ShortText ()); - if (pPreviousEvent->ShortText ()) - len_short_extern = - snprintf (buffer_short_extern, sizeof (buffer_short_extern) - 1, "%s", pPreviousEvent->ShortText ()); - if (len_short_intern > 0) { - if (len_short_extern < 1) - pPreviousEvent->SetShortText (buffer_short_intern); - else if (len_short_intern > len_short_extern) - pPreviousEvent->SetShortText (buffer_short_intern); - } - if (pEvent->Description ()) { - char buffer_title_intern[4096]; - char buffer_title_extern[4096]; - int len_title_intern = 0; - int len_title_extern = 0; - if (pEvent->Description ()) - len_title_intern = - snprintf (buffer_title_intern, sizeof (buffer_title_intern) - 1, "%s", pEvent->Description ()); - if (pPreviousEvent->Description ()) - len_title_extern = - snprintf (buffer_title_extern, sizeof (buffer_title_extern) - 1, "%s", - pPreviousEvent->Description ()); - if (len_title_intern > 0) { - if (len_title_extern < 1) - pPreviousEvent->SetDescription (buffer_title_intern); - else if (len_title_intern > len_title_extern) - pPreviousEvent->SetDescription (buffer_title_intern); - } - } - if (pPreviousEvent->Vps () == 0 && pEvent->Vps () != 0) - pPreviousEvent->SetVps (pEvent->Vps ()); - pSchedule->DelEvent (pEvent); - pPreviousEvent->FixEpgBugs (); - } else - pSchedule->DelEvent (pPreviousEvent); - } - } -#endif /* DDEPGENTRY */ - EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent); - } - if (Empty && Tid == 0x4E && getSectionNumber () == 0) - // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running - pSchedule->ClrRunningStatus (channel); - if (Tid == 0x4E) - pSchedule->SetPresentSeen (); - if (OnlyRunningStatus) { - LogD(4, prep("OnlyRunningStatus")); - return; - } - if (Modified) { - if (!HasExternalData) - pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ()); - sortSchedules(Schedules, channel->GetChannelID()); - } - LogD(4, prep("end of cEIT2")); - -} -//end of cEIT2 - -} //end namespace SI - void cFilterEEPG::ProcessNextFormat (bool FirstTime = false) { /* for (int i = 0; i <= HIGHEST_FORMAT; i++) @@ -17,21 +17,6 @@ //#define NAGRA 6 //#define HIGHEST_FORMAT 6 -enum EFormat { -//First all batchmode, load ONCE protocols: - MHW1 = 0, - MHW2 , - SKY_IT , - SKY_UK , - NAGRA , -//Than all CONTinuous protocols, so they will be processed LAST: - PREMIERE , - FREEVIEW , - DISH_BEV , - EIT , -//the highest number of EPG-formats that is supported by this plugin - HIGHEST_FORMAT = EIT -} Format; #define NAGRA_TABLE_ID 0x55 //the lower the table Id, the more "current" it is; table_id 0x00 never gets overwritten, now/next are at 0x4e or 0x4f! #define DEFAULT_TABLE_ID 0x30 @@ -0,0 +1,643 @@ +/* + * eit2.c + * + * Created on: Oct 16, 2012 + * Author: d.petrovski + */ +#include "eit2.h" + +#include <string> +#include <vdr/config.h> +#include "log.h" +#include "util.h" +#include "dish.h" +#include "equivhandler.h" + +using namespace std; +using namespace util; + +namespace SI +{ + +cEvent* cEIT2::ProcessEitEvent(cSchedule* pSchedule,const SI::EIT::Event* EitEvent, + uchar Tid, uchar versionNumber) +{ + bool ExternalData = false; + // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. + if (EitEvent->getStartTime () == 0 || (EitEvent->getStartTime () > 0 && EitEvent->getDuration () == 0)) + return NULL; + Empty = false; + if (!SegmentStart) + SegmentStart = EitEvent->getStartTime (); + SegmentEnd = EitEvent->getStartTime () + EitEvent->getDuration (); + // int versionNumber = getVersionNumber(); + + cEvent *newEvent = NULL; + cEvent *pEvent = (cEvent *) pSchedule->GetEvent (EitEvent->getEventId (), EitEvent->getStartTime ()); + if (!pEvent) { + if (OnlyRunningStatus) + return NULL; + // If we don't have that event yet, we create a new one. + // Otherwise we copy the information into the existing event anyway, because the data might have changed. + pEvent = newEvent = new cEvent (EitEvent->getEventId ()); + if (!pEvent) + return NULL; + } else { + //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber); + // We have found an existing event, either through its event ID or its start time. + pEvent->SetSeen (); + + // If the existing event has a zero table ID it was defined externally and shall + // not be overwritten. + if (pEvent->TableID () == 0x00) { + if (pEvent->Version () == versionNumber) + return NULL; + /*HasExternalData = */ExternalData = true; + } + // If the new event has a higher table ID, let's skip it. + // The lower the table ID, the more "current" the information. + else if (Tid > pEvent->TableID()) + return NULL; + // If the new event comes from the same table and has the same version number + // as the existing one, let's skip it to avoid unnecessary work. + // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like + // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on + // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned + // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. + else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber) + return NULL; + } + if (!ExternalData) { + pEvent->SetEventID (EitEvent->getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-( + pEvent->SetTableID (Tid); + pEvent->SetStartTime (EitEvent->getStartTime ()); + pEvent->SetDuration (EitEvent->getDuration ()); + } + if (newEvent) + pSchedule->AddEvent (newEvent); + if (Tid == 0x4E) { // we trust only the present/following info on the actual TS + if (EitEvent->getRunningStatus () >= SI::RunningStatusNotRunning) + pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), channel); + } + if (OnlyRunningStatus) + return NULL; // do this before setting the version, so that the full update can be done later + pEvent->SetVersion (versionNumber); + + ProcessEventDescriptors(ExternalData, channel->Source(), Tid, EitEvent, + pEvent, Schedules, channel); + + Modified = true; + return pEvent; +} + +void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source, + u_char Tid, const SI::EIT::Event* SiEitEvent, cEvent* pEvent, + cSchedules* Schedules, cChannel* channel) +{ + + cEvent *rEvent = NULL; + int LanguagePreferenceShort = -1; + int LanguagePreferenceExt = -1; + unsigned char nDescriptorTag; + bool UseExtendedEventDescriptor = false; + SI::Descriptor * d; + SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; + SI::ShortEventDescriptor * ShortEventDescriptor = NULL; + //SI::DishDescriptor *DishExtendedEventDescriptor = NULL; + SI::DishDescriptor *DishEventDescriptor = NULL; + //uchar DishTheme = 0, DishCategory = 0; + + + cLinkChannels *LinkChannels = NULL; + cComponents *Components = NULL; + + + DescriptorLoop dl = SiEitEvent->eventDescriptors; + for (SI::Loop::Iterator it2; (d = dl.getNext(it2)); ) + { + if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) + { + delete d; + LogD(2, prep("continue:d->getDescriptorTAG():%x)"), d->getDescriptorTag ()); + continue; + } + + //LogD(2, prep("EEPGDEBUG:d->getDescriptorTAG():%x)"), d->getDescriptorTag ()); + nDescriptorTag = d->getDescriptorTag(); + switch (nDescriptorTag) + { + case SI::ExtendedEventDescriptorTag: + { + SI::ExtendedEventDescriptor * eed = + (SI::ExtendedEventDescriptor *) d; + if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, + LanguagePreferenceExt) || !ExtendedEventDescriptors) + { + delete ExtendedEventDescriptors; + ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; + UseExtendedEventDescriptor = true; + } + if (UseExtendedEventDescriptor) + { + ExtendedEventDescriptors->Add(eed); + d = NULL; // so that it is not deleted + } + if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) + UseExtendedEventDescriptor = false; + } + break; + case SI::ShortEventDescriptorTag: + { + SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d; + if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, + LanguagePreferenceShort) || !ShortEventDescriptor) + { + delete ShortEventDescriptor; + ShortEventDescriptor = sed; + d = NULL; // so that it is not deleted + } + } + break; +#if APIVERSNUM > 10711 + case SI::ContentDescriptorTag: + { + SI::ContentDescriptor *cd = (SI::ContentDescriptor *) d; + SI::ContentDescriptor::Nibble Nibble; + int NumContents = 0; + uchar Contents[MaxEventContents] = + { 0 }; + for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3);) + { + if (NumContents < MaxEventContents) + { + Contents[NumContents] = ((Nibble.getContentNibbleLevel1() + & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); + NumContents++; + } + if (DishEventDescriptor && NumContents == 1) + { + DishEventDescriptor->setContent(Nibble); + } + // LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2() + // , Nibble.getUserNibble1(), Nibble.getUserNibble2()); + + } + pEvent->SetContents(Contents); + } + break; +#endif + case SI::ParentalRatingDescriptorTag: + { + int LanguagePreferenceRating = -1; + SI::ParentalRatingDescriptor *prd = + (SI::ParentalRatingDescriptor *) d; + SI::ParentalRatingDescriptor::Rating Rating; + for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3);) + { + if (I18nIsPreferredLanguage(Setup.EPGLanguages, + Rating.languageCode, LanguagePreferenceRating)) + { + int ParentalRating = (Rating.getRating() & 0xFF); + switch (ParentalRating) + { + // values defined by the DVB standard (minimum age = rating + 3 years): + case 0x01 ... 0x0F: + ParentalRating += 3; + break; + // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?): + case 0x11: + ParentalRating = 10; + break; + case 0x12: + ParentalRating = 12; + break; + case 0x13: + ParentalRating = 16; + break; + default: + ParentalRating = 0; + } + pEvent->SetParentalRating(ParentalRating); + } + } + } + break; + case SI::PDCDescriptorTag: + { + SI::PDCDescriptor * pd = (SI::PDCDescriptor *) d; + time_t now = time(NULL); + struct tm tm_r; + struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' + t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting + int month = t.tm_mon; + t.tm_mon = pd->getMonth() - 1; + t.tm_mday = pd->getDay(); + t.tm_hour = pd->getHour(); + t.tm_min = pd->getMinute(); + t.tm_sec = 0; + if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan + t.tm_year++; + else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec + t.tm_year--; + time_t vps = mktime(&t); + pEvent->SetVps(vps); + } + break; + case SI::TimeShiftedEventDescriptorTag: + { + if (Schedules) { + SI::TimeShiftedEventDescriptor * tsed = + (SI::TimeShiftedEventDescriptor *) d; + cSchedule *rSchedule = (cSchedule *) Schedules->GetSchedule( + tChannelID(Source, channel->Nid(), channel->Tid(), + tsed->getReferenceServiceId())); + if (!rSchedule) + break; + rEvent = (cEvent *) rSchedule->GetEvent( + tsed->getReferenceEventId()); + if (!rEvent) + break; + pEvent->SetTitle(rEvent->Title()); + pEvent->SetShortText(rEvent->ShortText()); + pEvent->SetDescription(rEvent->Description()); + } + } + break; + case SI::LinkageDescriptorTag: + { + SI::LinkageDescriptor * ld = (SI::LinkageDescriptor *) d; + tChannelID linkID(Source, ld->getOriginalNetworkId(), + ld->getTransportStreamId(), ld->getServiceId()); + if (ld->getLinkageType() == 0xB0) + { // Premiere World + time_t now = time(NULL); + bool hit = SiEitEvent->getStartTime() <= now + && now + < SiEitEvent->getStartTime() + SiEitEvent->getDuration(); + if (hit) + { + char linkName[ld->privateData.getLength() + 1]; + strn0cpy(linkName, (const char *) ld->privateData.getData(), + sizeof(linkName)); + // TODO is there a standard way to determine the character set of this string? + cChannel *link = Channels.GetByChannelID(linkID); + if (link != channel) + { // only link to other channels, not the same one + //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX + if (link) + { + if (Setup.UpdateChannels == 1 + || Setup.UpdateChannels >= 3) + link->SetName(linkName, "", ""); + } + else if (Setup.UpdateChannels >= 4) + { + cChannel *transponder = channel; + if (channel->Tid() != ld->getTransportStreamId()) + transponder = Channels.GetByTransponderID(linkID); + link = Channels.NewChannel(transponder, linkName, + "", "", ld->getOriginalNetworkId(), + ld->getTransportStreamId(), ld->getServiceId()); + } + if (link) + { + if (!LinkChannels) + LinkChannels = new cLinkChannels; + LinkChannels->Add(new cLinkChannel(link)); + } + } + else + channel->SetPortalName(linkName); + } + } + } + break; + case SI::ComponentDescriptorTag: + { + SI::ComponentDescriptor * cd = (SI::ComponentDescriptor *) d; + uchar Stream = cd->getStreamContent(); + uchar Type = cd->getComponentType(); + //if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles + if (1 <= Stream && Stream <= 6 && Type != 0) + { // 1=MPEG2-video, 2=MPEG1-audio, 3=subtitles, 4=AC3-audio, 5=H.264-video, 6=HEAAC-audio + if (!Components) + Components = new cComponents; + char buffer[Utf8BufSize (256)]; + Components->SetComponent(Components->NumComponents(), Stream, + Type, I18nNormalizeLanguageCode(cd->languageCode), + cd->description.getText(buffer, sizeof(buffer))); + } + } + break; + case SI::DishExtendedEventDescriptorTag: + { + SI::UnimplementedDescriptor *deed = + (SI::UnimplementedDescriptor *) d; + if (!DishEventDescriptor) + { + DishEventDescriptor = new SI::DishDescriptor(); + } + DishEventDescriptor->setExtendedtData(Tid + 1, deed->getData()); + // HasExternalData = true; + } + break; + case SI::DishShortEventDescriptorTag: + { + SI::UnimplementedDescriptor *dsed = + (SI::UnimplementedDescriptor *) d; + if (!DishEventDescriptor) + { + DishEventDescriptor = new SI::DishDescriptor(); + } + DishEventDescriptor->setShortData(Tid + 1, dsed->getData()); + // HasExternalData = true; + } + break; + case SI::DishRatingDescriptorTag: + { + if (d->getLength() == 4) + { + if (!DishEventDescriptor) + { + DishEventDescriptor = new SI::DishDescriptor(); + } + uint16_t rating = d->getData().TwoBytes(2); + DishEventDescriptor->setRating(rating); + } + } + break; + case SI::DishSeriesDescriptorTag: + { + if (d->getLength() == 10) + { + //LogD(2, prep("DishSeriesDescriptorTag: %s)"), (const char*) d->getData().getData()); + if (!DishEventDescriptor) + { + DishEventDescriptor = new SI::DishDescriptor(); + } + DishEventDescriptor->setEpisodeInfo(d->getData()); + } + // else { + // LogD(2, prep("DishSeriesDescriptorTag length: %d)"), d->getLength()); + // } + } + break; + default: + break; + } + delete d; + } + if (!rEvent) { + if (ShortEventDescriptor) { + char buffer[Utf8BufSize (256)]; + unsigned char *f; + int l = ShortEventDescriptor->name.getLength(); + f = (unsigned char *) ShortEventDescriptor->name.getData().getData(); + decodeText2 (f, l, buffer, sizeof (buffer)); + //ShortEventDescriptor->name.getText(buffer, sizeof(buffer)); + LogD(2, prep("Title: %s Decoded: %s"), f, buffer); + pEvent->SetTitle (buffer); + LogD(3, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title()); + l = ShortEventDescriptor->text.getLength(); + if (l > 0) { //Set the Short Text only if there is data so that we do not overwrite valid data + f = (unsigned char *) ShortEventDescriptor->text.getData().getData(); + decodeText2 (f, l, buffer, sizeof (buffer)); + //ShortEventDescriptor->text.getText(buffer, sizeof(buffer)); + pEvent->SetShortText (buffer); + } + LogD(3, prep("ShortText: %s"), pEvent->ShortText()); + LogD(2, prep("ShortText: %s Decoded: %s"), f, buffer); + } else if (/*!HasExternalData*/!DishEventDescriptor) { + pEvent->SetTitle (NULL); + pEvent->SetShortText (NULL); + LogD(3, prep("SetTitle (NULL)")); + } + if (ExtendedEventDescriptors) { + char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1]; + pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")); + LogD(3, prep("Description: %s"), pEvent->Description()); + } else if (!/*HasExternalData*/DishEventDescriptor) + pEvent->SetDescription (NULL); + + if (DishEventDescriptor) { + if (DishEventDescriptor->getName()) + pEvent->SetTitle(DishEventDescriptor->getName()); + //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName()); + pEvent->SetShortText(DishEventDescriptor->getShortText()); + char *tmp; + string fmt; + + const char * description = DishEventDescriptor->getDescription(); + //BEV sets the description previously with ExtendedEventDescriptor + if (0 == strcmp(DishEventDescriptor->getDescription(),"") && pEvent->Description()) + description = pEvent->Description(); + + + fmt = "%s"; + if (DishEventDescriptor->hasTheme()) { + fmt += "\nTheme: "; + } + fmt += "%s"; + if (DishEventDescriptor->hasCategory()) { + fmt += "\nCategory: "; + } + fmt += "%s"; + + if ((0 != strcmp(DishEventDescriptor->getRating(),"") + || 0 != strcmp(DishEventDescriptor->getStarRating(),""))) { + fmt += "\n\nRating: "; + } + fmt += "%s %s"; + if (0 != strcmp(DishEventDescriptor->getProgramId(),"")) { + fmt += "\n\nProgram ID: "; + } + fmt += "%s %s%s"; + time_t orgAirDate = DishEventDescriptor->getOriginalAirDate(); + char datestr [80]; + bool dateok = false; + if (orgAirDate == 0) { + dateok = strftime (datestr,80," Original Air Date: %a %b %d %Y",gmtime(&orgAirDate)) > 0; + } + + Asprintf (&tmp, fmt.c_str(), description + , DishEventDescriptor->getTheme(), DishEventDescriptor->getCategory() + , DishEventDescriptor->getRating(), DishEventDescriptor->getStarRating() + , DishEventDescriptor->getProgramId(), DishEventDescriptor->getSeriesId() + , orgAirDate == 0 || !dateok ? "" : datestr); + pEvent->SetDescription(tmp); + free(tmp); + + + //LogD(2, prep("DishDescription: %s"), DishEventDescriptor->getDescription()); + //LogD(2, prep("DishShortText: %s"), DishEventDescriptor->getShortText()); + } + + } + delete ExtendedEventDescriptors; + delete ShortEventDescriptor; + delete DishEventDescriptor; + + pEvent->SetComponents (Components); + + // LogD(2, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title()); + + // if (pEvent->ChannelID() == tChannelID::FromString("S119.0W-4100-6-110-110")) { + // LogD(2, prep("ID: %d Title: %s Time: %d Tid: 0x%x"), pEvent->EventID(), pEvent->Title(), pEvent->StartTime(), pEvent->TableID()); + // } + + // if (!HasExternalData) + pEvent->FixEpgBugs (); + if (LinkChannels) + channel->SetLinkChannels (LinkChannels); +} + +cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus) +: SI::EIT (Data, false) +, OnlyRunningStatus(OnlyRunningStatus) +, Schedules(Schedules) +{ + + //LogD(2, prep("cEIT2::cEIT2")); + if (Tid > 0 && (Format == DISH_BEV || (cSetupEEPG::getInstance()->ProcessEIT && isEITPid))) Tid--; + + if (!CheckCRCAndParse ()) { + LogD(2, prep("!CheckCRCAndParse ()")); + return; + } + + bool searchOtherSatPositions = Format == DISH_BEV; + + tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ()); + channel = GetChannelByID (channelID, searchOtherSatPositions); + if (!channel) { + LogD(3, prep("!channel channelID: %s"), *channelID.ToString()); + return; // only collect data for known channels + } + + //LogD(5, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format); + + cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true); + + Empty = true; + Modified = false; + // bool HasExternalData = false; + SegmentStart = 0; + SegmentEnd = 0; + + SI::EIT::Event SiEitEvent; + for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) { + int versionNumber = getVersionNumber(); + // bool ExternalData = false; + // // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. + // if (SiEitEvent.getStartTime () == 0 || (SiEitEvent.getStartTime () > 0 && SiEitEvent.getDuration () == 0)) + // continue; + // Empty = false; + // if (!SegmentStart) + // SegmentStart = SiEitEvent.getStartTime (); + // SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration (); + // int versionNumber = getVersionNumber(); + // + // cEvent *newEvent = NULL; + // cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ()); + // if (!pEvent) { + // if (OnlyRunningStatus) + // continue; + // // If we don't have that event yet, we create a new one. + // // Otherwise we copy the information into the existing event anyway, because the data might have changed. + // pEvent = newEvent = new cEvent (SiEitEvent.getEventId ()); + // if (!pEvent) + // continue; + // } else { + // //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber); + // // We have found an existing event, either through its event ID or its start time. + // pEvent->SetSeen (); + // + // // If the existing event has a zero table ID it was defined externally and shall + // // not be overwritten. + // if (pEvent->TableID () == 0x00) { + // if (pEvent->Version () == versionNumber) + // continue; + // /*HasExternalData = */ExternalData = true; + // } + // // If the new event has a higher table ID, let's skip it. + // // The lower the table ID, the more "current" the information. + // else if (Tid > pEvent->TableID()) + // continue; + // // If the new event comes from the same table and has the same version number + // // as the existing one, let's skip it to avoid unnecessary work. + // // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like + // // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on + // // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned + // // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. + // else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber) + // continue; + // } + // if (!ExternalData) { + // pEvent->SetEventID (SiEitEvent.getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-( + // pEvent->SetTableID (Tid); + // pEvent->SetStartTime (SiEitEvent.getStartTime ()); + // pEvent->SetDuration (SiEitEvent.getDuration ()); + // } + // if (newEvent) + // pSchedule->AddEvent (newEvent); + // if (Tid == 0x4E) { // we trust only the present/following info on the actual TS + // if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning) + // pSchedule->SetRunningStatus (pEvent, SiEitEvent.getRunningStatus (), channel); + // } + // if (OnlyRunningStatus) + // continue; // do this before setting the version, so that the full update can be done later + // pEvent->SetVersion (versionNumber); + // + // ProcessEventDescriptors(ExternalData, Source, Tid, SiEitEvent, + // pEvent, Schedules, channel); + // + // Modified = true; + cEvent *pEvent = ProcessEitEvent(pSchedule, &SiEitEvent, + Tid, versionNumber); + if (pEvent) + EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent); + } + + //// + + if (Empty && Tid == 0x4E && getSectionNumber () == 0) + // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running + pSchedule->ClrRunningStatus (channel); + if (Tid == 0x4E) + pSchedule->SetPresentSeen (); + if (OnlyRunningStatus) { + LogD(4, prep("OnlyRunningStatus")); + return; + } + if (Modified) { + // if (!HasExternalData) + pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ()); + sortSchedules(Schedules, channel->GetChannelID()); + } + LogD(4, prep("end of cEIT2")); + +} +//end of cEIT2 + +cEIT2::cEIT2 (cSchedule * Schedule) +: Empty(true) +, Modified(false) +, OnlyRunningStatus(false) +, SegmentStart(0) +, SegmentEnd(0) +, Schedules(NULL) +{ + //LogD(2, prep("cEIT2::cEIT2")); + // if (Tid > 0 && (Format == DISH_BEV || (SetupPE->ProcessEIT && isEITPid))) Tid--; + + bool searchOtherSatPositions = Format == DISH_BEV; + + tChannelID channelID (Schedule->ChannelID().Source(), getOriginalNetworkId (), getTransportStreamId (), getServiceId ()); + channel = GetChannelByID (channelID, searchOtherSatPositions); + if (!channel) { + LogD(3, prep("!channel channelID: %s"), *channelID.ToString()); + return; // only collect data for known channels + } +} +} //end namespace SI + @@ -0,0 +1,50 @@ +#ifndef CEIT2_H_ +#define CEIT2_H_ +#include <libsi/section.h> +#include <libsi/descriptor.h> +#include <libsi/si.h> +#include <vdr/epg.h> + +namespace SI +{ +enum DescriptorTagExt { + DishRatingDescriptorTag = 0x89, + DishShortEventDescriptorTag = 0x91, + DishExtendedEventDescriptorTag = 0x92, + DishSeriesDescriptorTag = 0x96, +}; + +// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag; + +/*extern const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL); +extern bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode); +extern bool SystemCharacterTableIsSingleByte;*/ +class cEIT2:public SI::EIT +{ +public: + cEIT2(cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false, + bool OnlyRunningStatus = false); + cEIT2 (cSchedule * Schedule); + //protected: + // void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent); + cEvent* ProcessEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version); + +private: + void ProcessEventDescriptors(bool ExternalData, int Source, u_char Tid, + const SI::EIT::Event* SiEitEvent, cEvent* pEvent, + cSchedules* Schedules, cChannel* channel); + +private: + bool Empty; + bool Modified; + // bool HasExternalData = false; + bool OnlyRunningStatus; + time_t SegmentStart; + time_t SegmentEnd; + cSchedules* Schedules; + cChannel* channel; + +}; +} //end namespace SI + +#endif /* CEIT2_H_ */ diff --git a/epghandler.c b/epghandler.c index 44ee909..0262d75 100644 --- a/epghandler.c +++ b/epghandler.c @@ -9,7 +9,9 @@ #if APIVERSNUM > 10725 #include "log.h" #include "equivhandler.h" +#include "eit2.h" #include <vdr/sources.h> +#include <libsi/si.h> cEEpgHandler::cEEpgHandler() { LogD(4, prep("cEEpgHandler()")); @@ -27,8 +29,11 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule, //DISH NID 0x1001 to 0x100B BEV 0x100 and 0x101 //TODO move the eit handling code at least for NA providers here instead of discarding. int nid = Schedule->ChannelID().Nid(); - if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) + if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) { + SI::cEIT2 eit2(Schedule); + eit2.ProcessEitEvent(Schedule, EitEvent, TableID, Version); return true; + } //TODO Should it be added in setup? if (EitEvent->getDurationHour() > _LONG_EVENT_HOURS) { @@ -43,6 +48,25 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule, } } + //VDR creates new event if the EitEvent StartTime is different than EEPG time so + //the EEPG event has to be deleted but the data should be kept + const cEvent* ev = Schedule->GetEvent(EitEvent->getEventId(),EitEvent->getStartTime()); + if (!ev){ + ev = Schedule->GetEvent(EitEvent->getEventId()); + if (ev && ((ev->StartTime()>EitEvent->getStartTime() && ev->StartTime()<=EitEvent->getStartTime()+EitEvent->getDuration()) + || (EitEvent->getStartTime() > ev->StartTime() && EitEvent->getStartTime() <= ev->EndTime()))) { + LogD(0, prep("!!!Deleting Event id:%d title:%s start_time:%d new_start_time:%d duration:%d new_duration:%d"), ev->EventID(), ev->Title(), ev->StartTime(), EitEvent->getStartTime(), ev->Duration(), EitEvent->getDuration()); + + if (ev->Description() && strcmp(ev->Description(),"") != 0) + origDescription = ev->Description(); + if (ev->ShortText() && strcmp(ev->ShortText(),"") != 0) + origShortText = ev->ShortText(); + Schedule->DropOutdated(ev->StartTime()-1,ev->EndTime()+1,ev->TableID()-1,ev->Version()); + LogD(0, prep("!!!End Deleting Event")); + } + } + + return false; // return true; @@ -148,6 +172,7 @@ bool cEEpgHandler::HandleEvent(cEvent* Event) { return true; } + bool cEEpgHandler::SortSchedule(cSchedule* Schedule) { Schedule->Sort(); diff --git a/epghandler.h b/epghandler.h index 3219f58..4e60e57 100644 --- a/epghandler.h +++ b/epghandler.h @@ -34,6 +34,8 @@ public: virtual bool SortSchedule(cSchedule *Schedule); virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); +// bool ParseEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version); + private: std::string origShortText; std::string origDescription; diff --git a/equivhandler.c b/equivhandler.c index a742150..281d2f3 100644 --- a/equivhandler.c +++ b/equivhandler.c @@ -170,8 +170,8 @@ void cEquivHandler::updateEquivalent(tChannelID channelID, cEvent *pEvent){ ret = equiChanMap.equal_range(*channelID.ToString()); for (it=ret.first; it!=ret.second; ++it) { - LogD(3, prep("equivalent channel exists")); tChannelID equChannelID (tChannelID::FromString((*it).second.c_str())); + LogD(3, prep("equivalent channel '%s' exists"), *equChannelID.ToString()); cEvent* newEvent = new cEvent (pEvent->EventID()); cloneEvent(pEvent, newEvent); @@ -9,7 +9,8 @@ #define LOG_H_ #include <string> -#include <stdarg.h> +#include <vdr/tools.h> +#include <vdr/thread.h> #include "setupeepg.h" #define VERBOSE 1 diff --git a/setupeepg.c b/setupeepg.c index 54f8243..ee2565e 100644 --- a/setupeepg.c +++ b/setupeepg.c @@ -14,6 +14,7 @@ cSetupEEPG* cSetupEEPG::_setupEEPG = NULL; cSetupEEPG::cSetupEEPG (void) { + ConfDir = NULL; OptPat = 1; OrderInfo = 1; RatingInfo = 1; @@ -5,6 +5,8 @@ * Author: d.petrovski */ #include "util.h" +#include "log.h" +#include "equivhandler.h" #include <vdr/channels.h> #include <vdr/thread.h> #include <vdr/epg.h> @@ -21,6 +23,12 @@ int Yesterday; int YesterdayEpoch; int YesterdayEpochUTC; +struct hufftab *tables[2][128]; +int table_size[2][128]; + +EFormat Format; +cEquivHandler* EquivHandler; + cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos) { cChannel *VC = Channels.GetByChannelID(channelID, true); @@ -155,7 +163,7 @@ class cAddEventThread : public cThread private: cTimeMs LastHandleEvent; // cList<cAddEventListItem> *list; - std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare> *map_list; + std::map<tChannelID,cList<cEvent>*,tChannelIDCompare> *map_list; enum { INSERT_TIMEOUT_IN_MS = 10000 }; protected: virtual void Action(void); @@ -169,14 +177,14 @@ cAddEventThread::cAddEventThread(void) :cThread("cAddEventThread"), LastHandleEvent() { // list = new cList<cAddEventListItem>; - map_list = new std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>; + map_list = new std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>; } cAddEventThread::~cAddEventThread(void) { LOCK_THREAD; // list->cList::Clear(); - std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>::iterator it; + std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it; for ( it=map_list->begin() ; it != map_list->end(); it++ ) (*it).second->cList::Clear(); Cancel(3); @@ -197,21 +205,28 @@ void cAddEventThread::Action(void) // EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version()); // list->Del(e); // } - std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>::iterator it; + std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it; it=map_list->begin(); while (schedules && it != map_list->end()) { cSchedule *schedule = (cSchedule *)schedules->GetSchedule(Channels.GetByChannelID((*it).first), true); while (((*it).second->First()) != NULL) { - cEvent* event = *(*it).second->First(); + cEvent* event = (*it).second->First(); cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime()); - if (pEqvEvent) + if (pEqvEvent){ + LogD (0, prep("schedule->DelEvent(event)")); schedule->DelEvent(pEqvEvent); + } - schedule->AddEvent(event); + LogD (0, prep("schedule->AddEvent(event)")); + //cCondWait::SleepMs(10); + if (event) + schedule->AddEvent(event); (*it).second->Del(event); } EpgHandlers.SortSchedule(schedule); + //sortSchedules(schedules, (*it).first); + //schedule->Sort(); delete (*it).second; map_list->erase(it); it=map_list->begin(); @@ -224,16 +239,21 @@ void cAddEventThread::Action(void) void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID) { + LogD (0, prep("AddEventT start")); LOCK_THREAD; + LogD (0, prep("AddEventT lock ")); if (map_list->empty() || map_list->count(ChannelID) == 0) { - cList<cEvent *>* list = new cList<cEvent *>; + LogD (0, prep("AddEventT if")); + cList<cEvent>* list = new cList<cEvent>; list->Add(Event); map_list->insert(std::make_pair(ChannelID, list)); } else { + LogD (0, prep("AddEventT else")); (*map_list->find(ChannelID)).second->Add(Event); } // list->Add(new cAddEventListItem(Event, ChannelID)); LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS); + LogD (0, prep("AddEventT end")); } static cAddEventThread AddEventThread; @@ -242,11 +262,144 @@ static cAddEventThread AddEventThread; void AddEvent(cEvent *Event, tChannelID ChannelID) { + LogD (0, prep("AddEvent")); AddEventThread.AddEvent(Event, ChannelID); if (!AddEventThread.Active()) AddEventThread.Start(); } +/** \brief Decode an EPG string as necessary + * + * \param src - Possibly encoded string + * \param size - Size of the buffer + * + * \retval NULL - Can't decode + * \return A decoded string + */ +char *freesat_huffman_decode (const unsigned char *src, size_t size) +{ + int tableid; +// freesat_decode_error = 0; + + if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) { + int uncompressed_len = 30; + char *uncompressed = (char *) calloc (1, uncompressed_len + 1); + unsigned value = 0, byte = 2, bit = 0; + int p = 0; + unsigned char lastch = START; + + tableid = src[1] - 1; + while (byte < 6 && byte < size) { + value |= src[byte] << ((5 - byte) * 8); + byte++; + } + //freesat_table_load (); /**< Load the tables as necessary */ + + do { + bool found = false; + unsigned bitShift = 0; + if (lastch == ESCAPE) { + char nextCh = (value >> 24) & 0xff; + found = true; + // Encoded in the next 8 bits. + // Terminated by the first ASCII character. + bitShift = 8; + if ((nextCh & 0x80) == 0) + lastch = nextCh; + if (p >= uncompressed_len) { + uncompressed_len += 10; + uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1); + } + uncompressed[p++] = nextCh; + uncompressed[p] = 0; + } else { + int j; + for (j = 0; j < table_size[tableid][lastch]; j++) { + unsigned mask = 0, maskbit = 0x80000000; + short kk; + for (kk = 0; kk < tables[tableid][lastch][j].bits; kk++) { + mask |= maskbit; + maskbit >>= 1; + } + if ((value & mask) == tables[tableid][lastch][j].value) { + char nextCh = tables[tableid][lastch][j].next; + bitShift = tables[tableid][lastch][j].bits; + if (nextCh != STOP && nextCh != ESCAPE) { + if (p >= uncompressed_len) { + uncompressed_len += 10; + uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1); + } + uncompressed[p++] = nextCh; + uncompressed[p] = 0; + } + found = true; + lastch = nextCh; + break; + } + } + } + if (found) { + // Shift up by the number of bits. + unsigned b; + for (b = 0; b < bitShift; b++) { + value = (value << 1) & 0xfffffffe; + if (byte < size) + value |= (src[byte] >> (7 - bit)) & 1; + if (bit == 7) { + bit = 0; + byte++; + } else + bit++; + } + } else { + LogE (0, prep("Missing table %d entry: <%s>"), tableid + 1, uncompressed); + // Entry missing in table. + return uncompressed; + } + } while (lastch != STOP && value != 0); + + return uncompressed; + } + return NULL; +} + +void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize) +{ + if (from[0] == 0x1f) { + char *temp = freesat_huffman_decode (from, len); + if (temp) { + len = strlen (temp); + len = len < buffsize - 1 ? len : buffsize - 1; + strncpy (buffer, temp, len); + buffer[len] = 0; + free (temp); + return; + } + } + + SI::String convStr; + SI::CharArray charArray; + charArray.assign(from, len); + convStr.setData(charArray, len); + //LogE(5, prep("decodeText2 from %s - length %d"), from, len); + convStr.getText(buffer, buffsize); + //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize); +} + +void sortSchedules(cSchedules * Schedules, tChannelID channelID){ + + LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString()); + + cChannel *pChannel = GetChannelByID (channelID, false); + cSchedule *pSchedule; + if (pChannel) { + pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true)); + pSchedule->Sort(); + Schedules->SetModified(pSchedule); + } + if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0) + EquivHandler->sortEquivalents(channelID, Schedules); +} } @@ -11,9 +11,18 @@ class cChannel; struct tChannelID; class cEvent; +class cEquivHandler; +class cSchedules; + +#define START '\0' +#define STOP '\0' +#define ESCAPE '\1' + +#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() ) namespace util { + extern int AvailableSources[32]; extern int NumberOfAvailableSources; @@ -21,12 +30,62 @@ extern int Yesterday; extern int YesterdayEpoch; extern int YesterdayEpochUTC; +extern enum EFormat +{ +//First all batchmode, load ONCE protocols: + MHW1 = 0, + MHW2, + SKY_IT, + SKY_UK, + NAGRA, +//Than all CONTinuous protocols, so they will be processed LAST: + PREMIERE, + FREEVIEW, + DISH_BEV, + EIT, +//the highest number of EPG-formats that is supported by this plugin + HIGHEST_FORMAT = EIT +} Format; + +extern cEquivHandler* EquivHandler; + void AddEvent(cEvent *event, tChannelID ChannelID); cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos); -time_t LocalTime2UTC (time_t t); -time_t UTC2LocalTime (time_t t); -void GetLocalTimeOffset (void); -void CleanString (unsigned char *String); +time_t LocalTime2UTC(time_t t); +time_t UTC2LocalTime(time_t t); +void GetLocalTimeOffset(void); +void CleanString(unsigned char *String); +void decodeText2(const unsigned char *from, int len, char *buffer, int buffsize); +char *freesat_huffman_decode(const unsigned char *src, size_t size); +void sortSchedules(cSchedules * Schedules, tChannelID channelID); + +//struct sNode +//{ +// char *Value; +// struct sNode *P0; +// struct sNode *P1; +//}; +// +//typedef struct sNode sNodeH; + +template<class T> T REALLOC(T Var, size_t Size) +{ + T p = (T) realloc(Var, Size); + if (!p) free(Var); + return p; +} + +struct hufftab +{ + unsigned int value; + short bits; + char next; +}; + +extern struct hufftab *tables[2][128]; +extern int table_size[2][128]; +//static sNodeH* sky_tables[2]; + } #endif /* UTIL_H_ */ |