diff -Naur vdr-1.4.0-noEIT/channels.c vdr-1.4.0/channels.c --- vdr-1.4.0-noEIT/channels.c 2006-01-14 10:51:02.000000000 -0500 +++ vdr-1.4.0/channels.c 2006-05-07 18:50:25.000000000 -0500 @@ -970,7 +970,7 @@ return NULL; } -cChannel *cChannels::GetByChannelID(tChannelID ChannelID, bool TryWithoutRid, bool TryWithoutPolarization) +cChannel *cChannels::GetByChannelID(tChannelID ChannelID, bool TryWithoutRid, bool TryWithoutPolarization, bool TryWithoutSource) { int sid = ChannelID.Sid(); cList *list = channelsHashSid.GetList(sid); @@ -980,6 +980,13 @@ if (channel->Sid() == sid && channel->GetChannelID() == ChannelID) return channel; } + if (TryWithoutSource) { + ChannelID.ClrSource(); + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep() && channel->GetChannelID().ClrSource() == ChannelID) + return channel; + } + } if (TryWithoutRid) { ChannelID.ClrRid(); for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { diff -Naur vdr-1.4.0-noEIT/channels.c.orig vdr-1.4.0/channels.c.orig --- vdr-1.4.0-noEIT/channels.c.orig 1969-12-31 19:00:00.000000000 -0500 +++ vdr-1.4.0/channels.c.orig 2006-01-14 10:51:02.000000000 -0500 @@ -0,0 +1,1047 @@ +/* + * channels.c: Channel handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: channels.c 1.48 2006/01/14 15:51:02 kls Exp $ + */ + +#include "channels.h" +#include +#include +#include "device.h" +#include "epg.h" + +// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' +// format characters in order to allow any number of blanks after a numeric +// value! + +// -- Channel Parameter Maps ------------------------------------------------- + +const tChannelParameterMap InversionValues[] = { + { 0, INVERSION_OFF }, + { 1, INVERSION_ON }, + { 999, INVERSION_AUTO }, + { -1 } + }; + +const tChannelParameterMap BandwidthValues[] = { + { 6, BANDWIDTH_6_MHZ }, + { 7, BANDWIDTH_7_MHZ }, + { 8, BANDWIDTH_8_MHZ }, + { 999, BANDWIDTH_AUTO }, + { -1 } + }; + +const tChannelParameterMap CoderateValues[] = { + { 0, FEC_NONE }, + { 12, FEC_1_2 }, + { 23, FEC_2_3 }, + { 34, FEC_3_4 }, + { 45, FEC_4_5 }, + { 56, FEC_5_6 }, + { 67, FEC_6_7 }, + { 78, FEC_7_8 }, + { 89, FEC_8_9 }, + { 999, FEC_AUTO }, + { -1 } + }; + +const tChannelParameterMap ModulationValues[] = { + { 0, QPSK }, + { 16, QAM_16 }, + { 32, QAM_32 }, + { 64, QAM_64 }, + { 128, QAM_128 }, + { 256, QAM_256 }, + { 999, QAM_AUTO }, + { -1 } + }; + +const tChannelParameterMap TransmissionValues[] = { + { 2, TRANSMISSION_MODE_2K }, + { 8, TRANSMISSION_MODE_8K }, + { 999, TRANSMISSION_MODE_AUTO }, + { -1 } + }; + +const tChannelParameterMap GuardValues[] = { + { 4, GUARD_INTERVAL_1_4 }, + { 8, GUARD_INTERVAL_1_8 }, + { 16, GUARD_INTERVAL_1_16 }, + { 32, GUARD_INTERVAL_1_32 }, + { 999, GUARD_INTERVAL_AUTO }, + { -1 } + }; + +const tChannelParameterMap HierarchyValues[] = { + { 0, HIERARCHY_NONE }, + { 1, HIERARCHY_1 }, + { 2, HIERARCHY_2 }, + { 4, HIERARCHY_4 }, + { 999, HIERARCHY_AUTO }, + { -1 } + }; + +int UserIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->userValue == Value) + return map - Map; + map++; + } + return -1; +} + +int DriverIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->driverValue == Value) + return map - Map; + map++; + } + return -1; +} + +int MapToUser(int Value, const tChannelParameterMap *Map) +{ + int n = DriverIndex(Value, Map); + if (n >= 0) + return Map[n].userValue; + return -1; +} + +int MapToDriver(int Value, const tChannelParameterMap *Map) +{ + int n = UserIndex(Value, Map); + if (n >= 0) + return Map[n].driverValue; + return -1; +} + +// -- tChannelID ------------------------------------------------------------- + +const tChannelID tChannelID::InvalidID; + +tChannelID tChannelID::FromString(const char *s) +{ + char *sourcebuf = NULL; + int nid; + int tid; + int sid; + int rid = 0; + int fields = sscanf(s, "%a[^-]-%d-%d-%d-%d", &sourcebuf, &nid, &tid, &sid, &rid); + if (fields == 4 || fields == 5) { + int source = cSource::FromString(sourcebuf); + free(sourcebuf); + if (source >= 0) + return tChannelID(source, nid, tid, sid, rid); + } + return tChannelID::InvalidID; +} + +cString tChannelID::ToString(void) const +{ + char buffer[256]; + snprintf(buffer, sizeof(buffer), rid ? "%s-%d-%d-%d-%d" : "%s-%d-%d-%d", *cSource::ToString(source), nid, tid, sid, rid); + return buffer; +} + +tChannelID &tChannelID::ClrPolarization(void) +{ + while (tid > 100000) + tid -= 100000; + return *this; +} + +// -- cChannel --------------------------------------------------------------- + +cChannel::cChannel(void) +{ + name = strdup(""); + shortName = strdup(""); + provider = strdup(""); + portalName = strdup(""); + memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); + inversion = INVERSION_AUTO; + bandwidth = BANDWIDTH_AUTO; + coderateH = FEC_AUTO; + coderateL = FEC_AUTO; + modulation = QAM_AUTO; + transmission = TRANSMISSION_MODE_AUTO; + guard = GUARD_INTERVAL_AUTO; + hierarchy = HIERARCHY_AUTO; + modification = CHANNELMOD_NONE; + schedule = NULL; + linkChannels = NULL; + refChannel = NULL; +} + +cChannel::cChannel(const cChannel &Channel) +{ + name = NULL; + shortName = NULL; + provider = NULL; + portalName = NULL; + schedule = NULL; + linkChannels = NULL; + refChannel = NULL; + *this = Channel; +} + +cChannel::~cChannel() +{ + delete linkChannels; + linkChannels = NULL; // more than one channel can link to this one, so we need the following loop + for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { + if (Channel->linkChannels) { + for (cLinkChannel *lc = Channel->linkChannels->First(); lc; lc = Channel->linkChannels->Next(lc)) { + if (lc->Channel() == this) { + Channel->linkChannels->Del(lc); + break; + } + } + if (Channel->linkChannels->Count() == 0) { + delete Channel->linkChannels; + Channel->linkChannels = NULL; + } + } + } + free(name); + free(shortName); + free(provider); + free(portalName); +} + +cChannel& cChannel::operator= (const cChannel &Channel) +{ + name = strcpyrealloc(name, Channel.name); + shortName = strcpyrealloc(shortName, Channel.shortName); + provider = strcpyrealloc(provider, Channel.provider); + portalName = strcpyrealloc(portalName, Channel.portalName); + memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__); + return *this; +} + +int cChannel::Transponder(int Frequency, char Polarization) +{ + // some satellites have transponders at the same frequency, just with different polarization: + switch (tolower(Polarization)) { + case 'h': Frequency += 100000; break; + case 'v': Frequency += 200000; break; + case 'l': Frequency += 300000; break; + case 'r': Frequency += 400000; break; + } + return Frequency; +} + +int cChannel::Transponder(void) const +{ + int tf = frequency; + while (tf > 20000) + tf /= 1000; + if (IsSat()) + tf = Transponder(tf, polarization); + return tf; +} + +int cChannel::Modification(int Mask) +{ + int Result = modification & Mask; + modification = CHANNELMOD_NONE; + return Result; +} + +void cChannel::CopyTransponderData(const cChannel *Channel) +{ + if (Channel) { + frequency = Channel->frequency; + source = Channel->source; + srate = Channel->srate; + polarization = Channel->polarization; + inversion = Channel->inversion; + bandwidth = Channel->bandwidth; + coderateH = Channel->coderateH; + coderateL = Channel->coderateL; + modulation = Channel->modulation; + transmission = Channel->transmission; + guard = Channel->guard; + hierarchy = Channel->hierarchy; + } +} + +bool cChannel::SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH) +{ + // Workarounds for broadcaster stupidity: + // Some providers broadcast the transponder frequency of their channels with two different + // values (like 12551 and 12552), so we need to allow for a little tolerance here + if (abs(frequency - Frequency) <= 1) + Frequency = frequency; + // Sometimes the transponder frequency is set to 0, which is just wrong + if (Frequency == 0) + return false; + + if (source != Source || frequency != Frequency || polarization != Polarization || srate != Srate || coderateH != CoderateH) { + if (Number()) { + dsyslog("changing transponder data of channel %d from %s:%d:%c:%d:%d to %s:%d:%c:%d:%d", Number(), *cSource::ToString(source), frequency, polarization, srate, coderateH, *cSource::ToString(Source), Frequency, Polarization, Srate, CoderateH); + modification |= CHANNELMOD_TRANSP; + Channels.SetModified(); + } + source = Source; + frequency = Frequency; + polarization = Polarization; + srate = Srate; + coderateH = CoderateH; + modulation = QPSK; + schedule = NULL; + } + return true; +} + +bool cChannel::SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH) +{ + if (source != Source || frequency != Frequency || modulation != Modulation || srate != Srate || coderateH != CoderateH) { + if (Number()) { + dsyslog("changing transponder data of channel %d from %s:%d:%d:%d:%d to %s:%d:%d:%d:%d", Number(), *cSource::ToString(source), frequency, modulation, srate, coderateH, *cSource::ToString(Source), Frequency, Modulation, Srate, CoderateH); + modification |= CHANNELMOD_TRANSP; + Channels.SetModified(); + } + source = Source; + frequency = Frequency; + modulation = Modulation; + srate = Srate; + coderateH = CoderateH; + schedule = NULL; + } + return true; +} + +bool cChannel::SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CoderateH, int CoderateL, int Guard, int Transmission) +{ + if (source != Source || frequency != Frequency || bandwidth != Bandwidth || modulation != Modulation || hierarchy != Hierarchy || coderateH != CoderateH || coderateL != CoderateL || guard != Guard || transmission != Transmission) { + if (Number()) { + dsyslog("changing transponder data of channel %d from %s:%d:%d:%d:%d:%d:%d:%d:%d to %s:%d:%d:%d:%d:%d:%d:%d:%d", Number(), *cSource::ToString(source), frequency, bandwidth, modulation, hierarchy, coderateH, coderateL, guard, transmission, *cSource::ToString(Source), Frequency, Bandwidth, Modulation, Hierarchy, CoderateH, CoderateL, Guard, Transmission); + modification |= CHANNELMOD_TRANSP; + Channels.SetModified(); + } + source = Source; + frequency = Frequency; + bandwidth = Bandwidth; + modulation = Modulation; + hierarchy = Hierarchy; + coderateH = CoderateH; + coderateL = CoderateL; + guard = Guard; + transmission = Transmission; + schedule = NULL; + } + return true; +} + +void cChannel::SetId(int Nid, int Tid, int Sid, int Rid) +{ + if (nid != Nid || tid != Tid || sid != Sid || rid != Rid) { + if (Number()) { + dsyslog("changing id of channel %d from %d-%d-%d-%d to %d-%d-%d-%d", Number(), nid, tid, sid, rid, Nid, Tid, Sid, Rid); + modification |= CHANNELMOD_ID; + Channels.SetModified(); + Channels.UnhashChannel(this); + } + nid = Nid; + tid = Tid; + sid = Sid; + rid = Rid; + if (Number()) + Channels.HashChannel(this); + schedule = NULL; + } +} + +void cChannel::SetName(const char *Name, const char *ShortName, const char *Provider) +{ + if (!isempty(Name)) { + bool nn = strcmp(name, Name) != 0; + bool ns = strcmp(shortName, ShortName) != 0; + bool np = strcmp(provider, Provider) != 0; + if (nn || ns || np) { + if (Number()) { + dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider); + modification |= CHANNELMOD_NAME; + Channels.SetModified(); + } + if (nn) + name = strcpyrealloc(name, Name); + if (ns) + shortName = strcpyrealloc(shortName, ShortName); + if (np) + provider = strcpyrealloc(provider, Provider); + } + } +} + +void cChannel::SetPortalName(const char *PortalName) +{ + if (!isempty(PortalName) && strcmp(portalName, PortalName) != 0) { + if (Number()) { + dsyslog("changing portal name of channel %d from '%s' to '%s'", Number(), portalName, PortalName); + modification |= CHANNELMOD_NAME; + Channels.SetModified(); + } + portalName = strcpyrealloc(portalName, PortalName); + } +} + +#define STRDIFF 0x01 +#define VALDIFF 0x02 + +static int IntArraysDiffer(const int *a, const int *b, const char na[][MAXLANGCODE2] = NULL, const char nb[][MAXLANGCODE2] = NULL) +{ + int result = 0; + for (int i = 0; a[i] || b[i]; i++) { + if (a[i] && na && nb && strcmp(na[i], nb[i]) != 0) + result |= STRDIFF; + if (a[i] != b[i]) + result |= VALDIFF; + if (!a[i] || !b[i]) + break; + } + return result; +} + +static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[][MAXLANGCODE2] = NULL) +{ + char *q = s; + int i = 0; + while (a[i] || i == 0) { + q += sprintf(q, Base == 16 ? "%s%X" : "%s%d", i ? "," : "", a[i]); + if (a[i] && n && *n[i]) + q += sprintf(q, "=%s", n[i]); + if (!a[i]) + break; + i++; + } + *q = 0; + return q - s; +} + +void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int Tpid) +{ + int mod = CHANNELMOD_NONE; + if (vpid != Vpid || ppid != Ppid || tpid != Tpid) + mod |= CHANNELMOD_PIDS; + int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs); + if (m & STRDIFF) + mod |= CHANNELMOD_LANGS; + if (m & VALDIFF) + mod |= CHANNELMOD_PIDS; + if (mod) { + const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia + char OldApidsBuf[BufferSize]; + char NewApidsBuf[BufferSize]; + char *q = OldApidsBuf; + q += IntArrayToString(q, apids, 10, alangs); + if (dpids[0]) { + *q++ = ';'; + q += IntArrayToString(q, dpids, 10, dlangs); + } + *q = 0; + q = NewApidsBuf; + q += IntArrayToString(q, Apids, 10, ALangs); + if (Dpids[0]) { + *q++ = ';'; + q += IntArrayToString(q, Dpids, 10, DLangs); + } + *q = 0; + dsyslog("changing pids of channel %d from %d+%d:%s:%d to %d+%d:%s:%d", Number(), vpid, ppid, OldApidsBuf, tpid, Vpid, Ppid, NewApidsBuf, Tpid); + vpid = Vpid; + ppid = Ppid; + for (int i = 0; i < MAXAPIDS; i++) { + apids[i] = Apids[i]; + strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2); + } + apids[MAXAPIDS] = 0; + for (int i = 0; i < MAXDPIDS; i++) { + dpids[i] = Dpids[i]; + strn0cpy(dlangs[i], DLangs[i], MAXLANGCODE2); + } + dpids[MAXDPIDS] = 0; + tpid = Tpid; + modification |= mod; + Channels.SetModified(); + } +} + +void cChannel::SetCaIds(const int *CaIds) +{ + if (caids[0] && caids[0] <= 0x00FF) + return; // special values will not be overwritten + if (IntArraysDiffer(caids, CaIds)) { + char OldCaIdsBuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia + char NewCaIdsBuf[MAXCAIDS * 5 + 10]; + IntArrayToString(OldCaIdsBuf, caids, 16); + IntArrayToString(NewCaIdsBuf, CaIds, 16); + dsyslog("changing caids of channel %d from %s to %s", Number(), OldCaIdsBuf, NewCaIdsBuf); + for (int i = 0; i <= MAXCAIDS; i++) { // <= to copy the terminating 0 + caids[i] = CaIds[i]; + if (!CaIds[i]) + break; + } + modification |= CHANNELMOD_CA; + Channels.SetModified(); + } +} + +void cChannel::SetCaDescriptors(int Level) +{ + if (Level > 0) { + modification |= CHANNELMOD_CA; + Channels.SetModified(); + if (Level > 1) + dsyslog("changing ca descriptors of channel %d", Number()); + } +} + +void cChannel::SetLinkChannels(cLinkChannels *LinkChannels) +{ + if (!linkChannels && !LinkChannels) + return; + if (linkChannels && LinkChannels) { + cLinkChannel *lca = linkChannels->First(); + cLinkChannel *lcb = LinkChannels->First(); + while (lca && lcb) { + if (lca->Channel() != lcb->Channel()) { + lca = NULL; + break; + } + lca = linkChannels->Next(lca); + lcb = LinkChannels->Next(lcb); + } + if (!lca && !lcb) { + delete LinkChannels; + return; // linkage has not changed + } + } + char buffer[((linkChannels ? linkChannels->Count() : 0) + (LinkChannels ? LinkChannels->Count() : 0)) * 6 + 256]; // 6: 5 digit channel number plus blank, 256: other texts (see below) plus reserve + char *q = buffer; + q += sprintf(q, "linking channel %d from", Number()); + if (linkChannels) { + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { + lc->Channel()->SetRefChannel(NULL); + q += sprintf(q, " %d", lc->Channel()->Number()); + } + delete linkChannels; + } + else + q += sprintf(q, " none"); + q += sprintf(q, " to"); + linkChannels = LinkChannels; + if (linkChannels) { + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { + lc->Channel()->SetRefChannel(this); + q += sprintf(q, " %d", lc->Channel()->Number()); + //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name()); + } + } + else + q += sprintf(q, " none"); + dsyslog(buffer); +} + +void cChannel::SetRefChannel(cChannel *RefChannel) +{ + refChannel = RefChannel; +} + +static int PrintParameter(char *p, char Name, int Value) +{ + return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0; +} + +cString cChannel::ParametersToString(void) const +{ + char type = **cSource::ToString(source); + if (isdigit(type)) + type = 'S'; +#define ST(s) if (strchr(s, type)) + char buffer[64]; + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); + ST("CST") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues)); + ST("CST") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues)); + ST(" T") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues)); + ST("C T") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues)); + ST(" T") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); + return buffer; +} + +static const char *ParseParameter(const char *s, int &Value, const tChannelParameterMap *Map) +{ + if (*++s) { + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s) { + Value = MapToDriver(n, Map); + if (Value >= 0) + return p; + } + } + esyslog("ERROR: invalid value for parameter '%c'", *(s - 1)); + return NULL; +} + +bool cChannel::StringToParameters(const char *s) +{ + while (s && *s) { + switch (toupper(*s)) { + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; + case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; + case 'D': s = ParseParameter(s, coderateL, CoderateValues); break; + case 'G': s = ParseParameter(s, guard, GuardValues); break; + case 'H': polarization = *s++; break; + case 'I': s = ParseParameter(s, inversion, InversionValues); break; + case 'L': polarization = *s++; break; + case 'M': s = ParseParameter(s, modulation, ModulationValues); break; + case 'R': polarization = *s++; break; + case 'T': s = ParseParameter(s, transmission, TransmissionValues); break; + case 'V': polarization = *s++; break; + case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break; + default: esyslog("ERROR: unknown parameter key '%c'", *s); + return false; + } + } + return true; +} + +cString cChannel::ToText(const cChannel *Channel) +{ + char FullName[strlen(Channel->name) + 1 + strlen(Channel->shortName) + 1 + strlen(Channel->provider) + 1 + 10]; // +10: paranoia + char *q = FullName; + q += sprintf(q, "%s", Channel->name); + if (!isempty(Channel->shortName)) + q += sprintf(q, ",%s", Channel->shortName); + if (!isempty(Channel->provider)) + q += sprintf(q, ";%s", Channel->provider); + *q = 0; + strreplace(FullName, ':', '|'); + char *buffer; + if (Channel->groupSep) { + if (Channel->number) + asprintf(&buffer, ":@%d %s\n", Channel->number, FullName); + else + asprintf(&buffer, ":%s\n", FullName); + } + else { + char vpidbuf[32]; + char *q = vpidbuf; + q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid); + if (Channel->ppid && Channel->ppid != Channel->vpid) + q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid); + *q = 0; + const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia + char apidbuf[BufferSize]; + q = apidbuf; + q += IntArrayToString(q, Channel->apids, 10, Channel->alangs); + if (Channel->dpids[0]) { + *q++ = ';'; + q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs); + } + *q = 0; + char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia + q = caidbuf; + q += IntArrayToString(q, Channel->caids, 16); + *q = 0; + asprintf(&buffer, "%s:%d:%s:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d\n", FullName, Channel->frequency, *Channel->ParametersToString(), *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid); + } + return cString(buffer, true); +} + +cString cChannel::ToText(void) const +{ + return ToText(this); +} + +bool cChannel::Parse(const char *s) +{ + bool ok = true; + if (*s == ':') { + groupSep = true; + if (*++s == '@' && *++s) { + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s && n > 0) { + number = n; + s = p; + } + } + name = strcpyrealloc(name, skipspace(s)); + strreplace(name, '|', ':'); + } + else { + groupSep = false; + char *namebuf = NULL; + char *sourcebuf = NULL; + char *parambuf = NULL; + char *vpidbuf = NULL; + char *apidbuf = NULL; + char *caidbuf = NULL; + int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%a[^:]:%d :%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &caidbuf, &sid, &nid, &tid, &rid); + if (fields >= 9) { + if (fields == 9) { + // allow reading of old format + sid = atoi(caidbuf); + delete caidbuf; + caidbuf = NULL; + caids[0] = tpid; + caids[1] = 0; + tpid = 0; + } + vpid = ppid = 0; + apids[0] = 0; + dpids[0] = 0; + ok = false; + if (parambuf && sourcebuf && vpidbuf && apidbuf) { + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; + + char *p = strchr(vpidbuf, '+'); + if (p) + *p++ = 0; + if (sscanf(vpidbuf, "%d", &vpid) != 1) + return false; + if (p) { + if (sscanf(p, "%d", &ppid) != 1) + return false; + } + else + ppid = vpid; + + char *dpidbuf = strchr(apidbuf, ';'); + if (dpidbuf) + *dpidbuf++ = 0; + p = apidbuf; + char *q; + int NumApids = 0; + char *strtok_next; + while ((q = strtok_r(p, ",", &strtok_next)) != NULL) { + if (NumApids < MAXAPIDS) { + char *l = strchr(q, '='); + if (l) { + *l++ = 0; + strn0cpy(alangs[NumApids], l, MAXLANGCODE2); + } + else + *alangs[NumApids] = 0; + apids[NumApids++] = strtol(q, NULL, 10); + } + else + esyslog("ERROR: too many APIDs!"); // no need to set ok to 'false' + p = NULL; + } + apids[NumApids] = 0; + if (dpidbuf) { + char *p = dpidbuf; + char *q; + int NumDpids = 0; + char *strtok_next; + while ((q = strtok_r(p, ",", &strtok_next)) != NULL) { + if (NumDpids < MAXDPIDS) { + char *l = strchr(q, '='); + if (l) { + *l++ = 0; + strn0cpy(dlangs[NumDpids], l, MAXLANGCODE2); + } + else + *dlangs[NumDpids] = 0; + dpids[NumDpids++] = strtol(q, NULL, 10); + } + else + esyslog("ERROR: too many DPIDs!"); // no need to set ok to 'false' + p = NULL; + } + dpids[NumDpids] = 0; + } + + if (caidbuf) { + char *p = caidbuf; + char *q; + int NumCaIds = 0; + char *strtok_next; + while ((q = strtok_r(p, ",", &strtok_next)) != NULL) { + if (NumCaIds < MAXCAIDS) { + caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF; + if (NumCaIds == 1 && caids[0] <= 0x00FF) + break; + } + else + esyslog("ERROR: too many CA ids!"); // no need to set ok to 'false' + p = NULL; + } + caids[NumCaIds] = 0; + } + } + strreplace(namebuf, '|', ':'); + + char *p = strchr(namebuf, ';'); + if (p) { + *p++ = 0; + provider = strcpyrealloc(provider, p); + } + p = strchr(namebuf, ','); + if (p) { + *p++ = 0; + shortName = strcpyrealloc(shortName, p); + } + name = strcpyrealloc(name, namebuf); + + free(parambuf); + free(sourcebuf); + free(vpidbuf); + free(apidbuf); + free(caidbuf); + free(namebuf); + if (!GetChannelID().Valid()) { + esyslog("ERROR: channel data results in invalid ID!"); + return false; + } + } + else + return false; + } + return ok; +} + +bool cChannel::Save(FILE *f) +{ + return fprintf(f, "%s", *ToText()) > 0; +} + +// -- cChannelSorter --------------------------------------------------------- + +class cChannelSorter : public cListObject { +public: + cChannel *channel; + tChannelID channelID; + cChannelSorter(cChannel *Channel) { + channel = Channel; + channelID = channel->GetChannelID(); + } + virtual int Compare(const cListObject &ListObject) const { + cChannelSorter *cs = (cChannelSorter *)&ListObject; + return memcmp(&channelID, &cs->channelID, sizeof(channelID)); + } + }; + +// -- cChannels -------------------------------------------------------------- + +cChannels Channels; + +cChannels::cChannels(void) +{ + maxNumber = 0; + modified = CHANNELSMOD_NONE; +} + +void cChannels::DeleteDuplicateChannels(void) +{ + cList ChannelSorter; + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep()) + ChannelSorter.Add(new cChannelSorter(channel)); + } + ChannelSorter.Sort(); + cChannelSorter *cs = ChannelSorter.First(); + while (cs) { + cChannelSorter *next = ChannelSorter.Next(cs); + if (next && cs->channelID == next->channelID) { + dsyslog("deleting duplicate channel %s", *next->channel->ToText()); + Del(next->channel); + } + cs = next; + } +} + +bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist) +{ + if (cConfig::Load(FileName, AllowComments, MustExist)) { + DeleteDuplicateChannels(); + ReNumber(); + return true; + } + return false; +} + +void cChannels::HashChannel(cChannel *Channel) +{ + channelsHashSid.Add(Channel, Channel->Sid()); +} + +void cChannels::UnhashChannel(cChannel *Channel) +{ + channelsHashSid.Del(Channel, Channel->Sid()); +} + +int cChannels::GetNextGroup(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && !(channel->GroupSep() && *channel->Name())) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +int cChannels::GetPrevGroup(int Idx) +{ + cChannel *channel = Get(--Idx); + while (channel && !(channel->GroupSep() && *channel->Name())) + channel = Get(--Idx); + return channel ? Idx : -1; +} + +int cChannels::GetNextNormal(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && channel->GroupSep()) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +void cChannels::ReNumber( void ) +{ + channelsHashSid.Clear(); + int Number = 1; + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (channel->GroupSep()) { + if (channel->Number() > Number) + Number = channel->Number(); + } + else { + HashChannel(channel); + maxNumber = Number; + channel->SetNumber(Number++); + } + } +} + +cChannel *cChannels::GetByNumber(int Number, int SkipGap) +{ + cChannel *previous = NULL; + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep()) { + if (channel->Number() == Number) + return channel; + else if (SkipGap && channel->Number() > Number) + return SkipGap > 0 ? channel : previous; + previous = channel; + } + } + return NULL; +} + +cChannel *cChannels::GetByServiceID(int Source, int Transponder, unsigned short ServiceID) +{ + cList *list = channelsHashSid.GetList(ServiceID); + if (list) { + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cChannel *channel = (cChannel *)hobj->Object(); + if (channel->Sid() == ServiceID && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder)) + return channel; + } + } + return NULL; +} + +cChannel *cChannels::GetByChannelID(tChannelID ChannelID, bool TryWithoutRid, bool TryWithoutPolarization) +{ + int sid = ChannelID.Sid(); + cList *list = channelsHashSid.GetList(sid); + if (list) { + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cChannel *channel = (cChannel *)hobj->Object(); + if (channel->Sid() == sid && channel->GetChannelID() == ChannelID) + return channel; + } + if (TryWithoutRid) { + ChannelID.ClrRid(); + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cChannel *channel = (cChannel *)hobj->Object(); + if (channel->Sid() == sid && channel->GetChannelID().ClrRid() == ChannelID) + return channel; + } + } + if (TryWithoutPolarization) { + ChannelID.ClrPolarization(); + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cChannel *channel = (cChannel *)hobj->Object(); + if (channel->Sid() == sid && channel->GetChannelID().ClrPolarization() == ChannelID) + return channel; + } + } + } + return NULL; +} + +bool cChannels::HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel) +{ + tChannelID NewChannelID = NewChannel->GetChannelID(); + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep() && channel != OldChannel && channel->GetChannelID() == NewChannelID) + return false; + } + return true; +} + +bool cChannels::SwitchTo(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); +} + +void cChannels::SetModified(bool ByUser) +{ + modified = ByUser ? CHANNELSMOD_USER : !modified ? CHANNELSMOD_AUTO : modified; +} + +int cChannels::Modified(void) +{ + int Result = modified; + modified = CHANNELSMOD_NONE; + return Result; +} + +cChannel *cChannels::NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid) +{ + if (Transponder) { + dsyslog("creating new channel '%s,%s;%s' on %s transponder %d with id %d-%d-%d-%d", Name, ShortName, Provider, *cSource::ToString(Transponder->Source()), Transponder->Transponder(), Nid, Tid, Sid, Rid); + cChannel *NewChannel = new cChannel; + NewChannel->CopyTransponderData(Transponder); + NewChannel->SetId(Nid, Tid, Sid, Rid); + NewChannel->SetName(Name, ShortName, Provider); + Add(NewChannel); + ReNumber(); + return NewChannel; + } + return NULL; +} + +cString ChannelString(const cChannel *Channel, int Number) +{ + char buffer[256]; + if (Channel) { + if (Channel->GroupSep()) + snprintf(buffer, sizeof(buffer), "%s", Channel->Name()); + else + snprintf(buffer, sizeof(buffer), "%d%s %s", Channel->Number(), Number ? "-" : "", Channel->Name()); + } + else if (Number) + snprintf(buffer, sizeof(buffer), "%d-", Number); + else + snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***")); + return buffer; +} diff -Naur vdr-1.4.0-noEIT/channels.h vdr-1.4.0/channels.h --- vdr-1.4.0-noEIT/channels.h 2006-02-19 09:39:43.000000000 -0500 +++ vdr-1.4.0/channels.h 2006-05-07 18:50:25.000000000 -0500 @@ -76,8 +76,9 @@ public: tChannelID(void) { source = nid = tid = sid = rid = 0; } tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; } - bool operator== (const tChannelID &arg) const { return source == arg.source && nid == arg.nid && tid == arg.tid && sid == arg.sid && rid == arg.rid; } + bool operator== (const tChannelID &arg) const { return source == arg.source && nid == arg.nid && tid == arg.tid && sid == arg.sid;} // && rid == arg.rid; } bool Valid(void) const { return (nid || tid) && sid; } // rid is optional and source may be 0//XXX source may not be 0??? + tChannelID &ClrSource(void) { source = 0; return *this; } tChannelID &ClrRid(void) { rid = 0; return *this; } tChannelID &ClrPolarization(void); int Source(void) { return source; } @@ -236,7 +237,8 @@ void ReNumber(void); // Recalculate 'number' based on channel type cChannel *GetByNumber(int Number, int SkipGap = 0); cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID); - cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, bool TryWithoutPolarization = false); + cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, + bool TryWithoutPolarization = false, bool TryWithoutSource = false); int BeingEdited(void) { return beingEdited; } void IncBeingEdited(void) { beingEdited++; } void DecBeingEdited(void) { beingEdited--; } diff -Naur vdr-1.4.0-noEIT/channels.h.orig vdr-1.4.0/channels.h.orig --- vdr-1.4.0-noEIT/channels.h.orig 1969-12-31 19:00:00.000000000 -0500 +++ vdr-1.4.0/channels.h.orig 2006-02-19 09:39:43.000000000 -0500 @@ -0,0 +1,257 @@ +/* + * channels.h: Channel handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: channels.h 1.39 2006/02/19 14:39:43 kls Exp $ + */ + +#ifndef __CHANNELS_H +#define __CHANNELS_H + +#include "config.h" +#include "sources.h" +#include "thread.h" +#include "tools.h" + +#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) //XXX + +#define CHANNELMOD_NONE 0x00 +#define CHANNELMOD_ALL 0xFF +#define CHANNELMOD_NAME 0x01 +#define CHANNELMOD_PIDS 0x02 +#define CHANNELMOD_ID 0x04 +#define CHANNELMOD_CA 0x10 +#define CHANNELMOD_TRANSP 0x20 +#define CHANNELMOD_LANGS 0x40 +#define CHANNELMOD_RETUNE (CHANNELMOD_PIDS | CHANNELMOD_CA | CHANNELMOD_TRANSP) + +#define CHANNELSMOD_NONE 0 +#define CHANNELSMOD_AUTO 1 +#define CHANNELSMOD_USER 2 + +#define MAXAPIDS 32 // audio +#define MAXDPIDS 16 // dolby (AC3 + DTS) +#define MAXSPIDS 8 // subtitles +#define MAXCAIDS 8 // conditional access + +#define MAXLANGCODE1 4 // a 3 letter language code, zero terminated +#define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated + +#define CA_FTA 0x0000 +#define CA_DVB_MIN 0x0001 +#define CA_DVB_MAX 0x000F +#define CA_USER_MIN 0x0010 +#define CA_USER_MAX 0x00FF +#define CA_ENCRYPTED_MIN 0x0100 +#define CA_ENCRYPTED_MAX 0xFFFF + +struct tChannelParameterMap { + int userValue; + int driverValue; + }; + +//XXX into cChannel??? +int MapToUser(int Value, const tChannelParameterMap *Map); +int MapToDriver(int Value, const tChannelParameterMap *Map); +int UserIndex(int Value, const tChannelParameterMap *Map); +int DriverIndex(int Value, const tChannelParameterMap *Map); + +extern const tChannelParameterMap InversionValues[]; +extern const tChannelParameterMap BandwidthValues[]; +extern const tChannelParameterMap CoderateValues[]; +extern const tChannelParameterMap ModulationValues[]; +extern const tChannelParameterMap TransmissionValues[]; +extern const tChannelParameterMap GuardValues[]; +extern const tChannelParameterMap HierarchyValues[]; + +struct tChannelID { +private: + int source; + int nid; ///< actually the "original" network id + int tid; + int sid; + int rid; +public: + tChannelID(void) { source = nid = tid = sid = rid = 0; } + tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; } + bool operator== (const tChannelID &arg) const { return source == arg.source && nid == arg.nid && tid == arg.tid && sid == arg.sid && rid == arg.rid; } + bool Valid(void) const { return (nid || tid) && sid; } // rid is optional and source may be 0//XXX source may not be 0??? + tChannelID &ClrRid(void) { rid = 0; return *this; } + tChannelID &ClrPolarization(void); + int Source(void) { return source; } + int Nid(void) { return nid; } + int Tid(void) { return tid; } + int Sid(void) { return sid; } + int Rid(void) { return rid; } + static tChannelID FromString(const char *s); + cString ToString(void) const; + static const tChannelID InvalidID; + }; + +class cChannel; + +class cLinkChannel : public cListObject { +private: + cChannel *channel; +public: + cLinkChannel(cChannel *Channel) { channel = Channel; } + cChannel *Channel(void) { return channel; } + }; + +class cLinkChannels : public cList { + }; + +class cSchedule; + +class cChannel : public cListObject { + friend class cSchedules; + friend class cMenuEditChannel; +private: + static cString ToText(const cChannel *Channel); + char *name; + char *shortName; + char *provider; + char *portalName; + int __BeginData__; + int frequency; // MHz + int source; + int srate; + int vpid; + int ppid; + int apids[MAXAPIDS + 1]; // list is zero-terminated + char alangs[MAXAPIDS][MAXLANGCODE2]; + int dpids[MAXDPIDS + 1]; // list is zero-terminated + char dlangs[MAXDPIDS][MAXLANGCODE2]; + int spids[MAXSPIDS + 1]; // list is zero-terminated + char slangs[MAXSPIDS][MAXLANGCODE2]; + int tpid; + int caids[MAXCAIDS + 1]; // list is zero-terminated + int nid; + int tid; + int sid; + int rid; + int number; // Sequence number assigned on load + bool groupSep; + char polarization; + int inversion; + int bandwidth; + int coderateH; + int coderateL; + int modulation; + int transmission; + int guard; + int hierarchy; + int __EndData__; + int modification; + mutable const cSchedule *schedule; + cLinkChannels *linkChannels; + cChannel *refChannel; + cString ParametersToString(void) const; + bool StringToParameters(const char *s); +public: + cChannel(void); + cChannel(const cChannel &Channel); + ~cChannel(); + cChannel& operator= (const cChannel &Channel); + cString ToText(void) const; + bool Parse(const char *s); + bool Save(FILE *f); + const char *Name(void) const { return name; } + const char *ShortName(bool OrName = false) const { return (OrName && isempty(shortName)) ? name : shortName; } + const char *Provider(void) const { return provider; } + const char *PortalName(void) const { return portalName; } + int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf' + int Transponder(void) const; ///< Returns the transponder frequency in MHz, plus the polarization in case of sat + static int Transponder(int Frequency, char Polarization); ///< builds the transponder from the given Frequency and Polarization + int Source(void) const { return source; } + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } + int Ppid(void) const { return ppid; } + const int *Apids(void) const { return apids; } + const int *Dpids(void) const { return dpids; } + const int *Spids(void) const { return spids; } + int Apid(int i) const { return (0 <= i && i < MAXAPIDS) ? apids[i] : 0; } + int Dpid(int i) const { return (0 <= i && i < MAXDPIDS) ? dpids[i] : 0; } + int Spid(int i) const { return (0 <= i && i < MAXSPIDS) ? spids[i] : 0; } + const char *Alang(int i) const { return (0 <= i && i < MAXAPIDS) ? alangs[i] : ""; } + const char *Dlang(int i) const { return (0 <= i && i < MAXDPIDS) ? dlangs[i] : ""; } + const char *Slang(int i) const { return (0 <= i && i < MAXSPIDS) ? slangs[i] : ""; } + int Tpid(void) const { return tpid; } + int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; } + int Nid(void) const { return nid; } + int Tid(void) const { return tid; } + int Sid(void) const { return sid; } + int Rid(void) const { return rid; } + int Number(void) const { return number; } + void SetNumber(int Number) { number = Number; } + bool GroupSep(void) const { return groupSep; } + char Polarization(void) const { return polarization; } + int Inversion(void) const { return inversion; } + int Bandwidth(void) const { return bandwidth; } + int CoderateH(void) const { return coderateH; } + int CoderateL(void) const { return coderateL; } + int Modulation(void) const { return modulation; } + int Transmission(void) const { return transmission; } + int Guard(void) const { return guard; } + int Hierarchy(void) const { return hierarchy; } + const cLinkChannels* LinkChannels(void) const { return linkChannels; } + const cChannel *RefChannel(void) const { return refChannel; } + bool IsCable(void) const { return cSource::IsCable(source); } + bool IsSat(void) const { return cSource::IsSat(source); } + bool IsTerr(void) const { return cSource::IsTerr(source); } + tChannelID GetChannelID(void) const { return tChannelID(source, nid, (nid || tid) ? tid : Transponder(), sid, rid); } + int Modification(int Mask = CHANNELMOD_ALL); + void CopyTransponderData(const cChannel *Channel); + bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH); + bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); + bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission); + void SetId(int Nid, int Tid, int Sid, int Rid = 0); + void SetName(const char *Name, const char *ShortName, const char *Provider); + void SetPortalName(const char *PortalName); + void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int Tpid); + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); + void SetLinkChannels(cLinkChannels *LinkChannels); + void SetRefChannel(cChannel *RefChannel); + }; + +class cChannels : public cRwLock, public cConfig { +private: + int maxNumber; + int modified; + int beingEdited; + cHash channelsHashSid; + void DeleteDuplicateChannels(void); +public: + cChannels(void); + bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false); + void HashChannel(cChannel *Channel); + void UnhashChannel(cChannel *Channel); + int GetNextGroup(int Idx); // Get next channel group + int GetPrevGroup(int Idx); // Get previous channel group + int GetNextNormal(int Idx); // Get next normal channel (not group) + void ReNumber(void); // Recalculate 'number' based on channel type + cChannel *GetByNumber(int Number, int SkipGap = 0); + cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID); + cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, bool TryWithoutPolarization = false); + int BeingEdited(void) { return beingEdited; } + void IncBeingEdited(void) { beingEdited++; } + void DecBeingEdited(void) { beingEdited--; } + bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL); + bool SwitchTo(int Number); + int MaxNumber(void) { return maxNumber; } + void SetModified(bool ByUser = false); + int Modified(void); + ///< Returns 0 if no channels have been modified, 1 if an automatic + ///< modification has been made, and 2 if the user has made a modification. + ///< Calling this function resets the 'modified' flag to 0. + cChannel *NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid = 0); + }; + +extern cChannels Channels; + +cString ChannelString(const cChannel *Channel, int Number); + +#endif //__CHANNELS_H diff -Naur vdr-1.4.0-noEIT/eit.c vdr-1.4.0/eit.c --- vdr-1.4.0-noEIT/eit.c 2006-02-19 04:51:02.000000000 -0500 +++ vdr-1.4.0/eit.c 2006-05-07 19:15:26.000000000 -0500 @@ -16,6 +16,7 @@ #include "i18n.h" #include "libsi/section.h" #include "libsi/descriptor.h" +#include "libsi/dish.h" // --- cEIT ------------------------------------------------------------------ @@ -30,10 +31,11 @@ if (!CheckCRCAndParse()) return; - tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId()); - cChannel *channel = Channels.GetByChannelID(channelID, true); + tChannelID channelID_search(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId()); + cChannel *channel = Channels.GetByChannelID(channelID_search, true, true, true); if (!channel) return; // only collect data for known channels + tChannelID channelID(channel->Source(), getOriginalNetworkId(), getTransportStreamId(), getServiceId()); cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); @@ -98,16 +100,27 @@ int LanguagePreferenceExt = -1; bool UseExtendedEventDescriptor = false; SI::Descriptor *d; + SI::DishExtendedEventDescriptor *DishExtendedEventDescriptor = NULL; + SI::DishShortEventDescriptor *DishShortEventDescriptor = NULL; SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor *ShortEventDescriptor = NULL; cLinkChannels *LinkChannels = NULL; cComponents *Components = NULL; - for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { + for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2, Tid)); ) { if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) { delete d; continue; } switch (d->getDescriptorTag()) { + case SI::DishExtendedEventDescriptorTag: { + SI::DishExtendedEventDescriptor *sed = (SI::DishExtendedEventDescriptor *)d; + if (!DishExtendedEventDescriptor) { + delete DishExtendedEventDescriptor; + DishExtendedEventDescriptor = sed; + d = NULL; // so that it is not deleted + } + } + break; case SI::ExtendedEventDescriptorTag: { SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { @@ -123,6 +136,15 @@ UseExtendedEventDescriptor = false; } break; + case SI::DishShortEventDescriptorTag: { + SI::DishShortEventDescriptor *sed = (SI::DishShortEventDescriptor *)d; + if (!DishShortEventDescriptor) { + delete DishShortEventDescriptor; + DishShortEventDescriptor = sed; + d = NULL; // so that it is not deleted + } + } + break; case SI::ShortEventDescriptorTag: { SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { @@ -219,6 +241,14 @@ } if (!rEvent) { + if (DishShortEventDescriptor) { + char buffer[256]; + pEvent->SetTitle(DishShortEventDescriptor->name.getText(buffer, 256)); + } + if (DishExtendedEventDescriptor) { + char buffer[256]; + pEvent->SetDescription(DishExtendedEventDescriptor->name.getText(buffer, 256)); + } if (ShortEventDescriptor) { char buffer[256]; pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer))); @@ -229,6 +259,8 @@ pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); } } + delete DishExtendedEventDescriptor; + delete DishShortEventDescriptor; delete ExtendedEventDescriptors; delete ShortEventDescriptor; @@ -298,15 +330,18 @@ cEitFilter::cEitFilter(void) { - Set(0x12, 0x4E, 0xFE); // event info, actual(0x4E)/other(0x4F) TS, present/following - Set(0x12, 0x50, 0xF0); // event info, actual TS, schedule(0x50)/schedule for future days(0x5X) - Set(0x12, 0x60, 0xF0); // event info, other TS, schedule(0x60)/schedule for future days(0x6X) +// Set(0x12, 0x4E, 0xFE); // event info, actual(0x4E)/other(0x4F) TS, present/following +// Set(0x12, 0x50, 0xF0); // event info, actual TS, schedule(0x50)/schedule for future days(0x5X) +// Set(0x12, 0x60, 0xF0); // event info, other TS, schedule(0x60)/schedule for future days(0x6X) Set(0x14, 0x70); // TDT + Set(0x12, 0x00, 0x00); + Set(0x0300, 0x00, 0x00); } void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { switch (Pid) { + case 0x0300: // Dish Network EEPG case 0x12: { cSchedulesLock SchedulesLock(true, 10); cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock); diff -Naur vdr-1.4.0-noEIT/libsi/Makefile vdr-1.4.0/libsi/Makefile --- vdr-1.4.0-noEIT/libsi/Makefile 2005-05-29 07:47:12.000000000 -0400 +++ vdr-1.4.0/libsi/Makefile 2006-05-07 18:50:25.000000000 -0500 @@ -23,7 +23,7 @@ ### The object files (add further files here): -OBJS = util.o si.o section.o descriptor.o +OBJS = util.o si.o section.o descriptor.o dish.o ### Implicit rules: @@ -51,4 +51,5 @@ dist: tar cvzf libsi.tar.gz -C .. libsi/util.c libsi/si.c libsi/section.c libsi/descriptor.c \ - libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr.pl + libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr.pl \ + libsi/dish.c diff -Naur vdr-1.4.0-noEIT/libsi/dish.c vdr-1.4.0/libsi/dish.c --- vdr-1.4.0-noEIT/libsi/dish.c 1969-12-31 19:00:00.000000000 -0500 +++ vdr-1.4.0/libsi/dish.c 2006-05-07 19:38:10.000000000 -0500 @@ -0,0 +1,539 @@ +/***************************************************************************** +* * +* 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. * +* * +* These routines can decompress the dishnetwork EIT title and descriptions * +* that are compressed. Also it can decompress the EPG 7 day guide title * +* and descriptions located on pid 768 * +* * +* Thanks to all those who helped make this possible. * +* Enjoy and carry it forward! * +* * +* The table contains the encoded sequences for each text character. * +* To decode, just start with the first bits of a compressed data byte * +* array and compare them with values in the table when a match is found * +* you have your first character, now move on to the next sequence of bits * +* until you have decoded the entire compressed data byte array. * +* * +* When using the table, start at the begining and compare for a sequence * +* of bits, compare only the number of bits, if the bits sequence don't * +* compare then continue down the table * +* * +******************************************************************************/ + +#include +#include "descriptor.h" +#include "dish.h" + +#include +#include +#include + +namespace SI { + + +void DishShortEventDescriptor::Parse() +{ + const unsigned char* str = data.getData(); + decompress(str+3, str[1]-1, (Tid>0x80)?2:1, name); +} + +void DishExtendedEventDescriptor::Parse() +{ + const unsigned char* str = data.getData(); + if ((str[3]&0xf8) == 0x80) + decompress(str+4, str[1]-2, (Tid>0x80)?2:1, name); + else + decompress(str+3, str[1]-1, (Tid>0x80)?2:1, name); +} + +struct DishDescriptor::_table DishDescriptor::Table128[MAX_TABLE128] = { + {0x0000, 0x20, 0x03}, // ' ' + {0x0002, 0x65, 0x04}, // 'e' + {0x0003, 0x74, 0x04}, // 't' + {0x0004, 0x61, 0x04}, // 'a' + {0x0005, 0x6F, 0x04}, // 'o' + {0x0006, 0x73, 0x04}, // 's' + {0x0007, 0x6E, 0x04}, // 'n' + {0x0020, 0x72, 0x06}, // 'r' + {0x0021, 0x69, 0x06}, // 'i' + {0x0022, 0x6C, 0x06}, // 'l' + {0x0023, 0x63, 0x06}, // 'c' + {0x0024, 0x68, 0x06}, // 'h' + {0x0025, 0x75, 0x06}, // 'u' + {0x0026, 0x64, 0x06}, // 'd' + {0x0027, 0x70, 0x06}, // 'p' + {0x0028, 0x6D, 0x06}, // 'm' + {0x0029, 0x67, 0x06}, // 'g' + {0x002A, 0x79, 0x06}, // 'y' + {0x002B, 0x76, 0x06}, // 'v' + {0x002C, 0x0A, 0x06}, // ''' + {0x002D, 0x2E, 0x06}, // '.' + {0x002E, 0x77, 0x06}, // 'w' + {0x002F, 0x66, 0x06}, // 'f' + {0x0060, 0x53, 0x07}, // 'S' + {0x0061, 0x62, 0x07}, // 'b' + {0x0062, 0x54, 0x07}, // 'T' + {0x0063, 0x22, 0x07}, // '"' + {0x0064, 0x6B, 0x07}, // 'k' + {0x0065, 0x50, 0x07}, // 'P' + {0x0066, 0x41, 0x07}, // 'A' + {0x0067, 0x43, 0x07}, // 'C' + {0x0068, 0x44, 0x07}, // 'D' + {0x0069, 0x4C, 0x07}, // 'L' + {0x006A, 0x4D, 0x07}, // 'M' + {0x006B, 0x49, 0x07}, // 'I' + {0x006C, 0x4E, 0x07}, // 'N' + {0x006D, 0x3A, 0x07}, // ':' + {0x006E, 0x52, 0x07}, // 'R' + {0x006F, 0x2C, 0x07}, // ',' + {0x00E0, 0x45, 0x08}, // 'E' + {0x00E1, 0x55, 0x08}, // 'U' + {0x00E2, 0x46, 0x08}, // 'F' + {0x00E3, 0x48, 0x08}, // 'H' + {0x00E4, 0x59, 0x08}, // 'Y' + {0x00E5, 0x56, 0x08}, // 'V' + {0x00E6, 0x2D, 0x08}, // '-' + {0x00E7, 0x7A, 0x08}, // 'z' + {0x00E8, 0x78, 0x08}, // 'x' + {0x00E9, 0x2F, 0x08}, // '/' + {0x00EA, 0x4F, 0x08}, // 'O' + {0x00EB, 0x3F, 0x08}, // '?' + {0x00EC, 0x57, 0x08}, // 'W' + {0x00ED, 0x47, 0x08}, // 'G' + {0x00EE, 0x42, 0x08}, // 'B' + {0x00EF, 0x33, 0x08}, // '3' + {0x01E0, 0x31, 0x09}, // '1' + {0x01E1, 0x71, 0x09}, // 'q' + {0x01E2, 0x30, 0x09}, // '0' + {0x01E3, 0x21, 0x09}, // '!' + {0x01E4, 0x6A, 0x09}, // 'j' + {0x01E5, 0x5A, 0x09}, // 'Z' + {0x01E6, 0x39, 0x09}, // '9' + {0x01E7, 0x34, 0x09}, // '4' + {0x01E8, 0x4B, 0x09}, // 'K' + {0x01E9, 0x2A, 0x09}, // '*' + {0x01EA, 0x37, 0x09}, // '7' + {0x01EB, 0x36, 0x09}, // '6' + {0x01EC, 0x35, 0x09}, // '5' + {0x01ED, 0x4A, 0x09}, // 'J' + {0x01EE, 0x38, 0x09}, // '8' + {0x01EF, 0x29, 0x09}, // ')' + {0x03E0, 0x28, 0x0A}, // '(' + {0x03E1, 0x58, 0x0A}, // 'X' + {0x03E2, 0x51, 0x0A}, // 'Q' + {0x03E3, 0x3C, 0x0A}, // '<' + {0x03E4, 0x32, 0x0A}, // '2' + {0x03E5, 0x27, 0x0A}, // ''' + {0x03E6, 0x26, 0x0A}, // '&' + {0x07CE, 0x7F, 0x0B}, // '' + {0x07CF, 0x7E, 0x0B}, // '~' + {0x07D0, 0x7D, 0x0B}, // '}' + {0x07D1, 0x7C, 0x0B}, // '|' + {0x07D2, 0x7B, 0x0B}, // '{' + {0x07D3, 0x60, 0x0B}, // '`' + {0x07D4, 0x5F, 0x0B}, // '_' + {0x07D5, 0x5E, 0x0B}, // '^' + {0x07D6, 0x5D, 0x0B}, // ']' + {0x07D7, 0x5C, 0x0B}, // '\' + {0x07D8, 0x5B, 0x0B}, // '[' + {0x07D9, 0x40, 0x0B}, // '@' + {0x07DA, 0x3E, 0x0B}, // '>' + {0x07DB, 0x3D, 0x0B}, // '=' + {0x07DC, 0x3B, 0x0B}, // ';' + {0x07DD, 0x2B, 0x0B}, // '+' + {0x07DE, 0x25, 0x0B}, // '%' + {0x07DF, 0x24, 0x0B}, // '$' + {0x07E0, 0x23, 0x0B}, // '#' + {0x07E1, 0x1F, 0x0B}, // '' + {0x07E2, 0x1E, 0x0B}, // '' + {0x07E3, 0x1D, 0x0B}, // '' + {0x07E4, 0x1C, 0x0B}, // '' + {0x07E5, 0x1B, 0x0B}, // '' + {0x07E6, 0x1A, 0x0B}, // '' + {0x07E7, 0x19, 0x0B}, // '' + {0x07E8, 0x18, 0x0B}, // '' + {0x07E9, 0x17, 0x0B}, // '' + {0x07EA, 0x16, 0x0B}, // '' + {0x07EB, 0x15, 0x0B}, // '' + {0x07EC, 0x14, 0x0B}, // '' + {0x07ED, 0x13, 0x0B}, // '' + {0x07EE, 0x12, 0x0B}, // '' + {0x07EF, 0x11, 0x0B}, // '' + {0x07F0, 0x10, 0x0B}, // '' + {0x07F1, 0x0F, 0x0B}, // '' + {0x07F2, 0x0E, 0x0B}, // '' + {0x07F3, 0x0D, 0x0B}, // '' + {0x07F4, 0x0C, 0x0B}, // '' + {0x07F5, 0x0B, 0x0B}, // '' + {0x07F6, 0x09, 0x0B}, // '' + {0x07F7, 0x08, 0x0B}, // '' + {0x07F8, 0x07, 0x0B}, // '' + {0x07F9, 0x06, 0x0B}, // '' + {0x07FA, 0x05, 0x0B}, // '' + {0x07FB, 0x04, 0x0B}, // '' + {0x07FC, 0x03, 0x0B}, // '' + {0x07FD, 0x02, 0x0B}, // '' + {0x07FE, 0x01, 0x0B}, // '' + {0x07FF, 0x00, 0x0B}, // '' +}; + +struct DishDescriptor::_table DishDescriptor::Table255[MAX_TABLE255] = { + {0x0000, 0x20, 0x02}, // ' ' + {0x0004, 0x65, 0x04}, // 'e' + {0x0005, 0x72, 0x04}, // 'r' + {0x0006, 0x6E, 0x04}, // 'n' + {0x0007, 0x61, 0x04}, // 'a' + {0x0010, 0x74, 0x05}, // 't' + {0x0011, 0x6F, 0x05}, // 'o' + {0x0012, 0x73, 0x05}, // 's' + {0x0013, 0x69, 0x05}, // 'i' + {0x0014, 0x6C, 0x05}, // 'l' + {0x0015, 0x75, 0x05}, // 'u' + {0x0016, 0x63, 0x05}, // 'c' + {0x0017, 0x64, 0x05}, // 'd' + {0x0060, 0x70, 0x07}, // 'p' + {0x0061, 0x6D, 0x07}, // 'm' + {0x0062, 0x76, 0x07}, // 'v' + {0x0063, 0x67, 0x07}, // 'g' + {0x0064, 0x68, 0x07}, // 'h' + {0x0065, 0x2E, 0x07}, // '.' + {0x0066, 0x66, 0x07}, // 'f' + {0x0067, 0x0A, 0x07}, // '' + {0x0068, 0x53, 0x07}, // 'S' + {0x0069, 0x41, 0x07}, // 'A' + {0x006A, 0x45, 0x07}, // 'E' + {0x006B, 0x43, 0x07}, // 'C' + {0x006C, 0x27, 0x07}, // ''' + {0x006D, 0x7A, 0x07}, // 'z' + {0x006E, 0x52, 0x07}, // 'R' + {0x006F, 0x22, 0x07}, // '"' + {0x00E0, 0x4C, 0x08}, // 'L' + {0x00E1, 0x49, 0x08}, // 'I' + {0x00E2, 0x4F, 0x08}, // 'O' + {0x00E3, 0x62, 0x08}, // 'b' + {0x00E4, 0x54, 0x08}, // 'T' + {0x00E5, 0x4E, 0x08}, // 'N' + {0x00E6, 0x55, 0x08}, // 'U' + {0x00E7, 0x79, 0x08}, // 'y' + {0x00E8, 0x44, 0x08}, // 'D' + {0x00E9, 0x50, 0x08}, // 'P' + {0x00EA, 0x71, 0x08}, // 'q' + {0x00EB, 0x56, 0x08}, // 'V' + {0x00EC, 0x2D, 0x08}, // '-' + {0x00ED, 0x3A, 0x08}, // ':' + {0x00EE, 0x2C, 0x08}, // ',' + {0x00EF, 0x48, 0x08}, // 'H' + {0x01E0, 0x4D, 0x09}, // 'M' + {0x01E1, 0x78, 0x09}, // 'x' + {0x01E2, 0x77, 0x09}, // 'w' + {0x01E3, 0x42, 0x09}, // 'B' + {0x01E4, 0x47, 0x09}, // 'G' + {0x01E5, 0x46, 0x09}, // 'F' + {0x01E6, 0x30, 0x09}, // '0' + {0x01E7, 0x3F, 0x09}, // '?' + {0x01E8, 0x33, 0x09}, // '3' + {0x01E9, 0x2F, 0x09}, // '/' + {0x01EA, 0x39, 0x09}, // '9' + {0x01EB, 0x31, 0x09}, // '1' + {0x01EC, 0x38, 0x09}, // '8' + {0x01ED, 0x6B, 0x09}, // 'k' + {0x01EE, 0x6A, 0x09}, // 'j' + {0x01EF, 0x21, 0x09}, // '!' + {0x03E0, 0x36, 0x0A}, // '6' + {0x03E1, 0x35, 0x0A}, // '5' + {0x03E2, 0x59, 0x0A}, // 'Y' + {0x03E3, 0x51, 0x0A}, // 'Q' + {0x07C8, 0x34, 0x0B}, // '4' + {0x07C9, 0x58, 0x0B}, // 'X' + {0x07CA, 0x32, 0x0B}, // '2' + {0x07CB, 0x2B, 0x0B}, // '+' + {0x07CC, 0x2A, 0x0B}, // '*' + {0x07CD, 0x5A, 0x0B}, // 'Z' + {0x07CE, 0x4A, 0x0B}, // 'J' + {0x07CF, 0x29, 0x0B}, // ')' + {0x0FA0, 0x28, 0x0C}, // '(' + {0x0FA1, 0x23, 0x0C}, // '#' + {0x0FA2, 0x57, 0x0C}, // 'W' + {0x0FA3, 0x4B, 0x0C}, // 'K' + {0x0FA4, 0x3C, 0x0C}, // '<' + {0x0FA5, 0x37, 0x0C}, // '7' + {0x0FA6, 0x7D, 0x0C}, // '}' + {0x0FA7, 0x7B, 0x0C}, // '{' + {0x0FA8, 0x60, 0x0C}, // '`' + {0x0FA9, 0x26, 0x0C}, // '&' + {0x1F54, 0xFE, 0x0D}, // 'þ' + {0x1F55, 0xFD, 0x0D}, // 'ý' + {0x1F56, 0xFC, 0x0D}, // 'ü' + {0x1F57, 0xFB, 0x0D}, // 'û' + {0x1F58, 0xFA, 0x0D}, // 'ú' + {0x1F59, 0xF9, 0x0D}, // 'ù' + {0x1F5A, 0xF8, 0x0D}, // 'ø' + {0x1F5B, 0xF7, 0x0D}, // '÷' + {0x1F5C, 0xF6, 0x0D}, // 'ö' + {0x1F5D, 0xF5, 0x0D}, // 'õ' + {0x1F5E, 0xF4, 0x0D}, // 'ô' + {0x1F5F, 0xF3, 0x0D}, // 'ó' + {0x1F60, 0xF2, 0x0D}, // 'ò' + {0x1F61, 0xF1, 0x0D}, // 'ñ' + {0x1F62, 0xF0, 0x0D}, // 'ð' + {0x1F63, 0xEF, 0x0D}, // 'ï' + {0x1F64, 0xEE, 0x0D}, // 'î' + {0x1F65, 0xED, 0x0D}, // 'í' + {0x1F66, 0xEC, 0x0D}, // 'ì' + {0x1F67, 0xEB, 0x0D}, // 'ë' + {0x1F68, 0xEA, 0x0D}, // 'ê' + {0x1F69, 0xE9, 0x0D}, // 'é' + {0x1F6A, 0xE8, 0x0D}, // 'è' + {0x1F6B, 0xE7, 0x0D}, // 'ç' + {0x1F6C, 0xE6, 0x0D}, // 'æ' + {0x1F6D, 0xE5, 0x0D}, // 'å' + {0x1F6E, 0xE4, 0x0D}, // 'ä' + {0x1F6F, 0xE3, 0x0D}, // 'ã' + {0x1F70, 0xE2, 0x0D}, // 'â' + {0x1F71, 0xE1, 0x0D}, // 'á' + {0x1F72, 0xE0, 0x0D}, // 'à' + {0x1F73, 0xDF, 0x0D}, // 'ß' + {0x1F74, 0xDE, 0x0D}, // 'Þ' + {0x1F75, 0xDD, 0x0D}, // 'Ý' + {0x1F76, 0xDC, 0x0D}, // 'Ü' + {0x1F77, 0xDB, 0x0D}, // 'Û' + {0x1F78, 0xDA, 0x0D}, // 'Ú' + {0x1F79, 0xD9, 0x0D}, // 'Ù' + {0x1F7A, 0xD8, 0x0D}, // 'Ø' + {0x1F7B, 0xD7, 0x0D}, // '×' + {0x1F7C, 0xD6, 0x0D}, // 'Ö' + {0x1F7D, 0xD5, 0x0D}, // 'Õ' + {0x1F7E, 0xD4, 0x0D}, // 'Ô' + {0x1F7F, 0xD3, 0x0D}, // 'Ó' + {0x1F80, 0xD2, 0x0D}, // 'Ò' + {0x1F81, 0xD1, 0x0D}, // '' + {0x1F82, 0xD0, 0x0D}, // '' + {0x1F83, 0xCF, 0x0D}, // '' + {0x1F84, 0xCE, 0x0D}, // '' + {0x1F85, 0xCD, 0x0D}, // '' + {0x1F86, 0xCC, 0x0D}, // '' + {0x1F87, 0xCB, 0x0D}, // '' + {0x1F88, 0xCA, 0x0D}, // '' + {0x1F89, 0xC9, 0x0D}, // '' + {0x1F8A, 0xC8, 0x0D}, // '' + {0x1F8B, 0xC7, 0x0D}, // '' + {0x1F8C, 0xC6, 0x0D}, // '' + {0x1F8D, 0xC5, 0x0D}, // '' + {0x1F8E, 0xC4, 0x0D}, // '' + {0x1F8F, 0xC3, 0x0D}, // '' + {0x1F90, 0xC2, 0x0D}, // '' + {0x1F91, 0xC1, 0x0D}, // '' + {0x1F92, 0xC0, 0x0D}, // '' + {0x1F93, 0xBF, 0x0D}, // '' + {0x1F94, 0xBE, 0x0D}, // '' + {0x1F95, 0xBD, 0x0D}, // '' + {0x1F96, 0xBC, 0x0D}, // '' + {0x1F97, 0xBB, 0x0D}, // '' + {0x1F98, 0xBA, 0x0D}, // '' + {0x1F99, 0xB9, 0x0D}, // '' + {0x1F9A, 0xB8, 0x0D}, // '' + {0x1F9B, 0xB7, 0x0D}, // '' + {0x1F9C, 0xB6, 0x0D}, // '' + {0x1F9D, 0xB5, 0x0D}, // '' + {0x1F9E, 0xB4, 0x0D}, // '' + {0x1F9F, 0xB3, 0x0D}, // '' + {0x1FA0, 0xB2, 0x0D}, // '' + {0x1FA1, 0xB1, 0x0D}, // '' + {0x1FA2, 0xB0, 0x0D}, // '' + {0x1FA3, 0xAF, 0x0D}, // '' + {0x1FA4, 0xAE, 0x0D}, // '' + {0x1FA5, 0xAD, 0x0D}, // '' + {0x1FA6, 0xAC, 0x0D}, // '' + {0x1FA7, 0xAB, 0x0D}, // '' + {0x1FA8, 0xAA, 0x0D}, // '' + {0x1FA9, 0xA9, 0x0D}, // '' + {0x1FAA, 0xA8, 0x0D}, // '' + {0x1FAB, 0xA7, 0x0D}, // '' + {0x1FAC, 0xA6, 0x0D}, // '' + {0x1FAD, 0xA5, 0x0D}, // '' + {0x1FAE, 0xA4, 0x0D}, // '' + {0x1FAF, 0xA3, 0x0D}, // '' + {0x1FB0, 0xA2, 0x0D}, // '' + {0x1FB1, 0xA1, 0x0D}, // '' + {0x1FB2, 0xA0, 0x0D}, // '' + {0x1FB3, 0x9F, 0x0D}, // '' + {0x1FB4, 0x9E, 0x0D}, // '' + {0x1FB5, 0x9D, 0x0D}, // '' + {0x1FB6, 0x9C, 0x0D}, // '' + {0x1FB7, 0x9B, 0x0D}, // '' + {0x1FB8, 0x9A, 0x0D}, // '' + {0x1FB9, 0x99, 0x0D}, // '' + {0x1FBA, 0x98, 0x0D}, // '' + {0x1FBB, 0x97, 0x0D}, // '' + {0x1FBC, 0x96, 0x0D}, // '' + {0x1FBD, 0x95, 0x0D}, // '' + {0x1FBE, 0x94, 0x0D}, // '' + {0x1FBF, 0x93, 0x0D}, // '' + {0x1FC0, 0x92, 0x0D}, // '' + {0x1FC1, 0x91, 0x0D}, // '' + {0x1FC2, 0x90, 0x0D}, // '' + {0x1FC3, 0x8F, 0x0D}, // '' + {0x1FC4, 0x8E, 0x0D}, // '' + {0x1FC5, 0x8D, 0x0D}, // '' + {0x1FC6, 0x8C, 0x0D}, // '' + {0x1FC7, 0x8B, 0x0D}, // '' + {0x1FC8, 0x8A, 0x0D}, // '' + {0x1FC9, 0x89, 0x0D}, // '' + {0x1FCA, 0x88, 0x0D}, // '' + {0x1FCB, 0x87, 0x0D}, // '' + {0x1FCC, 0x86, 0x0D}, // '' + {0x1FCD, 0x85, 0x0D}, // '' + {0x1FCE, 0x84, 0x0D}, // '' + {0x1FCF, 0x83, 0x0D}, // '' + {0x1FD0, 0x82, 0x0D}, // '' + {0x1FD1, 0x81, 0x0D}, // '' + {0x1FD2, 0x80, 0x0D}, // '' + {0x1FD3, 0x7F, 0x0D}, // '' + {0x1FD4, 0x7E, 0x0D}, // '' + {0x1FD5, 0x7C, 0x0D}, // '' + {0x1FD6, 0x5F, 0x0D}, // '' + {0x1FD7, 0x5E, 0x0D}, // '' + {0x1FD8, 0x5D, 0x0D}, // '' + {0x1FD9, 0x5C, 0x0D}, // '' + {0x1FDA, 0x5B, 0x0D}, // '' + {0x1FDB, 0x40, 0x0D}, // '' + {0x1FDC, 0x3E, 0x0D}, // '' + {0x1FDD, 0x3D, 0x0D}, // '' + {0x1FDE, 0x3B, 0x0D}, // '' + {0x1FDF, 0x25, 0x0D}, // '' + {0x1FE0, 0x24, 0x0D}, // '' + {0x1FE1, 0x1F, 0x0D}, // '' + {0x1FE2, 0x1E, 0x0D}, // '' + {0x1FE3, 0x1D, 0x0D}, // '' + {0x1FE4, 0x1C, 0x0D}, // '' + {0x1FE5, 0x1B, 0x0D}, // '' + {0x1FE6, 0x1A, 0x0D}, // '' + {0x1FE7, 0x19, 0x0D}, // '' + {0x1FE8, 0x18, 0x0D}, // '' + {0x1FE9, 0x17, 0x0D}, // '' + {0x1FEA, 0x16, 0x0D}, // '' + {0x1FEB, 0x15, 0x0D}, // '' + {0x1FEC, 0x14, 0x0D}, // '' + {0x1FED, 0x13, 0x0D}, // '' + {0x1FEE, 0x12, 0x0D}, // '' + {0x1FEF, 0x11, 0x0D}, // '' + {0x1FF0, 0x10, 0x0D}, // '' + {0x1FF1, 0x0F, 0x0D}, // '' + {0x1FF2, 0x0E, 0x0D}, // '' + {0x1FF3, 0x0D, 0x0D}, // '' + {0x1FF4, 0x0C, 0x0D}, // '' + {0x1FF5, 0x0B, 0x0D}, // '' + {0x1FF6, 0x09, 0x0D}, // '' + {0x1FF7, 0x08, 0x0D}, // '' + {0x1FF8, 0x07, 0x0D}, // '' + {0x1FF9, 0x06, 0x0D}, // '' + {0x1FFA, 0x05, 0x0D}, // '' + {0x1FFB, 0x04, 0x0D}, // '' + {0x1FFC, 0x03, 0x0D}, // '' + {0x1FFD, 0x02, 0x0D}, // '' + {0x1FFE, 0x01, 0x0D}, // '' + {0x1FFF, 0x00, 0x0D}, // '' +}; + + +// +// returns the bit value of any bit in the byte array +// +// for example 3 byte array the bits are as follows +// [0][1][2][3][4][5][6][7] [8][9][10][11][12][13][14][15] [16][17][18][19][20][21][22][23] +// + +int DishDescriptor::get_bit( int bit_index, const unsigned char *byteptr ) +{ + int byte_offset; + int bit_number; + + byte_offset = bit_index / 8; + bit_number = bit_index - ( byte_offset * 8 ); + + if ( byteptr[ byte_offset ] & ( 1 << (7 - bit_number) ) ) + return 1; + else + return 0; +} + +// +// returns the value of a sequence of bits in the byte array +// +unsigned int DishDescriptor::get_bits( int bit_index, int bit_count, const unsigned char *byteptr ) +{ + int i; + unsigned int bits = 0; + + for ( i = 0 ; i < bit_count ; i++ ) + bits = ( bits << 1 ) | get_bit( bit_index + i, byteptr ); + + return bits; +} + +// +// decompress the byte arrary and returns the result to a text string +// +void DishDescriptor::decompress(const unsigned char *compressed, int length, int table, String& result) +{ + int i; + int total_bits; + int current_bit = 0; + int count = 0; + unsigned int bits; + int table_size; + struct _table *ptrTable; + unsigned char *decompressed = (unsigned char*)malloc(4096); + + memset (decompressed, 0, sizeof(decompressed)); + + if ( table == 1 ) + { + table_size = MAX_TABLE128; + ptrTable = Table128; + } + else + { + table_size = MAX_TABLE255; + ptrTable = Table255; + } + + + total_bits = length * 8; + + // walk thru all the bits in the byte array, finding each sequence in the + // list and decoding it to a character. + while ( current_bit < total_bits - 3 ) + { + // starting from the current bit + // try to find the sequence in the decode list + + for ( i = 0; i < table_size; i++ ) + { + bits = get_bits( current_bit, ptrTable[i].number_of_bits, compressed ); + if ( bits == ptrTable[i].encoded_sequence ) + { + decompressed[ count++ ] = ptrTable[i].character; + current_bit += ptrTable[i].number_of_bits; + break; + } + } + + if ( i == table_size ) // if we get here then the bit sequence was not found ... problem try to recover + current_bit += 1; + } + + decompressed[ count ] = 0; + + CharArray dc; + dc.assign( decompressed, count+1); + result.setData(dc, count+1); + free (decompressed); +} + + +} //end of namespace diff -Naur vdr-1.4.0-noEIT/libsi/dish.h vdr-1.4.0/libsi/dish.h --- vdr-1.4.0-noEIT/libsi/dish.h 1969-12-31 19:00:00.000000000 -0500 +++ vdr-1.4.0/libsi/dish.h 2006-05-07 18:50:25.000000000 -0500 @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2003 by Marcel Wiesweg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * $Id: dish.h * + * * + ***************************************************************************/ + +#ifndef DISH_H +#define DISH_H + +#include "si.h" +#include "headers.h" + +#define MAX_TABLE128 128 +#define MAX_TABLE255 255 + +namespace SI { + +class DishDescriptor : public Descriptor { +public: + String name; //name of the event + u_char Tid; + +protected: + + struct _table { + unsigned int encoded_sequence; + unsigned char character; + unsigned char number_of_bits; + }; + + static struct _table Table128[MAX_TABLE128]; + static struct _table Table255[MAX_TABLE255]; + + int get_bit( int bit_index, const unsigned char *byteptr ); + unsigned int get_bits( int bit_index, int bit_count, const unsigned char *byteptr ); + void decompress(const unsigned char *compressed, int length, int table, String& result); +}; + +class DishShortEventDescriptor : public DishDescriptor { +public: + DishShortEventDescriptor(u_char TID) { Tid=TID; }; +protected: + virtual void Parse(); +}; + +class DishExtendedEventDescriptor : public DishDescriptor { +public: + DishExtendedEventDescriptor(u_char TID) { Tid=TID; }; +protected: + virtual void Parse(); +}; + +} //end of namespace + +#endif diff -Naur vdr-1.4.0-noEIT/libsi/si.c vdr-1.4.0/libsi/si.c --- vdr-1.4.0-noEIT/libsi/si.c 2006-02-18 05:38:20.000000000 -0500 +++ vdr-1.4.0/libsi/si.c 2006-05-07 18:50:25.000000000 -0500 @@ -13,6 +13,7 @@ #include #include "si.h" #include "descriptor.h" +#include "dish.h" namespace SI { @@ -105,9 +106,9 @@ return (DescriptorTag)((const DescriptorHeader*)d)->descriptor_tag; } -Descriptor *DescriptorLoop::getNext(Iterator &it) { +Descriptor *DescriptorLoop::getNext(Iterator &it, u_char Tid) { if (isValid() && it.igetLength(); @@ -314,7 +315,7 @@ *toShort = '\0'; } -Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) { +Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor, u_char Tid) { Descriptor *d=0; switch (domain) { case SI: @@ -425,6 +426,12 @@ case AncillaryDataDescriptorTag: d=new AncillaryDataDescriptor(); break; + case DishShortEventDescriptorTag: + d=new DishShortEventDescriptor(Tid); + break; + case DishExtendedEventDescriptorTag: + d=new DishExtendedEventDescriptor(Tid); + break; //note that it is no problem to implement one //of the unimplemented descriptors. diff -Naur vdr-1.4.0-noEIT/libsi/si.h vdr-1.4.0/libsi/si.h --- vdr-1.4.0-noEIT/libsi/si.h 2006-02-18 05:38:20.000000000 -0500 +++ vdr-1.4.0/libsi/si.h 2006-05-07 18:50:25.000000000 -0500 @@ -122,6 +122,8 @@ AdaptationFieldDataDescriptorTag = 0x70, ServiceIdentifierDescriptorTag = 0x71, ServiceAvailabilityDescriptorTag = 0x72, + DishShortEventDescriptorTag = 0x91, + DishExtendedEventDescriptorTag = 0x92, // Defined by ETSI TS 102 812 (MHP) // They once again start with 0x00 (see page 234, MHP specification) MHP_ApplicationDescriptorTag = 0x00, @@ -270,7 +272,7 @@ // Never returns null - maybe the UnimplementedDescriptor. //if returnUnimplemetedDescriptor==false: // Never returns the UnimplementedDescriptor - maybe null - static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor); + static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor, u_char Tid=0); }; class Loop : public VariableLengthPart { @@ -334,7 +336,7 @@ //i must be 0 to get the first descriptor (with the first call) //All returned descriptors must be delete'd. //returns null if no more descriptors available - Descriptor *getNext(Iterator &it); + Descriptor *getNext(Iterator &it, u_char Tid=0); //return the next descriptor with given tag, or 0 if not available. //if returnUnimplemetedDescriptor==true: // an UnimplementedDescriptor may be returned if the next matching descriptor is unimplemented, @@ -375,7 +377,7 @@ return count; } protected: - Descriptor *createDescriptor(int &i, bool returnUnimplemetedDescriptor); + Descriptor *createDescriptor(int &i, bool returnUnimplemetedDescriptor, u_char Tid=0); DescriptorTagDomain domain; }; diff -Naur vdr-1.4.0-noEIT/pat.c vdr-1.4.0/pat.c --- vdr-1.4.0-noEIT/pat.c 2006-01-27 10:48:29.000000000 -0500 +++ vdr-1.4.0/pat.c 2006-05-07 18:50:25.000000000 -0500 @@ -408,6 +408,10 @@ } } break; + //add DD pid's to autoscan + case 0x81: + Dpids[NumDpids++] = stream.getPid(); + break; //default: printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());//XXX } for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) {