summaryrefslogtreecommitdiff
path: root/epg.c
diff options
context:
space:
mode:
Diffstat (limited to 'epg.c')
-rw-r--r--epg.c194
1 files changed, 177 insertions, 17 deletions
diff --git a/epg.c b/epg.c
index 877ce24..5539ab0 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 1.22 2004/11/07 10:43:30 kls Exp $
+ * $Id: epg.c 1.24 2005/01/02 11:25:25 kls Exp $
*/
#include "epg.h"
@@ -16,6 +16,66 @@
#include <ctype.h>
#include <time.h>
+// --- tComponent ------------------------------------------------------------
+
+cString tComponent::ToString(void)
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%X %02X %-3s %s", stream, type, language, description ? description : "");
+ return buffer;
+}
+
+bool tComponent::FromString(const char *s)
+{
+ unsigned int Stream, Type;
+ int n = sscanf(s, "%X %02X %3c %a[^\n]", &Stream, &Type, language, &description);
+ if (n != 4)
+ description = NULL;
+ else if (isempty(description)) {
+ free(description);
+ description = NULL;
+ }
+ stream = Stream;
+ type = Type;
+ return n >= 3;
+}
+
+// --- cComponents -----------------------------------------------------------
+
+cComponents::cComponents(int NumComponents)
+{
+ numComponents = NumComponents;
+ components = MALLOC(tComponent, numComponents);
+ memset(components, 0, sizeof(tComponent) * numComponents);
+}
+
+cComponents::~cComponents(void)
+{
+ for (int i = 0; i < numComponents; i++)
+ free(components[i].description);
+ free(components);
+}
+
+bool cComponents::SetComponent(int Index, const char *s)
+{
+ if (Index < numComponents)
+ return components[Index].FromString(s);
+ return false;
+}
+
+bool cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description)
+{
+ if (Index < numComponents) {
+ tComponent *p = &components[Index];
+ p->stream = Stream;
+ p->type = Type;
+ strn0cpy(p->language, Language, sizeof(p->language));
+ p->description = strcpyrealloc(p->description, !isempty(Description) ? Description : NULL);
+ return true;
+ }
+ return false;
+}
+
// --- cEvent ----------------------------------------------------------------
cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID)
@@ -28,6 +88,7 @@ cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID)
title = NULL;
shortText = NULL;
description = NULL;
+ components = NULL;
startTime = 0;
duration = 0;
vps = 0;
@@ -39,6 +100,7 @@ cEvent::~cEvent()
free(title);
free(shortText);
free(description);
+ delete components;
}
int cEvent::Compare(const cListObject &ListObject) const
@@ -66,7 +128,7 @@ void cEvent::SetRunningStatus(int RunningStatus, cChannel *Channel)
{
if (Channel && runningStatus != RunningStatus && (RunningStatus > SI::RunningStatusNotRunning || runningStatus > SI::RunningStatusUndefined))
if (Channel->Number() <= 30)//XXX maybe log only those that have timers???
- isyslog("channel %d (%s) event %s '%s' status %d", Channel->Number(), Channel->Name(), GetTimeString(), Title(), RunningStatus);
+ isyslog("channel %d (%s) event %s '%s' status %d", Channel->Number(), Channel->Name(), *GetTimeString(), Title(), RunningStatus);
runningStatus = RunningStatus;
}
@@ -85,6 +147,12 @@ void cEvent::SetDescription(const char *Description)
description = strcpyrealloc(description, Description);
}
+void cEvent::SetComponents(cComponents *Components)
+{
+ delete components;
+ components = Components;
+}
+
void cEvent::SetStartTime(time_t StartTime)
{
startTime = StartTime;
@@ -119,9 +187,9 @@ bool cEvent::IsRunning(bool OrAboutToStart) const
return runningStatus >= (OrAboutToStart ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusPausing);
}
-const char *cEvent::GetDateString(void) const
+cString cEvent::GetDateString(void) const
{
- static char buf[32];
+ char buf[32];
struct tm tm_r;
tm *tm = localtime_r(&startTime, &tm_r);
char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
@@ -130,26 +198,26 @@ const char *cEvent::GetDateString(void) const
return buf;
}
-const char *cEvent::GetTimeString(void) const
+cString cEvent::GetTimeString(void) const
{
- static char buf[25];
+ char buf[25];
struct tm tm_r;
strftime(buf, sizeof(buf), "%R", localtime_r(&startTime, &tm_r));
return buf;
}
-const char *cEvent::GetEndTimeString(void) const
+cString cEvent::GetEndTimeString(void) const
{
- static char buf[25];
+ char buf[25];
time_t EndTime = startTime + duration;
struct tm tm_r;
strftime(buf, sizeof(buf), "%R", localtime_r(&EndTime, &tm_r));
return buf;
}
-const char *cEvent::GetVpsString(void) const
+cString cEvent::GetVpsString(void) const
{
- static char buf[25];
+ char buf[25];
struct tm tm_r;
strftime(buf, sizeof(buf), "%d.%m %R", localtime_r(&vps, &tm_r));
return buf;
@@ -168,6 +236,12 @@ void cEvent::Dump(FILE *f, const char *Prefix) const
fprintf(f, "%sD %s\n", Prefix, description);
strreplace(description, '|', '\n');
}
+ if (components) {
+ for (int i = 0; i < components->NumComponents(); i++) {
+ tComponent *p = components->Component(i);
+ fprintf(f, "%sX %s\n", Prefix, *p->ToString());
+ }
+ }
if (vps)
fprintf(f, "%sV %ld\n", Prefix, vps);
fprintf(f, "%se\n", Prefix);
@@ -178,8 +252,11 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
{
if (Schedule) {
cEvent *Event = NULL;
+ int NumComponents = 0;
+ char *ComponentStrings[MAXCOMPONENTS];
char *s;
- while ((s = readline(f)) != NULL) {
+ cReadLine ReadLine;
+ while ((s = ReadLine.Read(f)) != NULL) {
char *t = skipspace(s + 1);
switch (*s) {
case 'E': if (!Event) {
@@ -198,6 +275,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
Event->SetDuration(Duration);
}
}
+ NumComponents = 0;
}
break;
case 'T': if (Event)
@@ -211,10 +289,26 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
Event->SetDescription(t);
}
break;
+ case 'X': if (Event) {
+ if (NumComponents < MAXCOMPONENTS)
+ ComponentStrings[NumComponents++] = strdup(t);
+ else
+ dsyslog("more than %d component descriptors!", MAXCOMPONENTS);
+ }
+ break;
case 'V': if (Event)
Event->SetVps(atoi(t));
break;
- case 'e': Event = NULL;
+ case 'e': if (Event && NumComponents > 0) {
+ cComponents *Components = new cComponents(NumComponents);
+ for (int i = 0; i < NumComponents; i++) {
+ if (!Components->SetComponent(i, ComponentStrings[i]))
+ esyslog("ERROR: faulty component string in EPG data: '%s'", ComponentStrings[i]);
+ free(ComponentStrings[i]);
+ }
+ Event->SetComponents(Components);
+ }
+ Event = NULL;
break;
case 'c': // to keep things simple we react on 'c' here
return true;
@@ -227,7 +321,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
return false;
}
-#define MAXEPGBUGFIXSTATS 8
+#define MAXEPGBUGFIXSTATS 12
#define MAXEPGBUGFIXCHANS 100
struct tEpgBugFixStats {
int hits;
@@ -475,6 +569,72 @@ void cEvent::FixEpgBugs(void)
strreplace(title, '`', '\'');
strreplace(shortText, '`', '\'');
strreplace(description, '`', '\'');
+
+ if (Setup.EPGBugfixLevel <= 2)
+ return;
+
+ // The stream components have a "description" field which some channels
+ // apparently have no idea of how to set correctly:
+ if (components) {
+ for (int i = 0; i < components->NumComponents(); i++) {
+ tComponent *p = components->Component(i);
+ switch (p->stream) {
+ case 0x01: { // video
+ if (p->description) {
+ if (strcasecmp(p->description, "Video") == 0 ||
+ strcasecmp(p->description, "Bildformat") == 0) {
+ // Yes, we know it's video - that's what the 'stream' code
+ // is for! But _which_ video is it?
+ free(p->description);
+ p->description = NULL;
+ EpgBugFixStat(8, ChannelID());
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x01:
+ case 0x05: p->description = strdup("4:3"); break;
+ case 0x02:
+ case 0x03:
+ case 0x06:
+ case 0x07: p->description = strdup("16:9"); break;
+ case 0x04:
+ case 0x08: p->description = strdup(">16:9"); break;
+ case 0x09:
+ case 0x0D: p->description = strdup("HD 4:3"); break;
+ case 0x0A:
+ case 0x0B:
+ case 0x0E:
+ case 0x0F: p->description = strdup("HD 16:9"); break;
+ case 0x0C:
+ case 0x10: p->description = strdup("HD >16:9"); break;
+ }
+ EpgBugFixStat(9, ChannelID());
+ }
+ }
+ break;
+ case 0x02: { // audio
+ if (p->description) {
+ if (strcasecmp(p->description, "Audio") == 0) {
+ // Yes, we know it's audio - that's what the 'stream' code
+ // is for! But _which_ audio is it?
+ free(p->description);
+ p->description = NULL;
+ EpgBugFixStat(10, ChannelID());
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x05: p->description = strdup("Dolby Digital"); break;
+ // all others will just display the language
+ }
+ EpgBugFixStat(11, ChannelID());
+ }
+ }
+ break;
+ }
+ }
+ }
}
}
@@ -604,7 +764,7 @@ void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtT
{
cChannel *channel = Channels.GetByChannelID(channelID, true);
if (channel) {
- fprintf(f, "%sC %s %s\n", Prefix, channel->GetChannelID().ToString(), channel->Name());
+ fprintf(f, "%sC %s %s\n", Prefix, *channel->GetChannelID().ToString(), channel->Name());
const cEvent *p;
switch (DumpMode) {
case dmAll: {
@@ -635,8 +795,9 @@ void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtT
bool cSchedule::Read(FILE *f, cSchedules *Schedules)
{
if (Schedules) {
+ cReadLine ReadLine;
char *s;
- while ((s = readline(f)) != NULL) {
+ while ((s = ReadLine.Read(f)) != NULL) {
if (*s == 'C') {
s = skipspace(s + 1);
char *p = strchr(s, ' ');
@@ -698,8 +859,7 @@ const cSchedules *cSchedules::Schedules(cSchedulesLock &SchedulesLock)
void cSchedules::SetEpgDataFileName(const char *FileName)
{
delete epgDataFileName;
- if (FileName)
- epgDataFileName = strdup(FileName);
+ epgDataFileName = FileName ? strdup(FileName) : NULL;
}
void cSchedules::SetModified(cSchedule *Schedule)