diff options
author | kwacker <vdr@w-i-r.com> | 2010-04-11 13:17:33 +0200 |
---|---|---|
committer | kwacker <vdr@w-i-r.com> | 2010-04-11 13:17:33 +0200 |
commit | 9cd931834ecadbf5efefdf484abb966e9248ebbb (patch) | |
tree | 2678592d4252483a59c6d3c37b5d5925c875c387 | |
parent | af740943fe298b8cc4391f171cc5a13f7863b56f (diff) | |
download | x-vdr-9cd931834ecadbf5efefdf484abb966e9248ebbb.tar.gz x-vdr-9cd931834ecadbf5efefdf484abb966e9248ebbb.tar.bz2 |
aktuellen Extensionpatch NG hinzugefügt
-rw-r--r-- | vdr/extensions/ExtP-NG-vdr-1.7.14-V2.diff | 14724 | ||||
-rwxr-xr-x | vdr/extensions/vdr-1.7.14_extensions.diff | 465 |
2 files changed, 14976 insertions, 213 deletions
diff --git a/vdr/extensions/ExtP-NG-vdr-1.7.14-V2.diff b/vdr/extensions/ExtP-NG-vdr-1.7.14-V2.diff new file mode 100644 index 0000000..023d712 --- /dev/null +++ b/vdr/extensions/ExtP-NG-vdr-1.7.14-V2.diff @@ -0,0 +1,14724 @@ +diff -ruN vdr-1.7.14/Make.config.template vdr-1.7.14.ExtP_NG/Make.config.template +--- vdr-1.7.14/Make.config.template 2010-02-06 15:50:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/Make.config.template 2010-04-10 15:45:10.488736701 +0200 +@@ -41,8 +41,185 @@ + ## Define if you want vdr to not run as root + #VDR_USER = vdr + ++### VDR-Extensions: ++# Uncomment the patches you need ++# SORTRECORDS needs LIEMIEXT enabled ++# you can only enable MENUORG or SETUP ++ ++#ALTERNATECHANNEL = 1 ++#ATSC = 1 ++#CHANNELBIND = 1 ++#CHANNELPROVIDE = 1 ++#CUTTERLIMIT = 1 ++#CUTTERQUEUE = 1 ++#CUTTIME = 1 ++#DDEPGENTRY = 1 ++#DVLFRIENDLYNAMES = 1 ++#DVLSCRIPTADDON = 1 ++#DVLVIDPREFER = 1 ++#GRAPHTFT = 1 ++#HARDLINKCUTTER = 1 ++#JUMPINGSECONDS = 1 ++#JUMPPLAY = 1 ++#LIEMIEXT = 1 ++#LIRCSETTINGS = 1 ++#LNBSHARE = 1 ++#MAINMENUHOOKS = 1 ++#MCLI = 1 ++#MENUORG = 1 ++#NOEPG = 1 ++#PINPLUGIN = 1 ++#PLUGINMISSING = 1 ++#ROTOR = 1 ++#SETUP = 1 ++#SORTRECORDS = 1 ++#STATUS_EXTENSION = 1 ++#TIMERINFO = 1 ++#TTXTSUBS = 1 ++#VALIDINPUT = 1 ++#VOLCTRL = 1 ++#WAREAGLEICON = 1 ++#YAEPG = 1 + ### You don't need to touch the following: + + ifdef DVBDIR + INCLUDES += -I$(DVBDIR)/include + endif ++ ++ifdef ALTERNATECHANNEL ++DEFINES += -DUSE_ALTERNATECHANNEL ++endif ++ ++ifdef ATSC ++DEFINES += -DUSE_ATSC ++endif ++ ++ifdef CHANNELBIND ++DEFINES += -DUSE_CHANNELBIND ++endif ++ ++ifdef CHANNELPROVIDE ++DEFINES += -DUSE_CHANNELPROVIDE ++endif ++ ++ifdef CUTTERLIMIT ++DEFINES += -DUSE_CUTTERLIMIT ++endif ++ ++ifdef CUTTERQUEUE ++DEFINES += -DUSE_CUTTERQUEUE ++endif ++ ++ifdef CUTTIME ++DEFINES += -DUSE_CUTTIME ++endif ++ ++ifdef DDEPGENTRY ++DEFINES += -DUSE_DDEPGENTRY ++endif ++ ++ifdef DVLFRIENDLYNAMES ++DEFINES += -DUSE_DVLFRIENDLYNAMES ++endif ++ ++ifdef DVLSCRIPTADDON ++DEFINES += -DUSE_DVLSCRIPTADDON ++endif ++ ++ifdef DVLVIDPREFER ++DEFINES += -DUSE_DVLVIDPREFER ++endif ++ ++ifdef GRAPHTFT ++DEFINES += -DUSE_GRAPHTFT ++endif ++ ++ifdef HARDLINKCUTTER ++DEFINES += -DUSE_HARDLINKCUTTER ++endif ++ ++ifdef JUMPINGSECONDS ++DEFINES += -DUSE_JUMPINGSECONDS ++endif ++ ++ifdef JUMPPLAY ++DEFINES += -DUSE_JUMPPLAY ++endif ++ ++ifdef LIEMIEXT ++DEFINES += -DUSE_LIEMIEXT ++endif ++ ++ifdef LIRCSETTINGS ++DEFINES += -DUSE_LIRCSETTINGS ++endif ++ ++ifdef LNBSHARE ++DEFINES += -DUSE_LNBSHARE ++endif ++ ++ifdef MAINMENUHOOKS ++DEFINES += -DUSE_MAINMENUHOOKS ++endif ++ ++ifdef MCLI ++DEFINES += -DUSE_MCLI ++endif ++ ++ifdef MENUORG ++DEFINES += -DUSE_MENUORG ++else ++ifdef SETUP ++DEFINES += -DUSE_SETUP ++endif ++endif ++ ++ifdef NOEPG ++DEFINES += -DUSE_NOEPG ++endif ++ ++ifdef PINPLUGIN ++DEFINES += -DUSE_PINPLUGIN ++endif ++ ++ifdef PLUGINMISSING ++DEFINES += -DUSE_PLUGINMISSING ++endif ++ ++ifdef ROTOR ++DEFINES += -DUSE_ROTOR ++endif ++ ++ifdef SORTRECORDS ++ifdef LIEMIEXT ++DEFINES += -DUSE_SORTRECORDS ++endif ++endif ++ ++ifdef STATUS_EXTENSION ++DEFINES += -DUSE_STATUS_EXTENSION ++endif ++ ++ifdef TIMERINFO ++DEFINES += -DUSE_TIMERINFO ++endif ++ ++ifdef TTXTSUBS ++DEFINES += -DUSE_TTXTSUBS ++endif ++ ++ifdef VALIDINPUT ++DEFINES += -DUSE_VALIDINPUT ++endif ++ ++ifdef VOLCTRL ++DEFINES += -DUSE_VOLCTRL ++endif ++ ++ifdef WAREAGLEICON ++DEFINES += -DUSE_WAREAGLEICON ++endif ++ ++ifdef YAEPG ++DEFINES += -DUSE_YAEPG ++endif +diff -ruN vdr-1.7.14/Makefile vdr-1.7.14.ExtP_NG/Makefile +--- vdr-1.7.14/Makefile 2010-02-21 12:44:38.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/Makefile 2010-04-10 15:45:10.520736498 +0200 +@@ -44,6 +44,18 @@ + skinclassic.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\ + timers.o tools.o transfer.o vdr.o videodir.o + ++ifdef SETUP ++OBJS += tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o submenu.o ++endif ++ ++ifdef TTXTSUBS ++OBJS += vdrttxtsubshooks.o ++endif ++ ++ifdef WAREAGLEICON ++OBJS += iconpatch.o ++endif ++ + ifndef NO_KBD + DEFINES += -DREMOTE_KBD + endif +diff -ruN vdr-1.7.14/channels.c vdr-1.7.14.ExtP_NG/channels.c +--- vdr-1.7.14/channels.c 2010-02-21 14:36:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/channels.c 2010-04-10 15:45:09.286739173 +0200 +@@ -12,6 +12,9 @@ + #include "device.h" + #include "epg.h" + #include "timers.h" ++#ifdef USE_ALTERNATECHANNEL ++#include "tools.h" ++#endif /* ALTERNATECHANNEL */ + + // 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 +@@ -140,6 +143,18 @@ + return tf; + } + ++#ifdef USE_LNBSHARE ++char cChannel::Polarization(void) const ++{ ++ if (IsSat()) { ++ const char *p = strpbrk(parameters, "HVLRhvlr"); // lowercase for backwards compatibility ++ if (p) ++ return *p; ++ } ++ return NULL; ++} ++#endif /* LNBSHARE */ ++ + bool cChannel::HasTimer(void) const + { + for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) { +@@ -253,6 +268,14 @@ + } + } + ++#ifdef USE_ALTERNATECHANNEL ++void cChannel::SetAlternativeChannelID(const char *AlternativeChannelID) ++{ ++ if (!isempty(AlternativeChannelID)) ++ alternativeChannelID = tChannelID::FromString(AlternativeChannelID); ++} ++#endif /* ALTERNATECHANNEL */ ++ + #define STRDIFF 0x01 + #define VALDIFF 0x02 + +@@ -365,6 +388,29 @@ + } + } + ++#ifdef USE_TTXTSUBS ++void cChannel::SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages) ++{ ++ int mod = CHANNELMOD_NONE; ++ if (totalTtxtSubtitlePages != numberOfPages) ++ mod |= CHANNELMOD_PIDS; ++ totalTtxtSubtitlePages = fixedTtxtSubtitlePages; ++ for (int i = 0; (i < numberOfPages) && (totalTtxtSubtitlePages < MAXTXTPAGES); i++) { ++ if (teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine != pages[i].ttxtMagazine || ++ teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage != pages[i].ttxtPage || ++ teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType != pages[i].ttxtType || ++ strcmp(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, pages[i].ttxtLanguage)) { ++ mod |= CHANNELMOD_PIDS; ++ teletextSubtitlePages[totalTtxtSubtitlePages] = pages[i]; ++ } ++ totalTtxtSubtitlePages++; ++ } ++ modification |= mod; ++ Channels.SetModified(); ++} ++ ++#endif /* TTXTSUBS */ ++ + void cChannel::SetCaIds(const int *CaIds) + { + if (caids[0] && caids[0] <= CA_USER_MAX) +@@ -493,11 +539,28 @@ + q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs); + } + *q = 0; ++#ifdef USE_TTXTSUBS ++ const int TBufferSize = 5 + 1 + (MAXTXTPAGES * (3 + 1 + MAXLANGCODE1 + 1)) + 10; // '12345;150=deu,151=fin,...', +10: paranoia ++ char tpidbuf[TBufferSize]; ++ q = tpidbuf; ++ q += snprintf(q, sizeof(tpidbuf), "%d", Channel->tpid); ++ if (Channel->fixedTtxtSubtitlePages > 0) { ++ q += snprintf(q, sizeof(tpidbuf) - (q - tpidbuf), ";"); ++ for (int i = 0; i < Channel->fixedTtxtSubtitlePages; ++i) { ++ tTeletextSubtitlePage page = Channel->teletextSubtitlePages[i]; ++ q += snprintf(q, sizeof(tpidbuf) - (q - tpidbuf), "%d=%s", page.PageNumber(), page.ttxtLanguage); ++ } ++ } ++#endif /* TTXTSUBS */ + char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia + q = caidbuf; + q += IntArrayToString(q, Channel->caids, 16); + *q = 0; ++#ifdef USE_TTXTSUBS ++ buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%s:%s:%d:%d:%d:%d\n", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, tpidbuf, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid); ++#else + buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d\n", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid); ++#endif /* TTXTSUBS */ + } + return buffer; + } +@@ -531,8 +594,15 @@ + char *parambuf = NULL; + char *vpidbuf = NULL; + char *apidbuf = NULL; ++#ifdef USE_TTXTSUBS ++ char *tpidbuf = NULL; ++#endif /* TTXTSUBS */ + char *caidbuf = NULL; ++#ifdef USE_TTXTSUBS ++ int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%a[^:]:%a[^:]:%d :%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpidbuf, &caidbuf, &sid, &nid, &tid, &rid); ++#else + 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); ++#endif /* TTXTSUBS */ + if (fields >= 9) { + if (fields == 9) { + // allow reading of old format +@@ -616,6 +686,39 @@ + dpids[NumDpids] = 0; + } + ++#ifdef USE_TTXTSUBS ++ if (tpidbuf) { ++ char *p; ++ fixedTtxtSubtitlePages = 0; ++ // 2001;150=deu,151=fin ++ if ((p = strchr(tpidbuf, ';')) != NULL) { ++ char *q, *strtok_next; ++ *p++ = 0; ++ while ((q = strtok_r(p, ",", &strtok_next)) != NULL) { ++ if (fixedTtxtSubtitlePages < MAXTXTPAGES) { ++ int page; ++ char *l = strchr(q, '='); ++ if (l) ++ *l++ = 0; ++ if (sscanf(q, "%d", &page) == 1) { ++ teletextSubtitlePages[fixedTtxtSubtitlePages] = tTeletextSubtitlePage(page); ++ if (l) ++ strn0cpy(teletextSubtitlePages[fixedTtxtSubtitlePages].ttxtLanguage, l, MAXLANGCODE1); ++ fixedTtxtSubtitlePages++; ++ } ++ else ++ esyslog("ERROR: invalid Teletext page!"); // no need to set ok to 'false' ++ } ++ else ++ esyslog("ERROR: too many Teletext pages!"); // no need to set ok to 'false' ++ p = NULL; ++ } ++ totalTtxtSubtitlePages = fixedTtxtSubtitlePages; ++ } ++ if (sscanf(tpidbuf, "%d", &tpid) != 1) ++ return false; ++ } ++#endif /* TTXTSUBS */ + if (caidbuf) { + char *p = caidbuf; + char *q; +@@ -652,6 +755,9 @@ + free(sourcebuf); + free(vpidbuf); + free(apidbuf); ++#ifdef USE_TTXTSUBS ++ free(tpidbuf); ++#endif /* TTXTSUBS */ + free(caidbuf); + free(namebuf); + if (!GetChannelID().Valid()) { +@@ -725,6 +831,50 @@ + return false; + } + ++#ifdef USE_ALTERNATECHANNEL ++bool cChannels::LoadAlternativeChannels(const char *FileName) ++{ ++ FILE *fp; ++ char *line; ++ cReadLine ReadLine; ++ cChannel *origChannel; ++ tChannelID channelID; ++ if ((fp = fopen(FileName,"r"))==NULL) ++ { ++ esyslog("Can't open Alternative Channels-File <%s>",FileName); ++ return false; ++ } ++ while ((line = ReadLine.Read(fp)) != NULL) ++ { ++ if (line[0] != '#') ++ { ++ line=strtok(line, ";"); ++ if (line != NULL) ++ { ++ channelID = tChannelID::FromString(line); ++ if (channelID == tChannelID::InvalidID) ++ dsyslog("Skipping invalid channel ID <%s>",line); ++ else { ++ origChannel = Channels.GetByChannelID(channelID); ++ if (!origChannel) ++ dsyslog("Skipping unknown channel ID <%s>",line); ++ else { ++ line=strtok(NULL, ";"); ++ channelID = tChannelID::FromString(line); ++ if (channelID == tChannelID::InvalidID || !Channels.GetByChannelID(channelID)) ++ dsyslog("Skipping invalid/unknown alternative channel ID <%s>",line); ++ else ++ origChannel->SetAlternativeChannelID(line); ++ } ++ } ++ } ++ } ++ } while (line != NULL); ++ fclose(fp); ++ return true; ++} ++#endif /* ALTERNATECHANNEL */ ++ + void cChannels::HashChannel(cChannel *Channel) + { + channelsHashSid.Add(Channel, Channel->Sid()); +diff -ruN vdr-1.7.14/channels.h vdr-1.7.14.ExtP_NG/channels.h +--- vdr-1.7.14/channels.h 2010-03-07 14:47:13.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/channels.h 2010-04-10 15:45:09.370737290 +0200 +@@ -35,6 +35,9 @@ + #define MAXDPIDS 16 // dolby (AC3 + DTS) + #define MAXSPIDS 32 // subtitles + #define MAXCAIDS 8 // conditional access ++#ifdef USE_TTXTSUBS ++#define MAXTXTPAGES 8 // teletext pages ++#endif /* TTXTSUBS */ + + #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 +@@ -71,6 +74,18 @@ + static const tChannelID InvalidID; + }; + ++#ifdef USE_TTXTSUBS ++struct tTeletextSubtitlePage { ++ tTeletextSubtitlePage(void) { ttxtPage = ttxtMagazine = 0; ttxtType = 0x02; strcpy(ttxtLanguage, "und"); } ++ tTeletextSubtitlePage(int page) { ttxtMagazine = (page / 100) & 0x7; ttxtPage = (((page % 100) / 10) << 4) + (page % 10); ttxtType = 0x02; strcpy(ttxtLanguage, "und"); } ++ char ttxtLanguage[MAXLANGCODE1]; ++ uchar ttxtPage; ++ uchar ttxtMagazine; ++ uchar ttxtType; ++ int PageNumber(void) const { return BCDCHARTOINT(ttxtMagazine) * 100 + BCDCHARTOINT(ttxtPage); } ++ }; ++#endif /* TTXTSUBS */ ++ + class cChannel; + + class cLinkChannel : public cListObject { +@@ -96,6 +111,9 @@ + char *shortName; + char *provider; + char *portalName; ++#ifdef USE_ALTERNATECHANNEL ++ tChannelID alternativeChannelID; ++#endif /* ALTERNATECHANNEL */ + int __BeginData__; + int frequency; // MHz + int source; +@@ -113,6 +131,11 @@ + uint16_t compositionPageIds[MAXSPIDS]; + uint16_t ancillaryPageIds[MAXSPIDS]; + int tpid; ++#ifdef USE_TTXTSUBS ++ int fixedTtxtSubtitlePages; ++ int totalTtxtSubtitlePages; ++ tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES]; ++#endif /* TTXTSUBS */ + int caids[MAXCAIDS + 1]; // list is zero-terminated + int nid; + int tid; +@@ -139,6 +162,9 @@ + 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; } ++#ifdef USE_ALTERNATECHANNEL ++ const tChannelID AlternativeChannelID(void) const { return alternativeChannelID; } ++#endif /* ALTERNATECHANNEL */ + 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 +@@ -160,6 +186,10 @@ + uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); } + uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); } + int Tpid(void) const { return tpid; } ++#ifdef USE_TTXTSUBS ++ const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; } ++ int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; } ++#endif /* TTXTSUBS */ + const int *Caids(void) const { return caids; } + int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; } + int Nid(void) const { return nid; } +@@ -170,6 +200,9 @@ + void SetNumber(int Number) { number = Number; } + bool GroupSep(void) const { return groupSep; } + const char *Parameters(void) const { return parameters; } ++#ifdef USE_LNBSHARE ++ char Polarization(void) const; ++#endif /* LNBSHARE */ + const cLinkChannels* LinkChannels(void) const { return linkChannels; } + const cChannel *RefChannel(void) const { return refChannel; } + bool IsAtsc(void) const { return cSource::IsAtsc(source); } +@@ -185,7 +218,13 @@ + 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); ++#ifdef USE_ALTERNATECHANNEL ++ void SetAlternativeChannelID(const char *AlternativeChannelID); ++#endif /* ALTERNATECHANNEL */ + void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); ++#ifdef USE_TTXTSUBS ++ void SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages); ++#endif /* TTXTSUBS */ + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); + void SetLinkChannels(cLinkChannels *LinkChannels); +@@ -203,6 +242,9 @@ + public: + cChannels(void); + bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false); ++#ifdef USE_ALTERNATECHANNEL ++ bool LoadAlternativeChannels(const char *FileName); ++#endif /* ALTERNATECHANNEL */ + void HashChannel(cChannel *Channel); + void UnhashChannel(cChannel *Channel); + int GetNextGroup(int Idx); // Get next channel group +diff -ruN vdr-1.7.14/ci.c vdr-1.7.14.ExtP_NG/ci.c +--- vdr-1.7.14/ci.c 2010-01-02 11:39:50.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/ci.c 2010-04-10 15:45:09.396741389 +0200 +@@ -1911,6 +1911,10 @@ + AddPid(Channel->Sid(), *Apid, STREAM_TYPE_AUDIO); + for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++) + AddPid(Channel->Sid(), *Dpid, STREAM_TYPE_DOLBY); ++#ifdef USE_TTXTSUBS ++ if (Channel->Tpid() && Setup.SupportTeletext) ++ AddPid(Channel->Sid(), Channel->Tpid(), STREAM_TYPE_DOLBY); ++#endif /* TTXTSUBS */ + } + } + +@@ -1932,6 +1936,11 @@ + CaPmt.AddPid(*Apid, STREAM_TYPE_AUDIO); + for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++) + CaPmt.AddPid(*Dpid, STREAM_TYPE_DOLBY); ++#ifdef USE_TTXTSUBS ++ if (Channel->Tpid() && Setup.SupportTeletext) { ++ CaPmt.AddPid(Channel->Tpid(), STREAM_TYPE_DOLBY); // FIXME: STREAM_TYPE_DOLBY should probably be renamed STREAM_TYPE_PRIVATE ++ } ++#endif /* TTXTSUBS */ + cas->SendPMT(&CaPmt); + cTimeMs Timeout(QUERY_REPLY_TIMEOUT); + do { +diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c +--- vdr-1.7.14/config.c 2010-03-12 17:41:37.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/config.c 2010-04-10 15:45:09.424743485 +0200 +@@ -313,6 +313,12 @@ + strcpy(OSDLanguage, ""); // default is taken from environment + strcpy(OSDSkin, "sttng"); + strcpy(OSDTheme, "default"); ++#ifdef USE_VALIDINPUT ++ ShowValidInput = 0; ++#endif /* VALIDINPUT */ ++#ifdef USE_WAREAGLEICON ++ WarEagleIcons = 1; ++#endif /* WAREAGLEICON */ + PrimaryDVB = 1; + ShowInfoOnChSwitch = 1; + TimeoutRequChInfo = 1; +@@ -331,13 +337,27 @@ + TimeTransponder = 0; + MarginStart = 2; + MarginStop = 10; ++#ifdef USE_JUMPINGSECONDS ++ JumpSeconds = 60; ++ JumpSecondsSlow = 10; ++ JumpSecondsRepeat = 300; ++#endif /* JUMPINGSECONDS */ + AudioLanguages[0] = -1; + DisplaySubtitles = 0; ++#ifdef USE_TTXTSUBS ++ SupportTeletext = 0; ++#endif /* TTXTSUBS */ + SubtitleLanguages[0] = -1; + SubtitleOffset = 0; + SubtitleFgTransparency = 0; + SubtitleBgTransparency = 0; + EPGLanguages[0] = -1; ++#ifdef USE_DDEPGENTRY ++ DoubleEpgTimeDelta = 15; ++ DoubleEpgAction = 0; ++ MixEpgAction = 0; ++ DisableVPS = 0; ++#endif /* DDEPGENTRY */ + EPGScanTimeout = 5; + EPGBugfixLevel = 3; + EPGLinger = 0; +@@ -358,6 +378,9 @@ + VideoDisplayFormat = 1; + VideoFormat = 0; + UpdateChannels = 5; ++#ifdef USE_CHANNELBIND ++ ChannelBindingByRid = 0; ++#endif /* CHANNELBIND */ + UseDolbyDigital = 1; + ChannelInfoPos = 0; + ChannelInfoTime = 5; +@@ -383,6 +406,10 @@ + FontSmlSize = 18; + FontFixSize = 20; + MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT; ++#ifdef USE_HARDLINKCUTTER ++ MaxRecordingSize = DEFAULTRECORDINGSIZE; ++ HardLinkCutter = 0; ++#endif /* HARDLINKCUTTER */ + SplitEditedFiles = 0; + DelTimeshiftRec = 0; + MinEventTimeout = 30; +@@ -391,18 +418,83 @@ + MultiSpeedMode = 0; + ShowReplayMode = 0; + ResumeID = 0; ++#ifdef USE_JUMPPLAY ++ JumpPlay = 0; ++ PlayJump = 0; ++ PauseLastMark = 0; ++ ReloadMarks = 0; ++#endif /* JUMPPLAY */ + CurrentChannel = -1; + CurrentVolume = MAXVOLUME; + CurrentDolby = 0; ++#ifdef USE_CHANNELPROVIDE ++ LocalChannelProvide = 1; ++#endif /* CHANNELPROVIDE */ + InitialChannel = 0; + InitialVolume = -1; ++#ifdef USE_VOLCTRL ++ LRVolumeControl = 0; ++ LRChannelGroups = 1; ++ LRForwardRewind = 1; ++#endif /* VOLCTRL */ + ChannelsWrap = 0; + EmergencyExit = 1; ++#ifdef USE_LIEMIEXT ++ ShowRecDate = 1; ++ ShowRecTime = 1; ++ ShowRecLength = 0; ++ ShowProgressBar = 0; ++ MenuCmdPosition = 0; ++#endif /* LIEMIEXT */ ++#ifdef USE_LIRCSETTINGS ++ LircRepeatDelay = 350; ++ LircRepeatFreq = 100; ++ LircRepeatTimeout = 500; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LNBSHARE ++ VerboseLNBlog = 0; ++ for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; ++#endif /* LNBSHARE */ ++#ifdef USE_NOEPG ++ noEPGMode = 0; ++ noEPGList = strdup(""); ++#endif /* NOEPG */ ++#ifdef USE_SORTRECORDS ++ RecordingsSortMode = 0; ++ RecordingsSortDirsFirst = 0; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ CutterAutoDelete = 0; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ UseFriendlyFNames = 0; // default = disabled ++#endif /* DVLFRIENDLYFNAMES */ ++#ifdef USE_DVLVIDPREFER ++ UseVidPrefer = 0; // default = disabled ++ nVidPrefer = 1; ++ for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) { ++ VidPreferPrio[ zz ] = 50; ++ VidPreferSize[ zz ] = 100; ++ } ++ VidPreferSize[ 0 ] = 800; ++ VidPreferPrio[ 0 ] = 50; ++#endif /* DVLVIDPREFER */ ++} ++ ++#ifdef USE_NOEPG ++cSetup::~cSetup() ++{ ++ free(noEPGList); + } ++#endif /* NOEPG */ + + cSetup& cSetup::operator= (const cSetup &s) + { + memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); ++#ifdef USE_NOEPG ++ free(noEPGList); ++ noEPGList = strdup(s.noEPGList); ++#endif /* NOEPG */ + return *this; + } + +@@ -503,6 +595,12 @@ + if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } + else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); + else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); ++#ifdef USE_VALIDINPUT ++ else if (!strcasecmp(Name, "ShowValidInput")) ShowValidInput = atoi(Value); ++#endif /* VALIDINPUT */ ++#ifdef USE_WAREAGLEICON ++ else if (!strcasecmp(Name, "WarEagleIcons")) WarEagleIcons = atoi(Value); ++#endif /* WAREAGLEICON */ + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); +@@ -521,13 +619,27 @@ + else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); + else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); ++#ifdef USE_JUMPINGSECONDS ++ else if (!strcasecmp(Name, "JumpSeconds")) JumpSeconds = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSecondsSlow")) JumpSecondsSlow = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSecondsRepeat")) JumpSecondsRepeat = atoi(Value); ++#endif /* JUMPINGSECONDS */ + else if (!strcasecmp(Name, "AudioLanguages")) return ParseLanguages(Value, AudioLanguages); + else if (!strcasecmp(Name, "DisplaySubtitles")) DisplaySubtitles = atoi(Value); ++#ifdef USE_TTXTSUBS ++ else if (!strcasecmp(Name, "SupportTeletext")) SupportTeletext = atoi(Value); ++#endif /* TTXTSUBS */ + else if (!strcasecmp(Name, "SubtitleLanguages")) return ParseLanguages(Value, SubtitleLanguages); + else if (!strcasecmp(Name, "SubtitleOffset")) SubtitleOffset = atoi(Value); + else if (!strcasecmp(Name, "SubtitleFgTransparency")) SubtitleFgTransparency = atoi(Value); + else if (!strcasecmp(Name, "SubtitleBgTransparency")) SubtitleBgTransparency = atoi(Value); + else if (!strcasecmp(Name, "EPGLanguages")) return ParseLanguages(Value, EPGLanguages); ++#ifdef USE_DDEPGENTRY ++ else if (!strcasecmp(Name, "DoubleEpgTimeDelta")) DoubleEpgTimeDelta = atoi(Value); ++ else if (!strcasecmp(Name, "DoubleEpgAction")) DoubleEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "MixEpgAction")) MixEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "DisableVPS")) DisableVPS = atoi(Value); ++#endif /* DDEPGENTRY */ + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); + else if (!strcasecmp(Name, "EPGLinger")) EPGLinger = atoi(Value); +@@ -548,6 +660,9 @@ + else if (!strcasecmp(Name, "VideoDisplayFormat")) VideoDisplayFormat = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); ++#ifdef USE_CHANNELBIND ++ else if (!strcasecmp(Name, "ChannelBindingByRid")) ChannelBindingByRid= atoi(Value); ++#endif /* CHANNELBIND */ + else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); +@@ -573,6 +688,10 @@ + else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); + else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value); ++ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value); ++#endif /* HARDLINKCUTTER */ + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); + else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); +@@ -581,15 +700,102 @@ + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); ++#ifdef USE_JUMPPLAY ++ else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); ++ else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); ++ else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); ++ else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); ++#endif /* JUMPPLAY */ + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); ++#ifdef USE_CHANNELPROVIDE ++ else if (!strcasecmp(Name, "LocalChannelProvide")) LocalChannelProvide = atoi(Value); ++#endif /* CHANNELPROVIDE */ + else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); + else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); ++#ifdef USE_VOLCTRL ++ else if (!strcasecmp(Name, "LRVolumeControl")) LRVolumeControl = atoi(Value); ++ else if (!strcasecmp(Name, "LRChannelGroups")) LRChannelGroups = atoi(Value); ++ else if (!strcasecmp(Name, "LRForwardRewind")) LRForwardRewind = atoi(Value); ++#endif /* VOLCTRL */ + else if (!strcasecmp(Name, "ChannelsWrap")) ChannelsWrap = atoi(Value); + else if (!strcasecmp(Name, "EmergencyExit")) EmergencyExit = atoi(Value); ++#ifdef USE_LIEMIEXT ++ else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecTime")) ShowRecTime = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecLength")) ShowRecLength = atoi(Value); ++ else if (!strcasecmp(Name, "ShowProgressBar")) ShowProgressBar = atoi(Value); ++ else if (!strcasecmp(Name, "MenuCmdPosition")) MenuCmdPosition = atoi(Value); ++#endif /* LIEMIEXT */ ++#ifdef USE_LIRCSETTINGS ++ else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_NOEPG ++ else if (!strcasecmp(Name, "noEPGMode")) noEPGMode = atoi(Value); ++ else if (!strcasecmp(Name, "noEPGList")) { ++ free(noEPGList); ++ noEPGList = strdup(Value ? Value : ""); ++ } ++#endif /* NOEPG */ ++#ifdef USE_SORTRECORDS ++ else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); ++ else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); ++#endif /* DVLFRIENDLYFNAMES */ ++#ifdef USE_DVLVIDPREFER ++ else if (strcasecmp(Name, "UseVidPrefer") == 0) UseVidPrefer = atoi(Value); ++ else if (strcasecmp(Name, "nVidPrefer") == 0) nVidPrefer = atoi(Value); ++ else if (strstr(Name, "VidPrefer") == Name) { ++ char *x = (char *)&Name[ strlen(Name) - 1 ]; ++ int vN; ++ ++ if (isdigit(*x) != 0) { ++ while (isdigit(*x) != 0) ++ x--; ++ x++; ++ } ++ ++ vN = atoi(x); ++ if (vN < DVLVIDPREFER_MAX) { ++ if (strstr(Name, "VidPreferPrio") == Name) { ++ VidPreferPrio[ vN ] = atoi(Value); ++ if (VidPreferPrio[ vN ] > 99) ++ VidPreferPrio[ vN ] = 99; ++ } ++ else if (strstr(Name, "VidPreferSize") == Name) { ++ VidPreferSize[ vN ] = atoi(Value); ++ } ++ else ++ return false; ++ } ++ } ++#endif /* DVLVIDPREFER */ + else ++#ifdef USE_LNBSHARE ++ if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); ++ else { ++ char tmp[20]; ++ bool result = false; ++ for (int i = 1; i <= MAXDEVICES; i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ if (!strcasecmp(Name, tmp)) { ++ CardUsesLNBnr[i - 1] = atoi(Value); ++ result = true; ++ } ++ } ++ return result; ++ } ++#else + return false; ++#endif /* LNBSHARE */ + return true; + } + +@@ -598,6 +804,12 @@ + Store("OSDLanguage", OSDLanguage); + Store("OSDSkin", OSDSkin); + Store("OSDTheme", OSDTheme); ++#ifdef USE_VALIDINPUT ++ Store("ShowValidInput", ShowValidInput); ++#endif /* VALIDINPUT */ ++#ifdef USE_WAREAGLEICON ++ Store("WarEagleIcons", WarEagleIcons); ++#endif /* WAREAGLEICON */ + Store("PrimaryDVB", PrimaryDVB); + Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); + Store("TimeoutRequChInfo", TimeoutRequChInfo); +@@ -616,13 +828,27 @@ + Store("TimeTransponder", TimeTransponder); + Store("MarginStart", MarginStart); + Store("MarginStop", MarginStop); ++#ifdef USE_JUMPINGSECONDS ++ Store("JumpSeconds", JumpSeconds); ++ Store("JumpSecondsSlow", JumpSecondsSlow); ++ Store("JumpSecondsRepeat", JumpSecondsRepeat); ++#endif /* JUMPINGSECONDS */ + StoreLanguages("AudioLanguages", AudioLanguages); + Store("DisplaySubtitles", DisplaySubtitles); ++#ifdef USE_TTXTSUBS ++ Store("SupportTeletext", SupportTeletext); ++#endif /* TTXTSUBS */ + StoreLanguages("SubtitleLanguages", SubtitleLanguages); + Store("SubtitleOffset", SubtitleOffset); + Store("SubtitleFgTransparency", SubtitleFgTransparency); + Store("SubtitleBgTransparency", SubtitleBgTransparency); + StoreLanguages("EPGLanguages", EPGLanguages); ++#ifdef USE_DDEPGENTRY ++ Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta); ++ Store("DoubleEpgAction", DoubleEpgAction); ++ Store("MixEpgAction", MixEpgAction); ++ Store("DisableVPS", DisableVPS); ++#endif /* DDEPGENTRY */ + Store("EPGScanTimeout", EPGScanTimeout); + Store("EPGBugfixLevel", EPGBugfixLevel); + Store("EPGLinger", EPGLinger); +@@ -643,6 +869,9 @@ + Store("VideoDisplayFormat", VideoDisplayFormat); + Store("VideoFormat", VideoFormat); + Store("UpdateChannels", UpdateChannels); ++#ifdef USE_CHANNELBIND ++ Store("ChannelBindingByRid",ChannelBindingByRid); ++#endif /* CHANNELBIND */ + Store("UseDolbyDigital", UseDolbyDigital); + Store("ChannelInfoPos", ChannelInfoPos); + Store("ChannelInfoTime", ChannelInfoTime); +@@ -676,13 +905,75 @@ + Store("MultiSpeedMode", MultiSpeedMode); + Store("ShowReplayMode", ShowReplayMode); + Store("ResumeID", ResumeID); ++#ifdef USE_JUMPPLAY ++ Store("JumpPlay", JumpPlay); ++ Store("PlayJump", PlayJump); ++ Store("PauseLastMark", PauseLastMark); ++ Store("ReloadMarks", ReloadMarks); ++#endif /* JUMPPLAY */ + Store("CurrentChannel", CurrentChannel); + Store("CurrentVolume", CurrentVolume); + Store("CurrentDolby", CurrentDolby); ++#ifdef USE_CHANNELPROVIDE ++ Store("LocalChannelProvide",LocalChannelProvide); ++#endif /* CHANNELPROVIDE */ + Store("InitialChannel", InitialChannel); + Store("InitialVolume", InitialVolume); ++#ifdef USE_VOLCTRL ++ Store("LRVolumeControl", LRVolumeControl); ++ Store("LRChannelGroups", LRChannelGroups); ++ Store("LRForwardRewind", LRForwardRewind); ++#endif /* VOLCTRL */ + Store("ChannelsWrap", ChannelsWrap); + Store("EmergencyExit", EmergencyExit); ++#ifdef USE_LIEMIEXT ++ Store("ShowRecDate", ShowRecDate); ++ Store("ShowRecTime", ShowRecTime); ++ Store("ShowRecLength", ShowRecLength); ++ Store("ShowProgressBar", ShowProgressBar); ++ Store("MenuCmdPosition", MenuCmdPosition); ++#endif /* LIEMIEXT */ ++#ifdef USE_LIRCSETTINGS ++ Store("LircRepeatDelay", LircRepeatDelay); ++ Store("LircRepeatFreq", LircRepeatFreq); ++ Store("LircRepeatTimeout", LircRepeatTimeout); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LNBSHARE ++ Store("VerboseLNBlog", VerboseLNBlog); ++ char tmp[20]; ++ if (cDevice::NumDevices() > 1) { ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ Store(tmp, CardUsesLNBnr[i - 1]); ++ } ++ } ++#endif /* LNBSHARE */ ++#ifdef USE_NOEPG ++ Store("noEPGMode", noEPGMode); ++ Store("noEPGList", noEPGList); ++#endif /* NOEPG */ ++#ifdef USE_SORTRECORDS ++ Store("RecordingsSortMode", RecordingsSortMode); ++ Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Store("CutterAutoDelete", CutterAutoDelete); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ Store ("UseFriendlyFNames", UseFriendlyFNames); ++#endif /* DVLFRIENDLYFNAMES */ ++#ifdef USE_DVLVIDPREFER ++ Store ("UseVidPrefer", UseVidPrefer); ++ Store ("nVidPrefer", nVidPrefer); ++ ++ char vidBuf[32]; ++ for (int zz = 0; zz < nVidPrefer; zz++) { ++ sprintf(vidBuf, "VidPreferPrio%d", zz); ++ Store (vidBuf, VidPreferPrio[zz]); ++ sprintf(vidBuf, "VidPreferSize%d", zz); ++ Store (vidBuf, VidPreferSize[zz]); ++ } ++#endif /* DVLVIDPREFER */ + + Sort(); + +diff -ruN vdr-1.7.14/config.h vdr-1.7.14.ExtP_NG/config.h +--- vdr-1.7.14/config.h 2010-03-12 17:02:53.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/config.h 2010-04-10 15:45:09.438738230 +0200 +@@ -30,15 +30,39 @@ + #define APIVERSION "1.7.14" + #define APIVERSNUM 10714 // Version * 10000 + Major * 100 + Minor + ++#ifdef USE_YAEPG ++#define YAEPGHDVERSNUM 1 ++#endif /* YAEPG */ ++ + // When loading plugins, VDR searches them by their APIVERSION, which + // may be smaller than VDRVERSION in case there have been no changes to + // VDR header files since the last APIVERSION. This allows compiled + // plugins to work with newer versions of the core VDR as long as no + // VDR header files have changed. + ++#ifdef USE_CHANNELBIND ++#define CHANNELBINDINGVERSNUM 2 ++#endif /* CHANNELBIND */ ++ ++#ifdef USE_JUMPPLAY ++#define JUMPPLAYVERSNUM 100 ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++#define LIEMIKUUTIO 130 ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_MAINMENUHOOKS ++#define MAINMENUHOOKSVERSNUM 1.0 ++#endif /* MAINMENUHOOKS */ ++ + #define MAXPRIORITY 99 + #define MAXLIFETIME 99 + ++#ifdef USE_DVLVIDPREFER ++#define DVLVIDPREFER_MAX 12 ++#endif /* DVLVIDPREFER */ ++ + #define MINOSDWIDTH 480 + #define MAXOSDWIDTH 1920 + #define MINOSDHEIGHT 324 +@@ -216,6 +240,12 @@ + char OSDLanguage[I18N_MAX_LOCALE_LEN]; + char OSDSkin[MaxSkinName]; + char OSDTheme[MaxThemeName]; ++#ifdef USE_VALIDINPUT ++ int ShowValidInput; ++#endif /* VALIDINPUT */ ++#ifdef USE_WAREAGLEICON ++ int WarEagleIcons; ++#endif /* WAREAGLEICON */ + int PrimaryDVB; + int ShowInfoOnChSwitch; + int TimeoutRequChInfo; +@@ -233,12 +263,24 @@ + int TimeSource; + int TimeTransponder; + int MarginStart, MarginStop; ++#ifdef USE_JUMPINGSECONDS ++ int JumpSeconds, JumpSecondsSlow, JumpSecondsRepeat; ++#endif /* JUMPINGSECONDS */ + int AudioLanguages[I18N_MAX_LANGUAGES + 1]; + int DisplaySubtitles; ++#ifdef USE_TTXTSUBS ++ int SupportTeletext; ++#endif /* TTXTSUBS */ + int SubtitleLanguages[I18N_MAX_LANGUAGES + 1]; + int SubtitleOffset; + int SubtitleFgTransparency, SubtitleBgTransparency; + int EPGLanguages[I18N_MAX_LANGUAGES + 1]; ++#ifdef USE_DDEPGENTRY ++ int DoubleEpgTimeDelta; ++ int DoubleEpgAction; ++ int MixEpgAction; ++ int DisableVPS; ++#endif /* DDEPPGENTRY */ + int EPGScanTimeout; + int EPGBugfixLevel; + int EPGLinger; +@@ -257,6 +299,9 @@ + int VideoDisplayFormat; + int VideoFormat; + int UpdateChannels; ++#ifdef USE_CHANNELBIND ++ int ChannelBindingByRid; ++#endif /* CHANNELBIND */ + int UseDolbyDigital; + int ChannelInfoPos; + int ChannelInfoTime; +@@ -276,6 +321,10 @@ + int FontSmlSize; + int FontFixSize; + int MaxVideoFileSize; ++#ifdef USE_HARDLINKCUTTER ++ int MaxRecordingSize; ++ int HardLinkCutter; ++#endif /* HARDLINKCUTTER */ + int SplitEditedFiles; + int DelTimeshiftRec; + int MinEventTimeout, MinUserInactivity; +@@ -283,15 +332,70 @@ + int MultiSpeedMode; + int ShowReplayMode; + int ResumeID; ++#ifdef USE_JUMPPLAY ++ int JumpPlay; ++ int PlayJump; ++ int PauseLastMark; ++ int ReloadMarks; ++#endif /* JUMPPLAY */ + int CurrentChannel; + int CurrentVolume; + int CurrentDolby; ++#ifdef USE_CHANNELPROVIDE ++ int LocalChannelProvide; ++#endif /* CHANNELPROVIDE */ + int InitialChannel; + int InitialVolume; ++#ifdef USE_VOLCTRL ++ int LRVolumeControl; ++ int LRChannelGroups; ++ int LRForwardRewind; ++#endif /* VOLCTRL */ + int ChannelsWrap; + int EmergencyExit; ++#ifdef USE_LIRCSETTINGS ++ int LircRepeatDelay; ++ int LircRepeatFreq; ++ int LircRepeatTimeout; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; ++#endif /* LIEMIEXT */ ++#ifdef USE_LNBSHARE ++ int VerboseLNBlog; ++ #define MAXDEVICES 16 // Since VDR 1.3.32 we can not #include "device.h" for MAXDEVICES anymore. ++ // With this workaround a warning will be shown during compilation if ++ // MAXDEVICES changes in device.h. ++ int CardUsesLNBnr[MAXDEVICES]; ++#endif /* LNBShARE */ ++#ifdef USE_NOEPG ++ int noEPGMode; ++#endif /* NOEPG */ ++#ifdef USE_SORTRECORDS ++ int RecordingsSortMode; ++ int RecordingsSortDirsFirst; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ int CutterAutoDelete; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ int UseFriendlyFNames; ++#endif /* DVLFRIENDLYFNAMES */ ++#ifdef USE_DVLVIDPREFER ++ int UseVidPrefer; // 0 = VDR's default, 1 = use ++ int nVidPrefer; ++ int VidPreferPrio[DVLVIDPREFER_MAX]; ++ int VidPreferSize[DVLVIDPREFER_MAX]; ++#endif /* DVLVIDPREFER */ ++ + int __EndData__; ++#ifdef USE_NOEPG ++ char *noEPGList; // pointer not to be flat-copied ++#endif /* NOEPG */ + cSetup(void); ++#ifdef USE_NOEPG ++ ~cSetup(); ++#endif /* NOEPG */ + cSetup& operator= (const cSetup &s); + bool Load(const char *FileName); + bool Save(void); +diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c +--- vdr-1.7.14/cutter.c 2010-01-02 14:08:08.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/cutter.c 2010-04-10 15:45:09.627745454 +0200 +@@ -15,6 +15,19 @@ + + // --- cCuttingThread -------------------------------------------------------- + ++#ifdef USE_CUTTERLIMIT ++#ifndef CUTTER_MAX_BANDWIDTH ++#define CUTTER_MAX_BANDWIDTH MEGABYTE(10) // 10 MB/s ++#endif ++#ifndef CUTTER_REL_BANDWIDTH ++#define CUTTER_REL_BANDWIDTH 75 // % ++#endif ++#ifndef CUTTER_PRIORITY ++#define CUTTER_PRIORITY sched_get_priority_min(SCHED_OTHER) ++#endif ++#define CUTTER_TIMESLICE 100 // ms ++#endif /* CUTTERLIMIT */ ++ + class cCuttingThread : public cThread { + private: + const char *error; +@@ -67,6 +80,22 @@ + + void cCuttingThread::Action(void) + { ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) ++#endif /* HARDLINKCUTTER */ ++ { ++ sched_param tmp; ++ tmp.sched_priority = CUTTER_PRIORITY; ++ if(!pthread_setschedparam(pthread_self(), SCHED_OTHER, &tmp)) ++ printf("cCuttingThread::Action: cant set priority\n"); ++ } ++ ++ int bytes = 0; ++ int __attribute__((unused)) burst_size = CUTTER_MAX_BANDWIDTH * CUTTER_TIMESLICE / 1000; // max bytes/timeslice ++ cTimeMs __attribute__((unused)) t; ++#endif /* CUTTERLIMIT */ ++ + cMark *Mark = fromMarks.First(); + if (Mark) { + fromFile = fromFileName->Open(); +@@ -78,6 +107,9 @@ + Mark = fromMarks.Next(Mark); + off_t FileSize = 0; + int CurrentFileNumber = 0; ++#ifdef USE_HARDLINKCUTTER ++ bool SkipThisSourceFile = false; ++#endif /* HARDLINKCUTTER */ + int LastIFrame = 0; + toMarks.Add(0); + toMarks.Save(); +@@ -96,12 +128,101 @@ + + // Read one frame: + ++#ifdef USE_HARDLINKCUTTER ++ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) { ++ // Error, unless we're past last cut-in and there's no cut-out ++ if (Mark || LastMark) ++ error = "index"; ++ break; ++ } ++ ++ if (FileNumber != CurrentFileNumber) { ++ fromFile = fromFileName->SetOffset(FileNumber, FileOffset); ++ fromFile->SetReadAhead(MEGABYTE(20)); ++ CurrentFileNumber = FileNumber; ++ if (SkipThisSourceFile) { ++ // At end of fast forward: Always skip to next file ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 4"; ++ break; ++ } ++ FileSize = 0; ++ SkipThisSourceFile = false; ++ } ++ ++ ++ if (Setup.HardLinkCutter && FileOffset == 0) { ++ // We are at the beginning of a new source file. ++ // Do we need to copy the whole file? ++ ++ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame ++ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out ++ // if Mark, then we're between a cut-in and a cut-out ++ ++ uint16_t MarkFileNumber; ++ off_t MarkFileOffset; ++ // Get file number of next cut mark ++ if (!Mark && !LastMark ++ || Mark ++ && fromIndex->Get(Mark->position, &MarkFileNumber, &MarkFileOffset) ++ && (MarkFileNumber != CurrentFileNumber)) { ++ // The current source file will be copied completely. ++ // Start new output file unless we did that already ++ if (FileSize != 0) { ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 3"; ++ break; ++ } ++ FileSize = 0; ++ } ++ ++ // Safety check that file has zero size ++ struct stat buf; ++ if (stat(toFileName->Name(), &buf) == 0) { ++ if (buf.st_size != 0) { ++ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name()); ++ error = "nonzero file exist"; ++ break; ++ } ++ } ++ else if (errno != ENOENT) { ++ esyslog("cCuttingThread: stat failed on %s", toFileName->Name()); ++ error = "stat"; ++ break; ++ } ++ ++ // Clean the existing 0-byte file ++ toFileName->Close(); ++ cString ActualToFileName(ReadLink(toFileName->Name()), true); ++ unlink(ActualToFileName); ++ unlink(toFileName->Name()); ++ ++ // Try to create a hard link ++ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) { ++ // Success. Skip all data transfer for this file ++ SkipThisSourceFile = true; ++ cutIn = false; ++ toFile = NULL; // was deleted by toFileName->Close() ++ } ++ else { ++ // Fallback: Re-open the file if necessary ++ toFile = toFileName->Open(); ++ } ++ } ++ } ++ } ++ ++ if (!SkipThisSourceFile) { ++#else + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) { + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + fromFile->SetReadAhead(MEGABYTE(20)); + CurrentFileNumber = FileNumber; + } ++#endif /* HARDLINKCUTTER */ + if (fromFile) { + int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); + if (len < 0) { +@@ -118,19 +239,25 @@ + break; + } + } ++#ifndef USE_HARDLINKCUTTER + else { + // Error, unless we're past the last cut-in and there's no cut-out + if (Mark || LastMark) + error = "index"; + break; + } ++#endif /* HARDLINKCUTTER */ + + // Write one frame: + + if (Independent) { // every file shall start with an independent frame + if (LastMark) // edited version shall end before next I-frame + break; ++#ifdef USE_HARDLINKCUTTER ++ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) { ++#else + if (FileSize > maxVideoFileSize) { ++#endif /* HARDLINKCUTTER */ + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 1"; +@@ -140,7 +267,11 @@ + } + LastIFrame = 0; + ++#ifdef USE_HARDLINKCUTTER ++ if (!SkipThisSourceFile && cutIn) { ++#else + if (cutIn) { ++#endif /* HARDLINKCUTTER */ + if (isPesRecording) + cRemux::SetBrokenLink(buffer, Length); + else +@@ -148,7 +279,11 @@ + cutIn = false; + } + } ++#ifdef USE_HARDLINKCUTTER ++ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) { ++#else + if (toFile->Write(buffer, Length) < 0) { ++#endif /* HARDLINKCUTTER */ + error = "safe_write"; + break; + } +@@ -183,8 +318,45 @@ + } + } + else ++#ifdef USE_HARDLINKCUTTER ++ LastMark = true; // After last cut-out: Write on until next I-frame, then exit ++#else + LastMark = true; ++#endif /* HARDLINKCUTTER */ + } ++ ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) { ++#endif /* HARDLINKCUTTER */ ++ bytes += Length; ++ if(bytes >= burst_size) { ++ int elapsed = t.Elapsed(); ++ int sleep = 0; ++ ++#if CUTTER_REL_BANDWIDTH > 0 && CUTTER_REL_BANDWIDTH < 100 ++ // stay under max. relative bandwidth ++ ++ sleep = (elapsed * 100 / CUTTER_REL_BANDWIDTH) - elapsed; ++ //if(sleep<=0 && elapsed<=2) sleep = 1; ++ //if(sleep) esyslog("cutter: relative bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++#endif ++ // stay under max. absolute bandwidth ++ if(elapsed < CUTTER_TIMESLICE) { ++ sleep = max(CUTTER_TIMESLICE - elapsed, sleep); ++ //if(sleep) esyslog("cutter: absolute bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++ } ++ ++ if(sleep>0) ++ cCondWait::SleepMs(sleep); ++ t.Set(); ++ bytes = 0; ++ } ++#ifdef USE_HARDLINKCUTTER ++ } ++#endif /* HARDLINKCUTTER */ ++#endif /* CUTTERLIMIT */ ++ + } + Recordings.TouchUpdate(); + } +@@ -194,18 +366,87 @@ + + // --- cCutter --------------------------------------------------------------- + ++#ifdef USE_CUTTERQUEUE ++#define WAIT_BEFORE_NEXT_CUT (10*1000) // 10 seconds ++ ++class cStringListObject : public cListObject { ++ public: ++ cStringListObject(const char *s) { str = strdup(s); } ++ ~cStringListObject() { free(str); } ++ ++ const char *Value() { return str; } ++ operator const char * () { return str; } ++ ++ private: ++ char *str; ++}; ++#endif /* CUTTERQUEUE */ ++ + char *cCutter::editedVersionName = NULL; + cCuttingThread *cCutter::cuttingThread = NULL; + bool cCutter::error = false; + bool cCutter::ended = false; ++#ifdef USE_CUTTERQUEUE ++cMutex *cCutter::cutterLock = new cMutex(); ++ ++static uint64_t lastCuttingEndTime = 0; ++static cList<cStringListObject> cutterQueue; ++#endif /* CUTTERQUEUE */ + + bool cCutter::Start(const char *FileName) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++ ++ if(FileName) { ++ /* Add file to queue. ++ * If cutter is still active, next cutting will be started ++ * when vdr.c:main calls cCutter::Active and previous cutting has ++ * been stopped > 10 s before ++ */ ++ cutterQueue.Add(new cStringListObject(FileName)); ++ } ++ ++ if (cuttingThread) ++ return true; ++ ++ /* cut next file from queue */ ++ if(!(cutterQueue.First())) ++ return false; ++ FileName = cutterQueue.First()->Value(); ++#endif /* CUTTTERQUEUE */ ++ + if (!cuttingThread) { + error = false; + ended = false; + cRecording Recording(FileName); ++ ++#ifdef USE_CUTTIME ++ cMarks FromMarks; ++ FromMarks.Load(FileName); ++ cMark *First=FromMarks.First(); ++ if (First) Recording.SetStartTime(Recording.start+(int(First->position/Recording.FramesPerSecond()+30)/60)*60); ++#endif /* CUTTIME */ ++ + const char *evn = Recording.PrefixFileName('%'); ++ ++#ifdef USE_CUTTERQUEUE ++ if(!(Recordings.GetByName(FileName))) { ++ // Update Recordings, maybe its not initialized(if vdr --edit is used) ++ Recordings.Update(true); ++ if(!(Recordings.GetByName(FileName))) { ++ // Update Recordings, maybe its not initialized(if vdr --edit is used) ++ Recordings.Update(true); ++ if(!(Recordings.GetByName(FileName))) { ++ // Should _not_ remove any cutted recordings ++ // (original recording already deleted ?) ++ // so, just pop item from queue and return. ++ esyslog("can't cut non-existing recording %s", FileName); ++ cutterQueue.Del(cutterQueue.First()); ++ return true; // might be already queued recording ++ } ++ } ++#endif /* CUTTERQUEUE */ + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) + // remove a possible deleted recording with the same name to avoid symlink mixups: +@@ -231,6 +472,10 @@ + + void cCutter::Stop(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ ++ + bool Interrupted = cuttingThread && cuttingThread->Active(); + const char *Error = cuttingThread ? cuttingThread->Error() : NULL; + delete cuttingThread; +@@ -242,11 +487,20 @@ + esyslog("ERROR: '%s' during editing process", Error); + RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? + Recordings.DelByName(editedVersionName); ++#ifdef USE_CUTTERQUEUE ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ + } ++#ifdef USE_CUTTERQUEUE ++ lastCuttingEndTime = cTimeMs::Now(); ++#endif /* CUTTERQUEUE */ + } + + bool cCutter::Active(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + if (cuttingThread) { + if (cuttingThread->Active()) + return true; +@@ -257,12 +511,41 @@ + free(editedVersionName); + editedVersionName = NULL; + ended = true; ++#ifdef USE_CUTTERQUEUE ++ if (Setup.CutterAutoDelete) { ++ /* Remove original (if cutting was successful) */ ++ if(!error) { ++ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); ++ if (!recording) ++ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); ++ else { ++ if (recording->Delete()) ++ Recordings.DelByName(recording->FileName()); ++ else ++ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); ++ } ++ } ++ lastCuttingEndTime = cTimeMs::Now(); ++ } ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ + } ++#ifdef USE_CUTTERQUEUE ++ if(!cuttingThread && cutterQueue.First()) { ++ /* start next cutting from queue*/ ++ if(cTimeMs::Now() > lastCuttingEndTime + WAIT_BEFORE_NEXT_CUT) ++ Start(NULL); ++ } ++#endif /* CUTTERQUEUE */ ++ + return false; + } + + bool cCutter::Error(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = error; + error = false; + return result; +@@ -270,6 +553,9 @@ + + bool cCutter::Ended(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = ended; + ended = false; + return result; +diff -ruN vdr-1.7.14/cutter.h vdr-1.7.14.ExtP_NG/cutter.h +--- vdr-1.7.14/cutter.h 2010-01-02 13:09:54.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/cutter.h 2010-04-10 15:45:09.656737920 +0200 +@@ -11,6 +11,9 @@ + #define __CUTTER_H + + class cCuttingThread; ++#ifdef USE_CUTTERQUEUE ++class cMutex; ++#endif /* CUTTERQUEUE */ + + class cCutter { + private: +@@ -18,6 +21,9 @@ + static cCuttingThread *cuttingThread; + static bool error; + static bool ended; ++#ifdef USE_CUTTERQUEUE ++ static cMutex *cutterLock; ++#endif /* CUTTERQUEUE */ + public: + static bool Start(const char *FileName); + static void Stop(void); +diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c +--- vdr-1.7.14/device.c 2010-02-07 12:54:42.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/device.c 2010-04-10 15:45:09.684741026 +0200 +@@ -18,6 +18,12 @@ + #include "receiver.h" + #include "status.h" + #include "transfer.h" ++#ifdef USE_LNBSHARE ++#include "diseqc.h" ++#endif /* LNBSHARE */ ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + // --- cLiveSubtitle --------------------------------------------------------- + +@@ -83,6 +89,12 @@ + + SetVideoFormat(Setup.VideoFormat); + ++#ifdef USE_LNBSHARE ++ LNBstate = -1; ++ LNBnr = Setup.CardUsesLNBnr[cardIndex]; ++ LNBsource = NULL; ++#endif /* LNBSHARE */ ++ + mute = false; + volume = Setup.CurrentVolume; + +@@ -144,6 +156,16 @@ + useDevice |= (1 << n); + } + ++#ifdef USE_LNBSHARE ++void cDevice::SetLNBnr(void) ++{ ++ for (int i = 0; i < numDevices; i++) { ++ device[i]->LNBnr = Setup.CardUsesLNBnr[i]; ++ isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); ++ } ++} ++#endif /* LNBSHARE */ ++ + int cDevice::NextCardIndex(int n) + { + if (n > 0) { +@@ -208,6 +230,98 @@ + return d; + } + ++#ifdef USE_LNBSHARE ++cDevice *cDevice::GetBadDevice(const cChannel *Channel) ++{ ++ if(!cSource::IsSat(Channel->Source())) return NULL; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(cardIndex + 1, Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); ++ } ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); ++ } ++ } else { ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) { ++ requiredState = 1 ; ++ } else { ++ requiredState = 0; ++ } ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); ++ } ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); ++ } ++ } ++ return NULL; ++} ++ ++int cDevice::GetMaxBadPriority(const cChannel *Channel) ++{ ++ if(!cSource::IsSat(Channel->Source())) return -2; ++ bool PrimaryIsBad = false; ++ int maxBadPriority = -2; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(cardIndex + 1, Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) { ++ maxBadPriority = device[i]->Priority(); ++ } ++ if (i == ActualDevice()->CardIndex()) { ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ } else { ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) { ++ requiredState = 1 ; ++ } else { ++ requiredState = 0; ++ } ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) { ++ maxBadPriority = device[i]->Priority(); ++ } ++ if (i == ActualDevice()->CardIndex()) { ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ } ++ if (PrimaryIsBad && maxBadPriority == -2) { ++ maxBadPriority = -1; ++ } ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); ++ } ++ return maxBadPriority; ++} ++#endif /* LNBSHARE */ ++ + cDevice *cDevice::GetDevice(int Index) + { + return (0 <= Index && Index < numDevices) ? device[Index] : NULL; +@@ -236,6 +350,9 @@ + int NumCamSlots = CamSlots.Count(); + int SlotPriority[NumCamSlots]; + int NumUsableSlots = 0; ++#ifdef USE_MCLI ++ bool InternalCamNeeded = false; ++#endif /* MCLI */ + if (Channel->Ca() >= CA_ENCRYPTED_MIN) { + for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) { + SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used +@@ -249,7 +366,11 @@ + } + } + if (!NumUsableSlots) ++#ifdef USE_MCLI ++ InternalCamNeeded = true; // no CAM is able to decrypt this channel ++#else + return NULL; // no CAM is able to decrypt this channel ++#endif /* MCLI */ + } + + bool NeedsDetachReceivers = false; +@@ -257,6 +378,10 @@ + cCamSlot *s = NULL; + + uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact ++#ifdef USE_LNBSHARE ++ int badPriority; ++ uint32_t imp2; ++#endif /* LNBSHARE */ + for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { + if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) + continue; // there is no CAM available in this slot +@@ -265,11 +390,21 @@ + continue; // this device shall be temporarily avoided + if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1) + continue; // a specific card was requested, but not this one ++#ifdef USE_MCLI ++ if (InternalCamNeeded && !device[i]->HasInternalCam()) ++ continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs ++ if (NumUsableSlots && !device[i]->HasInternalCam() && !CamSlots.Get(j)->Assign(device[i], true)) ++#else + if (NumUsableSlots && !CamSlots.Get(j)->Assign(device[i], true)) ++#endif /* MCLI */ + continue; // CAM slot can't be used with this device + bool ndr; + if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job ++#ifdef USE_MCLI ++ if (NumUsableSlots && !device[i]->HasInternalCam() && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j)) ++#else + if (NumUsableSlots && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j)) ++#endif /* MCLI */ + ndr = true; // using a different CAM slot requires detaching receivers + // Put together an integer number that reflects the "impact" using + // this device would have on the overall system. Each condition is represented +@@ -284,18 +419,61 @@ + imp <<= 2; imp |= GetClippedNumProvidedSystems(2, device[i]) - 1; // avoid cards which support multiple delivery systems + imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device + imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) ++#ifdef USE_MCLI ++ imp <<= 8; imp |= min(max(((NumUsableSlots && !device[i]->HasInternalCam()) ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) ++#else + imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) ++#endif /* MCLI */ + imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers + imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device ++#ifdef USE_MCLI ++ imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels ++#else + imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels ++#endif /* MCLI */ + imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards ++#ifdef USE_MCLI ++ imp <<= 1; imp |= (NumUsableSlots && !device[i]->HasInternalCam()) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel ++#else + imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel ++#endif /* MCLI */ ++#ifdef USE_LNBSHARE ++ badPriority = device[i]->GetMaxBadPriority(Channel); ++ if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { ++ // channel is not available for the requested prioity ++ imp = 0xFFFFFFFF; ++ } else { ++ switch (badPriority) { ++ case -2: // not affected by LNB-sharing ++ imp2 = 0; ++ break; ++ case -1: // the primary device would need a channel switch ++ if ( LiveView ) { ++ imp2 = 0; // this has no impact if the new channel is needed for LiveView ++ } else { ++ imp += 1 << 17; ++ imp2 = 0xFFFFFFFF | 1 << 17; ++ } ++ break; ++ default: // a device receiving with lower priority would need to be stopped ++ imp += badPriority << 8; ++ imp2 = 0xFFFFFFFF | badPriority << 8; ++ break; ++ } ++ } ++ if (imp < Impact && imp2 < Impact) { ++#else + if (imp < Impact) { ++#endif /* LNBSHARE */ + // This device has less impact than any previous one, so we take it. + Impact = imp; + d = device[i]; + NeedsDetachReceivers = ndr; ++#ifdef USE_MCLI ++ if (NumUsableSlots && !device[i]->HasInternalCam()) ++#else + if (NumUsableSlots) ++#endif /* MCLI */ + s = CamSlots.Get(j); + } + } +@@ -561,6 +739,13 @@ + return -1; + } + ++#ifdef USE_MCLI ++int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length) ++{ ++ return safe_read(Handle, Buffer, Length); ++} ++#endif /* MCLI */ ++ + void cDevice::CloseFilter(int Handle) + { + close(Handle); +@@ -602,7 +787,11 @@ + bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const + { + for (int i = 0; i < numDevices; i++) { ++#ifdef USE_LNBSHARE ++ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) ++#else + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) ++#endif /* LNBSHARE */ + return false; + } + return true; +@@ -635,6 +824,25 @@ + + bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) + { ++ ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ if (this->GetMaxBadPriority(Channel) >= 0) { ++ Skins.Message(mtInfo, tr("Channel locked by LNB!")); ++ return false; ++ } ++ while ((tmpDevice = GetBadDevice(Channel)) != NULL) { ++ if ((tmpDevice->CardIndex() == ActualDevice()->CardIndex()) && LiveView) ++ tmpDevice->SwitchChannelForced(Channel, true); ++ else ++ tmpDevice->SwitchChannelForced(Channel, false); ++ } ++ return SwitchChannelForced(Channel, LiveView); ++} ++ ++bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) ++{ ++#endif /* LNBSHARE */ + if (LiveView) { + isyslog("switching to channel %d", Channel->Number()); + cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer +@@ -665,6 +873,9 @@ + cChannel *channel; + while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { + // try only channels which are currently available ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, channel) == false) ++#endif /* PINPLUGIN */ + if (GetDevice(channel, 0, true)) + break; + n = channel->Number() + Direction; +@@ -686,6 +897,11 @@ + + eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_PINPLUGIN ++ if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true) ++ return scrNotAvailable; ++#endif /* PINPLUGIN */ ++ + if (LiveView) { + StopReplay(); + DELETENULL(liveSubtitle); +@@ -698,11 +914,39 @@ + + eSetChannelResult Result = scrOk; + ++#ifdef USE_LNBSHARE ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) { ++ requiredState = 1; ++ } else { ++ requiredState = 0; ++ } ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; ++ if (Setup.VerboseLNBlog) { ++ isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); ++ } ++#endif /* LNBSHARE */ ++ + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + + if (NeedsTransferMode) { + if (Device && CanReplay()) { ++ ++#ifdef USE_LNBSHARE ++ if (Device->GetLNBnr() == LNBnr) { ++ if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(cardIndex + 1, Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { ++ if (CardIndex() == ActualDevice()->CardIndex()) { ++ SetChannelDevice(Channel, true); ++ } else { ++ SetChannelDevice(Channel, false); ++ } ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(cardIndex + 1, Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ } ++ } ++#endif /* LNBSHARE */ ++ + cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel + if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! + cControl::Launch(new cTransferControl(Device, Channel)); +@@ -720,6 +964,12 @@ + sectionHandler->SetStatus(false); + sectionHandler->SetChannel(NULL); + } ++ ++#ifdef USE_LNBSHARE ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(cardIndex + 1, Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++#endif /* LNBSHARE */ ++ + // Tell the camSlot about the channel switch and add all PIDs of this + // channel to it, for possible later decryption: + if (camSlot) +@@ -1012,6 +1262,10 @@ + int LanguagePreference = INT_MAX; // higher than the maximum possible value + for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { + const tTrackId *TrackId = GetTrack(eTrackType(i)); ++#ifdef USE_LIEMIEXT ++ if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) || ++ ((i == ttSubtitleFirst + 8) && !(*TrackId->language) && (LanguagePreference == INT_MAX)))) ++#endif /* LIEMIEXT */ + if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) + PreferredTrack = eTrackType(i); + } +@@ -1223,6 +1477,15 @@ + } + break; + case 0xBD: { // private stream 1 ++#ifdef USE_TTXTSUBS ++ // EBU Teletext data, ETSI EN 300 472 ++ // if PES data header length = 24 and data_identifier = 0x10..0x1F (EBU Data) ++ if (Data[8] == 0x24 && Data[45] >= 0x10 && Data[45] < 0x20) { ++ cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uint8_t*)Data, Length); ++ break; ++ } ++#endif /* TTXTSUBS */ ++ + int PayloadOffset = Data[8] + 9; + + // Compatibility mode for old subtitles plugin: +@@ -1382,6 +1645,9 @@ + tsToPesVideo.Reset(); + tsToPesAudio.Reset(); + tsToPesSubtitle.Reset(); ++#ifdef USE_TTXTSUBS ++ tsToPesTeletext.Reset(); ++#endif /* TTXTSUBS */ + } + else if (Length < TS_SIZE) { + esyslog("ERROR: skipped %d bytes of TS fragment", Length); +@@ -1427,6 +1693,19 @@ + if (!VideoOnly || HasIBPTrickSpeed()) + PlayTsSubtitle(Data, TS_SIZE); + } ++#ifdef USE_TTXTSUBS ++ else if (Pid == patPmtParser.Tpid()) { ++ if (!VideoOnly || HasIBPTrickSpeed()) { ++ int l; ++ tsToPesTeletext.PutTs(Data, Length); ++ if (const uchar *p = tsToPesTeletext.GetPes(l)) { ++ if ((l > 45) && (p[0] == 0x00) && (p[1] == 0x00) && (p[2] == 0x01) && (p[3] == 0xbd) && (p[8] == 0x24) && (p[45] >= 0x10) && (p[45] < 0x20)) ++ cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uchar *)p, l, false, patPmtParser.TeletextSubtitlePages(), patPmtParser.TotalTeletextSubtitlePages()); ++ tsToPesTeletext.Reset(); ++ } ++ } ++ } ++#endif /* TTXTSUBS */ + } + } + else if (Pid == patPmtParser.Ppid()) { +diff -ruN vdr-1.7.14/device.h vdr-1.7.14.ExtP_NG/device.h +--- vdr-1.7.14/device.h 2010-02-06 15:34:41.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/device.h 2010-04-10 15:45:09.706728067 +0200 +@@ -24,6 +24,9 @@ + #include "spu.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_ROTOR ++#include <linux/dvb/frontend.h> ++#endif /* ROTOR */ + + #define MAXDEVICES 16 // the maximum number of devices in the system + #define MAXPIDHANDLES 64 // the maximum number of different PIDs per device +@@ -156,6 +159,31 @@ + static void Shutdown(void); + ///< Closes down all devices. + ///< Must be called at the end of the program. ++#ifdef USE_LNBSHARE ++private: ++ char LNBstate; // Current frequency band and polarization of the DVB-tuner ++// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: ++ int *LNBsource; // [DiSEqC] DiSEqC-Source ++ int LNBnr; // Number of LNB used ++public: ++ char GetLNBconf(void) { return LNBstate; } ++ int *GetLNBsource(void) { return LNBsource; } ++ int GetLNBnr(void) { return LNBnr; } ++ static void SetLNBnr(void); ++ cDevice *GetBadDevice(const cChannel *Channel); ++ ///< Returns NULL if there is no device which uses the same LNB or if ++ ///< all of those devices are tuned to the same frequency band and ++ ///< polarization as of the requested channel. ++ ///< Otherwise returns the first device found. ++ int GetMaxBadPriority(const cChannel *Channel); ++ ///< Returns the highest priority of all receiving devices which use ++ ///< the same LNB and are tuned to a different frequency band or ++ ///< polarization as of the requested channel. ++ ///< Returns -1 if there are no such devices, but the primary device ++ ///< would be affected by switching to the requested channel. ++ ///< Returns -2 if there are no such devices and the primary device ++ ///< would not be affected by switching to the requested channel. ++#endif /* LNBSHARE */ + private: + static int nextCardIndex; + int cardIndex; +@@ -261,17 +289,28 @@ + bool SwitchChannel(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given Channel, initiating transfer mode + ///< if necessary. ++#ifdef USE_LNBSHARE ++ bool SwitchChannelForced(const cChannel *Channel, bool LiveView); ++ ///< Switches the device to the given channel, initiating transfer mode ++ ///< if necessary. Forces the switch without taking care of the LNB configuration. ++#endif /* LNBSHARE */ + static bool SwitchChannel(int Direction); + ///< Switches the primary device to the next available channel in the given + ///< Direction (only the sign of Direction is evaluated, positive values + ///< switch to higher channel numbers). + private: ++#ifndef USE_YAEPG + eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (actual physical setup). + public: ++#ifdef USE_YAEPG ++ eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ++ ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } + ///< Returns the number of the current channel on the primary device. + static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } +@@ -289,6 +328,9 @@ + virtual bool HasProgramme(void); + ///< Returns true if the device is currently showing any programme to + ///< the user, either through replaying or live. ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd) {return false;} ++#endif /* ROTOR */ + + // PID handle facilities + +@@ -342,6 +384,12 @@ + ///< Opens a file handle for the given filter data. + ///< A derived device that provides section data must + ///< implement this function. ++#ifdef USE_MCLI ++ virtual int ReadFilter(int Handle, void *Buffer, size_t Length); ++ ///< Read from a handle for the given filter data. ++ ///< a derived class need not implement this function, because this ++ ///< is done by the default implementation. ++#endif /* MCLI */ + virtual void CloseFilter(int Handle); + ///< Closes a file handle that has previously been opened + ///< by OpenFilter(). If this is as simple as calling close(Handle), +@@ -360,6 +408,14 @@ + public: + virtual bool HasCi(void); + ///< Returns true if this device has a Common Interface. ++#ifdef USE_MCLI ++ virtual bool HasInternalCam(void) { return false; } ++ ///< Returns true if this device handles encrypted channels itself ++ ///< without VDR assistance. This can be e.g. when the device is a ++ ///< client that gets the stream from another VDR instance that has ++ ///< already decrypted the stream. In this case ProvidesChannel() ++ ///< shall check whether the channel can be decrypted. ++#endif /* MCLI */ + void SetCamSlot(cCamSlot *CamSlot); + ///< Sets the given CamSlot to be used with this device. + cCamSlot *CamSlot(void) const { return camSlot; } +@@ -519,6 +575,9 @@ + cTsToPes tsToPesVideo; + cTsToPes tsToPesAudio; + cTsToPes tsToPesSubtitle; ++#ifdef USE_TTXTSUBS ++ cTsToPes tsToPesTeletext; ++#endif /* TTXTSUBS */ + bool isPlayingVideo; + protected: + const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; } +diff -ruN vdr-1.7.14/dvbdevice.c vdr-1.7.14.ExtP_NG/dvbdevice.c +--- vdr-1.7.14/dvbdevice.c 2010-03-07 14:58:24.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbdevice.c 2010-04-10 15:45:09.854742151 +0200 +@@ -246,6 +246,9 @@ + class cDvbTuner : public cThread { + private: + enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; ++#ifdef USE_ROTOR ++ bool SendDiseqc; ++#endif /* ROTOR */ + int device; + int fd_frontend; + int adapter, frontend; +@@ -259,6 +262,9 @@ + cMutex mutex; + cCondVar locked; + cCondVar newSet; ++#ifdef USE_ROTOR ++ dvb_diseqc_master_cmd diseqc_cmd; ++#endif /* ROTOR */ + bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); + bool SetFrontend(void); + virtual void Action(void); +@@ -268,6 +274,9 @@ + const cChannel *GetTransponder(void) const { return &channel; } + bool IsTunedTo(const cChannel *Channel) const; + void Set(const cChannel *Channel); ++#ifdef USE_ROTOR ++ bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + bool Locked(int TimeoutMs = 0); + }; + +@@ -275,6 +284,9 @@ + { + device = Device; + fd_frontend = Fd_Frontend; ++#ifdef USE_ROTOR ++ SendDiseqc=false; ++#endif /* ROTOR */ + adapter = Adapter; + frontend = Frontend; + frontendType = FrontendType; +@@ -329,6 +341,19 @@ + return tunerStatus >= tsLocked; + } + ++#ifdef USE_ROTOR ++bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ cMutexLock MutexLock(&mutex); ++ if ((frontendType!=SYS_DVBS2 && frontendType!=SYS_DVBS) || SendDiseqc) ++ return false; ++ diseqc_cmd=cmd; ++ SendDiseqc=true; ++ newSet.Broadcast(); ++ return true; ++} ++#endif /* ROTOR */ ++ + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) + { + if (TimeoutMs) { +@@ -520,6 +545,12 @@ + if (GetFrontendStatus(NewStatus, 10)) + Status = NewStatus; + cMutexLock MutexLock(&mutex); ++#ifdef USE_ROTOR ++ if (SendDiseqc) { ++ CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd)); ++ SendDiseqc=false; ++ } ++#endif /* ROTOR */ + switch (tunerStatus) { + case tsIdle: + break; +@@ -898,10 +929,25 @@ + + bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const + { ++#ifdef USE_CHANNELPROVIDE ++ if (Setup.LocalChannelProvide != 1) ++ return false; ++#endif /* CHANNELPROVIDE */ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority(); + bool needsDetachReceivers = false; + ++#ifdef USE_CHANNELBIND ++ if (Setup.ChannelBindingByRid && Channel->Rid()) { ++ if (0 == ((unsigned) Channel->Rid() & (1<<(unsigned) CardIndex())) ) { ++ #if 0 ++ printf("device %d doesn't provide channel %s", CardIndex(), *Channel->ToText()); ++ #endif ++ return false; ++ } ++ } ++#endif /* CHANNELBIND */ ++ + if (ProvidesTransponder(Channel)) { + result = hasPriority; + if (Priority >= 0 && Receiving(true)) { +@@ -956,6 +1002,13 @@ + return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false; + } + ++#ifdef USE_ROTOR ++bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ return dvbTuner->SendDiseqcCmd(cmd); ++} ++#endif /* ROTOR */ ++ + void cDvbDevice::SetTransferModeForDolbyDigital(int Mode) + { + setTransferModeForDolbyDigital = Mode; +diff -ruN vdr-1.7.14/dvbdevice.h vdr-1.7.14.ExtP_NG/dvbdevice.h +--- vdr-1.7.14/dvbdevice.h 2010-02-21 15:06:08.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbdevice.h 2010-04-10 15:45:09.863735987 +0200 +@@ -146,6 +146,9 @@ + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + public: + virtual bool HasLock(int TimeoutMs = 0); ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruN vdr-1.7.14/dvbplayer.c vdr-1.7.14.ExtP_NG/dvbplayer.c +--- vdr-1.7.14/dvbplayer.c 2010-03-07 15:24:26.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbplayer.c 2010-04-10 15:45:09.881743306 +0200 +@@ -204,6 +204,9 @@ + cNonBlockingFileReader *nonBlockingFileReader; + cRingBufferFrame *ringBuffer; + cPtsIndex ptsIndex; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#endif /* JUMPPLAY */ + cFileName *fileName; + cIndexFile *index; + cUnbufferedFile *replayFile; +@@ -250,7 +253,11 @@ + int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + + cDvbPlayer::cDvbPlayer(const char *FileName) ++#ifdef USE_JUMPPLAY ++:cThread("dvbplayer"), marks(FileName) ++#else + :cThread("dvbplayer") ++#endif /* JUMPPLAY */ + { + nonBlockingFileReader = NULL; + ringBuffer = NULL; +@@ -360,6 +367,12 @@ + if (index) { + int Index = ptsIndex.FindIndex(DeviceGetSTC()); + if (Index >= 0) { ++#ifdef USE_JUMPPLAY ++ // set resume position to 0 if replay stops at the first mark ++ if (Setup.PlayJump && marks.First() && ++ abs(Index - marks.First()->position) <= int(round(RESUMEBACKUP * framesPerSecond))) ++ Index = 0; ++#endif /* JUMPPLAY */ + Index -= int(round(RESUMEBACKUP * framesPerSecond)); + if (Index > 0) + Index = index->GetNextIFrame(Index, false); +@@ -386,11 +399,30 @@ + { + uchar *p = NULL; + int pc = 0; ++#ifdef USE_JUMPPLAY ++ bool cutIn = false; ++ int total = -1; ++#endif /* JUMPPLAY */ + + readIndex = Resume(); + if (readIndex >= 0) + isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, framesPerSecond)); + ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { ++ int Index = marks.First()->position; ++ uint16_t FileNumber; ++ off_t FileOffset; ++ if (index->Get(Index, &FileNumber, &FileOffset) && ++ NextFile(FileNumber, FileOffset)) { ++ isyslog("PlayJump: start replay at first mark %d (%s)", ++ Index, *IndexToHMSF(Index, true, framesPerSecond)); ++ readIndex = Index; ++ } ++ } ++ ++ bool LastMarkPause = false; ++#endif /* JUMPPLAY */ + nonBlockingFileReader = new cNonBlockingFileReader; + int Length = 0; + bool Sleep = false; +@@ -415,7 +447,11 @@ + + // Read the next frame from the file: + ++#ifdef USE_JUMPPLAY ++ if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { ++#else + if (playMode != pmStill && playMode != pmPause) { ++#endif /* JUMPPLAY */ + if (!readFrame && (replayFile || readIndex >= 0)) { + if (!nonBlockingFileReader->Reading()) { + if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) { +@@ -452,6 +488,46 @@ + else if (index) { + uint16_t FileNumber; + off_t FileOffset; ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump || Setup.PauseLastMark) { ++ // check for end mark - jump to next mark or pause ++ readIndex++; ++ marks.Reload(); ++ cMark *m = marks.Get(readIndex); ++ if (m && (m->Index() & 0x01) != 0) { ++ m = marks.Next(m); ++ int Index; ++ if (m) ++ Index = m->position; ++ else if (Setup.PauseLastMark) { ++ // pause at last mark ++ isyslog("PauseLastMark: pause at position %d (%s)", ++ readIndex, *IndexToHMSF(readIndex, true, framesPerSecond)); ++ LastMarkPause = true; ++ Index = -1; ++ } ++ else if (total == index->Last()) ++ // at last mark jump to end of recording ++ Index = index->Last() - 1; ++ else ++ // jump but stay off end of live-recordings ++ Index = index->GetNextIFrame(index->Last() - int(round(MAXSTUCKATEOF * framesPerSecond)), true); ++ // don't jump in edited recordings ++ if (Setup.PlayJump && Index > readIndex && ++ Index > index->GetNextIFrame(readIndex, true)) { ++ isyslog("PlayJump: %d frames to %d (%s)", ++ Index - readIndex, Index, ++ *IndexToHMSF(Index, true, framesPerSecond)); ++ readIndex = Index; ++ cutIn = true; ++ } ++ } ++ readIndex--; ++ } ++ // for detecting growing length of live-recordings ++ if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent) && readIndependent) ++ total = index->Last(); ++#endif /* JUMPPLAY */ + if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset)) + readIndex++; + else +@@ -496,6 +572,15 @@ + // Store the frame in the buffer: + + if (readFrame) { ++#ifdef USE_JUMPPLAY ++ if (cutIn) { ++ if (isPesRecording) ++ cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); ++ else ++ TsSetTeiOnBrokenPackets(readFrame->Data(), readFrame->Count()); ++ cutIn = false; ++ } ++#endif /* JUMPPLAY */ + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + else +@@ -561,8 +646,19 @@ + p = NULL; + } + } ++#ifdef USE_JUMPPLAY ++ else { ++ if (LastMarkPause) { ++ LastMarkPause = false; ++ playMode = pmPause; ++ } ++#else + else ++#endif /* JUMPPLAY */ + Sleep = true; ++#ifdef USE_JUMPPLAY ++ } ++#endif /* JUMPPLAY */ + + // Handle hitting begin/end of recording: + +diff -ruN vdr-1.7.14/eit.c vdr-1.7.14.ExtP_NG/eit.c +--- vdr-1.7.14/eit.c 2010-01-08 16:17:09.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/eit.c 2010-04-10 15:45:09.958741231 +0200 +@@ -24,8 +24,31 @@ + class cEIT : public SI::EIT { + public: + cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus = false); ++#ifdef USE_NOEPG ++private: ++ bool allowedEPG(tChannelID kanalID); ++#endif /* NOEPG */ + }; + ++#ifdef USE_NOEPG ++bool cEIT::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 */ ++ + cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) + :SI::EIT(Data, false) + { +@@ -37,6 +60,14 @@ + if (!channel) + return; // only collect data for known channels + ++#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; +@@ -83,7 +114,87 @@ + uchar TableID = pEvent->TableID(); + if (TableID == 0x00) { + if (pEvent->Version() == getVersionNumber()) ++#ifdef USE_DDEPGENTRY ++ { ++ 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 ++ continue; ++#endif /* DDEPGENTRY */ + HasExternalData = ExternalData = true; + } + // If the new event has a higher table ID, let's skip it. +@@ -108,7 +219,11 @@ + 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) +@@ -297,6 +412,82 @@ + 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), "%s", pEvent->ShortText()); ++ ++ if (pPreviousEvent->ShortText()) ++ len_short_extern = snprintf (buffer_short_extern, sizeof(buffer_short_extern), "%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), "%s", pEvent->Description()); ++ ++ if (pPreviousEvent->Description()) ++ len_title_extern = snprintf (buffer_title_extern, sizeof(buffer_title_extern), "%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 */ + } + if (Tid == 0x4E) { + if (Empty && getSectionNumber() == 0) +diff -ruN vdr-1.7.14/eitscan.c vdr-1.7.14.ExtP_NG/eitscan.c +--- vdr-1.7.14/eitscan.c 2010-02-07 13:12:05.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/eitscan.c 2010-04-10 15:45:09.980739226 +0200 +@@ -151,9 +151,17 @@ + if (Device->ProvidesTransponder(Channel)) { + if (!Device->Receiving()) { + bool MaySwitchTransponder = Device->MaySwitchTransponder(); ++#ifdef USE_LNBSHARE ++ if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#else + if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#endif /* LNBSHARE */ + if (!MaySwitchTransponder) { ++#ifdef USE_LNBSHARE ++ if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { ++#else + if (Device == cDevice::ActualDevice() && !currentChannel) { ++#endif /* LNBSHARE */ + cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode + currentChannel = Device->CurrentChannel(); + Skins.Message(mtInfo, tr("Starting EPG scan")); +diff -ruN vdr-1.7.14/epg.c vdr-1.7.14.ExtP_NG/epg.c +--- vdr-1.7.14/epg.c 2010-02-28 15:24:55.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/epg.c 2010-04-10 15:45:10.017741115 +0200 +@@ -930,6 +930,31 @@ + return pe; + } + ++#ifdef USE_DDEPGENTRY ++const cEvent *cSchedule::GetPreviousEvent(cEvent *Event) const ++{ ++ ++ if(!Event || Event->Duration() == 0 || Event->StartTime() == 0) ++ return NULL; ++ // Returns either the event info to the previous/following event to the given EventID or, if that one can't be found NULL :EW ++ cEvent *pt = NULL; ++ int epgTimeDelta = Setup.DoubleEpgTimeDelta * 60 + 1; ++ for (pt = events.First(); pt; pt = events.Next(pt)) ++ if(pt && pt->TableID() == 0x00) ++ if ((Event->StartTime() - pt->StartTime()) > - epgTimeDelta && (Event->StartTime() - pt->StartTime()) < epgTimeDelta) ++ { ++ if((pt->Duration() + (pt->Duration()/ 5) + 1) > Event->Duration() && (pt->Duration() - (pt->Duration()/ 5) - 1) < Event->Duration()) ++ return pt; ++ else if (pt->Title() && Event->Title() && (strcmp(pt->Title(), ".") != 0 && strcmp(Event->Title(), ".") != 0)) ++ { ++ if (strstr(pt->Title(), Event->Title()) != NULL || strstr(Event->Title(), pt->Title()) != NULL) ++ return pt; ++ } ++ } ++ return NULL; ++} ++#endif /* DDEPGENTRY */ ++ + void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel) + { + hasRunning = false; +diff -ruN vdr-1.7.14/epg.h vdr-1.7.14.ExtP_NG/epg.h +--- vdr-1.7.14/epg.h 2010-01-08 16:20:34.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/epg.h 2010-04-10 15:45:10.027736473 +0200 +@@ -163,6 +163,9 @@ + void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); + void Cleanup(time_t Time); + void Cleanup(void); ++#ifdef USE_DDEPGENTRY ++ const cEvent *GetPreviousEvent(cEvent *Event) const; //:EW ++#endif /* DDEPGENTRY */ + cEvent *AddEvent(cEvent *Event); + void DelEvent(cEvent *Event); + void HashEvent(cEvent *Event); +diff -ruN vdr-1.7.14/iconpatch.c vdr-1.7.14.ExtP_NG/iconpatch.c +--- vdr-1.7.14/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/iconpatch.c 2010-04-10 15:45:10.336740261 +0200 +@@ -0,0 +1,31 @@ ++#ifdef USE_WAREAGLEICON ++ ++#include "iconpatch.h" ++ ++#include <langinfo.h> ++#include <locale.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++bool IsLangUtf8(void) ++{ ++ char *CodeSet = NULL; ++ if (setlocale(LC_CTYPE, "")) ++ CodeSet = nl_langinfo(CODESET); ++ else { ++ char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed ++ if (LangEnv) { ++ CodeSet = strchr(LangEnv, '.'); ++ if (CodeSet) ++ CodeSet++; // skip the dot ++ } ++ } ++ ++ if (CodeSet && strcasestr(CodeSet, "UTF-8") != 0) ++ return true; ++ ++ return false; ++} ++ ++#endif /* WAREAGLEICON */ +diff -ruN vdr-1.7.14/iconpatch.h vdr-1.7.14.ExtP_NG/iconpatch.h +--- vdr-1.7.14/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/iconpatch.h 2010-04-10 15:45:10.348737591 +0200 +@@ -0,0 +1,73 @@ ++#ifdef USE_WAREAGLEICON ++/* ++ * iconpatch.h: Information of iconpatch ++ * ++ * Diese Datei ist die Übersichtsdatei für den Iconpatch. ++ * Hier werden kleine Infos abgelegt. ++ * Der Iconpatch ändert die Dateien: ++ * iconpatch.h ++ * menu.c ++ * recording.c ++ * fontosd.c ++ * ++ */ ++ ++// Iconpatch-Variablen - Anfang ++#define ICON_NUMBERSIGN "\x23" ++#define ICON_ASTERISK "\x2A" ++#define ICON_GREATER "\x3E" ++#define ICON_EXCLAM "\x21" ++#define ICON_PLUSMINUS "\xB1" ++ ++#define ICON_RESUME "\x80" ++#define ICON_DVD "\x81" ++#define ICON_FOLDER "\x82" ++#define ICON_BLANK "\x83" ++#define ICON_CUTTING "\x84" ++#define ICON_MOVE_FILE "\x85" ++#define ICON_MOVE_FOLDER "\x86" ++#define ICON_BAR_START "\x87" ++#define ICON_BAR_FILLED "\x88" ++#define ICON_BAR_CLEAR "\x89" ++#define ICON_BAR_END "\x8A" ++#define ICON_REC "\x8B" ++#define ICON_CLOCK "\x8C" ++#define ICON_TV_CRYPTED "\x8D" ++#define ICON_RADIO "\x8E" ++#define ICON_TV "\x8F" ++#define ICON_NEW "\x90" ++#define ICON_ARROW "\x91" ++#define ICON_RUNNING "\x92" ++#define ICON_VPS "\x93" ++#define ICON_CLOCK_UH "\x94" ++#define ICON_CLOCK_LH "\x95" ++ ++// UTF-8 Icons ++#define ICON_RESUME_UTF8 "\uE000" ++#define ICON_DVD_UTF8 "\uE001" ++#define ICON_FOLDER_UTF8 "\uE002" ++#define ICON_BLANK_UTF8 "\uE003" ++#define ICON_CUTTING_UTF8 "\uE004" ++#define ICON_MOVE_FILE_UTF8 "\uE005" ++#define ICON_MOVE_FOLDER_UTF8 "\uE006" ++#define ICON_BAR_START_UTF8 "\uE007" ++#define ICON_BAR_FILLED_UTF8 "\uE008" ++#define ICON_BAR_EMPTY_UTF8 "\uE009" ++#define ICON_BAR_CLOSE_UTF8 "\uE00A" ++#define ICON_REC_UTF8 "\uE00B" ++#define ICON_CLOCK_UTF8 "\uE00C" ++#define ICON_TV_CRYPTED_UTF8 "\uE00D" ++#define ICON_RADIO_UTF8 "\uE00E" ++#define ICON_TV_UTF8 "\uE00F" ++#define ICON_NEW_UTF8 "\uE010" ++#define ICON_ARROW_UTF8 "\uE011" ++#define ICON_RUNNING_UTF8 "\uE012" ++#define ICON_VPS_UTF8 "\uE013" ++#define ICON_CLOCK_UH_UTF8 "\uE014" ++#define ICON_CLOCK_LH_UTF8 "\uE015" ++ ++// Iconpatch-Variablen - Ende ++ ++bool IsLangUtf8(void); ++ ++#endif /* WAREAGLEICON */ +diff -ruN vdr-1.7.14/lirc.c vdr-1.7.14.ExtP_NG/lirc.c +--- vdr-1.7.14/lirc.c 2006-05-28 10:48:13.000000000 +0200 ++++ vdr-1.7.14.ExtP_NG/lirc.c 2010-04-10 15:45:10.452737940 +0200 +@@ -12,6 +12,10 @@ + #include "lirc.h" + #include <netinet/in.h> + #include <sys/socket.h> ++#ifdef USE_LIRCSETTINGS ++#include "config.h" ++#endif /* LIRCSETTINGS */ ++ + + #define REPEATDELAY 350 // ms + #define REPEATFREQ 100 // ms +@@ -94,7 +98,11 @@ + continue; + } + if (count == 0) { ++#ifdef USE_LIRCSETTINGS ++ if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast + if (repeat) + Put(LastKeyName, false, true); +@@ -104,18 +112,34 @@ + timeout = -1; + } + else { ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) ++#else + if (LastTime.Elapsed() < REPEATFREQ) ++#endif /* LIRCSETTINGS */ + continue; // repeat function kicks in after a short delay (after last key instead of first key) ++#ifdef USE_LIRCSETTINGS ++ if (FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast (for count != 0 as well) + repeat = true; ++#ifdef USE_LIRCSETTINGS ++ timeout = Setup.LircRepeatDelay; ++#else + timeout = REPEATDELAY; ++#endif /* LIRCSETTINGS */ + } + LastTime.Set(); + Put(KeyName, repeat); + } + else if (repeat) { // the last one was a repeat, so let's generate a release ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() >= (unsigned int)Setup.LircRepeatTimeout) { ++#else + if (LastTime.Elapsed() >= REPEATTIMEOUT) { ++#endif /* LIRCSETTINGS */ + Put(LastKeyName, false, true); + repeat = false; + *LastKeyName = 0; +diff -ruN vdr-1.7.14/mainmenuitemsprovider.h vdr-1.7.14.ExtP_NG/mainmenuitemsprovider.h +--- vdr-1.7.14/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/mainmenuitemsprovider.h 2010-04-10 15:45:10.477763751 +0200 +@@ -0,0 +1,62 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MAINMENUITEMSPROVIDER_H ++#define __MAINMENUITEMSPROVIDER_H ++ ++#include <vector> ++ ++class cOsdItem; ++class cOsdMenu; ++ ++class IMenuItemDefinition ++{ ++ public: ++ virtual ~IMenuItemDefinition() {}; ++ virtual bool IsCustomOsdItem() = 0; ++ virtual bool IsPluginItem() = 0; ++ virtual bool IsSeparatorItem() = 0; ++ virtual cOsdItem* CustomOsdItem() = 0; ++ virtual const char* PluginMenuEntry() = 0; ++ virtual bool IsSelected() = 0; ++ virtual int PluginIndex() = 0; ++}; ++ ++typedef std::vector<IMenuItemDefinition*> MenuItemDefinitions; ++ ++#define MENU_ITEMS_PROVIDER_SERVICE_ID "MenuOrgPatch-v0.4.2::MainMenuItemsProvider" ++ ++class IMainMenuItemsProvider ++{ ++ public: ++ virtual ~IMainMenuItemsProvider() {}; ++ virtual bool IsCustomMenuAvailable() = 0; ++ virtual MenuItemDefinitions* MainMenuItems() = 0; ++ virtual void EnterRootMenu() = 0; ++ virtual void EnterSubMenu(cOsdItem* item) = 0; ++ virtual bool LeaveSubMenu() = 0; ++ virtual cOsdMenu* Execute(cOsdItem* item) = 0; ++}; ++ ++#endif //__MAINMENUITEMSPROVIDER_H ++#endif /* MENUORG */ +diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c +--- vdr-1.7.14/menu.c 2010-03-12 17:03:07.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/menu.c 2010-04-10 15:45:10.637743132 +0200 +@@ -8,6 +8,9 @@ + */ + + #include "menu.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <limits.h> + #include <math.h> +@@ -31,6 +34,9 @@ + #include "timers.h" + #include "transfer.h" + #include "videodir.h" ++#ifdef USE_MENUORG ++#include "menuorgpatch.h" ++#endif /* MENUORG */ + + #define MAXWAIT4EPGINFO 3 // seconds + #define MODETIMEOUT 3 // seconds +@@ -203,6 +209,9 @@ + public: + cMenuEditChannel(cChannel *Channel, bool New = false); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEditChannel"; } ++#endif /* GRAPHTFT */ + }; + + cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New) +@@ -249,6 +258,9 @@ + Add(new cMenuEditIntItem( tr("Tid"), &data.tid, 0)); + Add(new cMenuEditIntItem( tr("Rid"), &data.rid, 0)); + XXX*/ ++#ifdef USE_CHANNELBIND ++ Add(new cMenuEditIntItem( tr("Rid"), &data.rid, 0)); // channel binding patch ++#endif /* CHANNELBIND */ + // Parameters for specific types of sources: + sourceParam = SourceParams.Get(**cSource::ToString(data.source)); + if (sourceParam) { +@@ -349,6 +361,16 @@ + if (!channel->GroupSep()) { + if (sortMode == csmProvider) + buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name()); ++#ifdef USE_WAREAGLEICON ++ else if (Setup.WarEagleIcons) { ++ if (channel->Vpid() == 1 || channel->Vpid() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name()); ++ else if (channel->Ca() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name()); ++ else ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_CRYPTED_UTF8 : ICON_TV_CRYPTED, channel->Name()); ++ } ++#endif /* WAREAGLEICON */ + else + buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name()); + } +@@ -379,6 +401,9 @@ + cMenuChannels(void); + ~cMenuChannels(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuChannels"; } ++#endif /* GRAPHTFT */ + }; + + cMenuChannels::cMenuChannels(void) +@@ -917,6 +942,17 @@ + Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); ++ else { ++ char* buf = 0; ++ if (asprintf(&buf, "%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")) > 0) { ++ Add(new cOsdItem(buf)); ++ free(buf); ++ } ++ } ++ ++#endif /* PINPLUGIN */ + Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); + SetFirstDayItem(); + } +@@ -1017,8 +1053,14 @@ + class cMenuTimerItem : public cOsdItem { + private: + cTimer *timer; ++#ifdef USE_TIMERINFO ++ char diskStatus; ++#endif /* TIMERINFO */ + public: + cMenuTimerItem(cTimer *Timer); ++#ifdef USE_TIMERINFO ++ void SetDiskStatus(char DiskStatus); ++#endif /* TIMERINFO */ + virtual int Compare(const cListObject &ListObject) const; + virtual void Set(void); + cTimer *Timer(void) { return timer; } +@@ -1027,6 +1069,9 @@ + cMenuTimerItem::cMenuTimerItem(cTimer *Timer) + { + timer = Timer; ++#ifdef USE_TIMERINFO ++ diskStatus = ' '; ++#endif /* TIMERINFO */ + Set(); + } + +@@ -1057,8 +1102,31 @@ + File++; + else + File = timer->File(); ++#ifdef USE_WAREAGLEICON ++#ifdef USE_TIMERINFO ++ cCharSetConv csc("ISO-8859-1", cCharSetConv::SystemCharacterTable()); ++ char diskStatusString[2] = { diskStatus, 0 }; ++ SetText(cString::sprintf("%s%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++ csc.Convert(diskStatusString), ++#else ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* TIMERINFO */ ++#else ++#ifdef USE_TIMERINFO ++ cCharSetConv csc("ISO-8859-1", cCharSetConv::SystemCharacterTable()); ++ char diskStatusString[2] = { diskStatus, 0 }; ++ SetText(cString::sprintf("%s%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++ csc.Convert(diskStatusString), ++#else + SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* TIMERINFO */ ++#endif /* WAREAGLEICON */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++ ++#else + !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ + timer->Channel()->Number(), + *name, + *name && **name ? " " : "", +@@ -1070,6 +1138,58 @@ + File)); + } + ++#ifdef USE_TIMERINFO ++void cMenuTimerItem::SetDiskStatus(char DiskStatus) ++{ ++ diskStatus = DiskStatus; ++ Set(); ++} ++ ++// --- cTimerEntry ----------------------------------------------------------- ++ ++class cTimerEntry : public cListObject { ++private: ++ cMenuTimerItem *item; ++ const cTimer *timer; ++ time_t start; ++public: ++ cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {} ++ cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {} ++ virtual int Compare(const cListObject &ListObject) const; ++ bool active(void) const { return timer->HasFlags(tfActive); } ++ time_t startTime(void) const { return start; } ++ int priority(void) const { return timer->Priority(); } ++ int duration(void) const; ++ bool repTimer(void) const { return !timer->IsSingleEvent(); } ++ bool isDummy(void) const { return item == NULL; } ++ const cTimer *Timer(void) const { return timer; } ++ void SetDiskStatus(char DiskStatus); ++ }; ++ ++int cTimerEntry::Compare(const cListObject &ListObject) const ++{ ++ cTimerEntry *entry = (cTimerEntry *)&ListObject; ++ int r = startTime() - entry->startTime(); ++ if (r == 0) ++ r = entry->priority() - priority(); ++ return r; ++} ++ ++int cTimerEntry::duration(void) const ++{ ++ int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) - ++ (timer->Start() / 100 * 60 + timer->Start() % 100); ++ if (dur < 0) ++ dur += 24 * 60; ++ return dur; ++} ++ ++void cTimerEntry::SetDiskStatus(char DiskStatus) ++{ ++ if (item) ++ item->SetDiskStatus(DiskStatus); ++} ++#endif /* TIMERINFO */ + // --- cMenuTimers ----------------------------------------------------------- + + class cMenuTimers : public cOsdMenu { +@@ -1082,14 +1202,25 @@ + eOSState Info(void); + cTimer *CurrentTimer(void); + void SetHelpKeys(void); ++#ifdef USE_TIMERINFO ++ void ActualiseDiskStatus(void); ++ bool actualiseDiskStatus; ++#endif /* TIMERINFO */ + public: + cMenuTimers(void); + virtual ~cMenuTimers(); ++#ifdef USE_TIMERINFO ++ virtual void Display(void); ++#endif /* TIMERINFO */ + virtual eOSState ProcessKey(eKeys Key); + }; + + cMenuTimers::cMenuTimers(void) ++#ifdef USE_TIMERINFO ++:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6) ++#else + :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) ++#endif /* TIMERINFO */ + { + helpKeys = -1; + for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { +@@ -1100,6 +1231,9 @@ + SetCurrent(First()); + SetHelpKeys(); + Timers.IncBeingEdited(); ++#ifdef USE_TIMERINFO ++ actualiseDiskStatus = true; ++#endif /* TIMERINFO */ + } + + cMenuTimers::~cMenuTimers() +@@ -1138,7 +1272,11 @@ + timer->OnOff(); + timer->SetEventFromSchedule(); + RefreshCurrent(); ++#ifdef USE_TIMERINFO ++ Display(); ++#else + DisplayCurrent(true); ++#endif /* TIMERINFO */ + if (timer->FirstDay()) + isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); + else +@@ -1197,6 +1335,68 @@ + return osContinue; + } + ++#ifdef USE_TIMERINFO ++void cMenuTimers::ActualiseDiskStatus(void) ++{ ++ if (!actualiseDiskStatus || !Count()) ++ return; ++ ++ // compute free disk space ++ int freeMB, freeMinutes, runshortMinutes; ++ VideoDiskSpace(&freeMB); ++ freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent ++ runshortMinutes = freeMinutes / 5; // 20 Percent ++ ++ // fill entries list ++ cTimerEntry *entry; ++ cList<cTimerEntry> entries; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ entries.Add(new cTimerEntry((cMenuTimerItem *)item)); ++ ++ // search last start time ++ time_t last = 0; ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ last = max(entry->startTime(), last); ++ ++ // add entries for repeating timers ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ if (entry->repTimer() && !entry->isDummy()) ++ for (time_t start = cTimer::IncDay(entry->startTime(), 1); ++ start <= last; ++ start = cTimer::IncDay(start, 1)) ++ if (entry->Timer()->DayMatches(start)) ++ entries.Add(new cTimerEntry(entry->Timer(), start)); ++ ++ // set the disk-status ++ entries.Sort(); ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) { ++ char status = ' '; ++ if (entry->active()) { ++ freeMinutes -= entry->duration(); ++ status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? 177 /* +/- */ : '-'; ++ } ++ entry->SetDiskStatus(status); ++#ifdef DEBUG_TIMER_INFO ++ dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d", ++ status, ++ entry->startTime(), ++ entry->active() ? "aktiv " : "n.akt.", ++ entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ", ++ entry->duration(), ++ entry->active() ? freeMinutes + entry->duration() : freeMinutes, ++ freeMinutes); ++#endif ++ } ++ ++ actualiseDiskStatus = false; ++} ++ ++void cMenuTimers::Display(void) ++{ ++ ActualiseDiskStatus(); ++ cOsdMenu::Display(); ++} ++#endif /* TIMERINFO */ + eOSState cMenuTimers::ProcessKey(eKeys Key) + { + int TimerNumber = HasSubMenu() ? Count() : -1; +@@ -1205,18 +1405,36 @@ + if (state == osUnknown) { + switch (Key) { + case kOk: return Edit(); ++#ifdef USE_TIMERINFO ++ case kRed: actualiseDiskStatus = true; ++ state = OnOff(); break; // must go through SetHelpKeys()! ++#else + case kRed: state = OnOff(); break; // must go through SetHelpKeys()! ++#endif /* TIMERINFO */ + case kGreen: return New(); ++#ifdef USE_TIMERINFO ++ case kYellow: actualiseDiskStatus = true; ++ state = Delete(); break; ++#else + case kYellow: state = Delete(); break; ++#endif /* TIMERINFO */ + case kInfo: + case kBlue: return Info(); + break; + default: break; + } + } ++#ifdef USE_TIMERINFO ++ if (TimerNumber >= 0 && !HasSubMenu()) { ++ if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok ++ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++ Sort(); ++ actualiseDiskStatus = true; ++#else + if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) { + // a newly created timer was confirmed with Ok + Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++#endif /* TIMERINFO */ + Display(); + } + if (Key != kNone) +@@ -1246,6 +1464,9 @@ + { + cOsdMenu::Display(); + DisplayMenu()->SetEvent(event); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetEvent(event); ++#endif /* GRAPHTFT */ + if (event->Description()) + cStatus::MsgOsdTextItem(event->Description()); + } +@@ -1293,7 +1514,12 @@ + const cChannel *channel; + bool withDate; + int timerMatch; ++#ifdef USE_LIEMIEXT ++ bool withBar; ++ cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false); ++#else + cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false); ++#endif /* LIEMIEXT */ + static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } + static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } + static eScheduleSortMode SortMode(void) { return sortMode; } +@@ -1303,12 +1529,19 @@ + + cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; + ++#ifdef USE_LIEMIEXT ++cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate, bool WithBar) ++#else + cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate) ++#endif /* LIEMIEXT */ + { + event = Event; + channel = Channel; + withDate = WithDate; + timerMatch = tmNone; ++#ifdef USE_LIEMIEXT ++ withBar = WithBar; ++#endif /* LIEMIEXT */ + Update(true); + } + +@@ -1323,7 +1556,30 @@ + return r; + } + ++#ifdef USE_WAREAGLEICON ++static const char *TimerMatchChars[9] = ++{ ++ " ", "t", "T", ++ ICON_BLANK, ICON_CLOCK_UH, ICON_CLOCK, ++ ICON_BLANK_UTF8, ICON_CLOCK_UH_UTF8, ICON_CLOCK_UTF8 ++}; ++#else + static const char *TimerMatchChars = " tT"; ++#endif /* WAREAGLEICON */ ++ ++#ifdef USE_LIEMIEXT ++static const char * const ProgressBar[7] = ++{ ++ "[ ]", ++ "[| ]", ++ "[|| ]", ++ "[||| ]", ++ "[|||| ]", ++ "[||||| ]", ++ "[||||||]" ++}; ++ ++#endif /* LIEMIEXT */ + + bool cMenuScheduleItem::Update(bool Force) + { +@@ -1332,17 +1588,54 @@ + Timers.GetMatch(event, &timerMatch); + if (Force || timerMatch != OldTimerMatch) { + cString buffer; ++#ifdef USE_WAREAGLEICON ++ const char *t = Setup.WarEagleIcons ? IsLangUtf8() ? TimerMatchChars[timerMatch+6] : TimerMatchChars[timerMatch+3] : TimerMatchChars[timerMatch]; ++ const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " "; ++ const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " "; ++#else + char t = TimerMatchChars[timerMatch]; + char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; + char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + const char *csn = channel ? channel->ShortName(true) : NULL; + cString eds = event->GetDateString(); + if (channel && withDate) ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + else if (channel) ++#ifdef USE_LIEMIEXT ++ if (Setup.ShowProgressBar && withBar) { ++ int progress = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 6.0 ); ++ if (progress < 0) progress = 0; ++ else if (progress > 6) progress = 6; ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++ } ++ else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#endif /* LIEMIEXT */ + else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + SetText(buffer); + result = true; + } +@@ -1368,13 +1661,21 @@ + static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } + static const cEvent *ScheduleEvent(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return now ? "MenuWhatsOnNow" : "MenuWhatsOnNext"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + int cMenuWhatsOn::currentChannel = 0; + const cEvent *cMenuWhatsOn::scheduleEvent = NULL; + + cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4, 4) ++#else + :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) ++#endif /* LIEMIEXT */ + { + now = Now; + helpKeys = -1; +@@ -1386,7 +1687,11 @@ + if (Schedule) { + const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); + if (Event) ++#ifdef USE_LIEMIEXT ++ Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr); ++#else + Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr); ++#endif /* LIEMIEXT */ + } + } + } +@@ -1395,6 +1700,20 @@ + SetHelpKeys(); + } + ++#ifdef USE_GRAPHTFT ++void cMenuWhatsOn::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) { ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++ } ++} ++#endif /* GRAPHTFT */ ++ + bool cMenuWhatsOn::Update(void) + { + bool result = false; +@@ -1535,6 +1854,10 @@ + cMenuSchedule(void); + virtual ~cMenuSchedule(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSchedule"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + cMenuSchedule::cMenuSchedule(void) +@@ -1560,6 +1883,20 @@ + cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared + } + ++#ifdef USE_GRAPHTFT ++void cMenuSchedule::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) { ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++ } ++} ++#endif /* GRAPHTFT */ ++ + void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) + { + Clear(); +@@ -1915,6 +2252,9 @@ + cMenuCam(cCamSlot *CamSlot); + virtual ~cMenuCam(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuCam::cMenuCam(cCamSlot *CamSlot) +@@ -2094,6 +2434,9 @@ + cMenuRecording(const cRecording *Recording, bool WithButtons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecording"; } ++#endif /* GRAPHTFT */ + }; + + cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) +@@ -2109,6 +2452,9 @@ + { + cOsdMenu::Display(); + DisplayMenu()->SetRecording(recording); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetRecording(recording); ++#endif /* GRAPHTFT */ + if (recording->Info()->Description()) + cStatus::MsgOsdTextItem(recording->Info()->Description()); + } +@@ -2169,7 +2515,11 @@ + fileName = strdup(Recording->FileName()); + name = NULL; + totalEntries = newEntries = 0; ++#ifdef USE_LIEMIEXT ++ SetText(Recording->Title('\t', true, Level, false)); ++#else + SetText(Recording->Title('\t', true, Level)); ++#endif /* LIEMIEXT */ + if (*Text() == '\t') + name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' + } +@@ -2185,13 +2535,183 @@ + totalEntries++; + if (New) + newEntries++; ++#ifdef USE_LIEMIEXT ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++} ++ ++// --- cMenuRenameRecording -------------------------------------------------- ++ ++class cMenuRenameRecording : public cOsdMenu { ++private: ++ char name[MaxFileName]; ++ cMenuEditStrItem *file; ++ cOsdItem *marksItem, *resumeItem; ++ bool isResume, isMarks; ++ cRecording *recording; ++ void SetHelpKeys(void); ++ eOSState SetFolder(void); ++public: ++ cMenuRenameRecording(cRecording *Recording); ++ virtual eOSState ProcessKey(eKeys Key); ++}; ++ ++cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording) ++:cOsdMenu(tr("Rename recording"), 12) ++{ ++ cMarks marks; ++ ++ file = NULL; ++ recording = Recording; ++ ++ if (recording) { ++ Utf8Strn0Cpy(name, recording->Name(), sizeof(name)); ++ Add(file = new cMenuEditStrItem(tr("File"), name, sizeof(name))); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->start)), osUnknown, false)); ++ ++ cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID()); ++ if (channel) ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false)); ++ ++ int recLen = cIndexFile::Length(recording->FileName(), recording->IsPesRecording()); ++ if (recLen >= 0) ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Length"), *IndexToHMSF(recLen, false, recording->FramesPerSecond())), osUnknown, false)); ++ else ++ recLen = 0; ++ ++ int dirSize = DirSizeMB(recording->FileName()); ++ double seconds = recLen / recording->FramesPerSecond(); ++ cString bitRate = seconds ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / seconds) : cString(""); ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Format"), recording->IsPesRecording() ? tr("PES") : tr("TS")), osUnknown, false)); ++ Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false)); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ isMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count(); ++ marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks); ++ Add(marksItem); ++ ++ cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); ++ isResume = (ResumeFile.Read() != -1); ++ resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume); ++ Add(resumeItem); ++ } ++ ++ SetHelpKeys(); ++} ++ ++void cMenuRenameRecording::SetHelpKeys(void) ++{ ++ SetHelp(tr("Button$Folder")); ++} ++ ++eOSState cMenuRenameRecording::SetFolder(void) ++{ ++ cMenuFolder *mf = (cMenuFolder *)SubMenu(); ++ if (mf) { ++ cString Folder = mf->GetFolder(); ++ char *p = strrchr(name, FOLDERDELIMCHAR); ++ if (p) ++ p++; ++ else ++ p = name; ++ if (!isempty(*Folder)) ++ strn0cpy(name, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(name)); ++ else if (p != name) ++ memmove(name, p, strlen(p) + 1); ++ SetCurrent(file); ++ Display(); ++ } ++ return CloseSubMenu(); ++} ++ ++eOSState cMenuRenameRecording::ProcessKey(eKeys Key) ++{ ++ eOSState state = cOsdMenu::ProcessKey(Key); ++ ++ if (state == osUnknown) { ++ switch (Key) { ++ case kOk: ++ if (recording->Rename(name)) { ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ return osRecordings; ++ } ++ else ++ Skins.Message(mtError, tr("Error while accessing recording!")); ++ break; ++ case kRed: ++ return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, name)); ++ break; ++ default: ++ break; ++ } ++ if (Key != kNone) ++ SetHelpKeys(); ++ return osContinue; ++ } ++ else if (state == osEnd && HasSubMenu()) ++ state = SetFolder(); ++ else if (state == osUser1) { ++ if (isMarks && Interface->Confirm(tr("Delete marks information?"))) { ++ cMarks marks; ++ marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()); ++ cMark *mark = marks.First(); ++ while (mark) { ++ cMark *nextmark = marks.Next(mark); ++ marks.Del(mark); ++ mark = nextmark; ++ } ++ marks.Save(); ++ isMarks = false; ++ marksItem->SetSelectable(isMarks); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ else if (state == osUser2) { ++ if (isResume && Interface->Confirm(tr("Delete resume information?"))) { ++ cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); ++ ResumeFile.Delete(); ++ isResume = false; ++ resumeItem->SetSelectable(isResume); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ ++ return state; ++#else + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++#endif /* LIEMIEXT */ + } + + // --- cMenuRecordings ------------------------------------------------------- + + cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7, 7) ++#else + :cOsdMenu(Base ? Base : tr("Recordings"), 9, 7) ++#endif /* LIEMIEXT */ + { + base = Base ? strdup(Base) : NULL; + level = Setup.RecordingDirs ? Level : -1; +@@ -2269,7 +2789,13 @@ + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { + if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == FOLDERDELIMCHAR)) { + cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); ++#ifdef USE_PINPLUGIN ++ if ((*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) ++ && (!cStatus::MsgReplayProtected(GetRecording(Item), Item->Name(), base, ++ Item->IsDirectory(), true))) { ++#else + if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { ++#endif /* PINPLUGIN */ + Add(Item); + LastItem = Item; + free(LastItemText); +@@ -2319,6 +2845,11 @@ + { + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base, ++ ri->IsDirectory()) == true) ++ return osContinue; ++#endif /* PINPLUGIN */ + if (ri->IsDirectory()) + Open(); + else { +@@ -2426,12 +2957,34 @@ + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++eOSState cMenuRecordings::Rename(void) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); ++ if (ri && !ri->IsDirectory()) { ++ cRecording *recording = GetRecording(ri); ++ if (recording) ++ return AddSubMenu(new cMenuRenameRecording(recording)); ++ } ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + eOSState cMenuRecordings::ProcessKey(eKeys Key) + { + bool HadSubMenu = HasSubMenu(); + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { ++#ifdef USE_SORTRECORDS ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ + switch (Key) { + case kPlay: + case kOk: return Play(); +@@ -2440,7 +2993,26 @@ + case kYellow: return Delete(); + case kInfo: + case kBlue: return Info(); ++#ifdef USE_SORTRECORDS ++ case k0: Setup.RecordingsSortMode = ++Setup.RecordingsSortMode % MAXSORTMODES; ++ Set(true); ++ Skins.Message(mtStatus, cString::sprintf("%s %d: %s", tr("Sorting"), Setup.RecordingsSortMode, RecordingsSortModeTexts[Setup.RecordingsSortMode])); ++ return osContinue; ++ case k1...k7: return Commands(Key); ++ case k8: return Rename(); ++ case k9: Recordings.ToggleSortOrder(); ++ Set(true); ++ return osContinue; ++#elif defined (USE_LIEMIEXT) ++ case k0: DirOrderState = !DirOrderState; ++ Set(true); ++ return osContinue; ++ case k8: return Rename(); ++ case k9: ++ case k1...k7: return Commands(Key); ++#else + case k1...k9: return Commands(Key); ++#endif /* LIEMIEXT & SORTRECORDS */ + case kNone: if (Recordings.StateChanged(recordingsState)) + Set(true); + break; +@@ -2505,6 +3077,9 @@ + cMenuSetupOSD(void); + virtual ~cMenuSetupOSD(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupOsd"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupOSD::cMenuSetupOSD(void) +@@ -2546,6 +3121,9 @@ + Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); + if (themes.NumThemes()) + Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); ++#ifdef USE_WAREAGLEICON ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons)); ++#endif /* WAREAGLEICON */ + Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5)); + Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5)); + Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0)); +@@ -2568,6 +3146,12 @@ + Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top"))); ++#endif /* LIEMIEXT */ ++#ifdef USE_VALIDINPUT ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Show valid input"), &data.ShowValidInput)); ++#endif /* VALIDINPUT */ + SetCurrent(Get(current)); + Display(); + } +@@ -2639,12 +3223,18 @@ + + class cMenuSetupEPG : public cMenuSetupBase { + private: ++#ifdef USE_NOEPG ++ const char *noEPGModes[2]; ++#endif /* NOEPG */ + int originalNumLanguages; + int numLanguages; + void Setup(void); + public: + cMenuSetupEPG(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupEpg"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupEPG::cMenuSetupEPG(void) +@@ -2661,11 +3251,19 @@ + { + int current = Current(); + ++#ifdef USE_NOEPG ++ noEPGModes[0] = tr("blacklist"); ++ noEPGModes[1] = tr("whitelist"); ++#endif /* NOEPG */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"), &data.ShowProgressBar)); ++#endif /* LIEMIEXT */ + Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); + if (data.SetSystemTime) + Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); +@@ -2674,6 +3272,15 @@ + for (int i = 0; i < numLanguages; i++) + // TRANSLATORS: note the singular! + Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); ++#ifdef USE_DDEPGENTRY ++ Add(new cMenuEditIntItem(tr("Setup.EPG$Period for double EPG search(min)"), &data.DoubleEpgTimeDelta)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$extern double Epg entry"), &data.DoubleEpgAction, "adjust", "delete")); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Mix intern and extern EPG"), &data.MixEpgAction)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Disable running VPS event"), &data.DisableVPS)); ++#endif /* DDEPGENTRY */ ++#ifdef USE_NOEPG ++ Add(new cMenuEditStraItem(tr("Setup.EPG$Mode of noEPG-Patch"), &data.noEPGMode, 2, noEPGModes)); ++#endif /* NOEPG */ + + SetCurrent(Get(current)); + Display(); +@@ -2740,6 +3347,9 @@ + public: + cMenuSetupDVB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupDvb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupDVB::cMenuSetupDVB(void) +@@ -2770,12 +3380,18 @@ + + Clear(); + ++#ifdef USE_CHANNELPROVIDE ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use DVB receivers"), &data.LocalChannelProvide)); ++#endif /* CHANNELPROVIDE */ + Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); + Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9")); + if (data.VideoFormat == 0) + Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts)); + Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital)); + Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts)); ++#ifdef USE_CHANNELBIND ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$channel binding by Rid"),&data.ChannelBindingByRid)); ++#endif /* CHANNELBIND */ + Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size())); + for (int i = 0; i < numAudioLanguages; i++) + Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); +@@ -2788,6 +3404,9 @@ + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); + } ++#ifdef USE_TTXTSUBS ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Enable teletext support"), &data.SupportTeletext)); ++#endif /* TTXTSUBS */ + + SetCurrent(Get(current)); + Display(); +@@ -2869,6 +3488,9 @@ + public: + cMenuSetupLNB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupLnb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupLNB::cMenuSetupLNB(void) +@@ -2883,6 +3505,23 @@ + + Clear(); + ++#ifdef USE_LNBSHARE ++ int numSatDevices = 0; ++ for (int i = 0; i < cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; ++ } ++ if (numSatDevices > 1) { ++ char tmp[40]; ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { ++ snprintf( tmp, 40, tr("Setup.LNB$DVB device %d uses LNB No."), i); ++ Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); ++ } ++ } ++ } ++ Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); ++#endif /* LNBSHARE */ ++ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + if (!data.DiSEqC) { + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); +@@ -2899,6 +3538,10 @@ + int oldDiSEqC = data.DiSEqC; + eOSState state = cMenuSetupBase::ProcessKey(Key); + ++#ifdef USE_LNBSHARE ++ if (Key == kOk) cDevice::SetLNBnr(); ++#endif /* LNBSHARE */ ++ + if (Key != kNone && data.DiSEqC != oldDiSEqC) + Setup(); + return state; +@@ -2949,6 +3592,9 @@ + public: + cMenuSetupCAM(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupCAM::cMenuSetupCAM(void) +@@ -3025,12 +3671,58 @@ + private: + const char *pauseKeyHandlingTexts[3]; + const char *delTimeshiftRecTexts[3]; ++#ifdef USE_SORTRECORDS ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++#endif /* SORTRECORDS */ ++#ifdef USE_DVLVIDPREFER ++ void Set(void); ++ int tmpNVidPrefer, ++ tmpUseVidPrefer; ++#endif /* DVLVIDPREFER */ + public: + cMenuSetupRecord(void); ++#ifdef USE_DVLVIDPREFER ++ eOSState ProcessKey(eKeys key); ++#endif /* DVLVIDPREFER */ + }; + + cMenuSetupRecord::cMenuSetupRecord(void) + { ++#ifdef USE_DVLVIDPREFER ++ Set(); ++} ++ ++eOSState cMenuSetupRecord::ProcessKey(eKeys key) ++{ ++ eOSState s = cMenuSetupBase::ProcessKey(key);; ++ ++ if (key != kNone) { ++ if (tmpNVidPrefer != data.nVidPrefer || tmpUseVidPrefer != data.UseVidPrefer) { ++ int cur = Current(); ++ ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Clear(); ++ Set(); ++ SetCurrent(Get(cur)); ++ Display(); ++ cMenuSetupBase::ProcessKey(kNone); ++ return osContinue; ++ } ++ } ++ return s; ++} ++ ++void cMenuSetupRecord::Set(void) ++{ ++#endif /* DVLVIDPREFER */ ++#ifdef USE_SORTRECORDS ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ + pauseKeyHandlingTexts[0] = tr("do not pause live video"); + pauseKeyHandlingTexts[1] = tr("confirm pause live video"); + pauseKeyHandlingTexts[2] = tr("pause live video"); +@@ -3046,14 +3738,49 @@ + Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); ++#ifdef USE_DVLVIDPREFER ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Video directory policy"), &data.UseVidPrefer)); ++ if (data.UseVidPrefer != 0) { ++ char tmp[ 64 ]; ++ Add(new cMenuEditIntItem(tr("Setup.Recording$Number of video directories"), &data.nVidPrefer, 1, DVLVIDPREFER_MAX)); ++ for (int zz = 0; zz < data.nVidPrefer; zz++) { ++ sprintf(tmp, tr("Setup.Recording$Video %d priority"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferPrio[ zz ], 0, 99)); ++ sprintf(tmp, tr("Setup.Recording$Video %d min. free MB"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferSize[ zz ], -1, 99999)); ++ } ++ } ++#endif /* DVLVIDPREFER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); ++#ifdef USE_DVLFRIENDLYFNAMES ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Friendly filenames"), &data.UseFriendlyFNames)); ++#endif /* DVLFRIENDLYFNAMES */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps)); + Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); + Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter)); ++#endif /* HARDLINKCUTTER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"), &data.ShowRecDate)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"), &data.ShowRecTime)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"), &data.ShowRecLength)); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); ++#endif /* CUTTERQUEUE */ + Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts)); + } + +@@ -3072,6 +3799,17 @@ + Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); + Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); ++#ifdef USE_JUMPINGSECONDS ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Jump Seconds"), &data.JumpSeconds)); ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Jump Seconds Slow"), &data.JumpSecondsSlow)); ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Jump Seconds (Repeat)"), &data.JumpSecondsRepeat)); ++#endif /* JUMPINGSECONDS */ ++#ifdef USE_JUMPPLAY ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); ++#endif /* JUMPPLAY */ + } + + void cMenuSetupReplay::Store(void) +@@ -3084,13 +3822,48 @@ + // --- cMenuSetupMisc -------------------------------------------------------- + + class cMenuSetupMisc : public cMenuSetupBase { ++#ifdef USE_VOLCTRL ++private: ++ const char *lrChannelGroupsTexts[3]; ++ const char *lrForwardRewindTexts[3]; ++ void Setup(void); ++#endif /* VOLCTRL */ + public: + cMenuSetupMisc(void); ++#ifdef USE_VOLCTRL ++ virtual eOSState ProcessKey(eKeys Key); ++#endif /* VOLCTRL */ + }; + + cMenuSetupMisc::cMenuSetupMisc(void) + { ++#ifdef USE_VOLCTRL ++ lrChannelGroupsTexts[0] = tr("no"); ++ lrChannelGroupsTexts[1] = tr("Setup.Miscellaneous$only in channelinfo"); ++ lrChannelGroupsTexts[2] = tr("yes"); ++ lrForwardRewindTexts[0] = tr("no"); ++ lrForwardRewindTexts[1] = tr("Setup.Miscellaneous$only in progress display"); ++ lrForwardRewindTexts[2] = tr("yes"); ++#endif /* VOLCTRL */ + SetSection(tr("Miscellaneous")); ++#ifdef USE_VOLCTRL ++ Setup(); ++} ++ ++eOSState cMenuSetupMisc::ProcessKey(eKeys Key) ++{ ++ int newLRVolumeControl = data.LRVolumeControl; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ if (Key != kNone && data.LRVolumeControl != newLRVolumeControl) ++ Setup(); ++ return state; ++} ++ ++void cMenuSetupMisc::Setup(void) ++{ ++ int current = Current(); ++ Clear(); ++#endif /* VOLCTRL */ + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); +@@ -3098,8 +3871,22 @@ + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); + Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); ++#ifdef USE_VOLCTRL ++ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Volume ctrl with left/right"), &data.LRVolumeControl)); ++ if (data.LRVolumeControl) { ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Channelgroups with left/right"), &data.LRChannelGroups, 3, lrChannelGroupsTexts)); ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Search fwd/back with left/right"), &data.LRForwardRewind, 3, lrForwardRewindTexts)); ++ } ++ SetCurrent(Get(current)); ++ Display(); ++#endif /* VOLCTRL */ + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap)); + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); ++#ifdef USE_LIRCSETTINGS ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); ++#endif /* LIRCSETTINGS */ + } + + // --- cMenuSetupPluginItem -------------------------------------------------- +@@ -3124,6 +3911,9 @@ + public: + cMenuSetupPlugins(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupPlugins"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupPlugins::cMenuSetupPlugins(void) +@@ -3173,6 +3963,9 @@ + public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetup"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetup::cMenuSetup(void) +@@ -3262,24 +4055,65 @@ + cMenuMain::cMenuMain(eOSState State) + :cOsdMenu("") + { ++#ifdef USE_SETUP ++ // Load Menu Configuration ++ cString menuXML = cString::sprintf("%s/setup/vdr-menu.%s.xml", cPlugin::ConfigDirectory(), Setup.OSDLanguage); ++ if (access(menuXML, 04) == -1) ++ menuXML = cString::sprintf("%s/setup/vdr-menu.xml", cPlugin::ConfigDirectory()); ++ subMenu.LoadXml(menuXML); ++ nrDynamicMenuEntries = 0; ++#endif /* SETUP */ ++ + replaying = false; + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + recordControlsState = 0; ++ ++#ifdef USE_MENUORG ++ MenuOrgPatch::EnterRootMenu(); ++#endif /* MENUORG */ + Set(); + + // Initial submenus: ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + + switch (State) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu)) ++ menu = new cMenuSchedule; ++ break; ++ case osChannels: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu)) ++ menu = new cMenuChannels; ++ break; ++ case osTimers: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu)) ++ menu = new cMenuTimers; ++ break; ++ case osRecordings: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu)) ++ menu = new cMenuRecordings(NULL, 0, true); ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: AddSubMenu(new cMenuSchedule); break; + case osChannels: AddSubMenu(new cMenuChannels); break; + case osTimers: AddSubMenu(new cMenuTimers); break; + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; + case osSetup: AddSubMenu(new cMenuSetup); break; + case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; ++#endif /* MAINMENUHOOKS */ + default: break; + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + } + + cOsdObject *cMenuMain::PluginOsdObject(void) +@@ -3289,37 +4123,156 @@ + return o; + } + ++#ifdef USE_SETUP ++void cMenuMain::Set(int current) ++#else + void cMenuMain::Set(void) ++#endif /* SETUP */ + { + Clear(); + SetTitle("VDR"); + SetHasHotkeys(); + ++#ifdef USE_MENUORG ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuItemDefinitions* menuItems = MenuOrgPatch::MainMenuItems(); ++ for (MenuItemDefinitions::iterator i = menuItems->begin(); i != menuItems->end(); i++) { ++ cOsdItem* osdItem = NULL; ++ if ((*i)->IsCustomOsdItem()) { ++ osdItem = (*i)->CustomOsdItem(); ++ if (osdItem && !(*i)->IsSeparatorItem()) ++ osdItem->SetText(hk(osdItem->Text())); ++ } ++ else if ((*i)->IsPluginItem()) { ++ const char *item = (*i)->PluginMenuEntry(); ++ if (item) ++ osdItem = new cMenuPluginItem(hk(item), (*i)->PluginIndex()); ++ } ++ if (osdItem) { ++ Add(osdItem); ++ if ((*i)->IsSelected()) ++ SetCurrent(osdItem); ++ } ++ } ++ } ++ else { ++#endif /* MENUORG */ ++#ifdef USE_SETUP ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ ++ // remember initial dynamic MenuEntries added ++ nrDynamicMenuEntries = Count(); ++ for (cSubMenuNode *node = subMenu.GetMenuTree()->First(); node; node = subMenu.GetMenuTree()->Next(node)) { ++ cSubMenuNode::Type type = node->GetType(); ++ if (type==cSubMenuNode::PLUGIN) { ++ const char *item = node->GetPluginMainMenuEntry(); ++#ifdef USE_PINPLUGIN ++ if (item && !cStatus::MsgPluginProtected(cPluginManager::GetPlugin(node->GetPluginIndex()), true)) ++#else ++ if (item) ++#endif /* PINPLUGIN */ ++ Add(new cMenuPluginItem(hk(item), node->GetPluginIndex())); ++ } ++ else if (type==cSubMenuNode::MENU) { ++ cString item = cString::sprintf("%s%s", node->GetName(), *subMenu.GetMenuSuffix()); ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(item, true)) ++ Add(new cOsdItem(hk(item), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(item))); ++#endif /* PINPLUGIN */ ++ } ++ else if ((type==cSubMenuNode::COMMAND) || (type==cSubMenuNode::THREAD)) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(node->GetName(), true)) ++ Add(new cOsdItem(hk(node->GetName()), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(node->GetName()))); ++#endif /* PINPLUGIN */ ++ } ++ else if (type==cSubMenuNode::SYSTEM) { ++ const char *item = node->GetName(); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgMenuItemProtected(item, true)) ++ ; // nothing to do ;) ++ else ++#endif /* PINPLUGIN */ ++ if (strcmp(item, "Schedule") == 0) ++ Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ else if (strcmp(item, "Channels") == 0) ++ Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ else if (strcmp(item, "Timers") == 0) ++ Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ else if (strcmp(item, "Recordings") == 0) ++ Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++ else if (strcmp(item, "Setup") == 0) { ++ cString itemSetup = cString::sprintf("%s%s", tr("Setup"), *subMenu.GetMenuSuffix()); ++ Add(new cOsdItem(hk(itemSetup), osSetup)); ++ } ++ else if (strcmp(item, "Commands") == 0 && Commands.Count() > 0) { ++ cString itemCommands = cString::sprintf("%s%s", tr("Commands"), *subMenu.GetMenuSuffix()); ++ Add(new cOsdItem(hk(itemCommands), osCommands)); ++ } ++ } ++ } ++ if (current >=0 && current<Count()) { ++ SetCurrent(Get(current)); ++ } ++ ++#else /* NO SETUP */ ++ + // Basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Schedule", true)) Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ if (!cStatus::MsgMenuItemProtected("Channels", true)) Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ if (!cStatus::MsgMenuItemProtected("Timers", true)) Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#else + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#endif /* PINPLUGIN */ + + // Plugins: + + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p, true)) { ++#endif /* PINPLUGIN */ + const char *item = p->MainMenuEntry(); + if (item) + Add(new cMenuPluginItem(hk(item), i)); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + break; + } + + // More basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#else + Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#endif /* PINPLUGIN */ + if (Commands.Count()) ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Commands", true)) ++#endif /* PINPLUGIN */ + Add(new cOsdItem(hk(tr("Commands")), osCommands)); ++#endif /* SETUP */ ++ ++#ifdef USE_MENUORG ++ } ++#endif /* MENUORG */ + + Update(true); + +@@ -3329,13 +4282,29 @@ + bool cMenuMain::Update(bool Force) + { + bool result = false; ++ ++#ifdef USE_SETUP ++ cOsdItem *fMenu = NULL; ++ if (Force && subMenu.isTopMenu()) { ++ fMenu = First(); ++ nrDynamicMenuEntries = 0; ++ } + ++ if (subMenu.isTopMenu()) { ++#endif /* SETUP */ + // Title with disk usage: + if (FreeDiskSpace.HasChanged(Force)) { + //XXX -> skin function!!! + SetTitle(cString::sprintf("%s - %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString())); + result = true; + } ++#ifdef USE_SETUP ++ } ++ else { ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), subMenu.GetParentMenuTitel())); ++ result = true; ++ } ++#endif /* SETUP */ + + bool NewReplaying = cControl::Control() != NULL; + if (Force || NewReplaying != replaying) { +@@ -3343,6 +4312,9 @@ + // Replay control: + if (replaying && !stopReplayItem) + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else ++#endif /* LIEMIEXT */ + Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); + else if (stopReplayItem && !replaying) { + Del(stopReplayItem->Index()); +@@ -3357,6 +4329,9 @@ + bool CutterActive = cCutter::Active(); + if (CutterActive && !cancelEditingItem) { + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); else ++#endif /* LIEMIEXT */ + Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); + result = true; + } +@@ -3377,6 +4352,9 @@ + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + cOsdItem *item = new cOsdItem(osStopRecord); + item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(item); else ++#endif /* LIEMIEXT */ + Add(item); + if (!stopRecordingItem) + stopRecordingItem = item; +@@ -3384,6 +4362,12 @@ + result = true; + } + ++#ifdef USE_SETUP ++ // adjust nrDynamicMenuEntries ++ if (fMenu != NULL) ++ nrDynamicMenuEntries = fMenu->Index(); ++#endif /* SETUP */ ++ + return result; + } + +@@ -3394,13 +4378,53 @@ + eOSState state = cOsdMenu::ProcessKey(Key); + HadSubMenu |= HasSubMenu(); + ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ ++#ifdef USE_PINPLUGIN ++ cOsdItem* item = Get(Current()); ++ ++ if (item && item->Text() && state != osContinue && state != osUnknown && state != osBack) ++ if (cStatus::MsgMenuItemProtected(item->Text())) ++ return osContinue; ++#endif /* PINPLUGIN */ ++ + switch (state) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu)) ++ menu = new cMenuSchedule; ++ else ++ state = osContinue; ++ break; ++ case osChannels: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu)) ++ menu = new cMenuChannels; ++ else ++ state = osContinue; ++ break; ++ case osTimers: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu)) ++ menu = new cMenuTimers; ++ else ++ state = osContinue; ++ break; ++ case osRecordings: ++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu)) ++ menu = new cMenuRecordings; ++ else ++ state = osContinue; ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: return AddSubMenu(new cMenuSchedule); + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimers: return AddSubMenu(new cMenuTimers); + case osRecordings: return AddSubMenu(new cMenuRecordings); + case osSetup: return AddSubMenu(new cMenuSetup); + case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); ++#endif /* MAINMENUHOOKS */ + case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { + cOsdItem *item = Get(Current()); + if (item) { +@@ -3419,6 +4443,9 @@ + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p)) { ++#endif /* PINPLUGIN */ + cOsdObject *menu = p->MainMenuAction(); + if (menu) { + if (menu->IsMenu()) +@@ -3428,11 +4455,63 @@ + return osPlugin; + } + } ++#ifdef USE_PINPLUGIN + } ++#endif /* PINPLUGIN */ + } ++ } + state = osEnd; + } + break; ++#ifdef USE_MENUORG ++ case osBack: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) ++ { ++ bool leavingMenuSucceeded = MenuOrgPatch::LeaveSubMenu(); ++ Set(); ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ recordControlsState = 0; ++ Update(true); ++ Display(); ++ if (leavingMenuSucceeded) ++ return osContinue; ++ else ++ return osEnd; ++ } ++ } ++ break; ++ case osUser1: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuOrgPatch::EnterSubMenu(Get(Current())); ++ Set(); ++ return osContinue; ++ } ++ } ++ break; ++ case osUser2: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ cOsdMenu* osdMenu = MenuOrgPatch::Execute(Get(Current())); ++ if (osdMenu) ++ return AddSubMenu(osdMenu); ++ return osEnd; ++ } ++ } ++ break; ++#endif /* MENUORG */ ++#ifdef USE_SETUP ++ case osBack: { ++ int newCurrent = 0; ++ if (subMenu.Up(&newCurrent)) { ++ Set(newCurrent); ++ return osContinue; ++ } ++ else ++ return osEnd; ++ } ++ break; ++#endif /* SETUP */ + default: switch (Key) { + case kRecord: + case kRed: if (!HadSubMenu) +@@ -3449,9 +4528,63 @@ + case kBlue: if (!HadSubMenu) + state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; + break; ++#ifdef USE_SETUP ++ case kOk: if (state == osUnknown) { ++ cString buffer; ++ int index = Current()-nrDynamicMenuEntries; ++ cSubMenuNode *node = subMenu.GetNode(index); ++ ++ if (node != NULL) { ++ if (node->GetType() == cSubMenuNode::MENU) { ++#ifdef USE_PINPLUGIN ++ subMenu.Down(node, Current()); ++#else ++ subMenu.Down(index); ++#endif /* PINPLUGIN */ ++ } ++ else if (node->GetType() == cSubMenuNode::COMMAND) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ const char *Result = subMenu.ExecuteCommand(node->GetCommand()); ++ if (Result) ++ return AddSubMenu(new cMenuText(node->GetName(), Result, fontFix)); ++ return osEnd; ++ } ++ } ++ else if (node->GetType() == cSubMenuNode::THREAD) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ buffer = cString::sprintf("%s", node->GetCommand()); ++ cExecCmdThread *execcmd = new cExecCmdThread(node->GetCommand()); ++ if (execcmd->Start()) ++ dsyslog("executing command '%s'", *buffer); ++ else ++ esyslog("ERROR: can't execute command '%s'", *buffer); ++ return osEnd; ++ } ++ } ++ } ++ ++ Set(); ++ return osContinue; ++ } ++ break; ++#endif /* SETUP */ + default: break; + } + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ return AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + if (!HasSubMenu() && Update(HadSubMenu)) + Display(); + if (Key != kNone) { +@@ -3598,6 +4731,9 @@ + if (Direction) { + while (Channel) { + Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, Channel) == false) ++#endif /* PINPLUGIN */ + if (!Channel && Setup.ChannelsWrap) + Channel = Direction > 0 ? Channels.First() : Channels.Last(); + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) +@@ -3658,6 +4794,13 @@ + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && !Setup.LRChannelGroups) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kNext|k_Repeat: + case kNext: + case kPrev|k_Repeat: +@@ -3817,6 +4960,17 @@ + eOSState cDisplayVolume::ProcessKey(eKeys Key) + { + switch (Key) { ++#ifdef USE_VOLCTRL ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ if (Setup.LRVolumeControl) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: +@@ -4064,8 +5218,16 @@ + + // --- cRecordControl -------------------------------------------------------- + ++#ifdef USE_ALTERNATECHANNEL ++cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause, cChannel *Channel) ++#else + cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) ++#endif /* ALTERNATECHANNEL */ + { ++#ifdef USE_DVLRECSCRIPTADDON ++ const cChannel *recChan = NULL; ++ char *chanName = NULL; ++#endif /* DVLRECSCRIPTADDON */ + // We're going to manipulate an event here, so we need to prevent + // others from modifying any EPG data: + cSchedulesLock SchedulesLock; +@@ -4110,12 +5272,29 @@ + return; + } + ++#ifdef USE_DVLRECSCRIPTADDON ++ if (timer) ++ if ((recChan = timer->Channel()) != NULL) ++ chanName = strdup(recChan->Name()); ++ if (chanName != NULL) { ++ cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName, chanName); ++ free(chanName); ++ } ++ else ++#endif /* DVLRECSCRIPTADDON */ + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + isyslog("record %s", fileName); + if (MakeDirs(fileName, true)) { ++#ifdef USE_ALTERNATECHANNEL ++ const cChannel *ch = Channel ? Channel : timer->Channel(); ++ if (ch) ++ recorder = new cRecorder(fileName, ch, timer->Priority()); ++ if (ch && device->AttachReceiver(recorder)) { ++#else + const cChannel *ch = timer->Channel(); + recorder = new cRecorder(fileName, ch, timer->Priority()); + if (device->AttachReceiver(recorder)) { ++#endif /* ALTERNATECHANNEL */ + Recording.WriteInfo(); + cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); + if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() +@@ -4124,7 +5303,12 @@ + return; + } + else ++#ifdef USE_ALTERNATECHANNEL ++ if (ch) + DELETENULL(recorder); ++#else ++ DELETENULL(recorder); ++#endif /* ALTERNATECHANNEL */ + } + if (!Timer) { + Timers.Del(timer); +@@ -4172,12 +5356,26 @@ + void cRecordControl::Stop(bool ExecuteUserCommand) + { + if (timer) { ++#ifdef USE_DVLRECSCRIPTADDON ++ char *chanName = NULL; ++ const cChannel *recChan = NULL; ++ ++ recChan = timer -> Channel(); ++ if (recChan != NULL) ++ chanName = strdup(recChan -> Name()); ++#endif /* DVLRECSCRIPTADDON */ + DELETENULL(recorder); + timer->SetRecording(false); + timer = NULL; + cStatus::MsgRecording(device, NULL, fileName, false); + if (ExecuteUserCommand) ++#ifdef USE_DVLRECSCRIPTADDON ++ cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName, chanName); ++ if (chanName != NULL) ++ free(chanName); ++#else + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); ++#endif /* DVLRECSCRIPTADDON */ + } + } + +@@ -4223,8 +5421,32 @@ + if (channel) { + int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; + cDevice *device = cDevice::GetDevice(channel, Priority, false); ++ ++#ifdef USE_ALTERNATECHANNEL ++ if (!device && channel->AlternativeChannelID().Valid()) {// check for alternatives ++ dsyslog("prepare to use alternative channel for channel %d", channel->Number()); ++ channel = Channels.GetByChannelID(channel->AlternativeChannelID()); ++ device = cDevice::GetDevice(channel, Priority, false); ++ if (device) ++ dsyslog("use of alternative channel %d successfully initiated", channel->Number()); ++ } ++#endif /* ALTERNATECHANNEL */ ++ + if (device) { + dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ while ((tmpDevice = device->GetBadDevice(channel))) { ++ if (tmpDevice->Replaying() == false) { ++ Stop(tmpDevice); ++ if (tmpDevice->CardIndex() == tmpDevice->ActualDevice()->CardIndex()) ++ tmpDevice->SwitchChannelForced(channel, true); ++ else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } ++#endif /* LNBSHARE */ + if (!device->SwitchChannel(channel, false)) { + ShutdownHandler.RequestEmergencyExit(); + return false; +@@ -4232,7 +5454,14 @@ + if (!Timer || Timer->Matches()) { + for (int i = 0; i < MAXRECORDCONTROLS; i++) { + if (!RecordControls[i]) { ++#ifdef USE_ALTERNATECHANNEL ++ RecordControls[i] = new cRecordControl(device, Timer, Pause, channel); ++#else + RecordControls[i] = new cRecordControl(device, Timer, Pause); ++#endif /* ALTERNATECHANNEL */ ++#ifdef USE_PINPLUGIN ++ cStatus::MsgRecordingFile(RecordControls[i]->FileName()); ++#endif /* PINPLUGIN */ + return RecordControls[i]->Process(time(NULL)); + } + } +@@ -4268,6 +5497,21 @@ + } + } + ++#ifdef USE_LNBSHARE ++void cRecordControls::Stop(cDevice *Device) ++{ ++ ChangeState(); ++ for (int i = 0; i < MAXRECORDCONTROLS; i++) { ++ if (RecordControls[i]) { ++ if (RecordControls[i]->Device() == Device) { ++ isyslog("stopping recording on DVB device %d due to higher priority", Device->CardIndex() + 1); ++ RecordControls[i]->Stop(); ++ } ++ } ++ } ++} ++#endif /* LNBSHARE */ ++ + bool cRecordControls::PauseLiveVideo(void) + { + Skins.Message(mtStatus, tr("Pausing live video...")); +@@ -4365,12 +5609,22 @@ + + // --- cReplayControl -------------------------------------------------------- + ++#ifdef USE_LIEMIEXT ++#define REPLAYCONTROLSKIPLIMIT 9 // s ++#define REPLAYCONTROLSKIPSECONDS 90 // s ++#define REPLAYCONTROLSKIPTIMEOUT 5000 // ms ++#endif /* LIEMIEXT */ ++ + cReplayControl *cReplayControl::currentReplayControl = NULL; + char *cReplayControl::fileName = NULL; + char *cReplayControl::title = NULL; + + cReplayControl::cReplayControl(void) ++#ifdef USE_JUMPPLAY ++:cDvbPlayerControl(fileName), marks(fileName) ++#else + :cDvbPlayerControl(fileName) ++#endif /* JUMPPLAY */ + { + currentReplayControl = this; + displayReplay = NULL; +@@ -4378,11 +5632,18 @@ + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value ++#ifdef USE_LIEMIEXT ++ lastSkipKey = kNone; ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipTimeout.Set(0); ++#endif /* LIEMIEXT */ + timeoutShow = 0; + timeSearchActive = false; + cRecording Recording(fileName); + cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); ++#ifndef USE_JUMPPLAY + marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording()); ++#endif /* JUMPPLAY */ + SetTrackDescriptions(false); + } + +@@ -4642,8 +5903,16 @@ + ShowTimed(2); + bool Play, Forward; + int Speed; ++#ifdef USE_JUMPPLAY ++ if (GetReplayMode(Play, Forward, Speed) && !Play) { ++#else + if (GetReplayMode(Play, Forward, Speed) && !Play) ++#endif /* JUMPPLAY */ + Goto(Current, true); ++#ifdef USE_JUMPPLAY ++ displayFrames = true; ++ } ++#endif /* JUMPPLAY */ + } + marks.Save(); + } +@@ -4656,8 +5925,22 @@ + if (GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ bool Play2, Forward2; ++ int Speed; ++ if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && ++ Play2 && Forward && m->position < Total - SecondsToFrames(3, FramesPerSecond())) { ++ Goto(m->position); ++ Play(); ++ } ++ else { ++ Goto(m->position, true); ++ displayFrames = true; ++ } ++#else + Goto(m->position, true); + displayFrames = true; ++#endif /* JUMPPLAY */ + } + } + } +@@ -4690,7 +5973,11 @@ + { + if (fileName) { + Hide(); ++#ifdef USE_CUTTERQUEUE ++ if (!cCutter::Active() || Interface->Confirm(tr("Cutter already running - Add to cutting queue?"))) { ++#else + if (!cCutter::Active()) { ++#endif /* CUTTERQUEUE */ + if (!marks.Count()) + Skins.Message(mtError, tr("No editing marks defined!")); + else if (!cCutter::Start(fileName)) +@@ -4712,7 +5999,11 @@ + if (!m) + m = marks.GetNext(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) ++#else + if ((m->Index() & 0x01) != 0) ++#endif /* JUMPPLAY */ + m = marks.Next(m); + if (m) { + Goto(m->position - SecondsToFrames(3, FramesPerSecond())); +@@ -4734,6 +6025,9 @@ + { + if (!Active()) + return osEnd; ++#ifdef USE_JUMPPLAY ++ marks.Reload(); ++#endif /* JUMPPLAY */ + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); +@@ -4752,6 +6046,22 @@ + return osContinue; + } + bool DoShowMode = true; ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && (!Setup.LRForwardRewind || (Setup.LRForwardRewind == 1 && !visible))) { ++ switch (Key) { ++ // Left/Right volume control ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ return osContinue; ++ break; ++ default: ++ break; ++ } ++ } ++#endif /* VOLCTRL */ + switch (Key) { + // Positioning: + case kPlay: +@@ -4769,25 +6079,73 @@ + case kFastFwd: + case kRight: Forward(); break; + case kRed: TimeSearch(); break; ++#ifdef USE_JUMPINGSECONDS ++ case kGreen|k_Repeat: ++ SkipSeconds(-(Setup.JumpSecondsRepeat)); break; ++ case kGreen: SkipSeconds(-(Setup.JumpSeconds)); break; ++ case k1|k_Repeat: ++ case k1: SkipSeconds(-Setup.JumpSecondsSlow); break; ++ case k3|k_Repeat: ++ case k3: SkipSeconds( Setup.JumpSecondsSlow); break; ++ case kYellow|k_Repeat: ++ SkipSeconds(Setup.JumpSecondsRepeat); break; ++ case kYellow: SkipSeconds(Setup.JumpSeconds); break; ++#else + case kGreen|k_Repeat: + case kGreen: SkipSeconds(-60); break; + case kYellow|k_Repeat: + case kYellow: SkipSeconds( 60); break; ++#endif /* JUMPINGSECONDS */ ++#ifdef USE_LIEMIEXT ++#ifndef USE_JUMPINGSECONDS ++ case k1|k_Repeat: ++ case k1: SkipSeconds(-20); break; ++ case k3|k_Repeat: ++ case k3: SkipSeconds( 20); break; ++#endif /* JUMPINGSECONDS */ ++ case kPrev|k_Repeat: ++ case kPrev: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kPrev; ++ } ++ else if (RAWKEY(lastSkipKey) != kPrev && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(-lastSkipSeconds); break; ++ case kNext|k_Repeat: ++ case kNext: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kNext; ++ } ++ else if (RAWKEY(lastSkipKey) != kNext && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(lastSkipSeconds); break; ++#endif /* LIEMIEXT */ + case kStop: + case kBlue: Hide(); + Stop(); + return osEnd; ++ + default: { + DoShowMode = false; + switch (Key) { + // Editing: + case kMarkToggle: MarkToggle(); break; ++#ifndef USE_LIEMIEXT + case kPrev|k_Repeat: + case kPrev: ++#endif /* LIEMIEXT */ + case kMarkJumpBack|k_Repeat: + case kMarkJumpBack: MarkJump(false); break; ++#ifndef USE_LIEMIEXT + case kNext|k_Repeat: + case kNext: ++#endif /* LIEMIEXT */ + case kMarkJumpForward|k_Repeat: + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: +diff -ruN vdr-1.7.14/menu.h vdr-1.7.14.ExtP_NG/menu.h +--- vdr-1.7.14/menu.h 2010-03-06 17:15:59.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/menu.h 2010-04-10 15:45:10.646737633 +0200 +@@ -18,6 +18,9 @@ + #include "menuitems.h" + #include "recorder.h" + #include "skins.h" ++#ifdef USE_SETUP ++#include "submenu.h" ++#endif /* SETUP */ + + class cMenuText : public cOsdMenu { + private: +@@ -51,6 +54,9 @@ + cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path = NULL); + cString GetFolder(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuText"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuCommands : public cOsdMenu { +@@ -84,6 +90,9 @@ + cMenuEditTimer(cTimer *Timer, bool New = false); + virtual ~cMenuEditTimer(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimerEdit"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEvent : public cOsdMenu { +@@ -93,22 +102,37 @@ + cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEvent"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuMain : public cOsdMenu { + private: ++#ifdef USE_SETUP ++ int nrDynamicMenuEntries; ++#endif /* SETUP */ + bool replaying; + cOsdItem *stopReplayItem; + cOsdItem *cancelEditingItem; + cOsdItem *stopRecordingItem; + int recordControlsState; + static cOsdObject *pluginOsdObject; ++#ifdef USE_SETUP ++ void Set(int current=0); ++ bool Update(bool Force = false); ++ cSubMenu subMenu; ++#else + void Set(void); + bool Update(bool Force = false); ++#endif /* SETUP */ + public: + cMenuMain(eOSState State = osUnknown); + virtual eOSState ProcessKey(eKeys Key); + static cOsdObject *PluginOsdObject(void); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuMain"; } ++#endif /* GRAPHTFT */ + }; + + class cDisplayChannel : public cOsdObject { +@@ -204,6 +228,9 @@ + eOSState Delete(void); + eOSState Info(void); + eOSState Commands(eKeys Key = kNone); ++#ifdef USE_LIEMIEXT ++ eOSState Rename(void); ++#endif /* LIEMIEXT */ + protected: + cRecording *GetRecording(cMenuRecordingItem *Item); + public: +@@ -222,7 +249,11 @@ + char *fileName; + bool GetEvent(void); + public: ++#ifdef USE_ALTERNATECHANNEL ++ cRecordControl(cDevice *Device, cTimer *Timer = NULL, bool Pause = false, cChannel *Channel = NULL); ++#else + cRecordControl(cDevice *Device, cTimer *Timer = NULL, bool Pause = false); ++#endif /* ALTERNATECHANNEL */ + virtual ~cRecordControl(); + bool Process(time_t t); + cDevice *Device(void) { return device; } +@@ -239,6 +270,9 @@ + public: + static bool Start(cTimer *Timer = NULL, bool Pause = false); + static void Stop(const char *InstantId); ++#ifdef USE_LNBSHARE ++ static void Stop(cDevice *Device); // LNB Sharing ++#endif /* LNBSHARE */ + static bool PauseLiveVideo(void); + static const char *GetInstantId(const char *LastInstantId); + static cRecordControl *GetRecordControl(const char *FileName); +@@ -253,11 +287,20 @@ + class cReplayControl : public cDvbPlayerControl { + private: + cSkinDisplayReplay *displayReplay; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#else + cMarks marks; ++#endif /* JUMPPLAY */ + bool visible, modeOnly, shown, displayFrames; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; ++#ifdef USE_LIEMIEXT ++ int lastSkipSeconds; ++ eKeys lastSkipKey; ++ cTimeMs lastSkipTimeout; ++#endif /* LIEMIEXT */ + time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchTime, timeSearchPos; +diff -ruN vdr-1.7.14/menuitems.c vdr-1.7.14.ExtP_NG/menuitems.c +--- vdr-1.7.14/menuitems.c 2010-02-16 15:44:35.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/menuitems.c 2010-04-10 15:45:10.665741204 +0200 +@@ -33,9 +33,21 @@ + free(name); + } + ++#ifdef USE_VALIDINPUT ++void cMenuEditItem::SetValue(const char *Value, bool HasPre, bool HasSucc) ++#else + void cMenuEditItem::SetValue(const char *Value) ++#endif /* VALIDINPUT */ + { + cString buffer = cString::sprintf("%s:\t%s", name, Value); ++#ifdef USE_VALIDINPUT ++ if (Setup.ShowValidInput) { ++ if (HasPre && HasSucc) buffer = cString::sprintf("%s:\t<%s>", name, Value); ++ else if (HasPre) buffer = cString::sprintf("%s:\t<%s", name, Value); ++ else if (HasSucc) buffer = cString::sprintf("%s:\t%s>", name, Value); ++ } ++#endif /* VALIDINPUT */ ++ + SetText(buffer); + cStatus::MsgOsdCurrentItem(buffer); + } +@@ -127,7 +139,11 @@ + { + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); ++#ifdef USE_VALIDINPUT ++ SetValue(buf, *value, !*value); ++#else + SetValue(buf); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditBitItem ------------------------------------------------------ +@@ -698,7 +714,11 @@ + + void cMenuEditStraItem::Set(void) + { ++#ifdef USE_VALIDINPUT ++ SetValue(strings[*value], (*value > min), (*value < max)); ++#else + SetValue(strings[*value]); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditChanItem ----------------------------------------------------- +diff -ruN vdr-1.7.14/menuitems.h vdr-1.7.14.ExtP_NG/menuitems.h +--- vdr-1.7.14/menuitems.h 2010-02-21 14:58:21.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/menuitems.h 2010-04-10 15:45:10.674735161 +0200 +@@ -22,7 +22,11 @@ + public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); ++#ifdef USE_VALIDINPUT ++ void SetValue(const char *Value, bool HasPre=false, bool HasSucc=false); ++#else + void SetValue(const char *Value); ++#endif /* VALIDINPUT */ + }; + + class cMenuEditIntItem : public cMenuEditItem { +@@ -198,6 +202,9 @@ + cMenuSetupPage(void); + virtual eOSState ProcessKey(eKeys Key); + void SetPlugin(cPlugin *Plugin); ++#ifdef USE_GRAPHTFT ++ const char* MenuKind() { return "MenuSetupPage"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__MENUITEMS_H +diff -ruN vdr-1.7.14/menuorgpatch.h vdr-1.7.14.ExtP_NG/menuorgpatch.h +--- vdr-1.7.14/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/menuorgpatch.h 2010-04-10 15:45:10.686736443 +0200 +@@ -0,0 +1,102 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MENUORGPATCH_H ++#define __MENUORGPATCH_H ++ ++#include "mainmenuitemsprovider.h" ++ ++class MenuOrgPatch ++{ ++ private: ++ static IMainMenuItemsProvider* _mainMenuItemsProvider; ++ ++ private: ++ static IMainMenuItemsProvider* MainMenuItemsProvider() ++ { ++ if (!_mainMenuItemsProvider) ++ { ++ IMainMenuItemsProvider* mainMenuItemsProvider; ++ ++ if (cPluginManager::CallFirstService(MENU_ITEMS_PROVIDER_SERVICE_ID, &mainMenuItemsProvider)) ++ { ++ _mainMenuItemsProvider = mainMenuItemsProvider; ++ } ++ } ++ return _mainMenuItemsProvider; ++ } ++ ++ public: ++ static bool IsCustomMenuAvailable() ++ { ++ return (MainMenuItemsProvider() != NULL) && (MainMenuItemsProvider()->IsCustomMenuAvailable()); ++ } ++ ++ static void EnterRootMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterRootMenu(); ++ } ++ } ++ ++ static bool LeaveSubMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->LeaveSubMenu(); ++ } ++ return false; ++ } ++ ++ static void EnterSubMenu(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterSubMenu(item); ++ } ++ } ++ ++ static MenuItemDefinitions* MainMenuItems() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->MainMenuItems(); ++ } ++ return NULL; ++ } ++ ++ static cOsdMenu* Execute(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->Execute(item); ++ } ++ return NULL; ++ } ++}; ++ ++IMainMenuItemsProvider* MenuOrgPatch::_mainMenuItemsProvider = NULL; ++ ++#endif //__MENUORGPATCH_H ++#endif /* MENUORG */ +diff -ruN vdr-1.7.14/osd.c vdr-1.7.14.ExtP_NG/osd.c +--- vdr-1.7.14/osd.c 2010-01-22 16:58:39.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/osd.c 2010-04-10 15:45:10.754742652 +0200 +@@ -743,6 +743,9 @@ + int cOsd::osdWidth = 0; + int cOsd::osdHeight = 0; + cVector<cOsd *> cOsd::Osds; ++#ifdef USE_PINPLUGIN ++bool cOsd::pinValid = false; ++#endif /* PINPLUGIN */ + + cOsd::cOsd(int Left, int Top, uint Level) + { +@@ -753,6 +756,9 @@ + width = height = 0; + level = Level; + active = false; ++#ifdef USE_YAEPG ++ vidWin.bpp = 0; ++#endif /* YAEPG */ + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i]->level > level) { + Osds.Insert(this, i); +diff -ruN vdr-1.7.14/osd.h vdr-1.7.14.ExtP_NG/osd.h +--- vdr-1.7.14/osd.h 2010-01-17 14:23:50.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/osd.h 2010-04-10 15:45:10.767741548 +0200 +@@ -270,6 +270,10 @@ + int left, top, width, height; + uint level; + bool active; ++#ifdef USE_YAEPG ++public: ++ tArea vidWin; ++#endif /* YAEPG */ + protected: + cOsd(int Left, int Top, uint Level); + ///< Initializes the OSD with the given coordinates. +@@ -401,6 +405,9 @@ + ///< 7: vertical, falling, upper + virtual void Flush(void); + ///< Actually commits all data to the OSD hardware. ++#ifdef USE_PINPLUGIN ++ static bool pinValid; ++#endif /* PINPLUGIN */ + }; + + class cOsdProvider { +diff -ruN vdr-1.7.14/osdbase.c vdr-1.7.14.ExtP_NG/osdbase.c +--- vdr-1.7.14/osdbase.c 2010-01-17 12:36:12.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/osdbase.c 2010-04-10 15:45:10.777738279 +0200 +@@ -22,6 +22,9 @@ + state = State; + selectable = true; + fresh = true; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + + cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) +@@ -31,8 +34,23 @@ + selectable = Selectable; + fresh = true; + SetText(Text); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++cOsdItem::cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu) ++{ ++ text = NULL; ++ state = State; ++ selectable = true; ++ fresh = true; ++ SetText(Text); ++ subMenu = SubMenu; ++} ++#endif /* SETUP & PINPLUGIN */ ++ + cOsdItem::~cOsdItem() + { + free(text); +@@ -77,6 +95,9 @@ + { + isMenu = true; + digit = 0; ++#ifdef USE_LIEMIEXT ++ key_nr = -1; ++#endif /* LIEMIEXT */ + hasHotkeys = false; + title = NULL; + SetTitle(Title); +@@ -97,6 +118,9 @@ + free(status); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDestroy(); ++#endif /* GRAPHTFT */ + if (!--displayMenuCount) + DELETENULL(displayMenu); + } +@@ -119,7 +143,11 @@ + digit = -1; // prevents automatic hotkeys - input already has them + if (digit >= 0) { + digit++; ++#ifdef USE_LIEMIEXT ++ buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s); ++#else + buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s); ++#endif /* LIEMIEXT */ + s = buffer; + } + } +@@ -202,6 +230,9 @@ + displayMenu->SetMessage(mtStatus, NULL); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDisplay(MenuKind()); ++#endif /* GRAPHTFT */ + displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX + displayMenu->SetTitle(title); + cStatus::MsgOsdTitle(title); +@@ -449,20 +480,79 @@ + } + } + ++#ifdef USE_LIEMIEXT ++#define MENUKEY_TIMEOUT 1500 ++#endif /* LIEMIEXT */ ++ + eOSState cOsdMenu::HotKey(eKeys Key) + { ++#ifdef USE_LIEMIEXT ++ bool match = false; ++ bool highlight = false; ++ int item_nr; ++ int i; ++ ++ if (Key == kNone) { ++ if (lastActivity.TimedOut()) ++ Key = kOk; ++ else ++ return osContinue; ++ } ++ else { ++ lastActivity.Set(MENUKEY_TIMEOUT); ++ } ++ for (cOsdItem *item = Last(); item; item = Prev(item)) { ++#else + for (cOsdItem *item = First(); item; item = Next(item)) { ++#endif /* LIEMIEXT */ + const char *s = item->Text(); ++#ifdef USE_LIEMIEXT ++ i = 0; ++ item_nr = 0; ++ if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') { ++ do { ++ item_nr = item_nr * 10 + (s[i] - '0'); ++ } ++ while ( !((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9')); ++ if ((Key == kOk) && (item_nr == key_nr)) { ++#else + if (s && (s = skipspace(s)) != NULL) { + if (*s == Key - k1 + '1') { ++#endif /* LIEMIEXT */ + current = item->Index(); + RefreshCurrent(); + Display(); + cRemote::Put(kOk, true); ++#ifdef USE_LIEMIEXT ++ key_nr = -1; ++#endif /* LIEMIEXT */ + break; + } ++#ifdef USE_LIEMIEXT ++ else if (Key != kOk) { ++ if (!highlight && (item_nr == (Key - k0))) { ++ highlight = true; ++ current = item->Index(); ++ } ++ if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) { ++ match = true; ++ key_nr = (Key - k0); ++ } ++ else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) { ++ current = item->Index(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ } ++#endif /* LIEMIEXT */ + } + } ++#ifdef USE_LIEMIEXT ++ if ((!match) && (Key != kNone)) { ++ key_nr = -1; ++ } ++#endif /* LIEMIEXT */ + return osContinue; + } + +@@ -501,8 +591,13 @@ + } + } + switch (Key) { ++#ifdef USE_LIEMIEXT ++ case kNone: ++ case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#else + case k0: return osUnknown; + case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#endif /* LIEMIEXT */ + case kUp|k_Repeat: + case kUp: CursorUp(); break; + case kDown|k_Repeat: +diff -ruN vdr-1.7.14/osdbase.h vdr-1.7.14.ExtP_NG/osdbase.h +--- vdr-1.7.14/osdbase.h 2010-01-16 15:25:31.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/osdbase.h 2010-04-10 15:45:10.786736628 +0200 +@@ -15,6 +15,10 @@ + #include "skins.h" + #include "tools.h" + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++#include "submenu.h" ++#endif /* SETUP & PINPLUGIN */ ++ + enum eOSState { osUnknown, + osContinue, + osSchedule, +@@ -51,16 +55,26 @@ + char *text; + eOSState state; + bool selectable; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cSubMenuNode* subMenu; ++#endif /* SETUP & PINPLUGIN */ + protected: + bool fresh; + public: + cOsdItem(eOSState State = osUnknown); + cOsdItem(const char *Text, eOSState State = osUnknown, bool Selectable = true); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu); ++#endif /* SETUP & PINPLUGIN */ + virtual ~cOsdItem(); + bool Selectable(void) const { return selectable; } + void SetText(const char *Text, bool Copy = true); + void SetSelectable(bool Selectable); + void SetFresh(bool Fresh); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ void SetSubMenu(cSubMenuNode* SubMenu) { subMenu = SubMenu; } ++ cSubMenuNode* SubMenu() { return subMenu; } ++#endif /* SETUP & PINPLUGIN */ + const char *Text(void) const { return text; } + virtual void Set(void) {} + virtual eOSState ProcessKey(eKeys Key); +@@ -95,6 +109,10 @@ + char *status; + int digit; + bool hasHotkeys; ++#ifdef USE_LIEMIEXT ++ int key_nr; ++ cTimeMs lastActivity; ++#endif /* LIEMIEXT */ + protected: + void SetDisplayMenu(void); + cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; } +@@ -131,6 +149,9 @@ + void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuUnknown"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__OSDBASE_H +diff -ruN vdr-1.7.14/pat.c vdr-1.7.14.ExtP_NG/pat.c +--- vdr-1.7.14/pat.c 2010-03-06 13:00:30.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/pat.c 2010-04-10 15:45:10.802741457 +0200 +@@ -13,6 +13,9 @@ + #include "libsi/section.h" + #include "libsi/descriptor.h" + #include "thread.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + #define PMT_SCAN_TIMEOUT 10 // seconds + +@@ -341,6 +344,10 @@ + char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" }; + char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" }; + int Tpid = 0; ++#ifdef USE_TTXTSUBS ++ tTeletextSubtitlePage TeletextSubtitlePages[MAXTXTPAGES]; ++ int NumTPages = 0; ++#endif /* TTXTSUBS */ + int NumApids = 0; + int NumDpids = 0; + int NumSpids = 0; +@@ -426,8 +433,27 @@ + NumSpids++; + } + break; ++#ifdef USE_TTXTSUBS ++ case SI::TeletextDescriptorTag: { ++#else + case SI::TeletextDescriptorTag: ++#endif /* TTXTSUBS */ + Tpid = esPid; ++#ifdef USE_TTXTSUBS ++ SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d; ++ SI::TeletextDescriptor::Teletext ttxt; ++ for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) { ++ bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05); ++ if ((NumTPages < MAXTXTPAGES) && ttxt.languageCode[0] && isSubtitlePage) { ++ strn0cpy(TeletextSubtitlePages[NumTPages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1); ++ TeletextSubtitlePages[NumTPages].ttxtPage = ttxt.getTeletextPageNumber(); ++ TeletextSubtitlePages[NumTPages].ttxtMagazine = ttxt.getTeletextMagazineNumber(); ++ TeletextSubtitlePages[NumTPages].ttxtType = ttxt.getTeletextType(); ++ NumTPages++; ++ } ++ } ++ } ++#endif /* TTXTSUBS */ + break; + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; +diff -ruN vdr-1.7.14/plugin.c vdr-1.7.14.ExtP_NG/plugin.c +--- vdr-1.7.14/plugin.c 2010-01-06 12:36:46.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/plugin.c 2010-04-10 15:45:10.848736538 +0200 +@@ -317,6 +317,14 @@ + char *p = strchr(s, ' '); + if (p) + *p = 0; ++#ifdef USE_PLUGINMISSING ++ struct stat st; ++ if (stat (cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), &st) && errno == ENOENT) { ++ esyslog("WARN: missing plugin '%s'", s); ++ fprintf(stderr, "vdr: missing plugin '%s'\n", s); ++ } ++ else ++#endif /* PLUGINMISSING */ + dlls.Add(new cDll(cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), Args)); + free(s); + } +@@ -325,7 +333,11 @@ + { + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + if (!dll->Load(Log)) ++#ifdef USE_PLUGINMISSING ++ ; ++#else + return false; ++#endif /* PLUGINMISSING */ + } + return true; + } +diff -ruN vdr-1.7.14/plugin.h vdr-1.7.14.ExtP_NG/plugin.h +--- vdr-1.7.14/plugin.h 2007-08-04 11:56:26.000000000 +0200 ++++ vdr-1.7.14.ExtP_NG/plugin.h 2010-04-10 15:45:10.861747307 +0200 +@@ -45,6 +45,9 @@ + + virtual const char *MainMenuEntry(void); + virtual cOsdObject *MainMenuAction(void); ++#ifdef USE_MCLI ++ virtual cOsdObject *AltMenuAction(void) { return NULL; }; ++#endif /* MCLI */ + + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); +diff -ruN vdr-1.7.14/po/ca_ES.po vdr-1.7.14.ExtP_NG/po/ca_ES.po +--- vdr-1.7.14/po/ca_ES.po 2010-03-12 17:41:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ca_ES.po 2010-04-10 15:45:12.406741501 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "cap" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarització" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Actualitza canals" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Idiomes d'àudio" + +diff -ruN vdr-1.7.14/po/cs_CZ.po vdr-1.7.14.ExtP_NG/po/cs_CZ.po +--- vdr-1.7.14/po/cs_CZ.po 2010-03-12 17:41:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/cs_CZ.po 2010-04-10 15:45:12.435736716 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "¾ádný" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizace" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Aktualizace kanálù" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Jazyky zvuku" + +diff -ruN vdr-1.7.14/po/da_DK.po vdr-1.7.14.ExtP_NG/po/da_DK.po +--- vdr-1.7.14/po/da_DK.po 2010-03-12 17:41:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/da_DK.po 2010-04-10 15:45:12.467742106 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "ingen" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisation" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Opdatér kanaler" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio sprog (ant.)" + +diff -ruN vdr-1.7.14/po/de_DE.po vdr-1.7.14.ExtP_NG/po/de_DE.po +--- vdr-1.7.14/po/de_DE.po 2010-03-12 17:41:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/de_DE.po 2010-04-10 15:45:12.504739261 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "keine" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisation" + +@@ -842,6 +845,24 @@ + msgid "Button$Scan" + msgstr "Scan" + ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Zeitspanne für dop. EPG-Suche(min)" ++ ++msgid "Setup.EPG$extern double Epg entry" ++msgstr "Doppelten externen EPG-Eintrag" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Internen und externen EPG mischen" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Erk. des lauf. VPS-Events abschalten" ++ ++msgid "Setup.Recording$Jump Seconds" ++msgstr "Sprungweite in Sekunden" ++ ++msgid "Setup.Recording$Jump Seconds (repeated)" ++msgstr "Sprungweite in Sek. (wiederh.)" ++ + msgid "Setup.EPG$EPG scan timeout (h)" + msgstr "Zeit bis zur EPG-Aktualisierung (h)" + +@@ -895,6 +916,9 @@ + msgid "DVB" + msgstr "DVB" + ++msgid "Setup.DVB$Use DVB receivers" ++msgstr "DVB Empfangsteile benutzen" ++ + msgid "Setup.DVB$Primary DVB interface" + msgstr "Primäres DVB-Interface" + +@@ -910,6 +934,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Kanäle aktualisieren" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "Kanal per Rid zuordnen" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio-Sprachen" + +@@ -934,6 +961,9 @@ + msgid "Setup.DVB$Subtitle background transparency" + msgstr "Untertitel-Transparenz Hintergrund" + ++msgid "Setup.DVB$Record Teletext Subtitles" ++msgstr "Teletext-Untertitel aufnehmen" ++ + msgid "LNB" + msgstr "LNB" + +@@ -1051,6 +1081,18 @@ + msgid "Replay" + msgstr "Wiedergabe" + ++msgid "Setup.Replay$Jump&Play" ++msgstr "Wiedergabe nach Sprung" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Sprung bei Schnittmarke" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause bei letzter Marke" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Marken aktualisieren" ++ + msgid "Setup.Replay$Multi speed mode" + msgstr "Mehrstufiger Vor-/Rücklauf" + +@@ -1315,3 +1357,57 @@ + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR wird in %s Minuten ausschalten" ++ ++msgid "Rename recording" ++msgstr "Aufzeichnung umbenennen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Länge" ++ ++msgid "Size" ++msgstr "Größe" ++ ++msgid "Format" ++msgstr "Format" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Delete marks information?" ++msgstr "Marks löschen?" ++ ++msgid "Delete resume information?" ++msgstr "Resume löschen?" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Befehle Position im Hauptmenü" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Zeitbalken anzeigen" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Aufnahmedatum anzeigen" ++ ++msgid "Setup.Recording$Show time" ++msgstr "AufnahmeZeit anzeigen" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Länge der Aufnahme anzeigen" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanal durch LNB gesperrt!" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB-Empfänger %d nutzt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "LNB-Nutzung protokollieren" ++ ++msgid "Childlock" ++msgstr "Kindersicherung" +diff -ruN vdr-1.7.14/po/el_GR.po vdr-1.7.14.ExtP_NG/po/el_GR.po +--- vdr-1.7.14/po/el_GR.po 2010-03-12 17:41:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/el_GR.po 2010-04-10 15:45:12.539740766 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "êáíÝíá" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Ðüëùóç" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "ÅíçìÝñùóç êáíáëéþí" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Ãëþóóåò Þ÷ïõ" + +diff -ruN vdr-1.7.14/po/es_ES.po vdr-1.7.14.ExtP_NG/po/es_ES.po +--- vdr-1.7.14/po/es_ES.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/es_ES.po 2010-04-10 15:45:12.568741800 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "ninguno" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarización" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Actualizar canales" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Idiomas de audio" + +diff -ruN vdr-1.7.14/po/et_EE.po vdr-1.7.14.ExtP_NG/po/et_EE.po +--- vdr-1.7.14/po/et_EE.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/et_EE.po 2010-04-10 15:45:12.591740207 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "puudu" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisatsioon" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Kanalite uuendamine" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio keeli" + +@@ -1315,3 +1321,45 @@ + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR lülitub välja %s minuti pärast" ++ ++msgid "Rename recording" ++msgstr "Ümbernimetamine" ++ ++msgid "Date" ++msgstr "Kuupäev" ++ ++msgid "Length" ++msgstr "Kestus" ++ ++msgid "Size" ++msgstr "Suurus" ++ ++msgid "Format" ++msgstr "Formaat" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Delete marks information?" ++msgstr "Kustutada märkide info?" ++ ++msgid "Delete resume information?" ++msgstr "Kustutada jätkamise info?" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Käsu asukoht peamenüüs" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Edenemisriba" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Salvestuse kuupäev" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Salvestuse kellaaeg" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Salvestuse kestus" +diff -ruN vdr-1.7.14/po/fi_FI.po vdr-1.7.14.ExtP_NG/po/fi_FI.po +--- vdr-1.7.14/po/fi_FI.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/fi_FI.po 2010-04-10 15:45:12.620745376 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "tyhjä" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisaatio" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Päivitä kanavat" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Äänen kielet" + +@@ -1318,3 +1324,48 @@ + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR sammuu %s minuutin kuluttua" ++ ++msgid "Rename recording" ++msgstr "Nimeä tallenne" ++ ++msgid "Date" ++msgstr "Päiväys" ++ ++msgid "Length" ++msgstr "Pituus" ++ ++msgid "Size" ++msgstr "Koko" ++ ++msgid "Format" ++msgstr "Tiedostomuoto" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Delete marks information?" ++msgstr "Poista tallenteen merkinnät?" ++ ++msgid "Delete resume information?" ++msgstr "Poista tallenteen paluutiedot?" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Komentojen sijainti päävalikossa" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Näytä aikajana" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Näytä tallenteen päiväys" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Näytä tallenteen ajankohta" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Näytä tallenteen kesto" ++ ++msgid "Parameters" ++msgstr "Parametrit" +diff -ruN vdr-1.7.14/po/fr_FR.po vdr-1.7.14.ExtP_NG/po/fr_FR.po +--- vdr-1.7.14/po/fr_FR.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/fr_FR.po 2010-04-10 15:45:12.650738547 +0200 +@@ -42,6 +42,9 @@ + msgid "none" + msgstr "aucun" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisation" + +@@ -848,6 +851,18 @@ + msgid "Button$Scan" + msgstr "Scan" + ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Intervalle de recherche du double EPG(min)" ++ ++msgid "Setup.EPG$extern double Epg entry" ++msgstr "Entrée EPG externe en double" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mixer EPG interne et externe" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Désactiver événement VPS" ++ + msgid "Setup.EPG$EPG scan timeout (h)" + msgstr "Inactivité avant rech. EPG (h)" + +@@ -916,6 +931,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Mettre à jour les chaînes" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Langues audio" + +@@ -1057,6 +1075,18 @@ + msgid "Replay" + msgstr "Lecture" + ++msgid "Setup.Replay$Jump&Play" ++msgstr "Lecture après saut" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Saut sur les marques de découpes" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause après la dernière marque" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Actualiser les marques" ++ + msgid "Setup.Replay$Multi speed mode" + msgstr "Mode multi-vitesses" + +@@ -1321,3 +1351,48 @@ + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'arrêtera dans %s minutes" ++ ++msgid "Rename recording" ++msgstr "Renommer l'enregistrement" ++ ++msgid "Date" ++msgstr "Date" ++ ++msgid "Length" ++msgstr "Longueur" ++ ++msgid "Size" ++msgstr "Taille" ++ ++msgid "Format" ++msgstr "Format" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Delete marks information?" ++msgstr "Effacer les informations de marquage" ++ ++msgid "Delete resume information?" ++msgstr "Effacer les informations de reprise" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Position des commandes dans le menu" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Montrer la barre de progression" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Montrer la date d'enregistrement" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Montrer l'heure d'enregistrement" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Montrer la longueur de l'enregistrement" ++ ++msgid "Parameters" ++msgstr "Paramètres" +diff -ruN vdr-1.7.14/po/hr_HR.po vdr-1.7.14.ExtP_NG/po/hr_HR.po +--- vdr-1.7.14/po/hr_HR.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/hr_HR.po 2010-04-10 15:45:12.676740196 +0200 +@@ -38,6 +38,9 @@ + msgid "none" + msgstr "ni¹ta" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizacija" + +@@ -912,6 +915,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Aktualiziraj programe" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio jezici" + +diff -ruN vdr-1.7.14/po/hu_HU.po vdr-1.7.14.ExtP_NG/po/hu_HU.po +--- vdr-1.7.14/po/hu_HU.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/hu_HU.po 2010-04-10 15:45:12.697741656 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "semmi" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizáció" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Adók aktualizálása" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio nyelvek" + +diff -ruN vdr-1.7.14/po/it_IT.po vdr-1.7.14.ExtP_NG/po/it_IT.po +--- vdr-1.7.14/po/it_IT.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/it_IT.po 2010-04-10 15:45:12.723739553 +0200 +@@ -43,6 +43,9 @@ + msgid "none" + msgstr "nessuno" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizzazione" + +@@ -917,6 +920,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Aggiornamento canali" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Lingue audio" + +diff -ruN vdr-1.7.14/po/nl_NL.po vdr-1.7.14.ExtP_NG/po/nl_NL.po +--- vdr-1.7.14/po/nl_NL.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/nl_NL.po 2010-04-10 15:45:12.785740553 +0200 +@@ -40,6 +40,9 @@ + msgid "none" + msgstr "geen" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisatie" + +@@ -914,6 +917,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Kanalen actualiseren" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio talen" + +diff -ruN vdr-1.7.14/po/nn_NO.po vdr-1.7.14.ExtP_NG/po/nn_NO.po +--- vdr-1.7.14/po/nn_NO.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/nn_NO.po 2010-04-10 15:45:12.809737908 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisasjon" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "" + +diff -ruN vdr-1.7.14/po/pl_PL.po vdr-1.7.14.ExtP_NG/po/pl_PL.po +--- vdr-1.7.14/po/pl_PL.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/pl_PL.po 2010-04-10 15:45:12.835738610 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "brak" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polaryzacja" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Aktualizuj kana³y" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Jêzyków d¼wiêku" + +diff -ruN vdr-1.7.14/po/pt_PT.po vdr-1.7.14.ExtP_NG/po/pt_PT.po +--- vdr-1.7.14/po/pt_PT.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/pt_PT.po 2010-04-10 15:45:12.870742039 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "nenhum" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarização" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Actualizar canais" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Idiomas de audio" + +diff -ruN vdr-1.7.14/po/ro_RO.po vdr-1.7.14.ExtP_NG/po/ro_RO.po +--- vdr-1.7.14/po/ro_RO.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ro_RO.po 2010-04-10 15:45:12.889740524 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "niciuna(ul)" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizare" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Actualizare canale" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Limbi sunet" + +diff -ruN vdr-1.7.14/po/ru_RU.po vdr-1.7.14.ExtP_NG/po/ru_RU.po +--- vdr-1.7.14/po/ru_RU.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ru_RU.po 2010-04-10 15:45:12.921738012 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "ÝØçÕÓÞ" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "¿ÞÛïàØ×ÐæØï" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "¾ÑÝÞÒÛïâì ÝÐáâàÞÙÚØ ÚÐÝÐÛÞÒ" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "¿àÕÔßÞçØâÐÕÜëÕ ï×ëÚØ (×ÒãÚ)" + +@@ -1316,3 +1322,45 @@ + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR ÒëÚÛîçØâáï çÕàÕ× %s ÜØÝãâ" ++ ++msgid "Rename recording" ++msgstr "¿ÕàÕØÜÕÝÞÒÐâì ×Ðߨáì" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Format" ++msgstr "" ++ ++msgid "PES" ++msgstr "" ++ ++msgid "TS" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "ÀÐ×ÜÕéÕÝØÕ ÚÞÜÐÝÔ Ò ÓÛÐÒÝÞÜ ÜÕÝî" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "¿ÞÚÐ×ëÒÐâì ÔÐâã" ++ ++msgid "Setup.Recording$Show time" ++msgstr "¿ÞÚÐ×ëÒÐâì ÒàÕÜï ×ÐߨáØ" ++ ++msgid "Setup.Recording$Show length" ++msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" +diff -ruN vdr-1.7.14/po/sl_SI.po vdr-1.7.14.ExtP_NG/po/sl_SI.po +--- vdr-1.7.14/po/sl_SI.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/sl_SI.po 2010-04-10 15:45:12.971742442 +0200 +@@ -37,6 +37,9 @@ + msgid "none" + msgstr "nobeden" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarizacija" + +@@ -911,6 +914,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Posodobi kanale" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Jeziki za zvok" + +diff -ruN vdr-1.7.14/po/sv_SE.po vdr-1.7.14.ExtP_NG/po/sv_SE.po +--- vdr-1.7.14/po/sv_SE.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/sv_SE.po 2010-04-10 15:45:12.996740450 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "ingen" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Polarisation" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Uppdatera kanaler" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Antal ljudspråk" + +diff -ruN vdr-1.7.14/po/tr_TR.po vdr-1.7.14.ExtP_NG/po/tr_TR.po +--- vdr-1.7.14/po/tr_TR.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/tr_TR.po 2010-04-10 15:45:13.021741692 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "hiç" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "Kutuplaþma" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Kanallarý yenile" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Audio dilleri" + +diff -ruN vdr-1.7.14/po/uk_UA.po vdr-1.7.14.ExtP_NG/po/uk_UA.po +--- vdr-1.7.14/po/uk_UA.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/uk_UA.po 2010-04-10 15:45:13.061743013 +0200 +@@ -36,6 +36,9 @@ + msgid "none" + msgstr "нічого" + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "ПолÑризаціÑ" + +@@ -910,6 +913,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "Оновлювати наÑтройки каналів" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "Бажані мови (звук)" + +diff -ruN vdr-1.7.14/po/zh_CN.po vdr-1.7.14.ExtP_NG/po/zh_CN.po +--- vdr-1.7.14/po/zh_CN.po 2010-03-12 17:41:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/po/zh_CN.po 2010-04-10 15:45:13.092741645 +0200 +@@ -39,6 +39,9 @@ + msgid "none" + msgstr "æ— " + ++msgid "Rid" ++msgstr "Rid" ++ + msgid "Polarization" + msgstr "æžåŒ–æ–¹å¼" + +@@ -913,6 +916,9 @@ + msgid "Setup.DVB$Update channels" + msgstr "更新频é“" + ++msgid "Setup.DVB$channel binding by Rid" ++msgstr "" ++ + msgid "Setup.DVB$Audio languages" + msgstr "声é“è¯è¨€" + +diff -ruN vdr-1.7.14/receiver.c vdr-1.7.14.ExtP_NG/receiver.c +--- vdr-1.7.14/receiver.c 2010-02-28 15:25:32.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/receiver.c 2010-04-10 15:45:11.056767270 +0200 +@@ -82,7 +82,12 @@ + (Channel->Ppid() == Channel->Vpid() || AddPid(Channel->Ppid())) && + AddPids(Channel->Apids()) && + AddPids(Channel->Dpids()) && ++#ifdef USE_TTXTSUBS ++ AddPids(Channel->Spids()) && ++ (!Setup.SupportTeletext || AddPid(Channel->Tpid())); ++#else + AddPids(Channel->Spids()); ++#endif /* TTXTSUBS */ + } + return true; + } +diff -ruN vdr-1.7.14/recorder.c vdr-1.7.14.ExtP_NG/recorder.c +--- vdr-1.7.14/recorder.c 2010-01-29 17:37:22.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/recorder.c 2010-04-10 15:45:11.083738273 +0200 +@@ -87,7 +87,11 @@ + bool cRecorder::NextFile(void) + { + if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame ++#ifdef USE_HARDLINKCUTTER ++ if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) { ++#else + if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) { ++#endif /* HARDLINKCUTTER */ + recordFile = fileName->NextFile(); + fileSize = 0; + } +diff -ruN vdr-1.7.14/recording.c vdr-1.7.14.ExtP_NG/recording.c +--- vdr-1.7.14/recording.c 2010-03-07 15:06:04.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/recording.c 2010-04-10 15:45:11.124740932 +0200 +@@ -8,6 +8,9 @@ + */ + + #include "recording.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <dirent.h> + #include <errno.h> +@@ -63,7 +66,13 @@ + #define MAX_LINK_LEVEL 6 + + bool VfatFileSystem = false; ++#ifdef USE_LIEMIEXT ++bool DirOrderState = false; ++#endif /* LIEMIEXT */ + int InstanceId = 0; ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf); ++#endif /* DVLFRIENDLYFNAMES */ + + cRecordings DeletedRecordings(true); + +@@ -601,7 +610,14 @@ + { + resume = RESUME_NOT_INITIALIZED; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = NULL; + name = NULL; + fileSizeMB = -1; // unknown +@@ -638,6 +654,11 @@ + break; + } + if (Timer->IsSingleEvent()) { ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ Timer -> SetFile(MakeFriendlyFilename(&name)); ++ else ++#endif /* DVLFRIENDLYFNAMES */ + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.SetModified(); + } +@@ -648,6 +669,10 @@ + name = strdup(cString::sprintf("%s~%s", Timer->File(), Subtitle)); + // substitute characters that would cause problems in file names: + strreplace(name, '\n', ' '); ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ MakeFriendlyFilename(&name); ++#endif /* DVLFRIENDLYFNAMES */ + start = Timer->StartTime(); + priority = Timer->Priority(); + lifetime = Timer->Lifetime(); +@@ -670,7 +695,14 @@ + framesPerSecond = DEFAULTFRAMESPERSECOND; + deleted = 0; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + FileName = fileName = strdup(FileName); + if (*(fileName + strlen(fileName) - 1) == '/') + *(fileName + strlen(fileName) - 1) = 0; +@@ -772,7 +804,13 @@ + cRecording::~cRecording() + { + free(titleBuffer); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ } ++#else + free(sortBuffer); ++#endif /* SORTRECORDS */ + free(fileName); + free(name); + delete info; +@@ -794,21 +832,46 @@ + t++; + } + if (s1 && s2) ++#ifdef USE_SORTRECORDS ++ if (Setup.RecordingsSortDirsFirst) ++ *s1 = 'b'; ++ ++ if ((Setup.RecordingsSortMode <= 1 && s1 != s && !strchr(".-$ª·", *(s1 - 1))) || ++ (Setup.RecordingsSortMode == 1 && s1 == s) || ++ (Setup.RecordingsSortMode == 3)) ++#endif /* SORTRECORDS */ + memmove(s1 + 1, s2, t - s2 + 1); + return s; + } + + char *cRecording::SortName(void) const + { ++#ifdef USE_SORTRECORDS ++ if (!sortBuffer[Setup.RecordingsSortMode] || ++ lastDirsFirst[Setup.RecordingsSortMode] != Setup.RecordingsSortDirsFirst) { ++ free(sortBuffer[Setup.RecordingsSortMode]); ++ lastDirsFirst[Setup.RecordingsSortMode] = Setup.RecordingsSortDirsFirst; ++ char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory))); ++#else + if (!sortBuffer) { + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); ++#endif /* SORTRECORDS */ + strreplace(s, '/', 'a'); // some locales ignore '/' when sorting + int l = strxfrm(NULL, s, 0) + 1; ++#ifdef USE_SORTRECORDS ++ sortBuffer[Setup.RecordingsSortMode] = MALLOC(char, l); ++ strxfrm(sortBuffer[Setup.RecordingsSortMode], s, l); ++#else + sortBuffer = MALLOC(char, l); + strxfrm(sortBuffer, s, l); ++#endif /* SORTRECORDS */ + free(s); + } ++#ifdef USE_SORTRECORDS ++ return sortBuffer[Setup.RecordingsSortMode]; ++#else + return sortBuffer; ++#endif /* SORTRECORDS */ + } + + int cRecording::GetResume(void) const +@@ -823,7 +886,15 @@ + int cRecording::Compare(const cListObject &ListObject) const + { + cRecording *r = (cRecording *)&ListObject; ++#ifdef USE_LIEMIEXT ++ if (DirOrderState) ++ return strcasecmp(FileName(), r->FileName()); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ return Recordings.GetSortOrder() * strcasecmp(SortName(), r->SortName()); ++#else + return strcasecmp(SortName(), r->SortName()); ++#endif /* USE_SORTRECORDS */ + } + + const char *cRecording::FileName(void) const +@@ -841,9 +912,17 @@ + return fileName; + } + ++#ifdef USE_LIEMIEXT ++const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const ++#else + const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const ++#endif /* LIEMIEXT */ + { ++#ifdef USE_WAREAGLEICON ++ const char *New = NewIndicator && IsNew() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_NEW_UTF8 : ICON_NEW : "*" : " "; ++#else + char New = NewIndicator && IsNew() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + free(titleBuffer); + titleBuffer = NULL; + if (Level < 0 || Level == HierarchyLevels()) { +@@ -854,7 +933,14 @@ + s++; + else + s = name; ++#ifdef USE_LIEMIEXT ++ if (Original) { ++#endif /* LIEMIEXT */ ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%s%c%s", ++#else + titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s", ++#endif /* WAREAGLEICON */ + t->tm_mday, + t->tm_mon + 1, + t->tm_year % 100, +@@ -864,6 +950,33 @@ + New, + Delimiter, + s)); ++#ifdef USE_LIEMIEXT ++ } ++ else { ++ cString RecLength("---"); ++ if (Setup.ShowRecLength && FileName()) { ++ int length = cIndexFile::Length(FileName(), IsPesRecording()); ++ if (length >= 0) ++ RecLength = cString::sprintf("%d'", length / SecondsToFrames(60, framesPerSecond)); ++ } ++ cString RecDate = cString::sprintf("%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100); ++ cString RecTime = cString::sprintf("%02d:%02d", t->tm_hour, t->tm_min); ++ cString RecDelimiter = cString::sprintf("%c", Delimiter); ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%s%s%s%s%s%s%s%s", ++#else ++ titleBuffer = strdup(cString::sprintf("%s%s%s%c%s%s%s%s", ++#endif /* WAREAGLEICON */ ++ (Setup.ShowRecDate ? *RecDate : ""), ++ (Setup.ShowRecDate && Setup.ShowRecTime ? *RecDelimiter : ""), ++ (Setup.ShowRecTime ? *RecTime : ""), ++ New, ++ (Setup.ShowRecTime || Setup.ShowRecDate ? *RecDelimiter : ""), ++ (Setup.ShowRecLength ? *RecLength : ""), ++ (Setup.ShowRecLength ? *RecDelimiter : ""), ++ s)); ++ } ++#endif /* LIEMIEXT */ + // let's not display a trailing FOLDERDELIMCHAR: + if (!NewIndicator) + stripspace(titleBuffer); +@@ -892,6 +1005,17 @@ + return titleBuffer; + } + ++#ifdef USE_CUTTIME ++void cRecording::SetStartTime(time_t Start) ++{ ++ start=Start; ++ if (fileName) { ++ free(fileName); ++ fileName = NULL; ++ } ++} ++#endif /* CUTTIME */ ++ + const char *cRecording::PrefixFileName(char Prefix) + { + cString p = PrefixVideoFileName(FileName(), Prefix); +@@ -1000,6 +1124,52 @@ + resume = RESUME_NOT_INITIALIZED; + } + ++#ifdef USE_LIEMIEXT ++bool cRecording::Rename(const char *newName) ++{ ++ bool result = false; ++ struct tm tm_r; ++ struct tm *t = localtime_r(&start, &tm_r); ++ char *localNewName = ExchangeChars(strdup(newName), true); ++ const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS; ++ int ch = isPesRecording ? priority : channel; ++ int ri = isPesRecording ? lifetime : instanceId; ++ char *newFileName = strdup(cString::sprintf(fmt, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch, ri)); ++ free(localNewName); ++ if (strcmp(FileName(), newFileName)) { ++ if (access(newFileName, F_OK) == 0) { ++ isyslog("recording %s already exists", newFileName); ++ } ++ else { ++ isyslog("renaming recording %s to %s", FileName(), newFileName); ++ result = MakeDirs(newFileName, true); ++ if (result) ++ result = RenameVideoFile(FileName(), newFileName); ++ if (result) { ++ free(fileName); ++ fileName = strdup(newFileName); ++ free(name); ++ name = strdup(newName); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ sortBuffer[i] = NULL; ++ } ++#else ++ free(sortBuffer); ++ sortBuffer = NULL; ++#endif /* SORTRECORDS */ ++ free(titleBuffer); ++ titleBuffer = NULL; ++ } ++ } ++ } ++ free(newFileName); ++ return result; ++} ++ ++#endif /* LIEMIEXT */ ++ + // --- cRecordings ----------------------------------------------------------- + + cRecordings Recordings; +@@ -1012,6 +1182,9 @@ + deleted = Deleted; + lastUpdate = 0; + state = 0; ++#ifdef USE_SORTRECORDS ++ SortOrder = 1; ++#endif /* SORTRECORDS */ + } + + cRecordings::~cRecordings() +@@ -1298,14 +1471,74 @@ + return NULL; + } + ++#ifdef USE_JUMPPLAY ++// --- cMarksReload ---------------------------------------------------------- ++ ++#define MARKS_RELOAD_MS 10000 ++ ++time_t cMarksReload::lastsavetime = 0; ++ ++cMarksReload::cMarksReload(const char *RecordingFileName) ++:recDir(RecordingFileName) ++{ ++ struct stat sbuf; ++ cRecording rec(recDir); ++ if (Load(recDir, rec.FramesPerSecond(), rec.IsPesRecording()) && ++ stat(FileName(), &sbuf) == 0) ++ lastmodtime = sbuf.st_mtime; ++ else ++ lastmodtime = 0; ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++} ++ ++bool cMarksReload::Reload(void) ++{ ++ // Check the timestamp of marks.vdr in 10 seconds intervals ++ // Independent but synchronized reloading of marks in two threads ++ if ((Setup.ReloadMarks && nextreload.TimedOut()) || ++ lastsavetime > lastmodtime) { ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++ struct stat sbuf; ++ if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { ++ lastmodtime = sbuf.st_mtime; ++ cRecording rec(recDir); ++ if (Load(recDir, rec.FramesPerSecond(), rec.IsPesRecording())) ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool cMarksReload::Save(void) ++{ ++ bool ok = cMarks::Save(); ++ struct stat sbuf; ++ if (ok && stat(FileName(), &sbuf) == 0) ++ lastsavetime = lastmodtime = sbuf.st_mtime; ++ return ok; ++} ++#endif /* JUMPPLAY */ ++ + // --- cRecordingUserCommand ------------------------------------------------- + + const char *cRecordingUserCommand::command = NULL; + ++#ifdef USE_DVLRECSCRIPTADDON ++void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, char *chanName) ++#else + void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) ++#endif /* DVLRECSCRIPTADDON */ + { + if (command) { ++#ifdef USE_DVLRECSCRIPTADDON ++ cString cmd; ++ if (chanName != NULL) ++ cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), chanName); ++ else ++ cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#else + cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#endif /* DVLRECSCRIPTADDON */ + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + } +@@ -1777,6 +2010,18 @@ + return false; + } + ++#ifdef USE_LIEMIEXT ++int cIndexFile::Length(const char *FileName, bool IsPesRecording) ++{ ++ struct stat buf; ++ cString fullname = cString::sprintf("%s%s", FileName, IsPesRecording ? INDEXFILESUFFIX ".vdr" : INDEXFILESUFFIX); ++ if (FileName && *fullname && access(fullname, R_OK) == 0 && stat(fullname, &buf) == 0) ++ return buf.st_size ? (buf.st_size - 1) / sizeof(tIndexTs) + 1 : 0; ++ return -1; ++} ++ ++#endif /* LIEMIEXT */ ++ + // --- cFileName ------------------------------------------------------------- + + #define MAXFILESPERRECORDINGPES 255 +@@ -1935,6 +2180,22 @@ + return NULL; + } + ++#ifdef USE_HARDLINKCUTTER ++off_t cFileName::MaxFileSize() { ++ const int maxVideoFileSize = isPesRecording ? MAXVIDEOFILESIZEPES : MAXVIDEOFILESIZETS; ++ const int setupMaxVideoFileSize = min(maxVideoFileSize, Setup.MaxVideoFileSize); ++ const int maxFileNumber = isPesRecording ? 255 : 65535; ++ ++ const off_t smallFiles = (maxFileNumber * off_t(maxVideoFileSize) - 1024 * Setup.MaxRecordingSize) ++ / max(maxVideoFileSize - setupMaxVideoFileSize, 1); ++ ++ if (fileNumber <= smallFiles) ++ return MEGABYTE(off_t(setupMaxVideoFileSize)); ++ ++ return MEGABYTE(off_t(maxVideoFileSize)); ++} ++#endif /* HARDLINKCUTTER */ ++ + cUnbufferedFile *cFileName::NextFile(void) + { + return SetOffset(fileNumber + 1); +@@ -1986,3 +2247,113 @@ + LOG_ERROR; + return r; + } ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf) ++{ ++ char *b, *x, *y; ++ ++ if (buf == NULL || *buf == NULL) ++ return(NULL); ++ ++ b = (char *)malloc(strlen(*buf) * 2); ++ x = *buf; ++ y = b; ++ ++ while (*x != 0) { ++ switch (*x) { ++ case 'Ä': ++ *y = 'A'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ä': ++ *y = 'a'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ö': ++ *y = 'O'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ö': ++ *y = 'o'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ü': ++ *y = 'U'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ü': ++ *y = 'u'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ß': ++ *y = 's'; ++ y++; ++ *y = 's'; ++ y++; x++; ++ break; ++ ++ // chars to replace ++ case ':': ++ case ';': ++ case '?': ++ case ' ': ++ case '\t': ++ *y = '_'; ++ y++; x++; ++ break; ++ ++ // chars to simply strip ++ case '\"': ++ case '*': ++ case '{': ++ case '}': ++ case '[': ++ case ']': ++ case '=': ++ case '<': ++ case '>': ++ case '#': ++ case '`': ++ case '|': ++ case '\\': ++ case '\n': ++ case '\r': ++ x++; ++ break; ++ ++ default: ++ *y = *x; ++ y++; x++; ++ break; ++ } ++ } ++ *y = 0; ++ ++ x = strdup(b); ++ free(b); ++ ++ free(*buf); ++ *buf = x; ++ ++ return(*buf); ++} ++#endif /* DVLFRIENDLYFNAMES */ +diff -ruN vdr-1.7.14/recording.h vdr-1.7.14.ExtP_NG/recording.h +--- vdr-1.7.14/recording.h 2010-03-07 15:06:15.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/recording.h 2010-04-10 15:45:11.134737044 +0200 +@@ -23,6 +23,9 @@ + #define TIMERMACRO_EPISODE "EPISODE" + + extern bool VfatFileSystem; ++#ifdef USE_LIEMIEXT ++extern bool DirOrderState; ++#endif /* LIEMIEXT */ + extern int InstanceId; + + void RemoveDeletedRecordings(void); +@@ -67,6 +70,9 @@ + const cEvent *GetEvent(void) const { return event; } + const char *Title(void) const { return event->Title(); } + const char *ShortText(void) const { return event->ShortText(); } ++#ifdef USE_GRAPHTFT ++ tEventID EventID(void) const { return event->EventID(); } ++#endif /* GRAPHTFT */ + const char *Description(void) const { return event->Description(); } + const cComponents *Components(void) const { return event->Components(); } + const char *Aux(void) const { return aux; } +@@ -78,12 +84,22 @@ + bool Write(void) const; + }; + ++#ifdef USE_SORTRECORDS ++#define SORTRECORDINGSVERSNUM 3 ++#define MAXSORTMODES 4 ++#endif /* SORTRECORDS */ ++ + class cRecording : public cListObject { + friend class cRecordings; + private: + mutable int resume; + mutable char *titleBuffer; ++#ifdef USE_SORTRECORDS ++ mutable char *sortBuffer[MAXSORTMODES]; ++ mutable char lastDirsFirst[MAXSORTMODES]; ++#else + mutable char *sortBuffer; ++#endif /* SORTRECORDS */ + mutable char *fileName; + mutable char *name; + mutable int fileSizeMB; +@@ -108,8 +124,15 @@ + virtual int Compare(const cListObject &ListObject) const; + const char *Name(void) const { return name; } + const char *FileName(void) const; ++#ifdef USE_LIEMIEXT ++ const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = true) const; ++#else + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; ++#endif /* LIEMIEXT */ + const cRecordingInfo *Info(void) const { return info; } ++#ifdef USE_CUTTIME ++ void SetStartTime(time_t Start); ++#endif /* CUTTIME */ + const char *PrefixFileName(char Prefix); + int HierarchyLevels(void) const; + void ResetResume(void) const; +@@ -128,6 +151,11 @@ + // Changes the file name so that it will be visible in the "Recordings" menu again and + // not processed by cRemoveDeletedRecordingsThread. + // Returns false in case of error ++#ifdef USE_LIEMIEXT ++ bool Rename(const char *newName); ++ // Changes the file name ++ // Returns false in case of error ++#endif /* LIEMIEXT */ + }; + + class cRecordings : public cList<cRecording>, public cThread { +@@ -136,6 +164,9 @@ + bool deleted; + time_t lastUpdate; + int state; ++#ifdef USE_SORTRECORDS ++ int SortOrder; ++#endif /* SORTRECORDS */ + const char *UpdateFileName(void); + void Refresh(bool Foreground = false); + void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); +@@ -166,6 +197,10 @@ + void AddByName(const char *FileName, bool TriggerUpdate = true); + void DelByName(const char *FileName); + int TotalFileSizeMB(void); ///< Only for deleted recordings! ++#ifdef USE_SORTRECORDS ++ void ToggleSortOrder(void) { SortOrder *= -1; } ++ const int GetSortOrder(void) { return SortOrder; } ++#endif /* SORTRECORDS */ + }; + + extern cRecordings Recordings; +@@ -198,6 +233,21 @@ + cMark *GetNext(int Position); + }; + ++#ifdef USE_JUMPPLAY ++class cMarksReload : public cMarks { ++private: ++ cString recDir; ++ cTimeMs nextreload; ++ time_t lastmodtime; ++ static time_t lastsavetime; ++public: ++ cMarksReload(const char *RecordingFileName); ++ bool Reload(void); ++ bool Save(void); ++ }; ++ ++#endif /* JUMPPLAY */ ++ + #define RUC_BEFORERECORDING "before" + #define RUC_AFTERRECORDING "after" + #define RUC_EDITEDRECORDING "edited" +@@ -207,7 +257,11 @@ + static const char *command; + public: + static void SetCommand(const char *Command) { command = Command; } ++#ifdef USE_DVLRECSCRIPTADDON ++ static void InvokeCommand(const char *State, const char *RecordingFileName, char *chanName = NULL); ++#else + static void InvokeCommand(const char *State, const char *RecordingFileName); ++#endif /* DVLRECSCRIPTADDON */ + }; + + // The maximum size of a single frame (up to HDTV 1920x1080): +@@ -220,9 +274,23 @@ + // before the next independent frame, to have a complete Group Of Pictures): + #define MAXVIDEOFILESIZETS 1048570 // MB + #define MAXVIDEOFILESIZEPES 2000 // MB ++#ifdef USE_HARDLINKCUTTER ++#define MINVIDEOFILESIZE 1 // MB ++#else + #define MINVIDEOFILESIZE 100 // MB ++#endif /* HARDLINKCUTTER */ + #define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES + ++#ifdef USE_HARDLINKCUTTER ++#define MINRECORDINGSIZE 25 // GB ++#define MAXRECORDINGSIZE 500 // GB ++#define DEFAULTRECORDINGSIZE 100 // GB ++// Dynamic recording size: ++// Keep recording file size at Setup.MaxVideoFileSize for as long as possible, ++// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize ++// will be reached, before recording to file 65535.vdr ++#endif /* HARDLINKCUTTER */ ++ + struct tIndexTs; + class cIndexFileGenerator; + +@@ -252,6 +320,10 @@ + bool StoreResume(int Index) { return resumeFile.Save(Index); } + bool IsStillRecording(void); + void Delete(void); ++#ifdef USE_LIEMIEXT ++ static int Length(const char *FileName, bool IsPesRecording = false); ++ ///< Calculates the recording length without reading the index. ++#endif /* LIEMIEXT */ + }; + + class cFileName { +@@ -271,6 +343,10 @@ + cUnbufferedFile *Open(void); + void Close(void); + cUnbufferedFile *SetOffset(int Number, off_t Offset = 0); // yes, Number is int for easier internal calculating ++#ifdef USE_HARDLINKCUTTER ++ off_t MaxFileSize(); ++ // Dynamic file size for this file ++#endif /* HARDLINKCUTTER */ + cUnbufferedFile *NextFile(void); + }; + +diff -ruN vdr-1.7.14/remux.c vdr-1.7.14.ExtP_NG/remux.c +--- vdr-1.7.14/remux.c 2010-02-28 15:42:07.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/remux.c 2010-04-10 15:45:11.187744435 +0200 +@@ -215,6 +215,32 @@ + return i; + } + ++#ifdef USE_TTXTSUBS ++int cPatPmtGenerator::MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount) ++{ ++ int i = 0, j = 0; ++ Target[i++] = SI::TeletextDescriptorTag; ++ int l = i; ++ Target[i++] = 0x00; // length ++ for (int n = 0; n < pageCount; n++) { ++ const char* Language = pages[n].ttxtLanguage; ++ Target[i++] = *Language++; ++ Target[i++] = *Language++; ++ Target[i++] = *Language++; ++ Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine; ++ Target[i++] = pages[n].ttxtPage; ++ j++; ++ } ++ if (j > 0) { ++ Target[l] = j * 5; // update length ++ IncEsInfoLength(i); ++ return i; ++ } ++ return 0; ++} ++ ++#endif /* TTXTSUBS */ ++ + int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language) + { + int i = 0; +@@ -296,6 +322,9 @@ + if (Channel) { + int Vpid = Channel->Vpid(); + int Ppid = Channel->Ppid(); ++#ifdef USE_TTXTSUBS ++ int Tpid = Channel->Tpid(); ++#endif /* TTXTSUBS */ + uchar *p = buf; + int i = 0; + p[i++] = 0x02; // table id +@@ -330,6 +359,12 @@ + i += MakeStream(buf + i, 0x06, Channel->Spid(n)); + i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n)); + } ++#ifdef USE_TTXTSUBS ++ if (Tpid) { ++ i += MakeStream(buf + i, 0x06, Tpid); ++ i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages()); ++ } ++#endif /* TTXTSUBS */ + + int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC + buf[SectionLength] |= (sl >> 8) & 0x0F; +@@ -403,6 +438,9 @@ + pmtPid = -1; + vpid = vtype = 0; + ppid = 0; ++#ifdef USE_TTXTSUBS ++ tpid = 0; ++#endif /* TTXTSUBS */ + } + + void cPatPmtParser::ParsePat(const uchar *Data, int Length) +@@ -488,11 +526,17 @@ + int NumSpids = 0; + vpid = vtype = 0; + ppid = 0; ++#ifdef USE_TTXTSUBS ++ tpid = 0; ++#endif /* TTXTSUBS */ + apids[0] = 0; + dpids[0] = 0; + spids[0] = 0; + atypes[0] = 0; + dtypes[0] = 0; ++#ifdef USE_TTXTSUBS ++ totalTtxtSubtitlePages = 0; ++#endif /* TTXTSUBS */ + SI::PMT::Stream stream; + for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) { + dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid()); +@@ -586,6 +630,30 @@ + spids[NumSpids]= 0; + } + break; ++#ifdef USE_TTXTSUBS ++ case SI::TeletextDescriptorTag: { ++ dbgpatpmt(" teletext"); ++ tpid = stream.getPid(); ++ SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d; ++ SI::TeletextDescriptor::Teletext ttxt; ++ if (totalTtxtSubtitlePages < MAXTXTPAGES) { ++ for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) { ++ bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05); ++ if (isSubtitlePage && ttxt.languageCode[0]) { ++ dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber()); ++ strn0cpy(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1); ++ teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage = ttxt.getTeletextPageNumber(); ++ teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine = ttxt.getTeletextMagazineNumber(); ++ teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType = ttxt.getTeletextType(); ++ totalTtxtSubtitlePages++; ++ if (totalTtxtSubtitlePages >= MAXTXTPAGES) ++ break; ++ } ++ } ++ } ++ } ++ break; ++#endif /* TTXTSUBS */ + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + dbgpatpmt(" '%s'", ld->languageCode); +diff -ruN vdr-1.7.14/remux.h vdr-1.7.14.ExtP_NG/remux.h +--- vdr-1.7.14/remux.h 2010-01-29 17:51:26.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/remux.h 2010-04-10 15:45:11.199740063 +0200 +@@ -170,6 +170,9 @@ + int MakeStream(uchar *Target, uchar Type, int Pid); + int MakeAC3Descriptor(uchar *Target); + int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId); ++#ifdef USE_TTXTSUBS ++ int MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount); ++#endif /* TTXTSUBS */ + int MakeLanguageDescriptor(uchar *Target, const char *Language); + int MakeCRC(uchar *Target, const uchar *Data, int Length); + void GeneratePmtPid(const cChannel *Channel); +@@ -215,6 +218,9 @@ + int vpid; + int ppid; + int vtype; ++#ifdef USE_TTXTSUBS ++ int tpid; ++#endif /* TTXTSUBS */ + int apids[MAXAPIDS + 1]; // list is zero-terminated + int atypes[MAXAPIDS + 1]; // list is zero-terminated + char alangs[MAXAPIDS][MAXLANGCODE2]; +@@ -227,6 +233,10 @@ + uint16_t compositionPageIds[MAXSPIDS]; + uint16_t ancillaryPageIds[MAXSPIDS]; + bool updatePrimaryDevice; ++#ifdef USE_TTXTSUBS ++ int totalTtxtSubtitlePages; ++ tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES]; ++#endif /* TTXTSUBS */ + protected: + int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; } + public: +@@ -259,6 +269,11 @@ + int Vtype(void) const { return vtype; } + ///< Returns the video stream type as defined by the current PMT, or 0 if no video + ///< stream type has been detected, yet. ++#ifdef USE_TTXTSUBS ++ int Tpid(void) { return tpid; } ++ ///< Returns the teletext pid as defined by the current PMT, or 0 if no teletext ++ ///< pid has been detected, yet. ++#endif /* TTXTSUBS */ + const int *Apids(void) const { return apids; } + const int *Dpids(void) const { return dpids; } + const int *Spids(void) const { return spids; } +@@ -273,6 +288,10 @@ + uchar SubtitlingType(int i) const { return (0 <= i && i < MAXSPIDS) ? subtitlingTypes[i] : uchar(0); } + uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); } + uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); } ++#ifdef USE_TTXTSUBS ++ const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; } ++ int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; } ++#endif /* TTXTSUBS */ + }; + + // TS to PES converter: +diff -ruN vdr-1.7.14/sections.c vdr-1.7.14.ExtP_NG/sections.c +--- vdr-1.7.14/sections.c 2007-10-14 14:52:07.000000000 +0200 ++++ vdr-1.7.14.ExtP_NG/sections.c 2010-04-10 15:45:11.300735330 +0200 +@@ -198,7 +198,11 @@ + if (fh) { + // Read section data: + unsigned char buf[4096]; // max. allowed size for any EIT section ++#ifdef USE_MCLI ++ int r = device->ReadFilter(fh->handle, buf, sizeof(buf)); ++#else + int r = safe_read(fh->handle, buf, sizeof(buf)); ++#endif /* MCLI */ + if (!DeviceHasLock) + continue; // we do the read anyway, to flush any data that might have come from a different transponder + if (r > 3) { // minimum number of bytes necessary to get section length +diff -ruN vdr-1.7.14/skins.c vdr-1.7.14.ExtP_NG/skins.c +--- vdr-1.7.14/skins.c 2009-06-06 17:12:31.000000000 +0200 ++++ vdr-1.7.14.ExtP_NG/skins.c 2010-04-10 15:45:11.417738004 +0200 +@@ -238,7 +238,11 @@ + } + cSkinDisplay::Current()->SetMessage(Type, s); + cSkinDisplay::Current()->Flush(); ++#ifdef USE_STATUS_EXTENSION ++ cStatus::MsgOsdStatusMessage(Type, s); ++#else + cStatus::MsgOsdStatusMessage(s); ++#endif /* STATUS_EXTENSION */ + eKeys k = kNone; + if (Type != mtStatus) { + k = Interface->Wait(Seconds); +@@ -249,7 +253,11 @@ + } + else { + cSkinDisplay::Current()->SetMessage(Type, NULL); ++#ifdef USE_STATUS_EXTENSION ++ cStatus::MsgOsdStatusMessage(Type, NULL); ++#else + cStatus::MsgOsdStatusMessage(NULL); ++#endif + } + } + else if (!s && displayMessage) { +diff -ruN vdr-1.7.14/status.c vdr-1.7.14.ExtP_NG/status.c +--- vdr-1.7.14/status.c 2008-02-16 15:46:31.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/status.c 2010-04-10 15:45:11.565737350 +0200 +@@ -83,6 +83,17 @@ + sm->OsdTitle(Title); + } + ++#ifdef USE_STATUS_EXTENSION ++void cStatus::MsgOsdStatusMessage(eMessageType type, const char *Message) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ { ++ sm->OsdStatusMessage(type, Message); ++ sm->OsdStatusMessage(Message); // For comaptibilty ++ } ++} ++#endif /* STATUS_EXTENSION */ ++ + void cStatus::MsgOsdStatusMessage(const char *Message) + { + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) +@@ -124,3 +135,88 @@ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); + } ++#ifdef USE_GRAPHTFT ++ ++void cStatus::MsgOsdSetEvent(const cEvent* event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetEvent(event); ++} ++ ++void cStatus::MsgOsdSetRecording(const cRecording* recording) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetRecording(recording); ++} ++ ++void cStatus::MsgOsdMenuDisplay(const char* kind) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDisplay(kind); ++} ++ ++void cStatus::MsgOsdMenuDestroy() ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDestroy(); ++} ++void cStatus::MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdEventItem(Event, Text, Index, Count); ++} ++#endif /* GRAPHTFT */ ++#ifdef USE_PINPLUGIN ++ ++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ChannelProtected(Device, Channel) == true) ++ return true; ++ ++ return false; ++} ++ ++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, ++ const char* Base, bool isDirectory, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgRecordingFile(const char* FileName) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingFile(FileName); ++} ++ ++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->TimerCreation(Timer, Event); ++} ++ ++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->PluginProtected(Plugin, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->UserAction(key, Interact); ++} ++ ++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->MenuItemProtected(Name, menuView) == true) ++ return true; ++ return false; ++} ++#endif /* PINPLUGIN */ +diff -ruN vdr-1.7.14/status.h vdr-1.7.14.ExtP_NG/status.h +--- vdr-1.7.14/status.h 2008-02-16 16:00:33.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/status.h 2010-04-10 15:45:11.579737535 +0200 +@@ -14,6 +14,9 @@ + #include "device.h" + #include "player.h" + #include "tools.h" ++#ifdef USE_PINPLUGIN ++#include "plugin.h" ++#endif + + enum eTimerChange { tcMod, tcAdd, tcDel }; + +@@ -64,6 +67,11 @@ + virtual void OsdStatusMessage(const char *Message) {} + // Message has been displayed in the status line of the menu. + // If Message is NULL, the status line has been cleared. ++#ifdef USE_STATUS_EXTENSION ++ virtual void OsdStatusMessage(eMessageType type, const char *Message) {} ++ // Message has been displayed in the status line of the menu. ++ // If Message is NULL, the status line has been cleared. ++#endif /* STATUS_EXTENSION */ + virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) {} + // The help keys have been set to the given values (may be NULL). + virtual void OsdItem(const char *Text, int Index) {} +@@ -80,6 +88,38 @@ + // The OSD displays the single line Text with the current channel information. + virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} + // The OSD displays the given programme information. ++#ifdef USE_GRAPHTFT ++ virtual void OsdSetRecording(const cRecording* recording) {} ++ // The OSD displays the recording information. ++ virtual void OsdSetEvent(const cEvent* event) {} ++ // The OSD displays the event information. ++ virtual void OsdMenuDisplay(const char* kind) {} ++ // report menu creation ++ virtual void OsdMenuDestroy() {} ++ // report menu destruvtion ++ virtual void OsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) {} ++ // The OSD displays the given single line Event as menu item at Index. ++#endif /* GRAPHTFT */ ++#ifdef USE_PINPLUGIN ++ virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } ++ // Checks if a channel is protected. ++ virtual bool ReplayProtected(const cRecording* Recording, const char* Name, ++ const char* Base, bool isDirectory, int menuView = false) { return false; } ++ // Checks if a recording is protected. ++ virtual void RecordingFile(const char* FileName) {} ++ // The given DVB device has started recording to FileName. FileName is the name of the ++ // recording directory ++ virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} ++ // The given timer is created ++ virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } ++ // Checks if a plugin is protected. ++ virtual void UserAction(const eKeys key, const cOsdObject* Interact) {} ++ // report user action ++ virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } ++ // Checks if a menu entry is protected. ++#endif /* PINPLUGIn */ ++ ++ + public: + cStatus(void); + virtual ~cStatus(); +@@ -94,6 +134,9 @@ + static void MsgSetSubtitleTrack(int Index, const char * const *Tracks); + static void MsgOsdClear(void); + static void MsgOsdTitle(const char *Title); ++#ifdef USE_STATUS_EXTENSION ++ static void MsgOsdStatusMessage(eMessageType type, const char *Message); ++#endif /* STATUS_EXTENSION */ + static void MsgOsdStatusMessage(const char *Message); + static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue); + static void MsgOsdItem(const char *Text, int Index); +@@ -101,6 +144,23 @@ + static void MsgOsdTextItem(const char *Text, bool Scroll = false); + static void MsgOsdChannel(const char *Text); + static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); ++#ifdef USE_GRAPHTFT ++ static void MsgOsdSetEvent(const cEvent* event); ++ static void MsgOsdSetRecording(const cRecording* recording); ++ static void MsgOsdMenuDisplay(const char* kind); ++ static void MsgOsdMenuDestroy(); ++ static void MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count); ++#endif /* GRAPHTFT */ ++#ifdef USE_PINPLUGIN ++ static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); ++ static bool MsgReplayProtected(const cRecording* Recording, const char* Name, ++ const char* Base, bool isDirectory, int menuView = false); ++ static void MsgRecordingFile(const char* FileName); ++ static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); ++ static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); ++ static void MsgUserAction(const eKeys key, const cOsdObject* Interact); ++ static bool MsgMenuItemProtected(const char* Name, int menuView = false); ++#endif /* PINPLUGIN */ + }; + + #endif //__STATUS_H +diff -ruN vdr-1.7.14/submenu.c vdr-1.7.14.ExtP_NG/submenu.c +--- vdr-1.7.14/submenu.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/submenu.c 2010-04-10 15:45:11.593741591 +0200 +@@ -0,0 +1,949 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#include "submenu.h" ++#include "plugin.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ ++ ++static const char* TAG_SYSTEM = "system"; ++static const char* TAG_PLUGIN = "plugin"; ++static const char* TAG_COMMAND = "command"; ++static const char* TAG_THREAD = "thread"; ++static const char* TAG_MENU = "menu"; ++static const char* TAG_UNDEFINED = "undefined"; ++static const char* TRUE_STR = "yes"; ++ ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++ ++cSubMenuNode::cSubMenuNode(TiXmlElement *xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ _level = level; ++ ++ if (xml != NULL && xml->Type() == TiXmlNode::ELEMENT) { ++ const char *tag = xml->Value(); ++ ++ if (cSubMenuNode::IsType(tag) != cSubMenuNode::UNDEFINED) { ++ SetType(tag); ++ SetName(xml->Attribute("name")); ++ if ((_type == COMMAND) || (_type == THREAD)) { ++ SetCommand(xml->Attribute("execute")); ++ const char *confirmStr = xml->Attribute("confirm"); ++ if (confirmStr != NULL && strcmp(confirmStr, TRUE_STR) == 0) ++ _commandConfirm = true; ++ } ++ else if (_type == PLUGIN) { // Add Plugin Index ++ SetCustomTitle(xml->Attribute("title")); ++ SetPlugin(); ++ } ++ else if (_type == MENU && xml->NoChildren() == false) { ++ xml = xml->FirstChildElement(); ++ do { ++ cSubMenuNode *node = new cSubMenuNode(xml, level+1, &_subMenus, currentMenu); ++ _subMenus.Add(node); ++ } while ((xml=xml->NextSiblingElement()) != NULL); ++ } ++ } ++ } ++ else ++ throw "Invalid XML Node"; ++} ++ ++/** ++ * Construct new Node empty Node ++ * ++ * ++ */ ++cSubMenuNode::cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ ++} ++ ++ ++/** ++ * ++ */ ++void cSubMenuNode::init() ++{ ++ _name = NULL; ++ _command = NULL; ++ _title = NULL; ++ _pluginMainMenuEntry = NULL; ++ _type = UNDEFINED; ++ _level = 0; ++ _parentMenu = NULL; ++ _currentMenu = NULL; ++ _pluginIndex = 0; ++ _commandConfirm = false; ++} ++ ++ ++cSubMenuNode::~ cSubMenuNode() ++{ ++ if (_name != NULL) ++ free((void*)_name); ++ if (_command != NULL) ++ free((void*)_command); ++ if (_title != NULL) ++ free((void*)_title); ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++} ++ ++/** ++ * ++ */ ++void cSubMenuNode::SetPlugin() ++{ ++ bool found = false; ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) { ++ if (strcmp(_name, p->Name()) == 0 && p->MainMenuEntry() != NULL) { ++ SetPluginMainMenuEntry(p->MainMenuEntry()); ++ _pluginIndex = i; ++ found = true; ++ break; ++ } ++ } ++ else ++ break; ++ } ++ ++ if (!found) ++ _type = UNDEFINED; ++} ++ ++ ++bool cSubMenuNode::SaveXml(TiXmlElement *root) ++{ ++ bool ok = true; ++ ++ if (root!=NULL) { ++ TiXmlElement *e = NULL; ++ switch(_type) { ++ case SYSTEM: ++ e = new TiXmlElement(TAG_SYSTEM); ++ e->SetAttribute("name", GetName()); ++ break; ++ case COMMAND: ++ e = new TiXmlElement(TAG_COMMAND); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case THREAD: ++ e = new TiXmlElement(TAG_THREAD); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case PLUGIN: ++ e = new TiXmlElement(TAG_PLUGIN); ++ e->SetAttribute("name", GetName()); ++ if (GetCustomTitle() != NULL && strcmp(GetCustomTitle(), "") != 0) ++ e->SetAttribute("title", GetCustomTitle()); ++ break; ++ case MENU: ++ e = new TiXmlElement(TAG_MENU); ++ e->SetAttribute("name", GetName()); ++ break; ++ case UNDEFINED: ++ default: ++ ok = false; ++ break; ++ } ++ if (ok) { ++ root->LinkEndChild(e); ++ if (HasSubMenus()) ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SaveXml(e); ++ } ++ } ++ ++ return(ok); ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::IsType(const char *name) ++{ ++ Type type = UNDEFINED; ++ ++ if (strcmp(name ,TAG_SYSTEM) == 0) ++ type = cSubMenuNode::SYSTEM; ++ else if (strcmp(name ,TAG_PLUGIN) == 0) ++ type = cSubMenuNode::PLUGIN; ++ else if (strcmp(name ,TAG_COMMAND) == 0) ++ type = cSubMenuNode::COMMAND; ++ else if (strcmp(name ,TAG_THREAD) == 0) ++ type = cSubMenuNode::THREAD; ++ else if (strcmp(name ,TAG_MENU) == 0) ++ type = cSubMenuNode::MENU; ++ ++ return(type); ++} ++ ++void cSubMenuNode::SetType(const char *name) ++{ ++ _type = IsType(name); ++} ++ ++void cSubMenuNode::SetType(enum Type type) ++{ ++ _type = type; ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::GetType() ++{ ++ return(_type); ++} ++ ++const char *cSubMenuNode::GetTypeAsString() ++{ ++ const char *str=NULL; ++ switch(_type) { ++ case SYSTEM: ++ str = TAG_SYSTEM; ++ break; ++ case COMMAND: ++ str = TAG_COMMAND; ++ break; ++ case THREAD: ++ str = TAG_THREAD; ++ break; ++ case PLUGIN: ++ str = TAG_PLUGIN; ++ break; ++ case MENU: ++ str = TAG_MENU; ++ break; ++ case UNDEFINED: ++ str = TAG_UNDEFINED; ++ default: ++ break; ++ } ++ ++ return(str); ++} ++ ++void cSubMenuNode::SetCommand(const char *command) ++{ ++ if (_command != NULL) ++ free((void*)_command); ++ ++ if (command != NULL) ++ _command = strdup(command); ++ else ++ _command = NULL; ++} ++ ++const char *cSubMenuNode::GetCommand() ++{ ++ return(_command); ++} ++ ++bool cSubMenuNode::CommandConfirm() ++{ ++ return(_commandConfirm); ++} ++ ++void cSubMenuNode::SetCommandConfirm(int val) ++{ ++ if (val == 1) ++ _commandConfirm = true; ++ else ++ _commandConfirm = false; ++} ++ ++void cSubMenuNode::SetCustomTitle(const char *title) ++{ ++ if (_title != NULL) ++ free((void*)_title); ++ ++ if (title != NULL) ++ _title = strdup(title); ++ else ++ _title = NULL; ++} ++ ++const char *cSubMenuNode::GetCustomTitle() ++{ ++ return(_title); ++} ++ ++void cSubMenuNode::SetName(const char *name) ++{ ++ if (_name) ++ free ((void*)_name); ++ ++ if (name != NULL) ++ _name = strdup(name); ++ else ++ _name = NULL; ++} ++ ++const char *cSubMenuNode::GetName() ++{ ++ return(_name); ++} ++ ++int cSubMenuNode::GetLevel() ++{ ++ return(_level); ++} ++ ++void cSubMenuNode::SetLevel(int level) ++{ ++ _level = level; ++ if (HasSubMenus()) { //Adjust Levels of Subnodes ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SetLevel(level+1); ++ } ++} ++ ++int cSubMenuNode::GetPluginIndex() ++{ ++ return(_pluginIndex); ++} ++ ++void cSubMenuNode::SetPluginIndex(int index) ++{ ++ _pluginIndex = index; ++} ++ ++void cSubMenuNode::SetPluginMainMenuEntry(const char *mainMenuEntry) ++{ ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++ ++ if (_title != NULL && strcmp(_title, "") != 0) ++ _pluginMainMenuEntry = strdup(_title); ++ else if (mainMenuEntry != NULL) ++ _pluginMainMenuEntry = strdup(mainMenuEntry); ++ else ++ _pluginMainMenuEntry = NULL; ++} ++ ++const char *cSubMenuNode::GetPluginMainMenuEntry() ++{ ++ return(_pluginMainMenuEntry); ++} ++ ++ ++cSubMenuNodes *cSubMenuNode::GetParentMenu() ++{ ++ return(_parentMenu); ++} ++ ++void cSubMenuNode::SetParentMenu(cSubMenuNodes *parent) ++{ ++ _parentMenu = parent; ++} ++ ++cSubMenuNodes *cSubMenuNode::GetCurrentMenu() ++{ ++ return(_currentMenu); ++} ++ ++void cSubMenuNode::SetCurrentMenu(cSubMenuNodes *current) ++{ ++ _currentMenu = current; ++} ++ ++ ++cSubMenuNodes *cSubMenuNode::GetSubMenus() ++{ ++ return(&_subMenus); ++} ++ ++bool cSubMenuNode::HasSubMenus() ++{ ++ if (_subMenus.Count() > 0) ++ return(true); ++ else ++ return(false); ++} ++ ++ ++void cSubMenuNode::Print(int index) ++{ ++ for (int i = 0; i < index; i++) ++ printf(" "); ++ ++ printf("Name=%s Type=%s Level=%d", _name, GetTypeAsString(), _level); ++ if (_type == COMMAND || _type == THREAD) ++ printf(" Command=%s", _command); ++ else if (_type == PLUGIN && _title != NULL) ++ printf(" Title=%s", _title); ++ printf("\n"); ++ ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->Print(index+4); ++} ++ ++ ++//################################################################################ ++//# ++//################################################################################ ++cSubMenu::cSubMenu() ++{ ++ _commandResult = NULL; ++ _currentMenuTree = &_menuTree; ++ _currentParentMenuTree = NULL; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = -1; ++#endif /* PINPLUGIN */ ++ _nodeArray = NULL; ++ _nrNodes = 0; ++} ++ ++ ++cSubMenu::~cSubMenu() ++{ ++ if (_commandResult) ++ free(_commandResult); ++ if (_nodeArray) ++ free(_nodeArray); ++ _nrNodes = 0; ++} ++ ++ ++bool cSubMenu::LoadXml(cString fname) ++{ ++ TiXmlDocument xmlDoc = TiXmlDocument(fname); ++ TiXmlElement *root = NULL; ++ cSubMenuNode *node = NULL; ++ ++ bool ok = true; ++ // Clear previously loaded Menu ++ _menuTree.Clear(); ++ _fname = fname; ++ ++ if ((ok = xmlDoc.LoadFile())) { ++ if ((root = xmlDoc.FirstChildElement("menus")) != NULL) { ++ cString tmp = root->Attribute("suffix"); ++#ifdef USE_WAREAGLEICON ++ if (strcmp(tmp, "ICON_FOLDER") == 0) tmp = cString::sprintf(" %s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER); ++ else if (strcmp(tmp, "ICON_MOVE_FOLDER") == 0) tmp = cString::sprintf(" %s", IsLangUtf8() ? ICON_MOVE_FOLDER_UTF8 : ICON_MOVE_FOLDER); ++#endif /* WAREAGLEICON */ ++ if (*tmp) ++ _menuSuffix = tmp; ++ else ++ _menuSuffix = cString::sprintf(" "); ++ ++ if ((root = root->FirstChildElement()) != NULL) { ++ do { ++ try { ++ node = new cSubMenuNode(root, 0, &_menuTree, NULL); ++ _menuTree.Add(node); ++ } ++ catch (char *message) { ++ esyslog("ERROR: while decoding XML Node"); ++ ok = false; ++ } ++ } while (ok == true && (root = root->NextSiblingElement()) != NULL); ++ addMissingPlugins(); ++ removeUndefinedNodes(); ++ } ++ } ++ else { ++ esyslog("ERROR: in %s, missing Tag <menus>\n", *fname); ++ ok = false; ++ } ++ } ++ else { ++ esyslog("ERROR: in %s : %s Col=%d Row=%d\n", ++ *fname, ++ xmlDoc.ErrorDesc(), ++ xmlDoc.ErrorCol(), ++ xmlDoc.ErrorRow()); ++ ok = false; ++ } ++ ++ return(ok); ++} ++ ++ ++bool cSubMenu::SaveXml() ++{ ++ return(SaveXml(_fname)); ++} ++ ++ ++bool cSubMenu::SaveXml(cString fname) ++{ ++ bool ok = true; ++ ++ if (*_fname) { ++ TiXmlDocument xml = TiXmlDocument(fname); ++ TiXmlComment comment; ++ comment.SetValue("\n\ ++- VDR Menu-Configuration File\n\ ++-\n\ ++-\n\ ++- Example:\n\ ++-\n\ ++ <menus>\n\ ++ <system name=\"Schedule\" />\n\ ++ <system name=\"Channels\" />\n\ ++ <system name=\"Timers\" />\n\ ++ <system name=\"Recordings\" />\n\ ++ <menu name=\"System\">\n\ ++ <system name=\"Setup\" />\n\ ++ <system name=\"Commands\" />\n\ ++ <plugin name=\"setup\" title=\"My Setup\" />\n\ ++ <command name=\"myCommand1\" execute=\"/usr/bin/mycommand1\" />\n\ ++ <command name=\"myCommand2\" execute=\"/usr/bin/mycommand2\" confirm=\"yes\" />\n\ ++ <thread name=\"myCommand3\" execute=\"/usr/bin/mycommand3\" confirm=\"yes\" />\n\ ++ <plugin name=\"epgsearch\" title=\"myProgram\" />\n\ ++ <menu name=\"mySubSubMenu\">\n\ ++ ...\n\ ++ </menu>\n\ ++ </menu>\n\ ++ <menu name=\"Suche\">\n\ ++ <plugin name=\"epgsearch\" />\n\ ++ ...\n\ ++ </menu>\n\ ++ </menus>\n\ ++"); ++ ++ TiXmlElement root("menus"); ++ root.SetAttribute("suffix", _menuSuffix); ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->SaveXml(&root); ++ ++ if (xml.InsertEndChild(comment) != NULL && xml.InsertEndChild(root) != NULL) ++ ok = xml.SaveFile(fname); ++ } ++ else ++ ok = false; ++ ++ return(ok); ++} ++ ++ ++cSubMenuNodes *cSubMenu::GetMenuTree() ++{ ++ return(_currentMenuTree); ++} ++ ++ ++void cSubMenu::PrintMenuTree() ++{ ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->Print(); ++} ++ ++ ++int cSubMenu::GetNrOfNodes() ++{ ++ if (_nrNodes == 0) { ++ if ((_nrNodes = countNodes(&_menuTree)) > 0) { ++ _nodeArray = (cSubMenuNode**) malloc(sizeof(cSubMenuNode*)*_nrNodes); ++ int index = 0; ++ tree2Array(&_menuTree, index); ++ } ++ } ++ ++ return(_nrNodes); ++} ++ ++ ++/** ++ * returns the specified node within the current menu ++ * @param index position in the current menu ++ * @return node or null if not found ++ */ ++cSubMenuNode *cSubMenu::GetNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ if (_currentMenuTree == NULL || (node=_currentMenuTree->Get(index)) == NULL) ++ esyslog("ERROR: illegal call of cSubMenu::GetNode(%d)", index); ++ ++ return(node); ++} ++ ++ ++/** ++ * Get the specified Node ++ * @param index specfies the absolut indes in the list of all nodes ++ * @return node or NULL if not found ++ */ ++cSubMenuNode *cSubMenu::GetAbsNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ GetNrOfNodes(); ++ if (_nrNodes > 0 && index >= 0 && index < _nrNodes) ++ node = _nodeArray[index]; ++ ++ return(node); ++} ++ ++ ++#ifdef USE_PINPLUGIN ++bool cSubMenu::Down(cSubMenuNode *node, int currentIndex) ++#else ++bool cSubMenu::Down(int index) ++#endif /* PINPLUGIN */ ++{ ++ bool ok = true; ++#ifdef USE_PINPLUGIN ++ if (_currentMenuTree != NULL && node && node->GetType() == cSubMenuNode::MENU) { ++#else ++ cSubMenuNode *node = NULL; ++ ++ if (_currentMenuTree != NULL && (node=_currentMenuTree->Get(index)) != NULL && node->GetType() == cSubMenuNode::MENU) { ++#endif /* PINPLUGIN */ ++ _currentParentMenuTree = _currentMenuTree; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = currentIndex; ++#endif /* PINPLUGIN */ ++ _currentMenuTree = node->GetSubMenus(); ++ } ++ else { ++ ok = false; ++#ifdef USE_PINPLUGIN ++ esyslog("ERROR: illegal call of cSubMenu::Down"); ++#else ++ esyslog("ERROR: illegal call of cSubMenu::Down(%d)", index); ++#endif /* PINPLUGIN */ ++ } ++ ++ return(ok); ++} ++ ++bool cSubMenu::Up(int *parentIndex) ++{ ++ bool ok = true; ++ ++ if (_currentMenuTree != NULL && parentIndex != NULL) { ++#ifndef USE_PINPLUGIN ++ cSubMenuNode *node = NULL; ++#endif /* PINPLUGIN */ ++ *parentIndex = 0; ++#ifdef USE_PINPLUGIN ++ if (_currentParentIndex >= 0) ++ *parentIndex = _currentParentIndex; ++#else ++ if (_currentParentMenuTree != NULL) ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ *parentIndex = i; ++ break; ++ } ++ } ++#endif /* PINPLUGIN */ ++ ++ _currentMenuTree = _currentParentMenuTree; ++ if (_currentMenuTree != NULL) ++ _currentParentMenuTree = _currentMenuTree->Get(0)->GetParentMenu(); ++ else ++ ok = false; ++ } ++ else { ++ ok = false; ++ esyslog("ERROR: illegal call of cSubMenu::Up()"); ++ } ++ ++ return(ok); ++} ++ ++const char *cSubMenu::ExecuteCommand(const char *cmd) ++{ ++ free(_commandResult); ++ _commandResult = NULL; ++ ++ dsyslog("executing command '%s'", cmd); ++ FILE *p = popen(cmd, "r"); ++ if (p) { ++ int l = 0; ++ int c; ++ while ((c = fgetc(p)) != EOF) { ++ if (l % 20 == 0) ++ _commandResult = (char *)realloc(_commandResult, l + 21); ++ _commandResult[l++] = c; ++ } ++ if (_commandResult) ++ _commandResult[l] = 0; ++ pclose(p); ++ } ++ else ++ esyslog("ERROR: can't open pipe for command '%s'", cmd); ++ ++ return _commandResult; ++} ++ ++/** ++ * Move Menu Entry to new Position ++ * @param index index of menu entry to move ++ * @param toIndex index of destination ++ * @param where After ore before the destination index ++ */ ++void cSubMenu::MoveMenu(int index, int toIndex, enum Where where) ++{ ++ if (index < 0 || index > _nrNodes || // invalid index is ignored ++ toIndex < 0 || toIndex > _nrNodes || index == toIndex) ++ return; ++ ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ cSubMenuNode *destNode = GetAbsNode(toIndex); ++ ++ if (where == cSubMenu::INTO && destNode->GetType() != cSubMenuNode::MENU) ++ return; ++ ++ if (where == cSubMenu::INTO) { ++ if (destNode->GetType() == cSubMenuNode::MENU) { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()+1); ++ srcNode->SetParentMenu(destNode->GetCurrentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetSubMenus()); ++ ++ destNode->GetSubMenus()->Add(srcNode); ++ reloadNodeArray(); ++ } ++ } ++ else { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()); ++ srcNode->SetParentMenu(destNode->GetParentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetCurrentMenu()); ++ ++ if (where == cSubMenu::BEHIND) { ++ destNode->GetCurrentMenu()->Add(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ else { ++ destNode->GetCurrentMenu()->Ins(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * Create a new Menu Entry ++ * @param index index of destination ++ * @param menuTitle Titel of new Menu entry ++ */ ++void cSubMenu::CreateMenu(int index, const char *menuTitle) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(menuTitle); ++ newNode->SetType(cSubMenuNode::MENU); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * delete the specified entry, or subtree if the specified entry is a menu ++ * @param index destion index ++ */ ++void cSubMenu::DeleteMenu(int index) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ srcNode->GetCurrentMenu()->Del(srcNode, true); ++ reloadNodeArray(); ++ } ++} ++ ++ ++// Private Methods ++ ++int cSubMenu::countNodes(cSubMenuNodes *tree) ++{ ++ int count = 0; ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ count++; ++ if (node->HasSubMenus()) ++ count += countNodes(node->GetSubMenus()); ++ } ++ } ++ return(count); ++} ++ ++ ++void cSubMenu::tree2Array(cSubMenuNodes *tree, int &index) ++{ ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ _nodeArray[index++]=node; ++ if (node->HasSubMenus()) ++ tree2Array(node->GetSubMenus(), index); ++ } ++ } ++ ++} ++ ++bool cSubMenu::IsPluginInMenu(const char *name) ++{ ++ bool found = false; ++ for (int i = 0; i < _nrNodes && found == false; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::PLUGIN && strcmp(name, node->GetName()) == 0) ++ found = true; ++ } ++ return(found); ++} ++ ++/** ++ * Adds the given plugin to the Menu-Tree if not allready in List ++ * @param name specifies the name of the plugin ++ */ ++void cSubMenu::AddPlugin(const char *name) ++{ ++ if (! IsPluginInMenu(name)) { ++ cSubMenuNode *node = new cSubMenuNode(&_menuTree, NULL); ++ node->SetName(name); ++ node->SetType("plugin"); ++ node->SetPlugin(); ++ _menuTree.Add(node); ++ } ++} ++ ++void cSubMenu::addMissingPlugins() ++{ ++ _nrNodes = GetNrOfNodes(); ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) ++ AddPlugin(p->Name()); ++ else ++ break; ++ } ++ reloadNodeArray(); ++} ++ ++/** ++ * Adds the given command to the Menu-Tree ++ * @param name specifies the name of the command ++ */ ++void cSubMenu::CreateCommand(int index, const char *name, const char *execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("command"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++void cSubMenu::CreateThread(int index, const char *name, const char *execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("thread"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * reloads the internal Array of Nodes ++ */ ++void cSubMenu::reloadNodeArray() ++{ ++ if (_nrNodes > 0) ++ free(_nodeArray); ++ _nodeArray = NULL; ++ _nrNodes = 0; ++ _nrNodes = GetNrOfNodes(); ++} ++ ++/** ++ * remove Undefined Nodes ++ */ ++void cSubMenu::removeUndefinedNodes() ++{ ++ bool remove = false; ++ ++ reloadNodeArray(); ++ for (int i = 0; i < _nrNodes; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::UNDEFINED) { ++ cSubMenuNodes *pMenu = node->GetCurrentMenu(); ++ pMenu->Del(node, true); ++ remove = true; ++ } ++ } ++ if (remove) ++ reloadNodeArray(); ++} ++ ++ ++/** ++* Retrieves the Menutitel of the parent Menu ++*/ ++const char *cSubMenu::GetParentMenuTitel() ++{ ++ const char *result = ""; ++ ++ if (_currentMenuTree != NULL && _currentParentMenuTree != NULL) { ++ cSubMenuNode *node = NULL; ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ result = node->GetName(); ++ break; ++ } ++ } ++ } ++ ++ return(result); ++} ++ ++#endif ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/submenu.h vdr-1.7.14.ExtP_NG/submenu.h +--- vdr-1.7.14/submenu.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/submenu.h 2010-04-10 15:45:11.601737459 +0200 +@@ -0,0 +1,159 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#define SUBMENU_H ++ ++#include "thread.h" ++#include "tools.h" ++#include "tinystr.h" ++ ++class cSubMenuNode; ++class cSubMenuNodes; ++class cSubMenu; ++ ++ ++class cSubMenuNodes : public cList<cSubMenuNode> {}; ++ ++// execute cmd thread ++class cExecCmdThread : public cThread { ++private: ++ cString ExecCmd; ++protected: ++ virtual void Action(void) { ++ if (system(ExecCmd) == 0) ++ esyslog("%s - finished", *ExecCmd); ++ delete(this); ++ }; ++public: ++ cExecCmdThread(char *cmd) { ++ ExecCmd = cString::sprintf("%s", cmd); ++ } ++ cExecCmdThread(const char *cmd) { ++ ExecCmd = cString::sprintf("%s", cmd); ++ } ++ ~cExecCmdThread() { ++ }; ++ }; ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++class cSubMenuNode : public cListObject { ++public: ++ enum Type { UNDEFINED, SYSTEM, COMMAND, THREAD, PLUGIN, MENU }; ++ cSubMenuNode(TiXmlElement *xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ ~cSubMenuNode(); ++ bool SaveXml(TiXmlElement *root); ++ static cSubMenuNode::Type IsType(const char *name); ++ void SetType(const char *name); ++ void SetType(enum Type type); ++ void SetPlugin(); ++ cSubMenuNode::Type GetType(); ++ const char *GetTypeAsString(); ++ void SetCommand(const char *command); ++ bool CommandConfirm(); ++ void SetCommandConfirm(int val); ++ const char *GetCommand(); ++ void SetCustomTitle(const char *title); ++ const char *GetCustomTitle(); ++ void SetName(const char *name); ++ const char*GetName(); ++ int GetLevel(); ++ void SetLevel(int level); ++ int GetPluginIndex(); ++ void SetPluginIndex(int index); ++ void SetPluginMainMenuEntry(const char *mainMenuEntry); ++ const char *GetPluginMainMenuEntry(); ++ cSubMenuNodes *GetParentMenu(); ++ void SetParentMenu(cSubMenuNodes *parent); ++ cSubMenuNodes *GetCurrentMenu(); ++ void SetCurrentMenu(cSubMenuNodes *current); ++ cSubMenuNodes *GetSubMenus(); ++ bool HasSubMenus(); ++ void Print(int index = 0); ++private: ++ Type _type; ++ int _level; ++ // Plugin Variables ++ int _pluginIndex; ++ const char *_pluginMainMenuEntry; ++ // common ++ const char *_name; ++ const char *_command; ++ bool _commandConfirm; ++ const char *_title; ++ cSubMenuNodes _subMenus; ++ cSubMenuNodes *_parentMenu; ++ cSubMenuNodes *_currentMenu; ++ void init(); ++ }; ++ ++ ++//################################################################################ ++//# SubMenu Class ++//################################################################################ ++class cSubMenu { ++public: ++ cSubMenu(); ++ ~cSubMenu(); ++ enum Where { BEFORE, BEHIND, INTO}; ++ bool LoadXml(cString fname); ++ bool SaveXml(cString fname); ++ bool SaveXml(); ++ cSubMenuNodes *GetMenuTree(); ++ bool Up(int *ParentIndex); ++#ifdef USE_PINPLUGIN ++ bool Down(cSubMenuNode* node, int currentIndex); ++#else ++ bool Down(int index); ++#endif /* PINPLUGIN */ ++ int GetNrOfNodes(); ++ cSubMenuNode* GetAbsNode(int index); ++ cSubMenuNode* GetNode(int index); ++ void PrintMenuTree(); ++ bool IsPluginInMenu(const char *name); ++ void AddPlugin(const char *name); ++ void CreateCommand(int index, const char *name, const char *execute, int confirm); ++ void CreateThread(int index, const char *name, const char *execute, int confirm); ++ const char *ExecuteCommand(const char *command); ++ void MoveMenu(int index, int toindex, enum Where); ++ void CreateMenu(int index, const char *menuTitle); ++ void DeleteMenu(int index); ++ cString GetMenuSuffix() { return _menuSuffix; } ++ void SetMenuSuffix(char *suffix) { _menuSuffix = suffix; } ++ bool isTopMenu() { return (_currentParentMenuTree == NULL); } ++ const char *GetParentMenuTitel(); ++private: ++ cSubMenuNodes _menuTree; ++ cSubMenuNodes *_currentMenuTree; ++ cSubMenuNodes *_currentParentMenuTree; ++#ifdef USE_PINPLUGIN ++ int _currentParentIndex; ++#endif /* PINPLUGIN */ ++ cString _fname; ++ char *_commandResult; ++ int _nrNodes; ++ cSubMenuNode **_nodeArray; ++ cString _menuSuffix; ++ int countNodes(cSubMenuNodes *tree); ++ void tree2Array(cSubMenuNodes *tree, int &index); ++ void addMissingPlugins(); ++ void reloadNodeArray(); ++ void removeUndefinedNodes(); ++ }; ++ ++#endif //__SUBMENU_H ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/svdrp.c vdr-1.7.14.ExtP_NG/svdrp.c +--- vdr-1.7.14/svdrp.c 2010-01-17 13:23:31.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/svdrp.c 2010-04-10 15:45:11.637740914 +0200 +@@ -304,6 +304,10 @@ + "REMO [ on | off ]\n" + " Turns the remote control on or off. Without a parameter, the current\n" + " status of the remote control is reported.", ++#ifdef USE_LIEMIEXT ++ "RENR <number> <new name>\n" ++ " Rename recording. Number must be the Number as returned by LSTR command.", ++#endif /* LIEMIEXT */ + "SCAN\n" + " Forces an EPG scan. If this is a single DVB device system, the scan\n" + " will be done on the primary device unless it is currently recording.", +@@ -1493,6 +1497,38 @@ + Reply(250, "EPG scan triggered"); + } + ++#ifdef USE_LIEMIEXT ++void cSVDRP::CmdRENR(const char *Option) ++{ ++ bool recordings = Recordings.Update(true); ++ if (recordings) { ++ if (*Option) { ++ char *tail; ++ int n = strtol(Option, &tail, 10); ++ cRecording *recording = Recordings.Get(n - 1); ++ if (recording && tail && tail != Option) { ++ char *oldName = strdup(recording->Name()); ++ tail = skipspace(tail); ++ if (recording->Rename(tail)) { ++ Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name()); ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ } ++ else ++ Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail); ++ free(oldName); ++ } ++ else ++ Reply(501, "Recording not found or wrong syntax"); ++ } ++ else ++ Reply(501, "Missing Input settings"); ++ } ++ else ++ Reply(550, "No recordings available"); ++} ++#endif /* LIEMIEXT */ ++ + void cSVDRP::CmdSTAT(const char *Option) + { + if (*Option) { +@@ -1608,6 +1644,9 @@ + else if (CMD("PLUG")) CmdPLUG(s); + else if (CMD("PUTE")) CmdPUTE(s); + else if (CMD("REMO")) CmdREMO(s); ++#ifdef USE_LIEMIEXT ++ else if (CMD("RENR")) CmdRENR(s); ++#endif /* LIEMIEXT */ + else if (CMD("SCAN")) CmdSCAN(s); + else if (CMD("STAT")) CmdSTAT(s); + else if (CMD("UPDT")) CmdUPDT(s); +diff -ruN vdr-1.7.14/svdrp.h vdr-1.7.14.ExtP_NG/svdrp.h +--- vdr-1.7.14/svdrp.h 2007-04-30 14:28:28.000000000 +0200 ++++ vdr-1.7.14.ExtP_NG/svdrp.h 2010-04-10 15:45:11.646738241 +0200 +@@ -79,6 +79,9 @@ + void CmdPLUG(const char *Option); + void CmdPUTE(const char *Option); + void CmdREMO(const char *Option); ++#ifdef USE_LIEMIEXT ++ void CmdRENR(const char *Option); ++#endif /* LIEMIEXT */ + void CmdSCAN(const char *Option); + void CmdSTAT(const char *Option); + void CmdUPDT(const char *Option); +diff -ruN vdr-1.7.14/timers.c vdr-1.7.14.ExtP_NG/timers.c +--- vdr-1.7.14/timers.c 2010-01-16 12:18:53.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/timers.c 2010-04-10 15:45:11.733740689 +0200 +@@ -46,6 +46,9 @@ + stop -= 2400; + priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; + lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + aux = NULL; + event = NULL; +@@ -84,6 +87,9 @@ + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + const char *Title = Event->Title(); + if (!isempty(Title)) +@@ -95,6 +101,9 @@ + } + aux = NULL; + event = NULL; // let SetEvent() be called to get a log message ++#ifdef USE_PINPLUGIN ++ cStatus::MsgTimerCreation(this, Event); ++#endif /* PINPLUGIN */ + } + + cTimer::cTimer(const cTimer &Timer) +@@ -129,6 +138,9 @@ + stop = Timer.stop; + priority = Timer.priority; + lifetime = Timer.lifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = Timer.fskProtection; ++#endif /* PINPLUGIN */ + strncpy(file, Timer.file, sizeof(file)); + free(aux); + aux = Timer.aux ? strdup(Timer.aux) : NULL; +@@ -323,6 +335,9 @@ + result = false; + } + } ++#ifdef USE_PINPLUGIN ++ fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"); ++#endif /* PINPLUGIN */ + free(channelbuffer); + free(daybuffer); + free(filebuffer); +@@ -632,6 +647,37 @@ + Matches(); // refresh start and end time + } + ++#ifdef USE_PINPLUGIN ++void cTimer::SetFskProtection(int aFlag) ++{ ++ char* p; ++ char* tmp = 0; ++ ++ fskProtection = aFlag; ++ ++ if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // add protection info to aux ++ ++ if (aux) { tmp = strdup(aux); free(aux); } ++ if (asprintf(&aux,"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : "") < 0 ) ++ aux = NULL; ++ } ++ else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // remove protection info to aux ++ ++ if (asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>")) >= 0 ) { ++ free(aux); ++ aux = strdup(tmp); ++ } ++ } ++ ++ if (tmp) ++ free(tmp); ++} ++#endif /* PINPLUGIN */ ++ + // --- cTimers --------------------------------------------------------------- + + cTimers Timers; +diff -ruN vdr-1.7.14/timers.h vdr-1.7.14.ExtP_NG/timers.h +--- vdr-1.7.14/timers.h 2008-02-16 15:33:23.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/timers.h 2010-04-10 15:45:11.743736984 +0200 +@@ -37,6 +37,9 @@ + int start; + int stop; + int priority; ++#ifdef USE_PINPLUGIN ++ int fskProtection; ++#endif /* PINPLUGIN */ + int lifetime; + mutable char file[MaxFileName]; + char *aux; +@@ -58,6 +61,9 @@ + int Start(void) const { return start; } + int Stop(void) const { return stop; } + int Priority(void) const { return priority; } ++#ifdef USE_PINPLUGIN ++ int FskProtection(void) const { return fskProtection; } ++#endif /* PINPLUGIN */ + int Lifetime(void) const { return lifetime; } + const char *File(void) const { return file; } + time_t FirstDay(void) const { return weekdays ? day : 0; } +@@ -86,6 +92,9 @@ + void SetInVpsMargin(bool InVpsMargin); + void SetPriority(int Priority); + void SetFlags(uint Flags); ++#ifdef USE_PINPLUGIN ++ void SetFskProtection(int aFlag); ++#endif /* PINPLUGIN */ + void ClrFlags(uint Flags); + void InvFlags(uint Flags); + bool HasFlags(uint Flags) const; +diff -ruN vdr-1.7.14/tinystr.c vdr-1.7.14.ExtP_NG/tinystr.c +--- vdr-1.7.14/tinystr.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinystr.c 2010-04-10 15:45:11.756737883 +0200 +@@ -0,0 +1,301 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++#ifndef TIXML_USE_STL ++ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++ ++#include "tinystr.h" ++ ++// TiXmlString constructor, based on a C string ++TiXmlString::TiXmlString (const char* instring) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (!instring) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = strlen (instring) + 1; ++ newstring = new char [newlen]; ++ memcpy (newstring, instring, newlen); ++ // strcpy (newstring, instring); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString copy constructor ++TiXmlString::TiXmlString (const TiXmlString& copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ // Prevent copy to self! ++ if ( © == this ) ++ return; ++ ++ if (! copy . allocated) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . cstring); ++ memcpy (newstring, copy . cstring, newlen); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString = operator. Safe when assign own content ++void TiXmlString ::operator = (const char * content) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! content) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = strlen (content) + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, content); ++ memcpy (newstring, content, newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// = operator. Safe when assign own content ++void TiXmlString ::operator = (const TiXmlString & copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! copy . length ()) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . c_str ()); ++ memcpy (newstring, copy . c_str (), newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char* str, int len ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size, size_suffix; ++ ++ // don't use strlen - it can overrun the len passed in! ++ const char* p = str; ++ size_suffix = 0; ++ ++ while ( *p && size_suffix < (unsigned)len ) ++ { ++ ++p; ++ ++size_suffix; ++ } ++ if ( !size_suffix) ++ return; ++ ++ new_size = length () + size_suffix + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ // strcpy (new_string, cstring); ++ memcpy (new_string, cstring, length ()); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strncat (new_string, str, len); ++ memcpy (new_string + length (), ++ str, ++ size_suffix); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strncat (cstring, str, len); ++ memcpy (cstring + length (), ++ str, ++ size_suffix); ++ } ++ current_length = new_size - 1; ++ cstring [current_length] = 0; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char * suffix ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size; ++ ++ new_size = length () + strlen (suffix) + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ memcpy (new_string, cstring, 1 + length ()); ++ // strcpy (new_string, cstring); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strcat (new_string, suffix); ++ memcpy (new_string + length (), ++ suffix, ++ strlen (suffix) + 1); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strcat (cstring, suffix); ++ memcpy (cstring + length (), ++ suffix, ++ strlen (suffix) + 1); ++ } ++ current_length = new_size - 1; ++} ++ ++// Check for TiXmlString equuivalence ++//bool TiXmlString::operator == (const TiXmlString & compare) const ++//{ ++// return (! strcmp (c_str (), compare . c_str ())); ++//} ++ ++//unsigned TiXmlString::length () const ++//{ ++// if (allocated) ++// // return strlen (cstring); ++// return current_length; ++// return 0; ++//} ++ ++ ++unsigned TiXmlString::find (char tofind, unsigned offset) const ++{ ++ char * lookup; ++ ++ if (offset >= length ()) ++ return (unsigned) notfound; ++ for (lookup = cstring + offset; * lookup; lookup++) ++ if (* lookup == tofind) ++ return lookup - cstring; ++ return (unsigned) notfound; ++} ++ ++ ++bool TiXmlString::operator == (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) == 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator < (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) > 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator > (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) < 0 ); ++ } ++ return false; ++} ++ ++ ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/tinystr.h vdr-1.7.14.ExtP_NG/tinystr.h +--- vdr-1.7.14/tinystr.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinystr.h 2010-04-10 15:45:11.768736847 +0200 +@@ -0,0 +1,244 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++ ++#ifndef TIXML_USE_STL ++ ++#ifndef TIXML_STRING_INCLUDED ++#define TIXML_STRING_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4786 ) // Debugger truncating names. ++#endif ++ ++#include <assert.h> ++ ++/* ++ TiXmlString is an emulation of the std::string template. ++ Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. ++ Only the member functions relevant to the TinyXML project have been implemented. ++ The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase ++ a string and there's no more room, we allocate a buffer twice as big as we need. ++*/ ++class TiXmlString ++{ ++ public : ++ // TiXmlString constructor, based on a string ++ TiXmlString (const char * instring); ++ ++ // TiXmlString empty constructor ++ TiXmlString () ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ } ++ ++ // TiXmlString copy constructor ++ TiXmlString (const TiXmlString& copy); ++ ++ // TiXmlString destructor ++ ~ TiXmlString () ++ { ++ empty_it (); ++ } ++ ++ // Convert a TiXmlString into a classical char * ++ const char * c_str () const ++ { ++ if (allocated) ++ return cstring; ++ return ""; ++ } ++ ++ // Return the length of a TiXmlString ++ unsigned length () const ++ { ++ return ( allocated ) ? current_length : 0; ++ } ++ ++ // TiXmlString = operator ++ void operator = (const char * content); ++ ++ // = operator ++ void operator = (const TiXmlString & copy); ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (const char * suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (char single) ++ { ++ append (single); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (TiXmlString & suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ bool operator == (const TiXmlString & compare) const; ++ bool operator < (const TiXmlString & compare) const; ++ bool operator > (const TiXmlString & compare) const; ++ ++ // Checks if a TiXmlString is empty ++ bool empty () const ++ { ++ return length () ? false : true; ++ } ++ ++ // single char extraction ++ const char& at (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // find a char in a string. Return TiXmlString::notfound if not found ++ unsigned find (char lookup) const ++ { ++ return find (lookup, 0); ++ } ++ ++ // find a char in a string from an offset. Return TiXmlString::notfound if not found ++ unsigned find (char tofind, unsigned offset) const; ++ ++ /* Function to reserve a big amount of data when we know we'll need it. Be aware that this ++ function clears the content of the TiXmlString if any exists. ++ */ ++ void reserve (unsigned size) ++ { ++ empty_it (); ++ if (size) ++ { ++ allocated = size; ++ cstring = new char [size]; ++ cstring [0] = 0; ++ current_length = 0; ++ } ++ } ++ ++ // [] operator ++ char& operator [] (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // Error value for find primitive ++ enum { notfound = 0xffffffff, ++ npos = notfound }; ++ ++ void append (const char *str, int len ); ++ ++ protected : ++ ++ // The base string ++ char * cstring; ++ // Number of chars allocated ++ unsigned allocated; ++ // Current string size ++ unsigned current_length; ++ ++ // New size computation. It is simplistic right now : it returns twice the amount ++ // we need ++ unsigned assign_new_size (unsigned minimum_to_allocate) ++ { ++ return minimum_to_allocate * 2; ++ } ++ ++ // Internal function that clears the content of a TiXmlString ++ void empty_it () ++ { ++ if (cstring) ++ delete [] cstring; ++ cstring = NULL; ++ allocated = 0; ++ current_length = 0; ++ } ++ ++ void append (const char *suffix ); ++ ++ // append function for another TiXmlString ++ void append (const TiXmlString & suffix) ++ { ++ append (suffix . c_str ()); ++ } ++ ++ // append for a single char. ++ void append (char single) ++ { ++ if ( cstring && current_length < (allocated-1) ) ++ { ++ cstring[ current_length ] = single; ++ ++current_length; ++ cstring[ current_length ] = 0; ++ } ++ else ++ { ++ char smallstr [2]; ++ smallstr [0] = single; ++ smallstr [1] = 0; ++ append (smallstr); ++ } ++ } ++ ++} ; ++ ++/* ++ TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. ++ Only the operators that we need for TinyXML have been developped. ++*/ ++class TiXmlOutStream : public TiXmlString ++{ ++public : ++ TiXmlOutStream () : TiXmlString () {} ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const char * in) ++ { ++ append (in); ++ return (* this); ++ } ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const TiXmlString & in) ++ { ++ append (in . c_str ()); ++ return (* this); ++ } ++} ; ++ ++#endif // TIXML_STRING_INCLUDED ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/tinyxml.c vdr-1.7.14.ExtP_NG/tinyxml.c +--- vdr-1.7.14/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxml.c 2010-04-10 15:45:11.784736808 +0200 +@@ -0,0 +1,1429 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include <ctype.h> ++#include "tinyxml.h" ++ ++#ifdef TIXML_USE_STL ++#include <sstream> ++#endif ++ ++ ++bool TiXmlBase::condenseWhiteSpace = true; ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream ) ++{ ++ TIXML_STRING buffer; ++ PutString( str, &buffer ); ++ (*stream) << buffer; ++} ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) ++{ ++ int i=0; ++ ++ while( i<(int)str.length() ) ++ { ++ unsigned char c = (unsigned char) str[i]; ++ ++ if ( c == '&' ++ && i < ( (int)str.length() - 2 ) ++ && str[i+1] == '#' ++ && str[i+2] == 'x' ) ++ { ++ // Hexadecimal character reference. ++ // Pass through unchanged. ++ // © -- copyright symbol, for example. ++ // ++ // The -1 is a bug fix from Rob Laveaux. It keeps ++ // an overflow from happening if there is no ';'. ++ // There are actually 2 ways to exit this loop - ++ // while fails (error case) and break (semicolon found). ++ // However, there is no mechanism (currently) for ++ // this function to return an error. ++ while ( i<(int)str.length()-1 ) ++ { ++ outString->append( str.c_str() + i, 1 ); ++ ++i; ++ if ( str[i] == ';' ) ++ break; ++ } ++ } ++ else if ( c == '&' ) ++ { ++ outString->append( entity[0].str, entity[0].strLength ); ++ ++i; ++ } ++ else if ( c == '<' ) ++ { ++ outString->append( entity[1].str, entity[1].strLength ); ++ ++i; ++ } ++ else if ( c == '>' ) ++ { ++ outString->append( entity[2].str, entity[2].strLength ); ++ ++i; ++ } ++ else if ( c == '\"' ) ++ { ++ outString->append( entity[3].str, entity[3].strLength ); ++ ++i; ++ } ++ else if ( c == '\'' ) ++ { ++ outString->append( entity[4].str, entity[4].strLength ); ++ ++i; ++ } ++ else if ( c < 32 ) ++ { ++ // Easy pass at non-alpha/numeric/symbol ++ // Below 32 is symbolic. ++ char buf[ 32 ]; ++ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); ++ outString->append( buf, strlen( buf ) ); ++ ++i; ++ } ++ else ++ { ++ //char realc = (char) c; ++ //outString->append( &realc, 1 ); ++ *outString += (char) c; // somewhat more efficient function call. ++ ++i; ++ } ++ } ++} ++ ++ ++// <-- Strange class for a bug fix. Search for STL_STRING_BUG ++TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str ) ++{ ++ buffer = new char[ str.length()+1 ]; ++ if ( buffer ) ++ { ++ strcpy( buffer, str.c_str() ); ++ } ++} ++ ++ ++TiXmlBase::StringToBuffer::~StringToBuffer() ++{ ++ delete [] buffer; ++} ++// End strange bug fix. --> ++ ++ ++TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() ++{ ++ parent = 0; ++ type = _type; ++ firstChild = 0; ++ lastChild = 0; ++ prev = 0; ++ next = 0; ++} ++ ++ ++TiXmlNode::~TiXmlNode() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++} ++ ++ ++void TiXmlNode::CopyTo( TiXmlNode* target ) const ++{ ++ target->SetValue (value.c_str() ); ++ target->userData = userData; ++} ++ ++ ++void TiXmlNode::Clear() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++ ++ firstChild = 0; ++ lastChild = 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) ++{ ++ node->parent = this; ++ ++ node->prev = lastChild; ++ node->next = 0; ++ ++ if ( lastChild ) ++ lastChild->next = node; ++ else ++ firstChild = node; // it was an empty list. ++ ++ lastChild = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) ++{ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ return LinkEndChild( node ); ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) ++{ ++ if ( !beforeThis || beforeThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->next = beforeThis; ++ node->prev = beforeThis->prev; ++ if ( beforeThis->prev ) ++ { ++ beforeThis->prev->next = node; ++ } ++ else ++ { ++ assert( firstChild == beforeThis ); ++ firstChild = node; ++ } ++ beforeThis->prev = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) ++{ ++ if ( !afterThis || afterThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->prev = afterThis; ++ node->next = afterThis->next; ++ if ( afterThis->next ) ++ { ++ afterThis->next->prev = node; ++ } ++ else ++ { ++ assert( lastChild == afterThis ); ++ lastChild = node; ++ } ++ afterThis->next = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) ++{ ++ if ( replaceThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = withThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ node->next = replaceThis->next; ++ node->prev = replaceThis->prev; ++ ++ if ( replaceThis->next ) ++ replaceThis->next->prev = node; ++ else ++ lastChild = node; ++ ++ if ( replaceThis->prev ) ++ replaceThis->prev->next = node; ++ else ++ firstChild = node; ++ ++ delete replaceThis; ++ node->parent = this; ++ return node; ++} ++ ++ ++bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) ++{ ++ if ( removeThis->parent != this ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ if ( removeThis->next ) ++ removeThis->next->prev = removeThis->prev; ++ else ++ lastChild = removeThis->prev; ++ ++ if ( removeThis->prev ) ++ removeThis->prev->next = removeThis->next; ++ else ++ firstChild = removeThis->next; ++ ++ delete removeThis; ++ return true; ++} ++ ++TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = firstChild; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING( _value )) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::LastChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = lastChild; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild(); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling(); ++ } ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild( val ); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling( val ); ++ } ++} ++ ++TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = next; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = prev; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++void TiXmlElement::RemoveAttribute( const char * name ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement* TiXmlNode::NextSiblingElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++ ++TiXmlDocument* TiXmlNode::GetDocument() const ++{ ++ const TiXmlNode* node; ++ ++ for( node = this; node; node = node->parent ) ++ { ++ if ( node->ToDocument() ) ++ return node->ToDocument(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement::TiXmlElement (const char * _value) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlElement::TiXmlElement( const std::string& _value ) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++#endif ++ ++ ++TiXmlElement::TiXmlElement( const TiXmlElement& copy) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlElement::operator=( const TiXmlElement& base ) ++{ ++ ClearThis(); ++ base.CopyTo( this ); ++} ++ ++ ++TiXmlElement::~TiXmlElement() ++{ ++ ClearThis(); ++} ++ ++ ++void TiXmlElement::ClearThis() ++{ ++ Clear(); ++ while( attributeSet.First() ) ++ { ++ TiXmlAttribute* node = attributeSet.First(); ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ ++ if ( node ) ++ return node->Value(); ++ ++ return 0; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, int* i ) const ++{ ++ const char * s = Attribute( name ); ++ if ( i ) ++ { ++ if ( s ) ++ *i = atoi( s ); ++ else ++ *i = 0; ++ } ++ return s; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, double* d ) const ++{ ++ const char * s = Attribute( name ); ++ if ( d ) ++ { ++ if ( s ) ++ *d = atof( s ); ++ else ++ *d = 0; ++ } ++ return s; ++} ++ ++ ++int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryIntValue( ival ); ++} ++ ++ ++int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryDoubleValue( dval ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, int val ) ++{ ++ char buf[64]; ++ sprintf( buf, "%d", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetDoubleAttribute( const char * name, double val ) ++{ ++ char buf[128]; ++ sprintf( buf, "%f", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, const char * _value ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ node->SetValue( _value ); ++ return; ++ } ++ ++ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); ++ if ( attrib ) ++ { ++ attributeSet.Add( attrib ); ++ } ++ else ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++} ++ ++void TiXmlElement::Print( FILE* cfile, int depth ) const ++{ ++ int i; ++ for ( i=0; i<depth; i++ ) ++ { ++ fprintf( cfile, " " ); ++ } ++ ++ fprintf( cfile, "<%s", value.c_str() ); ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ fprintf( cfile, " " ); ++ attrib->Print( cfile, depth ); ++ } ++ ++ // There are 3 different formatting approaches: ++ // 1) An element without children is printed as a <foo /> node ++ // 2) An element with only a text child is printed as <foo> text </foo> ++ // 3) An element with children is printed on multiple lines. ++ TiXmlNode* node; ++ if ( !firstChild ) ++ { ++ fprintf( cfile, " />" ); ++ } ++ else if ( firstChild == lastChild && firstChild->ToText() ) ++ { ++ fprintf( cfile, ">" ); ++ firstChild->Print( cfile, depth + 1 ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++ else ++ { ++ fprintf( cfile, ">" ); ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ if ( !node->ToText() ) ++ { ++ fprintf( cfile, "\n" ); ++ } ++ node->Print( cfile, depth+1 ); ++ } ++ fprintf( cfile, "\n" ); ++ for( i=0; i<depth; ++i ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++} ++ ++void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value; ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ (*stream) << " "; ++ attrib->StreamOut( stream ); ++ } ++ ++ // If this node has children, give it a closing tag. Else ++ // make it an empty tag. ++ TiXmlNode* node; ++ if ( firstChild ) ++ { ++ (*stream) << ">"; ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ node->StreamOut( stream ); ++ } ++ (*stream) << "</" << value << ">"; ++ } ++ else ++ { ++ (*stream) << " />"; ++ } ++} ++ ++ ++void TiXmlElement::CopyTo( TiXmlElement* target ) const ++{ ++ // superclass: ++ TiXmlNode::CopyTo( target ); ++ ++ // Element class: ++ // Clone the attributes, then clone the children. ++ TiXmlAttribute* attribute = 0; ++ for( attribute = attributeSet.First(); ++ attribute; ++ attribute = attribute->Next() ) ++ { ++ target->SetAttribute( attribute->Name(), attribute->Value() ); ++ } ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlElement::Clone() const ++{ ++ TiXmlElement* clone = new TiXmlElement( Value() ); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ ClearError(); ++} ++ ++TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++#endif ++ ++ ++TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDocument::operator=( const TiXmlDocument& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && LoadFile( buf.buffer, encoding ) ) ++ return true; ++ ++ return false; ++} ++ ++ ++bool TiXmlDocument::SaveFile() const ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && SaveFile( buf.buffer ) ) ++ return true; ++ ++ return false; ++} ++ ++bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding ) ++{ ++ // Delete the existing data: ++ Clear(); ++ location.Clear(); ++ ++ // There was a really terrifying little bug here. The code: ++ // value = filename ++ // in the STL case, cause the assignment method of the std::string to ++ // be called. What is strange, is that the std::string had the same ++ // address as it's c_str() method, and so bad things happen. Looks ++ // like a bug in the Microsoft STL implementation. ++ // See STL_STRING_BUG above. ++ // Fixed with the StringToBuffer class. ++ value = filename; ++ ++ FILE* file = fopen( value.c_str (), "r" ); ++ ++ if ( file ) ++ { ++ // Get the file size, so we can pre-allocate the string. HUGE speed impact. ++ long length = 0; ++ fseek( file, 0, SEEK_END ); ++ length = ftell( file ); ++ fseek( file, 0, SEEK_SET ); ++ ++ // Strange case, but good to handle up front. ++ if ( length == 0 ) ++ { ++ fclose( file ); ++ return false; ++ } ++ ++ // If we have a file, assume it is all one big XML file, and read it in. ++ // The document parser may decide the document ends sooner than the entire file, however. ++ TIXML_STRING data; ++ data.reserve( length ); ++ ++ const int BUF_SIZE = 2048; ++ char buf[BUF_SIZE]; ++ ++ while( fgets( buf, BUF_SIZE, file ) ) ++ { ++ data += buf; ++ } ++ fclose( file ); ++ ++ Parse( data.c_str(), 0, encoding ); ++ ++ if ( Error() ) ++ return false; ++ else ++ return true; ++ } ++ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return false; ++} ++ ++bool TiXmlDocument::SaveFile( const char * filename ) const ++{ ++ // The old c stuff lives on... ++ FILE* fp = fopen( filename, "w" ); ++ if ( fp ) ++ { ++ Print( fp, 0 ); ++ fclose( fp ); ++ return true; ++ } ++ return false; ++} ++ ++ ++void TiXmlDocument::CopyTo( TiXmlDocument* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->error = error; ++ target->errorDesc = errorDesc.c_str (); ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlDocument::Clone() const ++{ ++ TiXmlDocument* clone = new TiXmlDocument(); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlDocument::Print( FILE* cfile, int depth ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->Print( cfile, depth ); ++ fprintf( cfile, "\n" ); ++ } ++} ++ ++void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->StreamOut( out ); ++ ++ // Special rule for streams: stop after the root element. ++ // The stream in code will only read one element, so don't ++ // write more than one. ++ if ( node->ToElement() ) ++ break; ++ } ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Next() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( next->value.empty() && next->name.empty() ) ++ return 0; ++ return next; ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Previous() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( prev->value.empty() && prev->name.empty() ) ++ return 0; ++ return prev; ++} ++ ++ ++void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING n, v; ++ ++ PutString( name, &n ); ++ PutString( value, &v ); ++ ++ if (value.find ('\"') == TIXML_STRING::npos) ++ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); ++ else ++ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); ++} ++ ++ ++void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ if (value.find( '\"' ) != TIXML_STRING::npos) ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "'"; ++ PutString( value, stream ); ++ (*stream) << "'"; ++ } ++ else ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "\""; ++ PutString( value, stream ); ++ (*stream) << "\""; ++ } ++} ++ ++int TiXmlAttribute::QueryIntValue( int* ival ) const ++{ ++ if ( sscanf( value.c_str(), "%d", ival ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++int TiXmlAttribute::QueryDoubleValue( double* dval ) const ++{ ++ if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++void TiXmlAttribute::SetIntValue( int _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%d", _value); ++ SetValue (buf); ++} ++ ++void TiXmlAttribute::SetDoubleValue( double _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%lf", _value); ++ SetValue (buf); ++} ++ ++const int TiXmlAttribute::IntValue() const ++{ ++ return atoi (value.c_str ()); ++} ++ ++const double TiXmlAttribute::DoubleValue() const ++{ ++ return atof (value.c_str ()); ++} ++ ++ ++TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::operator=( const TiXmlComment& base ) ++{ ++ Clear(); ++ base.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ { ++ fputs( " ", cfile ); ++ } ++ fprintf( cfile, "<!--%s-->", value.c_str() ); ++} ++ ++void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<!--"; ++ //PutString( value, stream ); ++ (*stream) << value; ++ (*stream) << "-->"; ++} ++ ++ ++void TiXmlComment::CopyTo( TiXmlComment* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlComment::Clone() const ++{ ++ TiXmlComment* clone = new TiXmlComment(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING buffer; ++ PutString( value, &buffer ); ++ fprintf( cfile, "%s", buffer.c_str() ); ++} ++ ++ ++void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ PutString( value, stream ); ++} ++ ++ ++void TiXmlText::CopyTo( TiXmlText* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlText::Clone() const ++{ ++ TiXmlText* clone = 0; ++ clone = new TiXmlText( "" ); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const char * _version, ++ const char * _encoding, ++ const char * _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++#endif ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ fprintf (cfile, "<?xml "); ++ ++ if ( !version.empty() ) ++ fprintf (cfile, "version=\"%s\" ", version.c_str ()); ++ if ( !encoding.empty() ) ++ fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); ++ if ( !standalone.empty() ) ++ fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); ++ fprintf (cfile, "?>"); ++} ++ ++void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<?xml "; ++ ++ if ( !version.empty() ) ++ { ++ (*stream) << "version=\""; ++ PutString( version, stream ); ++ (*stream) << "\" "; ++ } ++ if ( !encoding.empty() ) ++ { ++ (*stream) << "encoding=\""; ++ PutString( encoding, stream ); ++ (*stream ) << "\" "; ++ } ++ if ( !standalone.empty() ) ++ { ++ (*stream) << "standalone=\""; ++ PutString( standalone, stream ); ++ (*stream) << "\" "; ++ } ++ (*stream) << "?>"; ++} ++ ++ ++void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->version = version; ++ target->encoding = encoding; ++ target->standalone = standalone; ++} ++ ++ ++TiXmlNode* TiXmlDeclaration::Clone() const ++{ ++ TiXmlDeclaration* clone = new TiXmlDeclaration(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlUnknown::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "<%s>", value.c_str() ); ++} ++ ++ ++void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown. ++} ++ ++ ++void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlUnknown::Clone() const ++{ ++ TiXmlUnknown* clone = new TiXmlUnknown(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlAttributeSet::TiXmlAttributeSet() ++{ ++ sentinel.next = &sentinel; ++ sentinel.prev = &sentinel; ++} ++ ++ ++TiXmlAttributeSet::~TiXmlAttributeSet() ++{ ++ assert( sentinel.next == &sentinel ); ++ assert( sentinel.prev == &sentinel ); ++} ++ ++ ++void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) ++{ ++ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. ++ ++ addMe->next = &sentinel; ++ addMe->prev = sentinel.prev; ++ ++ sentinel.prev->next = addMe; ++ sentinel.prev = addMe; ++} ++ ++void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node == removeMe ) ++ { ++ node->prev->next = node->next; ++ node->next->prev = node->prev; ++ node->next = 0; ++ node->prev = 0; ++ return; ++ } ++ } ++ assert( 0 ); // we tried to remove a non-linked attribute. ++} ++ ++TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node->name == name ) ++ return node; ++ } ++ return 0; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base) ++{ ++ TIXML_STRING tag; ++ tag.reserve( 8 * 1000 ); ++ base.StreamIn( &in, &tag ); ++ ++ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); ++ return in; ++} ++#endif ++ ++ ++TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base) ++{ ++ base.StreamOut (& out); ++ return out; ++} ++ ++ ++#ifdef TIXML_USE_STL ++std::string & operator<< (std::string& out, const TiXmlNode& base ) ++{ ++ std::ostringstream os_stream( std::ostringstream::out ); ++ base.StreamOut( &os_stream ); ++ ++ out.append( os_stream.str() ); ++ return out; ++} ++#endif ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild() const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement() const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/tinyxml.h vdr-1.7.14.ExtP_NG/tinyxml.h +--- vdr-1.7.14/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxml.h 2010-04-10 15:45:11.801740955 +0200 +@@ -0,0 +1,1372 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++ ++#ifndef TINYXML_INCLUDED ++#define TINYXML_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4530 ) ++#pragma warning( disable : 4786 ) ++#endif ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++// Help out windows: ++#if defined( _DEBUG ) && !defined( DEBUG ) ++#define DEBUG ++#endif ++ ++#if defined( DEBUG ) && defined( _MSC_VER ) ++#include <windows.h> ++#define TIXML_LOG OutputDebugString ++#else ++#define TIXML_LOG printf ++#endif ++ ++#ifdef TIXML_USE_STL ++ #include <string> ++ #include <iostream> ++ #define TIXML_STRING std::string ++ #define TIXML_ISTREAM std::istream ++ #define TIXML_OSTREAM std::ostream ++#else ++ #include "tinystr.h" ++ #define TIXML_STRING TiXmlString ++ #define TIXML_OSTREAM TiXmlOutStream ++#endif ++ ++class TiXmlDocument; ++class TiXmlElement; ++class TiXmlComment; ++class TiXmlUnknown; ++class TiXmlAttribute; ++class TiXmlText; ++class TiXmlDeclaration; ++class TiXmlParsingData; ++ ++const int TIXML_MAJOR_VERSION = 2; ++const int TIXML_MINOR_VERSION = 3; ++const int TIXML_PATCH_VERSION = 2; ++ ++/* Internal structure for tracking location of items ++ in the XML file. ++*/ ++struct TiXmlCursor ++{ ++ TiXmlCursor() { Clear(); } ++ void Clear() { row = col = -1; } ++ ++ int row; // 0 based. ++ int col; // 0 based. ++}; ++ ++ ++// Only used by Attribute::Query functions ++enum ++{ ++ TIXML_SUCCESS, ++ TIXML_NO_ATTRIBUTE, ++ TIXML_WRONG_TYPE ++}; ++ ++ ++// Used by the parsing routines. ++enum TiXmlEncoding ++{ ++ TIXML_ENCODING_UNKNOWN, ++ TIXML_ENCODING_UTF8, ++ TIXML_ENCODING_LEGACY ++}; ++ ++const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; ++ ++/** TiXmlBase is a base class for every class in TinyXml. ++ It does little except to establish that TinyXml classes ++ can be printed and provide some utility functions. ++ ++ In XML, the document and elements can contain ++ other elements and other types of nodes. ++ ++ @verbatim ++ A Document can contain: Element (container or leaf) ++ Comment (leaf) ++ Unknown (leaf) ++ Declaration( leaf ) ++ ++ An Element can contain: Element (container or leaf) ++ Text (leaf) ++ Attributes (not on tree) ++ Comment (leaf) ++ Unknown (leaf) ++ ++ A Decleration contains: Attributes (not on tree) ++ @endverbatim ++*/ ++class TiXmlBase ++{ ++ friend class TiXmlNode; ++ friend class TiXmlElement; ++ friend class TiXmlDocument; ++ ++public: ++ TiXmlBase() : userData(0) {} ++ virtual ~TiXmlBase() {} ++ ++ /** All TinyXml classes can print themselves to a filestream. ++ This is a formatted print, and will insert tabs and newlines. ++ ++ (For an unformatted stream, use the << operator.) ++ */ ++ virtual void Print( FILE* cfile, int depth ) const = 0; ++ ++ /** The world does not agree on whether white space should be kept or ++ not. In order to make everyone happy, these global, static functions ++ are provided to set whether or not TinyXml will condense all white space ++ into a single space or not. The default is to condense. Note changing this ++ values is not thread safe. ++ */ ++ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } ++ ++ /// Return the current white space setting. ++ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } ++ ++ /** Return the position, in the original source file, of this node or attribute. ++ The row and column are 1-based. (That is the first row and first column is ++ 1,1). If the returns values are 0 or less, then the parser does not have ++ a row and column value. ++ ++ Generally, the row and column value will be set when the TiXmlDocument::Load(), ++ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set ++ when the DOM was created from operator>>. ++ ++ The values reflect the initial load. Once the DOM is modified programmatically ++ (by adding or changing nodes and attributes) the new values will NOT update to ++ reflect changes in the document. ++ ++ There is a minor performance cost to computing the row and column. Computation ++ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. ++ ++ @sa TiXmlDocument::SetTabSize() ++ */ ++ int Row() const { return location.row + 1; } ++ int Column() const { return location.col + 1; } ///< See Row() ++ ++ void SetUserData( void* user ) { userData = user; } ++ void* GetUserData() { return userData; } ++ ++ // Table that returs, for a given lead byte, the total number of bytes ++ // in the UTF-8 sequence. ++ static const int utf8ByteTable[256]; ++ ++ virtual const char* Parse( const char* p, ++ TiXmlParsingData* data, ++ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; ++ ++protected: ++ ++ // See STL_STRING_BUG ++ // Utility class to overcome a bug. ++ class StringToBuffer ++ { ++ public: ++ StringToBuffer( const TIXML_STRING& str ); ++ ~StringToBuffer(); ++ char* buffer; ++ }; ++ ++ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); ++ inline static bool IsWhiteSpace( char c ) ++ { ++ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); ++ } ++ ++ virtual void StreamOut (TIXML_OSTREAM *) const = 0; ++ ++ #ifdef TIXML_USE_STL ++ static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); ++ #endif ++ ++ /* Reads an XML name into the string provided. Returns ++ a pointer just past the last character of the name, ++ or 0 if the function has an error. ++ */ ++ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); ++ ++ /* Reads text. Returns a pointer past the given end tag. ++ Wickedly complex options, but it keeps the (sensitive) code in one place. ++ */ ++ static const char* ReadText( const char* in, // where to start ++ TIXML_STRING* text, // the string read ++ bool ignoreWhiteSpace, // whether to keep the white space ++ const char* endTag, // what ends this text ++ bool ignoreCase, // whether to ignore case in the end tag ++ TiXmlEncoding encoding ); // the current encoding ++ ++ // If an entity has been found, transform it into a character. ++ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); ++ ++ // Get a character, while interpreting entities. ++ // The length can be from 0 to 4 bytes. ++ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) ++ { ++ assert( p ); ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ *length = utf8ByteTable[ *((unsigned char*)p) ]; ++ assert( *length >= 0 && *length < 5 ); ++ } ++ else ++ { ++ *length = 1; ++ } ++ ++ if ( *length == 1 ) ++ { ++ if ( *p == '&' ) ++ return GetEntity( p, _value, length, encoding ); ++ *_value = *p; ++ return p+1; ++ } ++ else if ( *length ) ++ { ++ strncpy( _value, p, *length ); ++ return p + (*length); ++ } ++ else ++ { ++ // Not valid text. ++ return 0; ++ } ++ } ++ ++ // Puts a string to a stream, expanding entities as it goes. ++ // Note this should not contian the '<', '>', etc, or they will be transformed into entities! ++ static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); ++ ++ static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); ++ ++ // Return true if the next characters in the stream are any of the endTag sequences. ++ // Ignore case only works for english, and should only be relied on when comparing ++ // to Engilish words: StringEqual( p, "version", true ) is fine. ++ static bool StringEqual( const char* p, ++ const char* endTag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ); ++ ++ ++ enum ++ { ++ TIXML_NO_ERROR = 0, ++ TIXML_ERROR, ++ TIXML_ERROR_OPENING_FILE, ++ TIXML_ERROR_OUT_OF_MEMORY, ++ TIXML_ERROR_PARSING_ELEMENT, ++ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, ++ TIXML_ERROR_READING_ELEMENT_VALUE, ++ TIXML_ERROR_READING_ATTRIBUTES, ++ TIXML_ERROR_PARSING_EMPTY, ++ TIXML_ERROR_READING_END_TAG, ++ TIXML_ERROR_PARSING_UNKNOWN, ++ TIXML_ERROR_PARSING_COMMENT, ++ TIXML_ERROR_PARSING_DECLARATION, ++ TIXML_ERROR_DOCUMENT_EMPTY, ++ TIXML_ERROR_EMBEDDED_NULL, ++ ++ TIXML_ERROR_STRING_COUNT ++ }; ++ static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; ++ ++ TiXmlCursor location; ++ ++ /// Field containing a generic user pointer ++ void* userData; ++ ++ // None of these methods are reliable for any language except English. ++ // Good for approximation, not great for accuracy. ++ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); ++ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); ++ inline static int ToLower( int v, TiXmlEncoding encoding ) ++ { ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( v < 128 ) return tolower( v ); ++ return v; ++ } ++ else ++ { ++ return tolower( v ); ++ } ++ } ++ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); ++ ++private: ++ TiXmlBase( const TiXmlBase& ); // not implemented. ++ void operator=( const TiXmlBase& base ); // not allowed. ++ ++ struct Entity ++ { ++ const char* str; ++ unsigned int strLength; ++ char chr; ++ }; ++ enum ++ { ++ NUM_ENTITY = 5, ++ MAX_ENTITY_LENGTH = 6 ++ ++ }; ++ static Entity entity[ NUM_ENTITY ]; ++ static bool condenseWhiteSpace; ++}; ++ ++ ++/** The parent class for everything in the Document Object Model. ++ (Except for attributes). ++ Nodes have siblings, a parent, and children. A node can be ++ in a document, or stand on its own. The type of a TiXmlNode ++ can be queried, and it can be cast to its more defined type. ++*/ ++class TiXmlNode : public TiXmlBase ++{ ++ friend class TiXmlDocument; ++ friend class TiXmlElement; ++ ++public: ++ #ifdef TIXML_USE_STL ++ ++ /** An input stream operator, for every class. Tolerant of newlines and ++ formatting, but doesn't expect them. ++ */ ++ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); ++ ++ /** An output stream operator, for every class. Note that this outputs ++ without any newlines or formatting, as opposed to Print(), which ++ includes tabs and new lines. ++ ++ The operator<< and operator>> are not completely symmetric. Writing ++ a node to a stream is very well defined. You'll get a nice stream ++ of output, without any extra whitespace or newlines. ++ ++ But reading is not as well defined. (As it always is.) If you create ++ a TiXmlElement (for example) and read that from an input stream, ++ the text needs to define an element or junk will result. This is ++ true of all input streams, but it's worth keeping in mind. ++ ++ A TiXmlDocument will read nodes until it reads a root element, and ++ all the children of that root element. ++ */ ++ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); ++ ++ /// Appends the XML node or attribute to a std::string. ++ friend std::string& operator<< (std::string& out, const TiXmlNode& base ); ++ ++ #else ++ // Used internally, not part of the public API. ++ friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); ++ #endif ++ ++ /** The types of XML nodes supported by TinyXml. (All the ++ unsupported types are picked up by UNKNOWN.) ++ */ ++ enum NodeType ++ { ++ DOCUMENT, ++ ELEMENT, ++ COMMENT, ++ UNKNOWN, ++ TEXT, ++ DECLARATION, ++ TYPECOUNT ++ }; ++ ++ virtual ~TiXmlNode(); ++ ++ /** The meaning of 'value' changes for the specific type of ++ TiXmlNode. ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ ++ The subclasses will wrap this function. ++ */ ++ const char * Value() const { return value.c_str (); } ++ ++ /** Changes the value of the node. Defined as: ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ */ ++ void SetValue(const char * _value) { value = _value;} ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "" ); ++ } ++ #endif ++ ++ /// Delete all the children of this node. Does not affect 'this'. ++ void Clear(); ++ ++ /// One step up the DOM. ++ TiXmlNode* Parent() const { return parent; } ++ ++ TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. ++ TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. ++ ++ TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. ++ TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** An alternate way to walk the children of a node. ++ One way to iterate over nodes is: ++ @verbatim ++ for( child = parent->FirstChild(); child; child = child->NextSibling() ) ++ @endverbatim ++ ++ IterateChildren does the same thing with the syntax: ++ @verbatim ++ child = 0; ++ while( child = parent->IterateChildren( child ) ) ++ @endverbatim ++ ++ IterateChildren takes the previous child as input and finds ++ the next one. If the previous child is null, it returns the ++ first. IterateChildren will return null when done. ++ */ ++ TiXmlNode* IterateChildren( TiXmlNode* previous ) const; ++ ++ /// This flavor of IterateChildren searches for children with a particular 'value' ++ TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. ++ #endif ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); ++ ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ ++ NOTE: the node to be added is passed by pointer, and will be ++ henceforth owned (and deleted) by tinyXml. This method is efficient ++ and avoids an extra copy, but should be used with care as it ++ uses a different memory model than the other insert functions. ++ ++ @sa InsertEndChild ++ */ ++ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); ++ ++ /** Add a new node related to this. Adds a child before the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); ++ ++ /** Add a new node related to this. Adds a child after the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); ++ ++ /** Replace a child of this node. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); ++ ++ /// Delete a child of this node. ++ bool RemoveChild( TiXmlNode* removeThis ); ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling() const { return prev; } ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* NextSibling() const { return next; } ++ ++ /// Navigate to a sibling node with the given 'value'. ++ TiXmlNode* NextSibling( const char * ) const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement() const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement() const; ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement( const char * value ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** Query the type (as an enumerated value, above) of this node. ++ The possible types are: DOCUMENT, ELEMENT, COMMENT, ++ UNKNOWN, TEXT, and DECLARATION. ++ */ ++ virtual int Type() const { return type; } ++ ++ /** Return a pointer to the Document this node lives in. ++ Returns null if not in a document. ++ */ ++ TiXmlDocument* GetDocument() const; ++ ++ /// Returns true if this node has no children. ++ bool NoChildren() const { return !firstChild; } ++ ++ TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ ++ /** Create an exact duplicate of this node and return it. The memory must be deleted ++ by the caller. ++ */ ++ virtual TiXmlNode* Clone() const = 0; ++ ++protected: ++ TiXmlNode( NodeType _type ); ++ ++ // Copy to the allocated object. Shared functionality between Clone, Copy constructor, ++ // and the assignment operator. ++ void CopyTo( TiXmlNode* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ // The real work of the input operator. ++ virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; ++ #endif ++ ++ // Figure out what is at *p, and parse it. Returns null if it is not an xml node. ++ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); ++ ++ // Internal Value function returning a TIXML_STRING ++ const TIXML_STRING& SValue() const { return value ; } ++ ++ TiXmlNode* parent; ++ NodeType type; ++ ++ TiXmlNode* firstChild; ++ TiXmlNode* lastChild; ++ ++ TIXML_STRING value; ++ ++ TiXmlNode* prev; ++ TiXmlNode* next; ++ ++private: ++ TiXmlNode( const TiXmlNode& ); // not implemented. ++ void operator=( const TiXmlNode& base ); // not allowed. ++}; ++ ++ ++/** An attribute is a name-value pair. Elements have an arbitrary ++ number of attributes, each with a unique name. ++ ++ @note The attributes are not TiXmlNodes, since they are not ++ part of the tinyXML document object model. There are other ++ suggested ways to look at this problem. ++*/ ++class TiXmlAttribute : public TiXmlBase ++{ ++ friend class TiXmlAttributeSet; ++ ++public: ++ /// Construct an empty attribute. ++ TiXmlAttribute() : TiXmlBase() ++ { ++ document = 0; ++ prev = next = 0; ++ } ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlAttribute( const std::string& _name, const std::string& _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ #endif ++ ++ /// Construct an attribute with a name and value. ++ TiXmlAttribute( const char * _name, const char * _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ ++ const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. ++ const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. ++ const int IntValue() const; ///< Return the value of this attribute, converted to an integer. ++ const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. ++ ++ /** QueryIntValue examines the value string. It is an alternative to the ++ IntValue() method with richer error checking. ++ If the value is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. ++ ++ A specialized but useful call. Note that for success it returns 0, ++ which is the opposite of almost all other TinyXml calls. ++ */ ++ int QueryIntValue( int* value ) const; ++ /// QueryDoubleValue examines the value string. See QueryIntValue(). ++ int QueryDoubleValue( double* value ) const; ++ ++ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. ++ void SetValue( const char* _value ) { value = _value; } ///< Set the value. ++ ++ void SetIntValue( int value ); ///< Set the value from an integer. ++ void SetDoubleValue( double value ); ///< Set the value from a double. ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetName( const std::string& _name ) ++ { ++ StringToBuffer buf( _name ); ++ SetName ( buf.buffer ? buf.buffer : "error" ); ++ } ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "error" ); ++ } ++ #endif ++ ++ /// Get the next sibling attribute in the DOM. Returns null at end. ++ TiXmlAttribute* Next() const; ++ /// Get the previous sibling attribute in the DOM. Returns null at beginning. ++ TiXmlAttribute* Previous() const; ++ ++ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } ++ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } ++ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } ++ ++ /* Attribute parsing starts: first letter of the name ++ returns: the next char after the value end quote ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++ // Prints this Attribute to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ // [internal use] ++ // Set the document pointer so the attribute can report errors. ++ void SetDocument( TiXmlDocument* doc ) { document = doc; } ++ ++private: ++ TiXmlAttribute( const TiXmlAttribute& ); // not implemented. ++ void operator=( const TiXmlAttribute& base ); // not allowed. ++ ++ TiXmlDocument* document; // A pointer back to a document, for error reporting. ++ TIXML_STRING name; ++ TIXML_STRING value; ++ TiXmlAttribute* prev; ++ TiXmlAttribute* next; ++}; ++ ++ ++/* A class used to manage a group of attributes. ++ It is only used internally, both by the ELEMENT and the DECLARATION. ++ ++ The set can be changed transparent to the Element and Declaration ++ classes that use it, but NOT transparent to the Attribute ++ which has to implement a next() and previous() method. Which makes ++ it a bit problematic and prevents the use of STL. ++ ++ This version is implemented with circular lists because: ++ - I like circular lists ++ - it demonstrates some independence from the (typical) doubly linked list. ++*/ ++class TiXmlAttributeSet ++{ ++public: ++ TiXmlAttributeSet(); ++ ~TiXmlAttributeSet(); ++ ++ void Add( TiXmlAttribute* attribute ); ++ void Remove( TiXmlAttribute* attribute ); ++ ++ TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } ++ TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } ++ TiXmlAttribute* Find( const char * name ) const; ++ ++private: ++ TiXmlAttribute sentinel; ++}; ++ ++ ++/** The element is a container class. It has a value, the element name, ++ and can contain other elements, text, comments, and unknowns. ++ Elements also contain an arbitrary number of attributes. ++*/ ++class TiXmlElement : public TiXmlNode ++{ ++public: ++ /// Construct an element. ++ TiXmlElement (const char * in_value); ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlElement( const std::string& _value ); ++ #endif ++ ++ TiXmlElement( const TiXmlElement& ); ++ ++ void operator=( const TiXmlElement& base ); ++ ++ virtual ~TiXmlElement(); ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ */ ++ const char* Attribute( const char* name ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an integer, ++ the integer value will be put in the return 'i', if 'i' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, int* i ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an double, ++ the double value will be put in the return 'd', if 'd' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, double* d ) const; ++ ++ /** QueryIntAttribute examines the attribute - it is an alternative to the ++ Attribute() method with richer error checking. ++ If the attribute is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. If the attribute ++ does not exist, then TIXML_NO_ATTRIBUTE is returned. ++ */ ++ int QueryIntAttribute( const char* name, int* value ) const; ++ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). ++ int QueryDoubleAttribute( const char* name, double* value ) const; ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char* name, const char * value ); ++ ++ #ifdef TIXML_USE_STL ++ const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } ++ const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } ++ const char* Attribute( const std::string& name, double* d ) const { return Attribute( name.c_str(), d ); } ++ int QueryIntAttribute( const std::string& name, int* value ) const { return QueryIntAttribute( name.c_str(), value ); } ++ int QueryDoubleAttribute( const std::string& name, double* value ) const { return QueryDoubleAttribute( name.c_str(), value ); } ++ ++ /// STL std::string form. ++ void SetAttribute( const std::string& name, const std::string& _value ) ++ { ++ StringToBuffer n( name ); ++ StringToBuffer v( _value ); ++ if ( n.buffer && v.buffer ) ++ SetAttribute (n.buffer, v.buffer ); ++ } ++ ///< STL std::string form. ++ void SetAttribute( const std::string& name, int _value ) ++ { ++ StringToBuffer n( name ); ++ if ( n.buffer ) ++ SetAttribute (n.buffer, _value); ++ } ++ #endif ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char * name, int value ); ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetDoubleAttribute( const char * name, double value ); ++ ++ /** Deletes an attribute with the given name. ++ */ ++ void RemoveAttribute( const char * name ); ++ #ifdef TIXML_USE_STL ++ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. ++ TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. ++ ++ /// Creates a new Element and returns it - the returned element is a copy. ++ virtual TiXmlNode* Clone() const; ++ // Print the Element to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: next char past '<' ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ ++ void CopyTo( TiXmlElement* target ) const; ++ void ClearThis(); // like clear, but initializes 'this' object as well ++ ++ // Used to be public [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++ /* [internal use] ++ Reads the "value" of the element -- another element, or text. ++ This should terminate with the current end tag. ++ */ ++ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++private: ++ ++ TiXmlAttributeSet attributeSet; ++}; ++ ++ ++/** An XML comment. ++*/ ++class TiXmlComment : public TiXmlNode ++{ ++public: ++ /// Constructs an empty comment. ++ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} ++ TiXmlComment( const TiXmlComment& ); ++ void operator=( const TiXmlComment& base ); ++ ++ virtual ~TiXmlComment() {} ++ ++ /// Returns a copy of this Comment. ++ virtual TiXmlNode* Clone() const; ++ /// Write this Comment to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: at the ! of the !-- ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlComment* target ) const; ++ ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** XML text. Contained in an element. ++*/ ++class TiXmlText : public TiXmlNode ++{ ++ friend class TiXmlElement; ++public: ++ /// Constructor. ++ TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ virtual ~TiXmlText() {} ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ #endif ++ ++ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlText& base ) { base.CopyTo( this ); } ++ ++ /// Write this text object to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected : ++ /// [internal use] Creates a new Element and returns it. ++ virtual TiXmlNode* Clone() const; ++ void CopyTo( TiXmlText* target ) const; ++ ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ bool Blank() const; // returns true if all white space and new lines ++ // [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++}; ++ ++ ++/** In correct XML the declaration is the first entry in the file. ++ @verbatim ++ <?xml version="1.0" standalone="yes"?> ++ @endverbatim ++ ++ TinyXml will happily read or write files without a declaration, ++ however. There are 3 possible attributes to the declaration: ++ version, encoding, and standalone. ++ ++ Note: In this version of the code, the attributes are ++ handled as special cases, not generic attributes, simply ++ because there can only be at most 3 and they are always the same. ++*/ ++class TiXmlDeclaration : public TiXmlNode ++{ ++public: ++ /// Construct an empty declaration. ++ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} ++ ++#ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ); ++#endif ++ ++ /// Construct. ++ TiXmlDeclaration( const char* _version, ++ const char* _encoding, ++ const char* _standalone ); ++ ++ TiXmlDeclaration( const TiXmlDeclaration& copy ); ++ void operator=( const TiXmlDeclaration& copy ); ++ ++ virtual ~TiXmlDeclaration() {} ++ ++ /// Version. Will return an empty string if none was found. ++ const char *Version() const { return version.c_str (); } ++ /// Encoding. Will return an empty string if none was found. ++ const char *Encoding() const { return encoding.c_str (); } ++ /// Is this a standalone document? ++ const char *Standalone() const { return standalone.c_str (); } ++ ++ /// Creates a copy of this Declaration and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this declaration to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlDeclaration* target ) const; ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ ++private: ++ ++ TIXML_STRING version; ++ TIXML_STRING encoding; ++ TIXML_STRING standalone; ++}; ++ ++ ++/** Any tag that tinyXml doesn't recognize is saved as an ++ unknown. It is a tag of text, but should not be modified. ++ It will be written back to the XML, unchanged, when the file ++ is saved. ++ ++ DTD tags get thrown into TiXmlUnknowns. ++*/ ++class TiXmlUnknown : public TiXmlNode ++{ ++public: ++ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} ++ virtual ~TiXmlUnknown() {} ++ ++ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } ++ ++ /// Creates a copy of this Unknown and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this Unknown to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlUnknown* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** Always the top level node. A document binds together all the ++ XML pieces. It can be saved, loaded, and printed to the screen. ++ The 'value' of a document node is the xml file name. ++*/ ++class TiXmlDocument : public TiXmlNode ++{ ++public: ++ /// Create an empty document, that has no name. ++ TiXmlDocument(); ++ /// Create a document with a name. The name of the document is also the filename of the xml. ++ TiXmlDocument( const char * documentName ); ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDocument( const std::string& documentName ); ++ #endif ++ ++ TiXmlDocument( const TiXmlDocument& copy ); ++ void operator=( const TiXmlDocument& copy ); ++ ++ virtual ~TiXmlDocument() {} ++ ++ /** Load a file using the current document value. ++ Returns true if successful. Will delete any existing ++ document data before loading. ++ */ ++ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the current document value. Returns true if successful. ++ bool SaveFile() const; ++ /// Load a file using the given filename. Returns true if successful. ++ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the given filename. Returns true if successful. ++ bool SaveFile( const char * filename ) const; ++ ++ #ifdef TIXML_USE_STL ++ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && LoadFile( f.buffer, encoding )); ++ } ++ bool SaveFile( const std::string& filename ) const ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && SaveFile( f.buffer )); ++ } ++ #endif ++ ++ /** Parse the given null terminated block of xml data. Passing in an encoding to this ++ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml ++ to use that encoding, regardless of what TinyXml might otherwise try to detect. ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ ++ /** Get the root element -- the only top level element -- of the document. ++ In well formed XML, there should only be one. TinyXml is tolerant of ++ multiple elements at the document level. ++ */ ++ TiXmlElement* RootElement() const { return FirstChildElement(); } ++ ++ /** If an error occurs, Error will be set to true. Also, ++ - The ErrorId() will contain the integer identifier of the error (not generally useful) ++ - The ErrorDesc() method will return the name of the error. (very useful) ++ - The ErrorRow() and ErrorCol() will return the location of the error (if known) ++ */ ++ bool Error() const { return error; } ++ ++ /// Contains a textual (english) description of the error if one occurs. ++ const char * ErrorDesc() const { return errorDesc.c_str (); } ++ ++ /** Generally, you probably want the error string ( ErrorDesc() ). But if you ++ prefer the ErrorId, this function will fetch it. ++ */ ++ const int ErrorId() const { return errorId; } ++ ++ /** Returns the location (if known) of the error. The first column is column 1, ++ and the first row is row 1. A value of 0 means the row and column wasn't applicable ++ (memory errors, for example, have no row/column) or the parser lost the error. (An ++ error in the error reporting, in that case.) ++ ++ @sa SetTabSize, Row, Column ++ */ ++ int ErrorRow() { return errorLocation.row+1; } ++ int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() ++ ++ /** By calling this method, with a tab size ++ greater than 0, the row and column of each node and attribute is stored ++ when the file is loaded. Very useful for tracking the DOM back in to ++ the source file. ++ ++ The tab size is required for calculating the location of nodes. If not ++ set, the default of 4 is used. The tabsize is set per document. Setting ++ the tabsize to 0 disables row/column tracking. ++ ++ Note that row and column tracking is not supported when using operator>>. ++ ++ The tab size needs to be enabled before the parse or load. Correct usage: ++ @verbatim ++ TiXmlDocument doc; ++ doc.SetTabSize( 8 ); ++ doc.Load( "myfile.xml" ); ++ @endverbatim ++ ++ @sa Row, Column ++ */ ++ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } ++ ++ int TabSize() const { return tabsize; } ++ ++ /** If you have handled the error, it can be reset with this call. The error ++ state is automatically cleared if you Parse a new XML block. ++ */ ++ void ClearError() { error = false; ++ errorId = 0; ++ errorDesc = ""; ++ errorLocation.row = errorLocation.col = 0; ++ //errorLocation.last = 0; ++ } ++ ++ /** Dump the document to standard out. */ ++ void Print() const { Print( stdout, 0 ); } ++ ++ /// Print this Document to a FILE stream. ++ virtual void Print( FILE* cfile, int depth = 0 ) const; ++ // [internal use] ++ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++protected : ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ // [internal use] ++ virtual TiXmlNode* Clone() const; ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++ void CopyTo( TiXmlDocument* target ) const; ++ ++ bool error; ++ int errorId; ++ TIXML_STRING errorDesc; ++ int tabsize; ++ TiXmlCursor errorLocation; ++}; ++ ++ ++/** ++ A TiXmlHandle is a class that wraps a node pointer with null checks; this is ++ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml ++ DOM structure. It is a separate utility class. ++ ++ Take an example: ++ @verbatim ++ <Document> ++ <Element attributeA = "valueA"> ++ <Child attributeB = "value1" /> ++ <Child attributeB = "value2" /> ++ </Element> ++ <Document> ++ @endverbatim ++ ++ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very ++ easy to write a *lot* of code that looks like: ++ ++ @verbatim ++ TiXmlElement* root = document.FirstChildElement( "Document" ); ++ if ( root ) ++ { ++ TiXmlElement* element = root->FirstChildElement( "Element" ); ++ if ( element ) ++ { ++ TiXmlElement* child = element->FirstChildElement( "Child" ); ++ if ( child ) ++ { ++ TiXmlElement* child2 = child->NextSiblingElement( "Child" ); ++ if ( child2 ) ++ { ++ // Finally do something useful. ++ @endverbatim ++ ++ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity ++ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe ++ and correct to use: ++ ++ @verbatim ++ TiXmlHandle docHandle( &document ); ++ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); ++ if ( child2 ) ++ { ++ // do something useful ++ @endverbatim ++ ++ Which is MUCH more concise and useful. ++ ++ It is also safe to copy handles - internally they are nothing more than node pointers. ++ @verbatim ++ TiXmlHandle handleCopy = handle; ++ @endverbatim ++ ++ What they should not be used for is iteration: ++ ++ @verbatim ++ int i=0; ++ while ( true ) ++ { ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); ++ if ( !child ) ++ break; ++ // do something ++ ++i; ++ } ++ @endverbatim ++ ++ It seems reasonable, but it is in fact two embedded while loops. The Child method is ++ a linear walk to find the element, so this code would iterate much more than it needs ++ to. Instead, prefer: ++ ++ @verbatim ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); ++ ++ for( child; child; child=child->NextSiblingElement() ) ++ { ++ // do something ++ } ++ @endverbatim ++*/ ++class TiXmlHandle ++{ ++public: ++ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. ++ TiXmlHandle( TiXmlNode* node ) { this->node = node; } ++ /// Copy constructor ++ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } ++ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } ++ ++ /// Return a handle to the first child node. ++ TiXmlHandle FirstChild() const; ++ /// Return a handle to the first child node with the given name. ++ TiXmlHandle FirstChild( const char * value ) const; ++ /// Return a handle to the first child element. ++ TiXmlHandle FirstChildElement() const; ++ /// Return a handle to the first child element with the given name. ++ TiXmlHandle FirstChildElement( const char * value ) const; ++ ++ /** Return a handle to the "index" child with the given name. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( const char* value, int index ) const; ++ /** Return a handle to the "index" child. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( int index ) const; ++ /** Return a handle to the "index" child element with the given name. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( const char* value, int index ) const; ++ /** Return a handle to the "index" child element. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( int index ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } ++ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } ++ ++ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } ++ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } ++ #endif ++ ++ /// Return the handle as a TiXmlNode. This may return null. ++ TiXmlNode* Node() const { return node; } ++ /// Return the handle as a TiXmlElement. This may return null. ++ TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } ++ /// Return the handle as a TiXmlText. This may return null. ++ TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } ++ /// Return the handle as a TiXmlUnknown. This may return null; ++ TiXmlUnknown* Unknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } ++ ++private: ++ TiXmlNode* node; ++}; ++ ++ ++#endif ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/tinyxmlerror.c vdr-1.7.14.ExtP_NG/tinyxmlerror.c +--- vdr-1.7.14/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxmlerror.c 2010-04-10 15:45:11.808773087 +0200 +@@ -0,0 +1,53 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++// The goal of the seperate error file is to make the first ++// step towards localization. tinyxml (currently) only supports ++// latin-1, but at least the error messages could now be translated. ++// ++// It also cleans up the code a bit. ++// ++ ++const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = ++{ ++ "No error", ++ "Error", ++ "Failed to open file", ++ "Memory allocation failed.", ++ "Error parsing Element.", ++ "Failed to read Element name", ++ "Error reading Element value.", ++ "Error reading Attributes.", ++ "Error: empty tag.", ++ "Error reading end tag.", ++ "Error parsing Unknown.", ++ "Error parsing Comment.", ++ "Error parsing Declaration.", ++ "Error document empty.", ++ "Error null (0) or unexpected EOF found in input stream.", ++}; ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/tinyxmlparser.c vdr-1.7.14.ExtP_NG/tinyxmlparser.c +--- vdr-1.7.14/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxmlparser.c 2010-04-10 15:45:11.828740629 +0200 +@@ -0,0 +1,1494 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++#include <ctype.h> ++ ++//#define DEBUG_PARSER ++ ++// Note tha "PutString" hardcodes the same list. This ++// is less flexible than it appears. Changing the entries ++// or order will break putstring. ++TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = ++{ ++ { "&", 5, '&' }, ++ { "<", 4, '<' }, ++ { ">", 4, '>' }, ++ { """, 6, '\"' }, ++ { "'", 6, '\'' } ++}; ++ ++// Bunch of unicode info at: ++// http://www.unicode.org/faq/utf_bom.html ++// Including the basic of this table, which determines the #bytes in the ++// sequence from the lead byte. 1 placed for invalid sequences -- ++// although the result will be junk, pass it through as much as possible. ++// Beware of the non-characters in UTF-8: ++// ef bb bf (Microsoft "lead bytes") ++// ef bf be ++// ef bf bf ++ ++ ++ ++const int TiXmlBase::utf8ByteTable[256] = ++{ ++ // 0 1 2 3 4 5 6 7 8 9 a b c d e f ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 ++ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte ++ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid ++}; ++ ++ ++void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) ++{ ++ const unsigned long BYTE_MASK = 0xBF; ++ const unsigned long BYTE_MARK = 0x80; ++ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; ++ ++ if (input < 0x80) ++ *length = 1; ++ else if ( input < 0x800 ) ++ *length = 2; ++ else if ( input < 0x10000 ) ++ *length = 3; ++ else if ( input < 0x200000 ) ++ *length = 4; ++ else ++ { *length = 0; return; } // This code won't covert this correctly anyway. ++ ++ output += *length; ++ ++ // Scary scary fall throughs. ++ switch (*length) ++ { ++ case 4: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 3: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 2: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 1: ++ --output; ++ *output = (char)(input | FIRST_BYTE_MARK[*length]); ++ } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalpha( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalpha( anyByte ); ++// } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalnum( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalnum( anyByte ); ++// } ++} ++ ++ ++class TiXmlParsingData ++{ ++ friend class TiXmlDocument; ++ public: ++ void Stamp( const char* now, TiXmlEncoding encoding ); ++ ++ const TiXmlCursor& Cursor() { return cursor; } ++ ++ private: ++ // Only used by the document! ++ TiXmlParsingData( const char* start, int _tabsize, int row, int col ) ++ { ++ assert( start ); ++ stamp = start; ++ tabsize = _tabsize; ++ cursor.row = row; ++ cursor.col = col; ++ } ++ ++ TiXmlCursor cursor; ++ const char* stamp; ++ int tabsize; ++}; ++ ++ ++void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) ++{ ++ assert( now ); ++ ++ // Do nothing if the tabsize is 0. ++ if ( tabsize < 1 ) ++ { ++ return; ++ } ++ ++ // Get the current row, column. ++ int row = cursor.row; ++ int col = cursor.col; ++ const char* p = stamp; ++ assert( p ); ++ ++ while ( p < now ) ++ { ++ // Code contributed by Fletcher Dunn: (modified by lee) ++ switch (*p) { ++ case 0: ++ // We *should* never get here, but in case we do, don't ++ // advance past the terminating null character, ever ++ return; ++ ++ case '\r': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ // Eat the character ++ ++p; ++ ++ // Check for \r\n sequence, and treat this as a single character ++ if (*p == '\n') { ++ ++p; ++ } ++ break; ++ ++ case '\n': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ ++ // Eat the character ++ ++p; ++ ++ // Check for \n\r sequence, and treat this as a single ++ // character. (Yes, this bizarre thing does occur still ++ // on some arcane platforms...) ++ if (*p == '\r') { ++ ++p; ++ } ++ break; ++ ++ case '\t': ++ // Eat the character ++ ++p; ++ ++ // Skip to next tab stop ++ col = (col / tabsize + 1) * tabsize; ++ break; ++ ++ case (char)(0xef): ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( *(p+1) && *(p+2) ) ++ { ++ // In these cases, don't advance the column. These are ++ // 0-width spaces. ++ if ( *(p+1)==(char)(0xbb) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbe) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else ++ { p +=3; ++col; } // A normal character. ++ } ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ ++ default: ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // Eat the 1 to 4 byte utf8 character. ++ int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)]; ++ if ( step == 0 ) ++ step = 1; // Error case from bad encoding, but handle gracefully. ++ p += step; ++ ++ // Just advance one column, of course. ++ ++col; ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ } ++ } ++ cursor.row = row; ++ cursor.col = col; ++ assert( cursor.row >= -1 ); ++ assert( cursor.col >= -1 ); ++ stamp = p; ++ assert( stamp ); ++} ++ ++ ++const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) ++{ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ while ( *p ) ++ { ++ // Skip the stupid Microsoft UTF-8 Byte order marks ++ if ( *(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbb ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbe ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ ++ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. ++ ++p; ++ else ++ break; ++ } ++ } ++ else ++ { ++ while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) ++ ++p; ++ } ++ ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ for( ;; ) ++ { ++ if ( !in->good() ) return false; ++ ++ int c = in->peek(); ++ // At this scope, we can't get to a document. So fail silently. ++ if ( !IsWhiteSpace( c ) || c <= 0 ) ++ return true; ++ ++ *tag += (char) in->get(); ++ } ++} ++ ++/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ) ++{ ++ //assert( character > 0 && character < 128 ); // else it won't work in utf-8 ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == character ) ++ return true; ++ if ( c <= 0 ) // Silent failure: can't get document at this scope ++ return false; ++ ++ in->get(); ++ *tag += (char) c; ++ } ++ return false; ++} ++#endif ++ ++const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) ++{ ++ *name = ""; ++ assert( p ); ++ ++ // Names start with letters or underscores. ++ // Of course, in unicode, tinyxml has no idea what a letter *is*. The ++ // algorithm is generous. ++ // ++ // After that, they can be letters, underscores, numbers, ++ // hyphens, or colons. (Colons are valid ony for namespaces, ++ // but tinyxml can't tell namespaces from names.) ++ if ( p && *p ++ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) ++ { ++ while( p && *p ++ && ( IsAlphaNum( (unsigned char ) *p, encoding ) ++ || *p == '_' ++ || *p == '-' ++ || *p == '.' ++ || *p == ':' ) ) ++ { ++ (*name) += *p; ++ ++p; ++ } ++ return p; ++ } ++ return 0; ++} ++ ++const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) ++{ ++ // Presume an entity, and pull it out. ++ TIXML_STRING ent; ++ int i; ++ *length = 0; ++ ++ if ( *(p+1) && *(p+1) == '#' && *(p+2) ) ++ { ++ unsigned long ucs = 0; ++ unsigned delta = 0; ++ unsigned mult = 1; ++ ++ if ( *(p+2) == 'x' ) ++ { ++ // Hexadecimal. ++ if ( !*(p+3) ) return 0; ++ ++ const char* q = p+3; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != 'x' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else if ( *q >= 'a' && *q <= 'f' ) ++ ucs += mult * (*q - 'a' + 10); ++ else if ( *q >= 'A' && *q <= 'F' ) ++ ucs += mult * (*q - 'A' + 10 ); ++ else ++ return 0; ++ mult *= 16; ++ --q; ++ } ++ } ++ else ++ { ++ // Decimal. ++ if ( !*(p+2) ) return 0; ++ ++ const char* q = p+2; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != '#' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else ++ return 0; ++ mult *= 10; ++ --q; ++ } ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // convert the UCS to UTF-8 ++ ConvertUTF32ToUTF8( ucs, value, length ); ++ } ++ else ++ { ++ *value = (char)ucs; ++ *length = 1; ++ } ++ return p + delta + 1; ++ } ++ ++ // Now try to match it. ++ for( i=0; i<NUM_ENTITY; ++i ) ++ { ++ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) ++ { ++ assert( strlen( entity[i].str ) == entity[i].strLength ); ++ *value = entity[i].chr; ++ *length = 1; ++ return ( p + entity[i].strLength ); ++ } ++ } ++ ++ // So it wasn't an entity, its unrecognized, or something like that. ++ *value = *p; // Don't put back the last one, since we return it! ++ return p+1; ++} ++ ++ ++bool TiXmlBase::StringEqual( const char* p, ++ const char* tag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ) ++{ ++ assert( p ); ++ assert( tag ); ++ if ( !p || !*p ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ const char* q = p; ++ ++ if ( ignoreCase ) ++ { ++ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) ++ return true; ++ } ++ else ++ { ++ while ( *q && *tag && *q == *tag ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? ++ return true; ++ } ++ return false; ++} ++ ++const char* TiXmlBase::ReadText( const char* p, ++ TIXML_STRING * text, ++ bool trimWhiteSpace, ++ const char* endTag, ++ bool caseInsensitive, ++ TiXmlEncoding encoding ) ++{ ++ *text = ""; ++ if ( !trimWhiteSpace // certain tags always keep whitespace ++ || !condenseWhiteSpace ) // if true, whitespace is always kept ++ { ++ // Keep all the white space. ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ++ ) ++ { ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ text->append( cArr, len ); ++ } ++ } ++ else ++ { ++ bool whitespace = false; ++ ++ // Remove leading white space: ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ) ++ { ++ if ( *p == '\r' || *p == '\n' ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else if ( IsWhiteSpace( *p ) ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else ++ { ++ // If we've found whitespace, add it before the ++ // new character. Any whitespace just becomes a space. ++ if ( whitespace ) ++ { ++ (*text) += ' '; ++ whitespace = false; ++ } ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ if ( len == 1 ) ++ (*text) += cArr[0]; // more efficient ++ else ++ text->append( cArr, len ); ++ } ++ } ++ } ++ return p + strlen( endTag ); ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ // The basic issue with a document is that we don't know what we're ++ // streaming. Read something presumed to be a tag (and hope), then ++ // identify it, and call the appropriate stream method on the tag. ++ // ++ // This "pre-streaming" will never read the closing ">" so the ++ // sub-tag can orient itself. ++ ++ if ( !StreamTo( in, '<', tag ) ) ++ { ++ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ while ( in->good() ) ++ { ++ int tagIndex = (int) tag->length(); ++ while ( in->good() && in->peek() != '>' ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ break; ++ } ++ (*tag) += (char) c; ++ } ++ ++ if ( in->good() ) ++ { ++ // We now have something we presume to be a node of ++ // some sort. Identify it, and call the node to ++ // continue streaming. ++ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); ++ ++ if ( node ) ++ { ++ node->StreamIn( in, tag ); ++ bool isElement = node->ToElement() != 0; ++ delete node; ++ node = 0; ++ ++ // If this is the root element, we're done. Parsing will be ++ // done by the >> operator. ++ if ( isElement ) ++ { ++ return; ++ } ++ } ++ else ++ { ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ } ++ } ++ // We should have returned sooner. ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++} ++ ++#endif ++ ++const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) ++{ ++ ClearError(); ++ ++ // Parse away, at the document level. Since a document ++ // contains nothing but other tags, most of what happens ++ // here is skipping white space. ++ if ( !p || !*p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ // Note that, for a document, this needs to come ++ // before the while space skip, so that parsing ++ // starts from the pointer we are given. ++ location.Clear(); ++ if ( prevData ) ++ { ++ location.row = prevData->cursor.row; ++ location.col = prevData->cursor.col; ++ } ++ else ++ { ++ location.row = 0; ++ location.col = 0; ++ } ++ TiXmlParsingData data( p, TabSize(), location.row, location.col ); ++ location = data.Cursor(); ++ ++ if ( encoding == TIXML_ENCODING_UNKNOWN ) ++ { ++ // Check for the Microsoft UTF-8 lead bytes. ++ if ( *(p+0) && *(p+0) == (char)(0xef) ++ && *(p+1) && *(p+1) == (char)(0xbb) ++ && *(p+2) && *(p+2) == (char)(0xbf) ) ++ { ++ encoding = TIXML_ENCODING_UTF8; ++ } ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ while ( p && *p ) ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, &data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ break; ++ } ++ ++ // Did we get encoding info? ++ if ( encoding == TIXML_ENCODING_UNKNOWN ++ && node->ToDeclaration() ) ++ { ++ TiXmlDeclaration* dec = node->ToDeclaration(); ++ const char* enc = dec->Encoding(); ++ assert( enc ); ++ ++ if ( *enc == 0 ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice ++ else ++ encoding = TIXML_ENCODING_LEGACY; ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ // All is well. ++ return p; ++} ++ ++void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ // The first error in a chain is more accurate - don't set again! ++ if ( error ) ++ return; ++ ++ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); ++ error = true; ++ errorId = err; ++ errorDesc = errorString[ errorId ]; ++ ++ errorLocation.Clear(); ++ if ( pError && data ) ++ { ++ //TiXmlParsingData data( pError, prevData ); ++ data->Stamp( pError, encoding ); ++ errorLocation = data->Cursor(); ++ } ++} ++ ++ ++TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) ++{ ++ TiXmlNode* returnNode = 0; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if( !p || !*p || *p != '<' ) ++ { ++ return 0; ++ } ++ ++ TiXmlDocument* doc = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ ++ // What is this thing? ++ // - Elements start with a letter or underscore, but xml is reserved. ++ // - Comments: <!-- ++ // - Decleration: <?xml ++ // - Everthing else is unknown to tinyxml. ++ // ++ ++ const char* xmlHeader = { "<?xml" }; ++ const char* commentHeader = { "<!--" }; ++ const char* dtdHeader = { "<!" }; ++ ++ if ( StringEqual( p, xmlHeader, true, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Declaration\n" ); ++ #endif ++ returnNode = new TiXmlDeclaration(); ++ } ++ else if ( StringEqual( p, commentHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Comment\n" ); ++ #endif ++ returnNode = new TiXmlComment(); ++ } ++ else if ( StringEqual( p, dtdHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(1)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ else if ( IsAlpha( *(p+1), encoding ) ++ || *(p+1) == '_' ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Element\n" ); ++ #endif ++ returnNode = new TiXmlElement( "" ); ++ } ++ else ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(2)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ ++ if ( returnNode ) ++ { ++ // Set the parent, so it can report errors ++ returnNode->parent = this; ++ } ++ else ++ { ++ if ( doc ) ++ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++ return returnNode; ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag) ++{ ++ // We're called with some amount of pre-parsing. That is, some of "this" ++ // element is in "tag". Go ahead and stream to the closing ">" ++ while( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c ; ++ ++ if ( c == '>' ) ++ break; ++ } ++ ++ if ( tag->length() < 3 ) return; ++ ++ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. ++ // If not, identify and stream. ++ ++ if ( tag->at( tag->length() - 1 ) == '>' ++ && tag->at( tag->length() - 2 ) == '/' ) ++ { ++ // All good! ++ return; ++ } ++ else if ( tag->at( tag->length() - 1 ) == '>' ) ++ { ++ // There is more. Could be: ++ // text ++ // closing tag ++ // another node. ++ for ( ;; ) ++ { ++ StreamWhiteSpace( in, tag ); ++ ++ // Do we have text? ++ if ( in->good() && in->peek() != '<' ) ++ { ++ // Yep, text. ++ TiXmlText text( "" ); ++ text.StreamIn( in, tag ); ++ ++ // What follows text is a closing tag or another node. ++ // Go around again and figure it out. ++ continue; ++ } ++ ++ // We now have either a closing tag...or another node. ++ // We should be at a "<", regardless. ++ if ( !in->good() ) return; ++ assert( in->peek() == '<' ); ++ int tagIndex = tag->length(); ++ ++ bool closingTag = false; ++ bool firstCharFound = false; ++ ++ for( ;; ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->peek(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ if ( c == '>' ) ++ break; ++ ++ *tag += (char) c; ++ in->get(); ++ ++ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) ++ { ++ firstCharFound = true; ++ if ( c == '/' ) ++ closingTag = true; ++ } ++ } ++ // If it was a closing tag, then read in the closing '>' to clean up the input stream. ++ // If it was not, the streaming will be done by the tag. ++ if ( closingTag ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ assert( c == '>' ); ++ *tag += (char) c; ++ ++ // We are done, once we've found our closing tag. ++ return; ++ } ++ else ++ { ++ // If not a closing tag, id it, and stream. ++ const char* tagloc = tag->c_str() + tagIndex; ++ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); ++ if ( !node ) ++ return; ++ node->StreamIn( in, tag ); ++ delete node; ++ node = 0; ++ ++ // No return: go around from the beginning: text, closing tag, or node. ++ } ++ } ++ } ++} ++#endif ++ ++const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ TiXmlDocument* document = GetDocument(); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); ++ return 0; ++ } ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ ++ if ( *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); ++ return 0; ++ } ++ ++ p = SkipWhiteSpace( p+1, encoding ); ++ ++ // Read the name. ++ const char* pErr = p; ++ ++ p = ReadName( p, &value, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); ++ return 0; ++ } ++ ++ TIXML_STRING endTag ("</"); ++ endTag += value; ++ endTag += ">"; ++ ++ // Check for and read attributes. Also look for an empty ++ // tag or an end tag. ++ while ( p && *p ) ++ { ++ pErr = p; ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ if ( *p == '/' ) ++ { ++ ++p; ++ // Empty tag. ++ if ( *p != '>' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); ++ return 0; ++ } ++ return (p+1); ++ } ++ else if ( *p == '>' ) ++ { ++ // Done with attributes (if there were any.) ++ // Read the value -- which can include other ++ // elements -- read the end tag, and return. ++ ++p; ++ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. ++ if ( !p || !*p ) ++ return 0; ++ ++ // We should find the end tag now ++ if ( StringEqual( p, endTag.c_str(), false, encoding ) ) ++ { ++ p += endTag.length(); ++ return p; ++ } ++ else ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); ++ return 0; ++ } ++ } ++ else ++ { ++ // Try to read an attribute: ++ TiXmlAttribute* attrib = new TiXmlAttribute(); ++ if ( !attrib ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); ++ return 0; ++ } ++ ++ attrib->SetDocument( document ); ++ const char* pErr = p; ++ p = attrib->Parse( p, data, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); ++ delete attrib; ++ return 0; ++ } ++ ++ // Handle the strange case of double attributes: ++ TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); ++ if ( node ) ++ { ++ node->SetValue( attrib->Value() ); ++ delete attrib; ++ return 0; ++ } ++ ++ attributeSet.Add( attrib ); ++ } ++ } ++ return p; ++} ++ ++ ++const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ ++ const char* pWithWhiteSpace = p; ++ // Read in text and elements in any order. ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ) ++ { ++ if ( *p != '<' ) ++ { ++ // Take what we have, make a text element. ++ TiXmlText* textNode = new TiXmlText( "" ); ++ ++ if ( !textNode ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); ++ return 0; ++ } ++ ++ if ( TiXmlBase::IsWhiteSpaceCondensed() ) ++ { ++ p = textNode->Parse( p, data, encoding ); ++ } ++ else ++ { ++ // Special case: we want to keep the white space ++ // so that leading spaces aren't removed. ++ p = textNode->Parse( pWithWhiteSpace, data, encoding ); ++ } ++ ++ if ( !textNode->Blank() ) ++ LinkEndChild( textNode ); ++ else ++ delete textNode; ++ } ++ else ++ { ++ // We hit a '<' ++ // Have we hit a new element or an end tag? ++ if ( StringEqual( p, "</", false, encoding ) ) ++ { ++ return p; ++ } ++ else ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); ++ } ++ return p; ++} ++ ++ ++#ifdef TIXML_USE_STL ++void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ if ( !p || !*p || *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); ++ return 0; ++ } ++ ++p; ++ value = ""; ++ ++ while ( p && *p && *p != '>' ) ++ { ++ value += *p; ++ ++p; ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); ++ } ++ if ( *p == '>' ) ++ return p+1; ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ ++ if ( c == '>' ++ && tag->at( tag->length() - 2 ) == '-' ++ && tag->at( tag->length() - 3 ) == '-' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ value = ""; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ const char* startTag = "<!--"; ++ const char* endTag = "-->"; ++ ++ if ( !StringEqual( p, startTag, false, encoding ) ) ++ { ++ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); ++ return 0; ++ } ++ p += strlen( startTag ); ++ p = ReadText( p, &value, false, endTag, false, encoding ); ++ return p; ++} ++ ++ ++const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) return 0; ++ ++ int tabsize = 4; ++ if ( document ) ++ tabsize = document->TabSize(); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ // Read the name, the '=' and the value. ++ const char* pErr = p; ++ p = ReadName( p, &name, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p || *p != '=' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ ++p; // skip '=' ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ const char* end; ++ ++ if ( *p == '\'' ) ++ { ++ ++p; ++ end = "\'"; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else if ( *p == '"' ) ++ { ++ ++p; ++ end = "\""; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else ++ { ++ // All attribute values should be in single or double quotes. ++ // But this is such a common error that the parser will try ++ // its best, even without them. ++ value = ""; ++ while ( p && *p // existence ++ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace ++ && *p != '/' && *p != '>' ) // tag end ++ { ++ value += *p; ++ ++p; ++ } ++ } ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == '<' ) ++ return; ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ in->get(); ++ } ++} ++#endif ++ ++const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ value = ""; ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ bool ignoreWhite = true; ++ ++ const char* end = "<"; ++ p = ReadText( p, &value, ignoreWhite, end, false, encoding ); ++ if ( p ) ++ return p-1; // don't truncate the '<' ++ return 0; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) ++{ ++ p = SkipWhiteSpace( p, _encoding ); ++ // Find the beginning, find the end, and look for ++ // the stuff in-between. ++ TiXmlDocument* document = GetDocument(); ++ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); ++ return 0; ++ } ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, _encoding ); ++ location = data->Cursor(); ++ } ++ p += 5; ++ ++ version = ""; ++ encoding = ""; ++ standalone = ""; ++ ++ while ( p && *p ) ++ { ++ if ( *p == '>' ) ++ { ++ ++p; ++ return p; ++ } ++ ++ p = SkipWhiteSpace( p, _encoding ); ++ if ( StringEqual( p, "version", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ version = attrib.Value(); ++ } ++ else if ( StringEqual( p, "encoding", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ encoding = attrib.Value(); ++ } ++ else if ( StringEqual( p, "standalone", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ standalone = attrib.Value(); ++ } ++ else ++ { ++ // Read over whatever it is. ++ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++ ++p; ++ } ++ } ++ return 0; ++} ++ ++bool TiXmlText::Blank() const ++{ ++ for ( unsigned i=0; i<value.length(); i++ ) ++ if ( !IsWhiteSpace( value[i] ) ) ++ return false; ++ return true; ++} ++#endif /* SETUP */ +diff -ruN vdr-1.7.14/vdr.c vdr-1.7.14.ExtP_NG/vdr.c +--- vdr-1.7.14/vdr.c 2010-02-21 15:08:09.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/vdr.c 2010-04-10 15:45:12.079739794 +0200 +@@ -587,7 +587,12 @@ + RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf")); + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); + Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")); ++#ifdef USE_ALTERNATECHANNEL ++ KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) && ++ Channels.LoadAlternativeChannels(AddDirectory(ConfigDirectory, "channel_alternative.conf")); ++#else + KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true); ++#endif /* ALTERNATECHANNEL */ + Folders.Load(AddDirectory(ConfigDirectory, "folders.conf")); + + if (!*cFont::GetFontFileName(Setup.FontOsd)) { +@@ -919,6 +924,21 @@ + Recordings.Update(); + DeletedRecordings.Update(); + } ++#ifdef USE_MCLI ++ cPlugin *mcliPlugin = cPluginManager::GetPlugin("mcli"); ++ if (mcliPlugin) { ++ if (!ShutdownHandler.countdown) { // if kPower has been pressed, cMenuShutdown takes precedence over other menus ++ cOsdObject *MyMenu = mcliPlugin->AltMenuAction(); ++ if (MyMenu) { // is there any cam-menu waiting? ++ DELETE_MENU; ++ if (cControl::Control()) ++ cControl::Control()->Hide(); ++ Menu = MyMenu; ++ Menu->Show(); ++ } ++ } ++ } ++#endif /* MCLI */ + // CAM control: + if (!Menu && !cOsd::IsOpen()) + Menu = CamControl(); +@@ -929,6 +949,9 @@ + cOsdObject *Interact = Menu ? Menu : cControl::Control(); + eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse()); + if (ISREALKEY(key)) { ++#ifdef USE_PINPLUGIN ++ cStatus::MsgUserAction(key, Interact); ++#endif /* PINPLUGIN */ + EITScanner.Activity(); + // Cancel shutdown countdown: + if (ShutdownHandler.countdown) +@@ -1001,10 +1024,16 @@ + cControl::Control()->Hide(); + cPlugin *plugin = cPluginManager::GetPlugin(PluginName); + if (plugin) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(plugin)) { ++#endif /* PINPLUGIN */ + Menu = plugin->MainMenuAction(); + if (Menu) + Menu->Show(); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + esyslog("ERROR: unknown plugin '%s'", PluginName); + } +@@ -1194,13 +1223,26 @@ + Channels.SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]); + break; + } ++#ifdef USE_VOLCTRL ++ // Left/Right volume control ++#else + // Direct Channel Select: + case k1 ... k9: + // Left/Right rotates through channel groups: ++#endif /* VOLCTRL */ + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && Setup.LRChannelGroups < 2) { ++ cRemote::Put(NORMALKEY(key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++ // Direct Channel Select: ++ case k1 ... k9: ++#endif /* VOLCTRL */ + // Previous/Next rotates through channel groups: + case kPrev|k_Repeat: + case kPrev: +@@ -1218,9 +1260,15 @@ + // Instant resume of the last viewed recording: + case kPlay: + if (cReplayControl::LastReplayed()) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { ++#endif /* PINPLUGIN */ + cControl::Shutdown(); + cControl::Launch(new cReplayControl); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + break; + default: break; + } +diff -ruN vdr-1.7.14/vdrttxtsubshooks.c vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c +--- vdr-1.7.14/vdrttxtsubshooks.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c 2010-04-10 15:45:12.093736132 +0200 +@@ -0,0 +1,62 @@ ++/* ++ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge@nada.kth.se> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <stdint.h> ++ ++#include "vdrttxtsubshooks.h" ++ ++// XXX Really should be a list... ++static cVDRTtxtsubsHookListener *gListener; ++ ++// ------ class cVDRTtxtsubsHookProxy ------ ++ ++class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener ++{ ++ public: ++ virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); }; ++ virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); }; ++ virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0) ++ { if(gListener) gListener->PlayerTeletextData(p, length, IsPesRecording, teletextSubtitlePages, pageCount); }; ++ virtual int ManualPageNumber(const cChannel *channel) ++ { if(gListener) return gListener->ManualPageNumber(channel); else return 0; }; ++}; ++ ++ ++// ------ class cVDRTtxtsubsHookListener ------ ++ ++cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener() ++{ ++ gListener = 0; ++} ++ ++void cVDRTtxtsubsHookListener::HookAttach(void) ++{ ++ gListener = this; ++ //printf("cVDRTtxtsubsHookListener::HookAttach\n"); ++} ++ ++static cVDRTtxtsubsHookProxy gProxy; ++ ++cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void) ++{ ++ return &gProxy; ++} +diff -ruN vdr-1.7.14/vdrttxtsubshooks.h vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h +--- vdr-1.7.14/vdrttxtsubshooks.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h 2010-04-10 15:45:12.108759292 +0200 +@@ -0,0 +1,46 @@ ++/* ++ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge@nada.kth.se> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef __VDRTTXTSUBSHOOKS_H ++#define __VDRTTXTSUBSHOOKS_H ++ ++#define TTXTSUBSVERSNUM 2 ++ ++class cDevice; ++class cChannel; ++struct tTeletextSubtitlePage; ++ ++class cVDRTtxtsubsHookListener { ++ public: ++ cVDRTtxtsubsHookListener(void) {}; ++ virtual ~cVDRTtxtsubsHookListener(); ++ ++ void HookAttach(void); ++ ++ virtual void HideOSD(void) {}; ++ virtual void ShowOSD(void) {}; ++ virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording = true, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0) {}; ++ virtual int ManualPageNumber(const cChannel *channel) { return 0; }; ++ ++ // used by VDR to call hook listeners ++ static cVDRTtxtsubsHookListener *Hook(void); ++}; ++ ++#endif +diff -ruN vdr-1.7.14/videodir.c vdr-1.7.14.ExtP_NG/videodir.c +--- vdr-1.7.14/videodir.c 2008-02-16 14:00:03.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/videodir.c 2010-04-10 15:45:12.125736672 +0200 +@@ -36,6 +36,11 @@ + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); ++#ifdef USE_DVLVIDPREFER ++ char *GetVidPath(int nVid); ++ bool GetPreferedVideoDir(void); ++ bool IsVidDirOK(int nVid, int *freeMB = NULL); ++#endif /* DVLVIDPREFER */ + }; + + cVideoDirectory::cVideoDirectory(void) +@@ -117,6 +122,9 @@ + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { ++#ifdef USE_DVLVIDPREFER ++ if (Setup.UseVidPrefer == 0) { ++#endif /* DVLVIDPREFER */ + // Find the directory with the most free space: + int MaxFree = Dir.FreeMB(); + while (Dir.Next()) { +@@ -126,14 +134,24 @@ + MaxFree = Free; + } + } ++#ifdef USE_DVLVIDPREFER ++ } ++ else Dir.GetPreferedVideoDir(); ++#endif /* DVLVIDPREFER */ + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return NULL; // errno has been set by MakeDirs() ++#ifdef USE_DVLVIDPREFER ++ if (strcmp(ActualFileName, FileName) != 0) { ++#endif /* DVLVIDPREFER */ + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return NULL; + } ++#ifdef USE_DVLVIDPREFER ++ } ++#endif /* DVLVIDPREFER */ + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } +@@ -168,6 +186,123 @@ + return RemoveFileOrDir(FileName, true); + } + ++#ifdef USE_HARDLINKCUTTER ++static bool StatNearestDir(const char *FileName, struct stat *Stat) ++{ ++ cString Name(FileName); ++ char *p; ++ while ((p = strrchr((char*)(const char*)Name + 1, '/')) != NULL) { ++ *p = 0; // truncate at last '/' ++ if (stat(Name, Stat) == 0) { ++ isyslog("StatNearestDir: Stating %s", (const char*)Name); ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool HardLinkVideoFile(const char *OldName, const char *NewName) ++{ ++ // Incoming name must be in base video directory: ++ if (strstr(OldName, VideoDirectory) != OldName) { ++ esyslog("ERROR: %s not in %s", OldName, VideoDirectory); ++ return false; ++ } ++ if (strstr(NewName, VideoDirectory) != NewName) { ++ esyslog("ERROR: %s not in %s", NewName, VideoDirectory); ++ return false; ++ } ++ ++ const char *ActualNewName = NewName; ++ cString ActualOldName(ReadLink(OldName), true); ++ ++ // Some safety checks: ++ struct stat StatOldName; ++ if (lstat(ActualOldName, &StatOldName) == 0) { ++ if (S_ISLNK(StatOldName.st_mode)) { ++ esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName); ++ return false; ++ } ++ } ++ else { ++ esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName); ++ return false; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev); ++ ++ // Find the video directory where ActualOldName is located ++ ++ cVideoDirectory Dir; ++ struct stat StatDir; ++ if (!StatNearestDir(NewName, &StatDir)) { ++ esyslog("HardLinkVideoFile: stat failed on %s", NewName); ++ return false; ++ } ++ ++ isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev); ++ if (StatDir.st_dev != StatOldName.st_dev) { ++ // Not yet found. ++ ++ if (!Dir.IsDistributed()) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Search in video01 and upwards ++ bool found = false; ++ while (Dir.Next()) { ++ Dir.Store(); ++ const char *TmpNewName = Dir.Adjust(NewName); ++ if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) { ++ isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev); ++ ActualNewName = TmpNewName; ++ found = true; ++ break; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev); ++ } ++ if (ActualNewName == NewName) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Looking good, we have a match. Create necessary folders. ++ if (!MakeDirs(ActualNewName, false)) ++ return false; ++ // There's no guarantee that the directory of ActualNewName ++ // is on the same device as the dir that StatNearestDir found. ++ // But worst case is that the link fails. ++ } ++ ++#ifdef HARDLINK_TEST_ONLY ++ // Do the hard link to *.vdr_ for testing only ++ char *name = NULL; ++ asprintf(&name, "%s_",ActualNewName); ++ link(ActualOldName, name); ++ free(name); ++ return false; ++#endif // HARDLINK_TEST_ONLY ++ ++ // Try creating the hard link ++ if (link(ActualOldName, ActualNewName) != 0) { ++ // Failed to hard link. Maybe not allowed on file system. ++ LOG_ERROR_STR(ActualNewName); ++ isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName); ++ return false; ++ } ++ ++ if (ActualNewName != NewName) { ++ // video01 and up. Do the remaining symlink ++ if (symlink(ActualNewName, NewName) < 0) { ++ LOG_ERROR_STR(NewName); ++ return false; ++ } ++ } ++ return true; ++} ++ ++#endif /* HARDLINKCUTTER */ ++ + bool VideoFileSpaceAvailable(int SizeMB) + { + cVideoDirectory Dir; +@@ -232,6 +367,129 @@ + } while (Dir.Next()); + } + ++#ifdef USE_DVLVIDPREFER ++// returns path to nVid'th video directory or NULL if not existing ++char *cVideoDirectory::GetVidPath(int nVid) ++{ ++ char *b = strdup(VideoDirectory); ++ int l = strlen(b), di, n; ++ ++ while (l-- > 0 && isdigit(b[ l ])); ++ ++ l++; ++ di = strlen(b) - l; ++ ++ // di == number of digits ++ n = atoi(&b[ l ]); ++ if (n != 0) ++ return NULL; ++ ++ // add requested number to dir name ++ sprintf(&b[ l ], "%0*d", di, nVid); ++ ++ if (DirectoryOk(b) == true) ++ return b; ++ ++ free(b); ++ return NULL; ++} ++ ++// checks if a video dir is 'valid' ++bool cVideoDirectory::IsVidDirOK(int nVid, int *freeMB) ++{ ++ char *dn; ++ int fMB; ++ ++ if (nVid >= Setup.nVidPrefer) ++ return false; ++ ++ if (Setup.VidPreferSize[ nVid ] == -1) ++ return false; ++ ++ dn = GetVidPath(nVid); ++ if (dn == NULL) ++ return false; ++ ++ fMB = FreeDiskSpaceMB(dn, NULL); ++ if (freeMB != NULL) ++ *freeMB = fMB; ++ ++ free(dn); ++ ++ if (Setup.VidPreferSize[ nVid ] >= fMB) ++ return false; ++ return true; ++} ++ ++ ++// calculates which video dir to use ++bool cVideoDirectory::GetPreferedVideoDir(void) ++{ ++ cVideoDirectory d; ++ int nDirs = 1, ++ vidUse = Setup.nVidPrefer; ++ int i, top, topFree, x; ++ ++ if (name == NULL) ++ return(false); ++ ++ // count available video dirs ++ while (d.Next() == true) ++ nDirs++; ++ ++ if (vidUse > nDirs) ++ vidUse = nDirs; ++ ++ // check for prefered video dir ++ for (i = 0, top = -1, topFree = 0; i < vidUse; i++) { ++ if (IsVidDirOK(i, &x) == true) { ++ if (top == -1) { ++ // nothing set yet, use first 'ok' dir ++ top = i; ++ topFree = x; ++ } ++ else { ++ // check if we got a higher priority ++ if (Setup.VidPreferPrio[ i ] >= Setup.VidPreferPrio[ top ]) { ++ top = i; ++ topFree = x; ++ } ++ // check if we got same priority but more space ++ else if (Setup.VidPreferPrio[ i ] == Setup.VidPreferPrio[ top ] && x >= topFree) { ++ top = i; ++ topFree = x; ++ } ++ } ++ } ++ } ++ ++ if (top == -1) { ++ isyslog("VidPrefer: no prefered video directory could be determined!"); ++ ++ // something went wrong here... ++ // let VDR determine the video directory ++ int MaxFree = FreeMB(); ++ ++ while (Next()) { ++ int Free = FreeDiskSpaceMB(Name()); ++ ++ if (Free > MaxFree) { ++ Store(); ++ MaxFree = Free; ++ } ++ } ++ } ++ else { ++ isyslog("VidPrefer: prefered video directory '%d' set.", top); ++ if (stored != NULL) ++ free(stored); ++ stored = GetVidPath(top); ++ } ++ ++ return true; ++} ++#endif /* DVLVIDPREFER */ ++ + bool IsOnVideoDirectoryFileSystem(const char *FileName) + { + cVideoDirectory Dir; +diff -ruN vdr-1.7.14/videodir.h vdr-1.7.14.ExtP_NG/videodir.h +--- vdr-1.7.14/videodir.h 2008-02-16 13:53:11.000000000 +0100 ++++ vdr-1.7.14.ExtP_NG/videodir.h 2010-04-10 15:45:12.148736552 +0200 +@@ -19,6 +19,9 @@ + int CloseVideoFile(cUnbufferedFile *File); + bool RenameVideoFile(const char *OldName, const char *NewName); + bool RemoveVideoFile(const char *FileName); ++#ifdef USE_HARDLINKCUTTER ++bool HardLinkVideoFile(const char *OldName, const char *NewName); ++#endif /* HARDLINKCUTTER */ + bool VideoFileSpaceAvailable(int SizeMB); + int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent + cString PrefixVideoFileName(const char *FileName, char Prefix); diff --git a/vdr/extensions/vdr-1.7.14_extensions.diff b/vdr/extensions/vdr-1.7.14_extensions.diff index 2d08e23..023d712 100755 --- a/vdr/extensions/vdr-1.7.14_extensions.diff +++ b/vdr/extensions/vdr-1.7.14_extensions.diff @@ -1,6 +1,6 @@ diff -ruN vdr-1.7.14/Make.config.template vdr-1.7.14.ExtP_NG/Make.config.template --- vdr-1.7.14/Make.config.template 2010-02-06 15:50:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/Make.config.template 2010-03-14 14:02:05.346985224 +0100 ++++ vdr-1.7.14.ExtP_NG/Make.config.template 2010-04-10 15:45:10.488736701 +0200 @@ -41,8 +41,185 @@ ## Define if you want vdr to not run as root #VDR_USER = vdr @@ -90,7 +90,7 @@ diff -ruN vdr-1.7.14/Make.config.template vdr-1.7.14.ExtP_NG/Make.config.templat +DEFINES += -DUSE_DVLSCRIPTADDON +endif + -+ifdef DVLVDIPREFER ++ifdef DVLVIDPREFER +DEFINES += -DUSE_DVLVIDPREFER +endif + @@ -189,7 +189,7 @@ diff -ruN vdr-1.7.14/Make.config.template vdr-1.7.14.ExtP_NG/Make.config.templat +endif diff -ruN vdr-1.7.14/Makefile vdr-1.7.14.ExtP_NG/Makefile --- vdr-1.7.14/Makefile 2010-02-21 12:44:38.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/Makefile 2010-03-14 14:02:05.369985286 +0100 ++++ vdr-1.7.14.ExtP_NG/Makefile 2010-04-10 15:45:10.520736498 +0200 @@ -44,6 +44,18 @@ skinclassic.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\ timers.o tools.o transfer.o vdr.o videodir.o @@ -211,7 +211,7 @@ diff -ruN vdr-1.7.14/Makefile vdr-1.7.14.ExtP_NG/Makefile endif diff -ruN vdr-1.7.14/channels.c vdr-1.7.14.ExtP_NG/channels.c --- vdr-1.7.14/channels.c 2010-02-21 14:36:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/channels.c 2010-03-14 14:02:04.541995571 +0100 ++++ vdr-1.7.14.ExtP_NG/channels.c 2010-04-10 15:45:09.286739173 +0200 @@ -12,6 +12,9 @@ #include "device.h" #include "epg.h" @@ -434,7 +434,7 @@ diff -ruN vdr-1.7.14/channels.c vdr-1.7.14.ExtP_NG/channels.c channelsHashSid.Add(Channel, Channel->Sid()); diff -ruN vdr-1.7.14/channels.h vdr-1.7.14.ExtP_NG/channels.h --- vdr-1.7.14/channels.h 2010-03-07 14:47:13.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/channels.h 2010-03-14 14:02:04.585995558 +0100 ++++ vdr-1.7.14.ExtP_NG/channels.h 2010-04-10 15:45:09.370737290 +0200 @@ -35,6 +35,9 @@ #define MAXDPIDS 16 // dolby (AC3 + DTS) #define MAXSPIDS 32 // subtitles @@ -543,7 +543,7 @@ diff -ruN vdr-1.7.14/channels.h vdr-1.7.14.ExtP_NG/channels.h int GetNextGroup(int Idx); // Get next channel group diff -ruN vdr-1.7.14/ci.c vdr-1.7.14.ExtP_NG/ci.c --- vdr-1.7.14/ci.c 2010-01-02 11:39:50.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/ci.c 2010-03-14 14:02:04.608999551 +0100 ++++ vdr-1.7.14.ExtP_NG/ci.c 2010-04-10 15:45:09.396741389 +0200 @@ -1911,6 +1911,10 @@ AddPid(Channel->Sid(), *Apid, STREAM_TYPE_AUDIO); for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++) @@ -569,7 +569,7 @@ diff -ruN vdr-1.7.14/ci.c vdr-1.7.14.ExtP_NG/ci.c do { diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c --- vdr-1.7.14/config.c 2010-03-12 17:41:37.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/config.c 2010-03-14 14:02:04.634993963 +0100 ++++ vdr-1.7.14.ExtP_NG/config.c 2010-04-10 15:45:09.424743485 +0200 @@ -313,6 +313,12 @@ strcpy(OSDLanguage, ""); // default is taken from environment strcpy(OSDSkin, "sttng"); @@ -632,7 +632,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c SplitEditedFiles = 0; DelTimeshiftRec = 0; MinEventTimeout = 30; -@@ -391,18 +418,80 @@ +@@ -391,18 +418,83 @@ MultiSpeedMode = 0; ShowReplayMode = 0; ResumeID = 0; @@ -681,6 +681,9 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c + RecordingsSortMode = 0; + RecordingsSortDirsFirst = 0; +#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ CutterAutoDelete = 0; ++#endif /* CUTTERQUEUE */ +#ifdef USE_DVLFRIENDLYFNAMES + UseFriendlyFNames = 0; // default = disabled +#endif /* DVLFRIENDLYFNAMES */ @@ -713,7 +716,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c return *this; } -@@ -503,6 +592,12 @@ +@@ -503,6 +595,12 @@ if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); @@ -726,7 +729,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); -@@ -521,13 +616,27 @@ +@@ -521,13 +619,27 @@ else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); @@ -754,7 +757,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); else if (!strcasecmp(Name, "EPGLinger")) EPGLinger = atoi(Value); -@@ -548,6 +657,9 @@ +@@ -548,6 +660,9 @@ else if (!strcasecmp(Name, "VideoDisplayFormat")) VideoDisplayFormat = atoi(Value); else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); @@ -764,7 +767,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); -@@ -573,6 +685,10 @@ +@@ -573,6 +688,10 @@ else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); @@ -775,7 +778,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); -@@ -581,15 +697,99 @@ +@@ -581,15 +700,102 @@ else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); @@ -823,6 +826,9 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c + else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); + else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); +#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); ++#endif /* CUTTERQUEUE */ +#ifdef USE_DVLFRIENDLYFNAMES + else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); +#endif /* DVLFRIENDLYFNAMES */ @@ -875,7 +881,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c return true; } -@@ -598,6 +798,12 @@ +@@ -598,6 +804,12 @@ Store("OSDLanguage", OSDLanguage); Store("OSDSkin", OSDSkin); Store("OSDTheme", OSDTheme); @@ -888,7 +894,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c Store("PrimaryDVB", PrimaryDVB); Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); Store("TimeoutRequChInfo", TimeoutRequChInfo); -@@ -616,13 +822,27 @@ +@@ -616,13 +828,27 @@ Store("TimeTransponder", TimeTransponder); Store("MarginStart", MarginStart); Store("MarginStop", MarginStop); @@ -916,7 +922,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c Store("EPGScanTimeout", EPGScanTimeout); Store("EPGBugfixLevel", EPGBugfixLevel); Store("EPGLinger", EPGLinger); -@@ -643,6 +863,9 @@ +@@ -643,6 +869,9 @@ Store("VideoDisplayFormat", VideoDisplayFormat); Store("VideoFormat", VideoFormat); Store("UpdateChannels", UpdateChannels); @@ -926,7 +932,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c Store("UseDolbyDigital", UseDolbyDigital); Store("ChannelInfoPos", ChannelInfoPos); Store("ChannelInfoTime", ChannelInfoTime); -@@ -676,13 +899,73 @@ +@@ -676,13 +905,75 @@ Store("MultiSpeedMode", MultiSpeedMode); Store("ShowReplayMode", ShowReplayMode); Store("ResumeID", ResumeID); @@ -981,7 +987,9 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c + Store("RecordingsSortMode", RecordingsSortMode); + Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); +#endif /* SORTRECORDS */ -+ ++#ifdef USE_CUTTERQUEUE ++ Store("CutterAutoDelete", CutterAutoDelete); ++#endif /* CUTTERQUEUE */ +#ifdef USE_DVLFRIENDLYFNAMES + Store ("UseFriendlyFNames", UseFriendlyFNames); +#endif /* DVLFRIENDLYFNAMES */ @@ -1002,7 +1010,7 @@ diff -ruN vdr-1.7.14/config.c vdr-1.7.14.ExtP_NG/config.c diff -ruN vdr-1.7.14/config.h vdr-1.7.14.ExtP_NG/config.h --- vdr-1.7.14/config.h 2010-03-12 17:02:53.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/config.h 2010-03-14 14:02:04.646994485 +0100 ++++ vdr-1.7.14.ExtP_NG/config.h 2010-04-10 15:45:09.438738230 +0200 @@ -30,15 +30,39 @@ #define APIVERSION "1.7.14" #define APIVERSNUM 10714 // Version * 10000 + Major * 100 + Minor @@ -1102,7 +1110,7 @@ diff -ruN vdr-1.7.14/config.h vdr-1.7.14.ExtP_NG/config.h int SplitEditedFiles; int DelTimeshiftRec; int MinEventTimeout, MinUserInactivity; -@@ -283,15 +332,67 @@ +@@ -283,15 +332,70 @@ int MultiSpeedMode; int ShowReplayMode; int ResumeID; @@ -1149,6 +1157,9 @@ diff -ruN vdr-1.7.14/config.h vdr-1.7.14.ExtP_NG/config.h + int RecordingsSortMode; + int RecordingsSortDirsFirst; +#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ int CutterAutoDelete; ++#endif /* CUTTERQUEUE */ +#ifdef USE_DVLFRIENDLYFNAMES + int UseFriendlyFNames; +#endif /* DVLFRIENDLYFNAMES */ @@ -1172,7 +1183,7 @@ diff -ruN vdr-1.7.14/config.h vdr-1.7.14.ExtP_NG/config.h bool Save(void); diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c --- vdr-1.7.14/cutter.c 2010-01-02 14:08:08.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/cutter.c 2010-03-14 14:02:04.715992847 +0100 ++++ vdr-1.7.14.ExtP_NG/cutter.c 2010-04-10 15:45:09.627745454 +0200 @@ -15,6 +15,19 @@ // --- cCuttingThread -------------------------------------------------------- @@ -1424,7 +1435,7 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c } Recordings.TouchUpdate(); } -@@ -194,18 +366,80 @@ +@@ -194,18 +366,87 @@ // --- cCutter --------------------------------------------------------------- @@ -1494,18 +1505,25 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c + +#ifdef USE_CUTTERQUEUE + if(!(Recordings.GetByName(FileName))) { -+ // Should _not_ remove any cutted recordings -+ // (original recording already deleted ?) -+ // so, just pop item from queue and return. -+ esyslog("can't cut non-existing recording %s", FileName); -+ cutterQueue.Del(cutterQueue.First()); -+ return true; // might be already queued recording ++ // Update Recordings, maybe its not initialized(if vdr --edit is used) ++ Recordings.Update(true); ++ if(!(Recordings.GetByName(FileName))) { ++ // Update Recordings, maybe its not initialized(if vdr --edit is used) ++ Recordings.Update(true); ++ if(!(Recordings.GetByName(FileName))) { ++ // Should _not_ remove any cutted recordings ++ // (original recording already deleted ?) ++ // so, just pop item from queue and return. ++ esyslog("can't cut non-existing recording %s", FileName); ++ cutterQueue.Del(cutterQueue.First()); ++ return true; // might be already queued recording ++ } + } +#endif /* CUTTERQUEUE */ if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) // remove a possible deleted recording with the same name to avoid symlink mixups: -@@ -231,6 +465,10 @@ +@@ -231,6 +472,10 @@ void cCutter::Stop(void) { @@ -1516,7 +1534,7 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c bool Interrupted = cuttingThread && cuttingThread->Active(); const char *Error = cuttingThread ? cuttingThread->Error() : NULL; delete cuttingThread; -@@ -242,11 +480,20 @@ +@@ -242,11 +487,20 @@ esyslog("ERROR: '%s' during editing process", Error); RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? Recordings.DelByName(editedVersionName); @@ -1537,30 +1555,29 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c if (cuttingThread) { if (cuttingThread->Active()) return true; -@@ -257,12 +504,42 @@ +@@ -257,12 +511,41 @@ free(editedVersionName); editedVersionName = NULL; ended = true; +#ifdef USE_CUTTERQUEUE -+ /* Remove original (if cutting was successful) */ -+ if(!error) { -+ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); -+ if (!recording) { -+ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); -+ } else { -+ if (recording->Delete()) { -+ //Recordings.Del(recording); -+ //cReplayControl::ClearLastReplayed(ri->FileName()); -+ Recordings.DelByName(recording->FileName()); -+ } else { -+ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); -+ } -+ } - } -+ lastCuttingEndTime = cTimeMs::Now(); -+ cutterQueue.Del(cutterQueue.First()); ++ if (Setup.CutterAutoDelete) { ++ /* Remove original (if cutting was successful) */ ++ if(!error) { ++ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); ++ if (!recording) ++ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); ++ else { ++ if (recording->Delete()) ++ Recordings.DelByName(recording->FileName()); ++ else ++ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); ++ } ++ } ++ lastCuttingEndTime = cTimeMs::Now(); ++ } ++ cutterQueue.Del(cutterQueue.First()); +#endif /* CUTTERQUEUE */ -+ } + } +#ifdef USE_CUTTERQUEUE + if(!cuttingThread && cutterQueue.First()) { + /* start next cutting from queue*/ @@ -1580,7 +1597,7 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c bool result = error; error = false; return result; -@@ -270,6 +547,9 @@ +@@ -270,6 +553,9 @@ bool cCutter::Ended(void) { @@ -1592,7 +1609,7 @@ diff -ruN vdr-1.7.14/cutter.c vdr-1.7.14.ExtP_NG/cutter.c return result; diff -ruN vdr-1.7.14/cutter.h vdr-1.7.14.ExtP_NG/cutter.h --- vdr-1.7.14/cutter.h 2010-01-02 13:09:54.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/cutter.h 2010-03-14 14:02:04.729992477 +0100 ++++ vdr-1.7.14.ExtP_NG/cutter.h 2010-04-10 15:45:09.656737920 +0200 @@ -11,6 +11,9 @@ #define __CUTTER_H @@ -1615,7 +1632,7 @@ diff -ruN vdr-1.7.14/cutter.h vdr-1.7.14.ExtP_NG/cutter.h static void Stop(void); diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c --- vdr-1.7.14/device.c 2010-02-07 12:54:42.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/device.c 2010-03-14 14:02:04.750995187 +0100 ++++ vdr-1.7.14.ExtP_NG/device.c 2010-04-10 15:45:09.684741026 +0200 @@ -18,6 +18,12 @@ #include "receiver.h" #include "status.h" @@ -1949,7 +1966,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c if (LiveView) { StopReplay(); DELETENULL(liveSubtitle); -@@ -698,11 +916,39 @@ +@@ -698,11 +914,39 @@ eSetChannelResult Result = scrOk; @@ -1989,7 +2006,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! cControl::Launch(new cTransferControl(Device, Channel)); -@@ -720,6 +966,12 @@ +@@ -720,6 +964,12 @@ sectionHandler->SetStatus(false); sectionHandler->SetChannel(NULL); } @@ -2002,7 +2019,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c // Tell the camSlot about the channel switch and add all PIDs of this // channel to it, for possible later decryption: if (camSlot) -@@ -1012,6 +1264,10 @@ +@@ -1012,6 +1262,10 @@ int LanguagePreference = INT_MAX; // higher than the maximum possible value for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { const tTrackId *TrackId = GetTrack(eTrackType(i)); @@ -2013,7 +2030,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) PreferredTrack = eTrackType(i); } -@@ -1223,6 +1479,15 @@ +@@ -1223,6 +1477,15 @@ } break; case 0xBD: { // private stream 1 @@ -2029,7 +2046,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c int PayloadOffset = Data[8] + 9; // Compatibility mode for old subtitles plugin: -@@ -1382,6 +1647,9 @@ +@@ -1382,6 +1645,9 @@ tsToPesVideo.Reset(); tsToPesAudio.Reset(); tsToPesSubtitle.Reset(); @@ -2039,7 +2056,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c } else if (Length < TS_SIZE) { esyslog("ERROR: skipped %d bytes of TS fragment", Length); -@@ -1427,6 +1695,19 @@ +@@ -1427,6 +1693,19 @@ if (!VideoOnly || HasIBPTrickSpeed()) PlayTsSubtitle(Data, TS_SIZE); } @@ -2061,7 +2078,7 @@ diff -ruN vdr-1.7.14/device.c vdr-1.7.14.ExtP_NG/device.c else if (Pid == patPmtParser.Ppid()) { diff -ruN vdr-1.7.14/device.h vdr-1.7.14.ExtP_NG/device.h --- vdr-1.7.14/device.h 2010-02-06 15:34:41.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/device.h 2010-03-14 14:02:04.772993966 +0100 ++++ vdr-1.7.14.ExtP_NG/device.h 2010-04-10 15:45:09.706728067 +0200 @@ -24,6 +24,9 @@ #include "spu.h" #include "thread.h" @@ -2183,7 +2200,7 @@ diff -ruN vdr-1.7.14/device.h vdr-1.7.14.ExtP_NG/device.h const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; } diff -ruN vdr-1.7.14/dvbdevice.c vdr-1.7.14.ExtP_NG/dvbdevice.c --- vdr-1.7.14/dvbdevice.c 2010-03-07 14:58:24.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/dvbdevice.c 2010-03-14 14:02:04.858993520 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbdevice.c 2010-04-10 15:45:09.854742151 +0200 @@ -246,6 +246,9 @@ class cDvbTuner : public cThread { private: @@ -2299,7 +2316,7 @@ diff -ruN vdr-1.7.14/dvbdevice.c vdr-1.7.14.ExtP_NG/dvbdevice.c setTransferModeForDolbyDigital = Mode; diff -ruN vdr-1.7.14/dvbdevice.h vdr-1.7.14.ExtP_NG/dvbdevice.h --- vdr-1.7.14/dvbdevice.h 2010-02-21 15:06:08.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/dvbdevice.h 2010-03-14 14:02:04.865989999 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbdevice.h 2010-04-10 15:45:09.863735987 +0200 @@ -146,6 +146,9 @@ virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); public: @@ -2312,7 +2329,7 @@ diff -ruN vdr-1.7.14/dvbdevice.h vdr-1.7.14.ExtP_NG/dvbdevice.h diff -ruN vdr-1.7.14/dvbplayer.c vdr-1.7.14.ExtP_NG/dvbplayer.c --- vdr-1.7.14/dvbplayer.c 2010-03-07 15:24:26.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/dvbplayer.c 2010-03-14 14:02:04.881992796 +0100 ++++ vdr-1.7.14.ExtP_NG/dvbplayer.c 2010-04-10 15:45:09.881743306 +0200 @@ -204,6 +204,9 @@ cNonBlockingFileReader *nonBlockingFileReader; cRingBufferFrame *ringBuffer; @@ -2476,7 +2493,7 @@ diff -ruN vdr-1.7.14/dvbplayer.c vdr-1.7.14.ExtP_NG/dvbplayer.c diff -ruN vdr-1.7.14/eit.c vdr-1.7.14.ExtP_NG/eit.c --- vdr-1.7.14/eit.c 2010-01-08 16:17:09.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/eit.c 2010-03-14 14:02:04.949989942 +0100 ++++ vdr-1.7.14.ExtP_NG/eit.c 2010-04-10 15:45:09.958741231 +0200 @@ -24,8 +24,31 @@ class cEIT : public SI::EIT { public: @@ -2709,7 +2726,7 @@ diff -ruN vdr-1.7.14/eit.c vdr-1.7.14.ExtP_NG/eit.c if (Empty && getSectionNumber() == 0) diff -ruN vdr-1.7.14/eitscan.c vdr-1.7.14.ExtP_NG/eitscan.c --- vdr-1.7.14/eitscan.c 2010-02-07 13:12:05.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/eitscan.c 2010-03-14 14:02:04.967989369 +0100 ++++ vdr-1.7.14.ExtP_NG/eitscan.c 2010-04-10 15:45:09.980739226 +0200 @@ -151,9 +151,17 @@ if (Device->ProvidesTransponder(Channel)) { if (!Device->Receiving()) { @@ -2730,7 +2747,7 @@ diff -ruN vdr-1.7.14/eitscan.c vdr-1.7.14.ExtP_NG/eitscan.c Skins.Message(mtInfo, tr("Starting EPG scan")); diff -ruN vdr-1.7.14/epg.c vdr-1.7.14.ExtP_NG/epg.c --- vdr-1.7.14/epg.c 2010-02-28 15:24:55.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/epg.c 2010-03-14 14:02:04.997993332 +0100 ++++ vdr-1.7.14.ExtP_NG/epg.c 2010-04-10 15:45:10.017741115 +0200 @@ -930,6 +930,31 @@ return pe; } @@ -2765,7 +2782,7 @@ diff -ruN vdr-1.7.14/epg.c vdr-1.7.14.ExtP_NG/epg.c hasRunning = false; diff -ruN vdr-1.7.14/epg.h vdr-1.7.14.ExtP_NG/epg.h --- vdr-1.7.14/epg.h 2010-01-08 16:20:34.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/epg.h 2010-03-14 14:02:05.006989800 +0100 ++++ vdr-1.7.14.ExtP_NG/epg.h 2010-04-10 15:45:10.027736473 +0200 @@ -163,6 +163,9 @@ void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); void Cleanup(time_t Time); @@ -2778,7 +2795,7 @@ diff -ruN vdr-1.7.14/epg.h vdr-1.7.14.ExtP_NG/epg.h void HashEvent(cEvent *Event); diff -ruN vdr-1.7.14/iconpatch.c vdr-1.7.14.ExtP_NG/iconpatch.c --- vdr-1.7.14/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/iconpatch.c 2010-03-14 14:02:05.215987343 +0100 ++++ vdr-1.7.14.ExtP_NG/iconpatch.c 2010-04-10 15:45:10.336740261 +0200 @@ -0,0 +1,31 @@ +#ifdef USE_WAREAGLEICON + @@ -2813,7 +2830,7 @@ diff -ruN vdr-1.7.14/iconpatch.c vdr-1.7.14.ExtP_NG/iconpatch.c +#endif /* WAREAGLEICON */ diff -ruN vdr-1.7.14/iconpatch.h vdr-1.7.14.ExtP_NG/iconpatch.h --- vdr-1.7.14/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/iconpatch.h 2010-03-14 14:02:05.226986089 +0100 ++++ vdr-1.7.14.ExtP_NG/iconpatch.h 2010-04-10 15:45:10.348737591 +0200 @@ -0,0 +1,73 @@ +#ifdef USE_WAREAGLEICON +/* @@ -2890,7 +2907,7 @@ diff -ruN vdr-1.7.14/iconpatch.h vdr-1.7.14.ExtP_NG/iconpatch.h +#endif /* WAREAGLEICON */ diff -ruN vdr-1.7.14/lirc.c vdr-1.7.14.ExtP_NG/lirc.c --- vdr-1.7.14/lirc.c 2006-05-28 10:48:13.000000000 +0200 -+++ vdr-1.7.14.ExtP_NG/lirc.c 2010-03-14 14:02:05.310986139 +0100 ++++ vdr-1.7.14.ExtP_NG/lirc.c 2010-04-10 15:45:10.452737940 +0200 @@ -12,6 +12,10 @@ #include "lirc.h" #include <netinet/in.h> @@ -2951,7 +2968,7 @@ diff -ruN vdr-1.7.14/lirc.c vdr-1.7.14.ExtP_NG/lirc.c *LastKeyName = 0; diff -ruN vdr-1.7.14/mainmenuitemsprovider.h vdr-1.7.14.ExtP_NG/mainmenuitemsprovider.h --- vdr-1.7.14/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/mainmenuitemsprovider.h 2010-03-14 14:02:05.333986270 +0100 ++++ vdr-1.7.14.ExtP_NG/mainmenuitemsprovider.h 2010-04-10 15:45:10.477763751 +0200 @@ -0,0 +1,62 @@ +#ifdef USE_MENUORG +/* @@ -3017,7 +3034,7 @@ diff -ruN vdr-1.7.14/mainmenuitemsprovider.h vdr-1.7.14.ExtP_NG/mainmenuitemspro +#endif /* MENUORG */ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c --- vdr-1.7.14/menu.c 2010-03-12 17:03:07.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/menu.c 2010-03-14 14:02:05.449985065 +0100 ++++ vdr-1.7.14.ExtP_NG/menu.c 2010-04-10 15:45:10.637743132 +0200 @@ -8,6 +8,9 @@ */ @@ -3103,7 +3120,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); SetFirstDayItem(); } -@@ -1017,8 +1054,14 @@ +@@ -1017,8 +1053,14 @@ class cMenuTimerItem : public cOsdItem { private: cTimer *timer; @@ -3118,7 +3135,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c virtual int Compare(const cListObject &ListObject) const; virtual void Set(void); cTimer *Timer(void) { return timer; } -@@ -1027,6 +1070,9 @@ +@@ -1027,6 +1069,9 @@ cMenuTimerItem::cMenuTimerItem(cTimer *Timer) { timer = Timer; @@ -3128,7 +3145,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Set(); } -@@ -1057,8 +1103,31 @@ +@@ -1057,8 +1102,31 @@ File++; else File = timer->File(); @@ -3160,7 +3177,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c timer->Channel()->Number(), *name, *name && **name ? " " : "", -@@ -1070,6 +1139,58 @@ +@@ -1070,6 +1138,58 @@ File)); } @@ -3219,7 +3236,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c // --- cMenuTimers ----------------------------------------------------------- class cMenuTimers : public cOsdMenu { -@@ -1082,14 +1203,25 @@ +@@ -1082,14 +1202,25 @@ eOSState Info(void); cTimer *CurrentTimer(void); void SetHelpKeys(void); @@ -3245,7 +3262,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c { helpKeys = -1; for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { -@@ -1100,6 +1232,9 @@ +@@ -1100,6 +1231,9 @@ SetCurrent(First()); SetHelpKeys(); Timers.IncBeingEdited(); @@ -3255,7 +3272,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } cMenuTimers::~cMenuTimers() -@@ -1138,7 +1273,11 @@ +@@ -1138,7 +1272,11 @@ timer->OnOff(); timer->SetEventFromSchedule(); RefreshCurrent(); @@ -3267,7 +3284,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (timer->FirstDay()) isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); else -@@ -1197,6 +1336,68 @@ +@@ -1197,6 +1335,68 @@ return osContinue; } @@ -3336,7 +3353,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c eOSState cMenuTimers::ProcessKey(eKeys Key) { int TimerNumber = HasSubMenu() ? Count() : -1; -@@ -1205,18 +1406,36 @@ +@@ -1205,18 +1405,36 @@ if (state == osUnknown) { switch (Key) { case kOk: return Edit(); @@ -3373,7 +3390,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Display(); } if (Key != kNone) -@@ -1246,6 +1465,9 @@ +@@ -1246,6 +1464,9 @@ { cOsdMenu::Display(); DisplayMenu()->SetEvent(event); @@ -3383,7 +3400,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (event->Description()) cStatus::MsgOsdTextItem(event->Description()); } -@@ -1293,7 +1515,12 @@ +@@ -1293,7 +1514,12 @@ const cChannel *channel; bool withDate; int timerMatch; @@ -3396,7 +3413,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } static eScheduleSortMode SortMode(void) { return sortMode; } -@@ -1303,7 +1530,11 @@ +@@ -1303,12 +1529,19 @@ cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; @@ -3408,7 +3425,15 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c { event = Event; channel = Channel; -@@ -1323,7 +1554,30 @@ + withDate = WithDate; + timerMatch = tmNone; ++#ifdef USE_LIEMIEXT ++ withBar = WithBar; ++#endif /* LIEMIEXT */ + Update(true); + } + +@@ -1323,7 +1556,30 @@ return r; } @@ -3439,7 +3464,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c bool cMenuScheduleItem::Update(bool Force) { -@@ -1332,17 +1586,54 @@ +@@ -1332,17 +1588,54 @@ Timers.GetMatch(event, &timerMatch); if (Force || timerMatch != OldTimerMatch) { cString buffer; @@ -3476,13 +3501,13 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#else - buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ +#else +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#else -+ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ +#endif /* LIEMIEXT */ else @@ -3494,7 +3519,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c SetText(buffer); result = true; } -@@ -1368,13 +1659,21 @@ +@@ -1368,13 +1661,21 @@ static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } static const cEvent *ScheduleEvent(void); virtual eOSState ProcessKey(eKeys Key); @@ -3516,7 +3541,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c { now = Now; helpKeys = -1; -@@ -1386,7 +1685,11 @@ +@@ -1386,7 +1687,11 @@ if (Schedule) { const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); if (Event) @@ -3528,7 +3553,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } } } -@@ -1395,6 +1698,20 @@ +@@ -1395,6 +1700,20 @@ SetHelpKeys(); } @@ -3549,7 +3574,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c bool cMenuWhatsOn::Update(void) { bool result = false; -@@ -1535,6 +1852,10 @@ +@@ -1535,6 +1854,10 @@ cMenuSchedule(void); virtual ~cMenuSchedule(); virtual eOSState ProcessKey(eKeys Key); @@ -3560,7 +3585,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSchedule::cMenuSchedule(void) -@@ -1560,6 +1881,20 @@ +@@ -1560,6 +1883,20 @@ cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared } @@ -3581,7 +3606,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) { Clear(); -@@ -1915,6 +2250,9 @@ +@@ -1915,6 +2252,9 @@ cMenuCam(cCamSlot *CamSlot); virtual ~cMenuCam(); virtual eOSState ProcessKey(eKeys Key); @@ -3591,7 +3616,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuCam::cMenuCam(cCamSlot *CamSlot) -@@ -2094,6 +2432,9 @@ +@@ -2094,6 +2434,9 @@ cMenuRecording(const cRecording *Recording, bool WithButtons = false); virtual void Display(void); virtual eOSState ProcessKey(eKeys Key); @@ -3601,7 +3626,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) -@@ -2109,6 +2450,9 @@ +@@ -2109,6 +2452,9 @@ { cOsdMenu::Display(); DisplayMenu()->SetRecording(recording); @@ -3611,7 +3636,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (recording->Info()->Description()) cStatus::MsgOsdTextItem(recording->Info()->Description()); } -@@ -2169,7 +2513,11 @@ +@@ -2169,7 +2515,11 @@ fileName = strdup(Recording->FileName()); name = NULL; totalEntries = newEntries = 0; @@ -3623,7 +3648,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (*Text() == '\t') name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' } -@@ -2185,13 +2533,183 @@ +@@ -2185,13 +2535,183 @@ totalEntries++; if (New) newEntries++; @@ -3807,7 +3832,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c { base = Base ? strdup(Base) : NULL; level = Setup.RecordingDirs ? Level : -1; -@@ -2269,7 +2787,13 @@ +@@ -2269,7 +2789,13 @@ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == FOLDERDELIMCHAR)) { cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); @@ -3821,7 +3846,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(Item); LastItem = Item; free(LastItemText); -@@ -2319,6 +2843,11 @@ +@@ -2319,6 +2845,11 @@ { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri) { @@ -3833,7 +3858,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (ri->IsDirectory()) Open(); else { -@@ -2426,12 +2955,34 @@ +@@ -2426,12 +2957,34 @@ return osContinue; } @@ -3868,7 +3893,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c switch (Key) { case kPlay: case kOk: return Play(); -@@ -2440,7 +2991,26 @@ +@@ -2440,7 +2993,26 @@ case kYellow: return Delete(); case kInfo: case kBlue: return Info(); @@ -3895,7 +3920,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c case kNone: if (Recordings.StateChanged(recordingsState)) Set(true); break; -@@ -2505,6 +3075,9 @@ +@@ -2505,6 +3077,9 @@ cMenuSetupOSD(void); virtual ~cMenuSetupOSD(); virtual eOSState ProcessKey(eKeys Key); @@ -3905,7 +3930,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupOSD::cMenuSetupOSD(void) -@@ -2546,6 +3119,9 @@ +@@ -2546,6 +3121,9 @@ Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); if (themes.NumThemes()) Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); @@ -3915,7 +3940,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5)); Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5)); Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0)); -@@ -2568,6 +3144,12 @@ +@@ -2568,6 +3146,12 @@ Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu)); @@ -3928,7 +3953,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c SetCurrent(Get(current)); Display(); } -@@ -2639,12 +3221,18 @@ +@@ -2639,12 +3223,18 @@ class cMenuSetupEPG : public cMenuSetupBase { private: @@ -3947,7 +3972,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupEPG::cMenuSetupEPG(void) -@@ -2661,11 +3249,19 @@ +@@ -2661,11 +3251,19 @@ { int current = Current(); @@ -3967,7 +3992,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); if (data.SetSystemTime) Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); -@@ -2674,6 +3270,15 @@ +@@ -2674,6 +3272,15 @@ for (int i = 0; i < numLanguages; i++) // TRANSLATORS: note the singular! Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); @@ -3983,7 +4008,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c SetCurrent(Get(current)); Display(); -@@ -2740,6 +3345,9 @@ +@@ -2740,6 +3347,9 @@ public: cMenuSetupDVB(void); virtual eOSState ProcessKey(eKeys Key); @@ -3993,7 +4018,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupDVB::cMenuSetupDVB(void) -@@ -2770,12 +3378,18 @@ +@@ -2770,12 +3380,18 @@ Clear(); @@ -4012,7 +4037,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size())); for (int i = 0; i < numAudioLanguages; i++) Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); -@@ -2788,6 +3402,9 @@ +@@ -2788,6 +3404,9 @@ Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); } @@ -4022,7 +4047,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c SetCurrent(Get(current)); Display(); -@@ -2869,6 +3486,9 @@ +@@ -2869,6 +3488,9 @@ public: cMenuSetupLNB(void); virtual eOSState ProcessKey(eKeys Key); @@ -4032,7 +4057,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupLNB::cMenuSetupLNB(void) -@@ -2883,6 +3503,23 @@ +@@ -2883,6 +3505,23 @@ Clear(); @@ -4056,7 +4081,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); if (!data.DiSEqC) { Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); -@@ -2899,6 +3536,10 @@ +@@ -2899,6 +3538,10 @@ int oldDiSEqC = data.DiSEqC; eOSState state = cMenuSetupBase::ProcessKey(Key); @@ -4067,7 +4092,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (Key != kNone && data.DiSEqC != oldDiSEqC) Setup(); return state; -@@ -2949,6 +3590,9 @@ +@@ -2949,6 +3592,9 @@ public: cMenuSetupCAM(void); virtual eOSState ProcessKey(eKeys Key); @@ -4077,7 +4102,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupCAM::cMenuSetupCAM(void) -@@ -3025,12 +3669,57 @@ +@@ -3025,12 +3671,58 @@ private: const char *pauseKeyHandlingTexts[3]; const char *delTimeshiftRecTexts[3]; @@ -4125,6 +4150,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c +} + +void cMenuSetupRecord::Set(void) ++{ +#endif /* DVLVIDPREFER */ +#ifdef USE_SORTRECORDS + RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); @@ -4135,7 +4161,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c pauseKeyHandlingTexts[0] = tr("do not pause live video"); pauseKeyHandlingTexts[1] = tr("confirm pause live video"); pauseKeyHandlingTexts[2] = tr("pause live video"); -@@ -3046,14 +3735,46 @@ +@@ -3046,14 +3738,49 @@ Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts)); Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); @@ -4179,10 +4205,13 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c + Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); +#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); ++#endif /* CUTTERQUEUE */ Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts)); } -@@ -3072,6 +3793,17 @@ +@@ -3072,6 +3799,17 @@ Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); @@ -4200,7 +4229,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } void cMenuSetupReplay::Store(void) -@@ -3084,13 +3816,48 @@ +@@ -3084,13 +3822,48 @@ // --- cMenuSetupMisc -------------------------------------------------------- class cMenuSetupMisc : public cMenuSetupBase { @@ -4249,7 +4278,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); -@@ -3098,8 +3865,22 @@ +@@ -3098,8 +3871,22 @@ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); @@ -4272,7 +4301,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } // --- cMenuSetupPluginItem -------------------------------------------------- -@@ -3124,6 +3905,9 @@ +@@ -3124,6 +3911,9 @@ public: cMenuSetupPlugins(void); virtual eOSState ProcessKey(eKeys Key); @@ -4282,7 +4311,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetupPlugins::cMenuSetupPlugins(void) -@@ -3173,6 +3957,9 @@ +@@ -3173,6 +3963,9 @@ public: cMenuSetup(void); virtual eOSState ProcessKey(eKeys Key); @@ -4292,7 +4321,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c }; cMenuSetup::cMenuSetup(void) -@@ -3262,24 +4049,65 @@ +@@ -3262,24 +4055,65 @@ cMenuMain::cMenuMain(eOSState State) :cOsdMenu("") { @@ -4358,7 +4387,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } cOsdObject *cMenuMain::PluginOsdObject(void) -@@ -3289,37 +4117,156 @@ +@@ -3289,37 +4123,156 @@ return o; } @@ -4515,7 +4544,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Update(true); -@@ -3329,13 +4276,29 @@ +@@ -3329,13 +4282,29 @@ bool cMenuMain::Update(bool Force) { bool result = false; @@ -4545,7 +4574,17 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c bool NewReplaying = cControl::Control() != NULL; if (Force || NewReplaying != replaying) { -@@ -3357,6 +4320,9 @@ +@@ -3343,6 +4312,9 @@ + // Replay control: + if (replaying && !stopReplayItem) + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else ++#endif /* LIEMIEXT */ + Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); + else if (stopReplayItem && !replaying) { + Del(stopReplayItem->Index()); +@@ -3357,6 +4329,9 @@ bool CutterActive = cCutter::Active(); if (CutterActive && !cancelEditingItem) { // TRANSLATORS: note the leading blank! @@ -4555,17 +4594,17 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); result = true; } -@@ -3376,6 +4342,9 @@ - const char *s = NULL; +@@ -3377,6 +4352,9 @@ while ((s = cRecordControls::GetInstantId(s)) != NULL) { cOsdItem *item = new cOsdItem(osStopRecord); + item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); +#ifdef USE_LIEMIEXT + if (Setup.MenuCmdPosition) Ins(item); else +#endif /* LIEMIEXT */ - item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); Add(item); if (!stopRecordingItem) -@@ -3384,6 +4353,12 @@ + stopRecordingItem = item; +@@ -3384,6 +4362,12 @@ result = true; } @@ -4578,7 +4617,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c return result; } -@@ -3394,13 +4369,53 @@ +@@ -3394,13 +4378,53 @@ eOSState state = cOsdMenu::ProcessKey(Key); HadSubMenu |= HasSubMenu(); @@ -4632,7 +4671,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { cOsdItem *item = Get(Current()); if (item) { -@@ -3419,6 +4434,9 @@ +@@ -3419,6 +4443,9 @@ if (item) { cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); if (p) { @@ -4642,7 +4681,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c cOsdObject *menu = p->MainMenuAction(); if (menu) { if (menu->IsMenu()) -@@ -3428,11 +4446,63 @@ +@@ -3428,11 +4455,63 @@ return osPlugin; } } @@ -4706,7 +4745,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c default: switch (Key) { case kRecord: case kRed: if (!HadSubMenu) -@@ -3449,9 +4519,63 @@ +@@ -3449,9 +4528,63 @@ case kBlue: if (!HadSubMenu) state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; break; @@ -4770,7 +4809,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (!HasSubMenu() && Update(HadSubMenu)) Display(); if (Key != kNone) { -@@ -3598,6 +4722,9 @@ +@@ -3598,6 +4731,9 @@ if (Direction) { while (Channel) { Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); @@ -4780,7 +4819,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (!Channel && Setup.ChannelsWrap) Channel = Direction > 0 ? Channels.First() : Channels.Last(); if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) -@@ -3658,6 +4785,13 @@ +@@ -3658,6 +4794,13 @@ case kLeft: case kRight|k_Repeat: case kRight: @@ -4794,7 +4833,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c case kNext|k_Repeat: case kNext: case kPrev|k_Repeat: -@@ -3817,6 +4951,17 @@ +@@ -3817,6 +4960,17 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key) { switch (Key) { @@ -4812,7 +4851,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c case kVolUp|k_Repeat: case kVolUp: case kVolDn|k_Repeat: -@@ -4064,8 +5209,16 @@ +@@ -4064,8 +5218,16 @@ // --- cRecordControl -------------------------------------------------------- @@ -4829,7 +4868,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c // We're going to manipulate an event here, so we need to prevent // others from modifying any EPG data: cSchedulesLock SchedulesLock; -@@ -4110,12 +5263,29 @@ +@@ -4110,12 +5272,29 @@ return; } @@ -4859,7 +4898,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c Recording.WriteInfo(); cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() -@@ -4124,7 +5294,12 @@ +@@ -4124,7 +5303,12 @@ return; } else @@ -4872,7 +4911,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } if (!Timer) { Timers.Del(timer); -@@ -4172,12 +5347,26 @@ +@@ -4172,12 +5356,26 @@ void cRecordControl::Stop(bool ExecuteUserCommand) { if (timer) { @@ -4899,7 +4938,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } } -@@ -4223,8 +5412,32 @@ +@@ -4223,8 +5421,32 @@ if (channel) { int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; cDevice *device = cDevice::GetDevice(channel, Priority, false); @@ -4932,7 +4971,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (!device->SwitchChannel(channel, false)) { ShutdownHandler.RequestEmergencyExit(); return false; -@@ -4232,7 +5445,14 @@ +@@ -4232,7 +5454,14 @@ if (!Timer || Timer->Matches()) { for (int i = 0; i < MAXRECORDCONTROLS; i++) { if (!RecordControls[i]) { @@ -4947,7 +4986,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c return RecordControls[i]->Process(time(NULL)); } } -@@ -4268,6 +5488,21 @@ +@@ -4268,6 +5497,21 @@ } } @@ -4969,7 +5008,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c bool cRecordControls::PauseLiveVideo(void) { Skins.Message(mtStatus, tr("Pausing live video...")); -@@ -4365,12 +5600,22 @@ +@@ -4365,12 +5609,22 @@ // --- cReplayControl -------------------------------------------------------- @@ -4992,7 +5031,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c { currentReplayControl = this; displayReplay = NULL; -@@ -4378,11 +5623,18 @@ +@@ -4378,11 +5632,18 @@ lastCurrent = lastTotal = -1; lastPlay = lastForward = false; lastSpeed = -2; // an invalid value @@ -5011,7 +5050,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c SetTrackDescriptions(false); } -@@ -4642,8 +5894,16 @@ +@@ -4642,8 +5903,16 @@ ShowTimed(2); bool Play, Forward; int Speed; @@ -5028,7 +5067,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } marks.Save(); } -@@ -4656,8 +5916,22 @@ +@@ -4656,8 +5925,22 @@ if (GetIndex(Current, Total)) { cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); if (m) { @@ -5051,7 +5090,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c } } } -@@ -4690,7 +5964,11 @@ +@@ -4690,7 +5973,11 @@ { if (fileName) { Hide(); @@ -5063,7 +5102,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (!marks.Count()) Skins.Message(mtError, tr("No editing marks defined!")); else if (!cCutter::Start(fileName)) -@@ -4712,7 +5990,11 @@ +@@ -4712,7 +5999,11 @@ if (!m) m = marks.GetNext(Current); if (m) { @@ -5075,7 +5114,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c m = marks.Next(m); if (m) { Goto(m->position - SecondsToFrames(3, FramesPerSecond())); -@@ -4734,6 +6016,9 @@ +@@ -4734,6 +6025,9 @@ { if (!Active()) return osEnd; @@ -5085,7 +5124,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c if (visible) { if (timeoutShow && time(NULL) > timeoutShow) { Hide(); -@@ -4752,6 +6037,22 @@ +@@ -4752,6 +6046,22 @@ return osContinue; } bool DoShowMode = true; @@ -5108,7 +5147,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c switch (Key) { // Positioning: case kPlay: -@@ -4769,25 +6070,73 @@ +@@ -4769,25 +6079,73 @@ case kFastFwd: case kRight: Forward(); break; case kRed: TimeSearch(); break; @@ -5184,7 +5223,7 @@ diff -ruN vdr-1.7.14/menu.c vdr-1.7.14.ExtP_NG/menu.c case kMarkMoveBack|k_Repeat: diff -ruN vdr-1.7.14/menu.h vdr-1.7.14.ExtP_NG/menu.h --- vdr-1.7.14/menu.h 2010-03-06 17:15:59.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/menu.h 2010-03-14 14:02:05.457983500 +0100 ++++ vdr-1.7.14.ExtP_NG/menu.h 2010-04-10 15:45:10.646737633 +0200 @@ -18,6 +18,9 @@ #include "menuitems.h" #include "recorder.h" @@ -5308,7 +5347,7 @@ diff -ruN vdr-1.7.14/menu.h vdr-1.7.14.ExtP_NG/menu.h int timeSearchTime, timeSearchPos; diff -ruN vdr-1.7.14/menuitems.c vdr-1.7.14.ExtP_NG/menuitems.c --- vdr-1.7.14/menuitems.c 2010-02-16 15:44:35.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/menuitems.c 2010-03-14 14:02:05.473983960 +0100 ++++ vdr-1.7.14.ExtP_NG/menuitems.c 2010-04-10 15:45:10.665741204 +0200 @@ -33,9 +33,21 @@ free(name); } @@ -5357,7 +5396,7 @@ diff -ruN vdr-1.7.14/menuitems.c vdr-1.7.14.ExtP_NG/menuitems.c // --- cMenuEditChanItem ----------------------------------------------------- diff -ruN vdr-1.7.14/menuitems.h vdr-1.7.14.ExtP_NG/menuitems.h --- vdr-1.7.14/menuitems.h 2010-02-21 14:58:21.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/menuitems.h 2010-03-14 14:02:05.480986531 +0100 ++++ vdr-1.7.14.ExtP_NG/menuitems.h 2010-04-10 15:45:10.674735161 +0200 @@ -22,7 +22,11 @@ public: cMenuEditItem(const char *Name); @@ -5382,7 +5421,7 @@ diff -ruN vdr-1.7.14/menuitems.h vdr-1.7.14.ExtP_NG/menuitems.h #endif //__MENUITEMS_H diff -ruN vdr-1.7.14/menuorgpatch.h vdr-1.7.14.ExtP_NG/menuorgpatch.h --- vdr-1.7.14/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/menuorgpatch.h 2010-03-14 14:02:05.491985437 +0100 ++++ vdr-1.7.14.ExtP_NG/menuorgpatch.h 2010-04-10 15:45:10.686736443 +0200 @@ -0,0 +1,102 @@ +#ifdef USE_MENUORG +/* @@ -5488,7 +5527,7 @@ diff -ruN vdr-1.7.14/menuorgpatch.h vdr-1.7.14.ExtP_NG/menuorgpatch.h +#endif /* MENUORG */ diff -ruN vdr-1.7.14/osd.c vdr-1.7.14.ExtP_NG/osd.c --- vdr-1.7.14/osd.c 2010-01-22 16:58:39.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/osd.c 2010-03-14 14:02:05.544981887 +0100 ++++ vdr-1.7.14.ExtP_NG/osd.c 2010-04-10 15:45:10.754742652 +0200 @@ -743,6 +743,9 @@ int cOsd::osdWidth = 0; int cOsd::osdHeight = 0; @@ -5511,7 +5550,7 @@ diff -ruN vdr-1.7.14/osd.c vdr-1.7.14.ExtP_NG/osd.c Osds.Insert(this, i); diff -ruN vdr-1.7.14/osd.h vdr-1.7.14.ExtP_NG/osd.h --- vdr-1.7.14/osd.h 2010-01-17 14:23:50.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/osd.h 2010-03-14 14:02:05.556982734 +0100 ++++ vdr-1.7.14.ExtP_NG/osd.h 2010-04-10 15:45:10.767741548 +0200 @@ -270,6 +270,10 @@ int left, top, width, height; uint level; @@ -5535,7 +5574,7 @@ diff -ruN vdr-1.7.14/osd.h vdr-1.7.14.ExtP_NG/osd.h class cOsdProvider { diff -ruN vdr-1.7.14/osdbase.c vdr-1.7.14.ExtP_NG/osdbase.c --- vdr-1.7.14/osdbase.c 2010-01-17 12:36:12.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/osdbase.c 2010-03-14 14:02:05.566981514 +0100 ++++ vdr-1.7.14.ExtP_NG/osdbase.c 2010-04-10 15:45:10.777738279 +0200 @@ -22,6 +22,9 @@ state = State; selectable = true; @@ -5708,7 +5747,7 @@ diff -ruN vdr-1.7.14/osdbase.c vdr-1.7.14.ExtP_NG/osdbase.c case kDown|k_Repeat: diff -ruN vdr-1.7.14/osdbase.h vdr-1.7.14.ExtP_NG/osdbase.h --- vdr-1.7.14/osdbase.h 2010-01-16 15:25:31.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/osdbase.h 2010-03-14 14:02:05.587980830 +0100 ++++ vdr-1.7.14.ExtP_NG/osdbase.h 2010-04-10 15:45:10.786736628 +0200 @@ -15,6 +15,10 @@ #include "skins.h" #include "tools.h" @@ -5770,7 +5809,7 @@ diff -ruN vdr-1.7.14/osdbase.h vdr-1.7.14.ExtP_NG/osdbase.h #endif //__OSDBASE_H diff -ruN vdr-1.7.14/pat.c vdr-1.7.14.ExtP_NG/pat.c --- vdr-1.7.14/pat.c 2010-03-06 13:00:30.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/pat.c 2010-03-14 14:02:05.598984754 +0100 ++++ vdr-1.7.14.ExtP_NG/pat.c 2010-04-10 15:45:10.802741457 +0200 @@ -13,6 +13,9 @@ #include "libsi/section.h" #include "libsi/descriptor.h" @@ -5822,7 +5861,7 @@ diff -ruN vdr-1.7.14/pat.c vdr-1.7.14.ExtP_NG/pat.c SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; diff -ruN vdr-1.7.14/plugin.c vdr-1.7.14.ExtP_NG/plugin.c --- vdr-1.7.14/plugin.c 2010-01-06 12:36:46.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/plugin.c 2010-03-14 14:02:05.642980882 +0100 ++++ vdr-1.7.14.ExtP_NG/plugin.c 2010-04-10 15:45:10.848736538 +0200 @@ -317,6 +317,14 @@ char *p = strchr(s, ' '); if (p) @@ -5852,7 +5891,7 @@ diff -ruN vdr-1.7.14/plugin.c vdr-1.7.14.ExtP_NG/plugin.c } diff -ruN vdr-1.7.14/plugin.h vdr-1.7.14.ExtP_NG/plugin.h --- vdr-1.7.14/plugin.h 2007-08-04 11:56:26.000000000 +0200 -+++ vdr-1.7.14.ExtP_NG/plugin.h 2010-03-14 14:02:05.651981254 +0100 ++++ vdr-1.7.14.ExtP_NG/plugin.h 2010-04-10 15:45:10.861747307 +0200 @@ -45,6 +45,9 @@ virtual const char *MainMenuEntry(void); @@ -5865,7 +5904,7 @@ diff -ruN vdr-1.7.14/plugin.h vdr-1.7.14.ExtP_NG/plugin.h virtual bool SetupParse(const char *Name, const char *Value); diff -ruN vdr-1.7.14/po/ca_ES.po vdr-1.7.14.ExtP_NG/po/ca_ES.po --- vdr-1.7.14/po/ca_ES.po 2010-03-12 17:41:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/ca_ES.po 2010-03-14 14:02:06.837965477 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ca_ES.po 2010-04-10 15:45:12.406741501 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "cap" @@ -5888,7 +5927,7 @@ diff -ruN vdr-1.7.14/po/ca_ES.po vdr-1.7.14.ExtP_NG/po/ca_ES.po diff -ruN vdr-1.7.14/po/cs_CZ.po vdr-1.7.14.ExtP_NG/po/cs_CZ.po --- vdr-1.7.14/po/cs_CZ.po 2010-03-12 17:41:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/cs_CZ.po 2010-03-14 14:02:06.849965394 +0100 ++++ vdr-1.7.14.ExtP_NG/po/cs_CZ.po 2010-04-10 15:45:12.435736716 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "¾ádný" @@ -5911,7 +5950,7 @@ diff -ruN vdr-1.7.14/po/cs_CZ.po vdr-1.7.14.ExtP_NG/po/cs_CZ.po diff -ruN vdr-1.7.14/po/da_DK.po vdr-1.7.14.ExtP_NG/po/da_DK.po --- vdr-1.7.14/po/da_DK.po 2010-03-12 17:41:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/da_DK.po 2010-03-14 14:02:06.862968584 +0100 ++++ vdr-1.7.14.ExtP_NG/po/da_DK.po 2010-04-10 15:45:12.467742106 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "ingen" @@ -5934,7 +5973,7 @@ diff -ruN vdr-1.7.14/po/da_DK.po vdr-1.7.14.ExtP_NG/po/da_DK.po diff -ruN vdr-1.7.14/po/de_DE.po vdr-1.7.14.ExtP_NG/po/de_DE.po --- vdr-1.7.14/po/de_DE.po 2010-03-12 17:41:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/de_DE.po 2010-03-14 14:02:06.874967630 +0100 ++++ vdr-1.7.14.ExtP_NG/po/de_DE.po 2010-04-10 15:45:12.504739261 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "keine" @@ -6079,7 +6118,7 @@ diff -ruN vdr-1.7.14/po/de_DE.po vdr-1.7.14.ExtP_NG/po/de_DE.po +msgstr "Kindersicherung" diff -ruN vdr-1.7.14/po/el_GR.po vdr-1.7.14.ExtP_NG/po/el_GR.po --- vdr-1.7.14/po/el_GR.po 2010-03-12 17:41:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/el_GR.po 2010-03-14 14:02:06.887969497 +0100 ++++ vdr-1.7.14.ExtP_NG/po/el_GR.po 2010-04-10 15:45:12.539740766 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "êáíÝíá" @@ -6102,7 +6141,7 @@ diff -ruN vdr-1.7.14/po/el_GR.po vdr-1.7.14.ExtP_NG/po/el_GR.po diff -ruN vdr-1.7.14/po/es_ES.po vdr-1.7.14.ExtP_NG/po/es_ES.po --- vdr-1.7.14/po/es_ES.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/es_ES.po 2010-03-14 14:02:06.899966033 +0100 ++++ vdr-1.7.14.ExtP_NG/po/es_ES.po 2010-04-10 15:45:12.568741800 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "ninguno" @@ -6125,7 +6164,7 @@ diff -ruN vdr-1.7.14/po/es_ES.po vdr-1.7.14.ExtP_NG/po/es_ES.po diff -ruN vdr-1.7.14/po/et_EE.po vdr-1.7.14.ExtP_NG/po/et_EE.po --- vdr-1.7.14/po/et_EE.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/et_EE.po 2010-03-14 14:02:06.912967810 +0100 ++++ vdr-1.7.14.ExtP_NG/po/et_EE.po 2010-04-10 15:45:12.591740207 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "puudu" @@ -6194,7 +6233,7 @@ diff -ruN vdr-1.7.14/po/et_EE.po vdr-1.7.14.ExtP_NG/po/et_EE.po +msgstr "Salvestuse kestus" diff -ruN vdr-1.7.14/po/fi_FI.po vdr-1.7.14.ExtP_NG/po/fi_FI.po --- vdr-1.7.14/po/fi_FI.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/fi_FI.po 2010-03-14 14:02:06.924963607 +0100 ++++ vdr-1.7.14.ExtP_NG/po/fi_FI.po 2010-04-10 15:45:12.620745376 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "tyhjä" @@ -6266,7 +6305,7 @@ diff -ruN vdr-1.7.14/po/fi_FI.po vdr-1.7.14.ExtP_NG/po/fi_FI.po +msgstr "Parametrit" diff -ruN vdr-1.7.14/po/fr_FR.po vdr-1.7.14.ExtP_NG/po/fr_FR.po --- vdr-1.7.14/po/fr_FR.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/fr_FR.po 2010-03-14 14:02:06.937969373 +0100 ++++ vdr-1.7.14.ExtP_NG/po/fr_FR.po 2010-04-10 15:45:12.650738547 +0200 @@ -42,6 +42,9 @@ msgid "none" msgstr "aucun" @@ -6376,7 +6415,7 @@ diff -ruN vdr-1.7.14/po/fr_FR.po vdr-1.7.14.ExtP_NG/po/fr_FR.po +msgstr "Paramètres" diff -ruN vdr-1.7.14/po/hr_HR.po vdr-1.7.14.ExtP_NG/po/hr_HR.po --- vdr-1.7.14/po/hr_HR.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/hr_HR.po 2010-03-14 14:02:06.949965110 +0100 ++++ vdr-1.7.14.ExtP_NG/po/hr_HR.po 2010-04-10 15:45:12.676740196 +0200 @@ -38,6 +38,9 @@ msgid "none" msgstr "ni¹ta" @@ -6399,7 +6438,7 @@ diff -ruN vdr-1.7.14/po/hr_HR.po vdr-1.7.14.ExtP_NG/po/hr_HR.po diff -ruN vdr-1.7.14/po/hu_HU.po vdr-1.7.14.ExtP_NG/po/hu_HU.po --- vdr-1.7.14/po/hu_HU.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/hu_HU.po 2010-03-14 14:02:06.961966317 +0100 ++++ vdr-1.7.14.ExtP_NG/po/hu_HU.po 2010-04-10 15:45:12.697741656 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "semmi" @@ -6422,7 +6461,7 @@ diff -ruN vdr-1.7.14/po/hu_HU.po vdr-1.7.14.ExtP_NG/po/hu_HU.po diff -ruN vdr-1.7.14/po/it_IT.po vdr-1.7.14.ExtP_NG/po/it_IT.po --- vdr-1.7.14/po/it_IT.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/it_IT.po 2010-03-14 14:02:06.973964558 +0100 ++++ vdr-1.7.14.ExtP_NG/po/it_IT.po 2010-04-10 15:45:12.723739553 +0200 @@ -43,6 +43,9 @@ msgid "none" msgstr "nessuno" @@ -6445,7 +6484,7 @@ diff -ruN vdr-1.7.14/po/it_IT.po vdr-1.7.14.ExtP_NG/po/it_IT.po diff -ruN vdr-1.7.14/po/nl_NL.po vdr-1.7.14.ExtP_NG/po/nl_NL.po --- vdr-1.7.14/po/nl_NL.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/nl_NL.po 2010-03-14 14:02:06.998963388 +0100 ++++ vdr-1.7.14.ExtP_NG/po/nl_NL.po 2010-04-10 15:45:12.785740553 +0200 @@ -40,6 +40,9 @@ msgid "none" msgstr "geen" @@ -6468,7 +6507,7 @@ diff -ruN vdr-1.7.14/po/nl_NL.po vdr-1.7.14.ExtP_NG/po/nl_NL.po diff -ruN vdr-1.7.14/po/nn_NO.po vdr-1.7.14.ExtP_NG/po/nn_NO.po --- vdr-1.7.14/po/nn_NO.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/nn_NO.po 2010-03-14 14:02:07.009962551 +0100 ++++ vdr-1.7.14.ExtP_NG/po/nn_NO.po 2010-04-10 15:45:12.809737908 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "" @@ -6491,7 +6530,7 @@ diff -ruN vdr-1.7.14/po/nn_NO.po vdr-1.7.14.ExtP_NG/po/nn_NO.po diff -ruN vdr-1.7.14/po/pl_PL.po vdr-1.7.14.ExtP_NG/po/pl_PL.po --- vdr-1.7.14/po/pl_PL.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/pl_PL.po 2010-03-14 14:02:07.023967981 +0100 ++++ vdr-1.7.14.ExtP_NG/po/pl_PL.po 2010-04-10 15:45:12.835738610 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "brak" @@ -6514,7 +6553,7 @@ diff -ruN vdr-1.7.14/po/pl_PL.po vdr-1.7.14.ExtP_NG/po/pl_PL.po diff -ruN vdr-1.7.14/po/pt_PT.po vdr-1.7.14.ExtP_NG/po/pt_PT.po --- vdr-1.7.14/po/pt_PT.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/pt_PT.po 2010-03-14 14:02:07.035967399 +0100 ++++ vdr-1.7.14.ExtP_NG/po/pt_PT.po 2010-04-10 15:45:12.870742039 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "nenhum" @@ -6537,7 +6576,7 @@ diff -ruN vdr-1.7.14/po/pt_PT.po vdr-1.7.14.ExtP_NG/po/pt_PT.po diff -ruN vdr-1.7.14/po/ro_RO.po vdr-1.7.14.ExtP_NG/po/ro_RO.po --- vdr-1.7.14/po/ro_RO.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/ro_RO.po 2010-03-14 14:02:07.049963749 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ro_RO.po 2010-04-10 15:45:12.889740524 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "niciuna(ul)" @@ -6560,7 +6599,7 @@ diff -ruN vdr-1.7.14/po/ro_RO.po vdr-1.7.14.ExtP_NG/po/ro_RO.po diff -ruN vdr-1.7.14/po/ru_RU.po vdr-1.7.14.ExtP_NG/po/ru_RU.po --- vdr-1.7.14/po/ru_RU.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/ru_RU.po 2010-03-14 14:02:07.062965052 +0100 ++++ vdr-1.7.14.ExtP_NG/po/ru_RU.po 2010-04-10 15:45:12.921738012 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "ÝØçÕÓÞ" @@ -6629,7 +6668,7 @@ diff -ruN vdr-1.7.14/po/ru_RU.po vdr-1.7.14.ExtP_NG/po/ru_RU.po +msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" diff -ruN vdr-1.7.14/po/sl_SI.po vdr-1.7.14.ExtP_NG/po/sl_SI.po --- vdr-1.7.14/po/sl_SI.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/sl_SI.po 2010-03-14 14:02:07.086965624 +0100 ++++ vdr-1.7.14.ExtP_NG/po/sl_SI.po 2010-04-10 15:45:12.971742442 +0200 @@ -37,6 +37,9 @@ msgid "none" msgstr "nobeden" @@ -6652,7 +6691,7 @@ diff -ruN vdr-1.7.14/po/sl_SI.po vdr-1.7.14.ExtP_NG/po/sl_SI.po diff -ruN vdr-1.7.14/po/sv_SE.po vdr-1.7.14.ExtP_NG/po/sv_SE.po --- vdr-1.7.14/po/sv_SE.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/sv_SE.po 2010-03-14 14:02:07.099963332 +0100 ++++ vdr-1.7.14.ExtP_NG/po/sv_SE.po 2010-04-10 15:45:12.996740450 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "ingen" @@ -6675,7 +6714,7 @@ diff -ruN vdr-1.7.14/po/sv_SE.po vdr-1.7.14.ExtP_NG/po/sv_SE.po diff -ruN vdr-1.7.14/po/tr_TR.po vdr-1.7.14.ExtP_NG/po/tr_TR.po --- vdr-1.7.14/po/tr_TR.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/tr_TR.po 2010-03-14 14:02:07.113963530 +0100 ++++ vdr-1.7.14.ExtP_NG/po/tr_TR.po 2010-04-10 15:45:13.021741692 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "hiç" @@ -6698,7 +6737,7 @@ diff -ruN vdr-1.7.14/po/tr_TR.po vdr-1.7.14.ExtP_NG/po/tr_TR.po diff -ruN vdr-1.7.14/po/uk_UA.po vdr-1.7.14.ExtP_NG/po/uk_UA.po --- vdr-1.7.14/po/uk_UA.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/uk_UA.po 2010-03-14 14:02:07.128967016 +0100 ++++ vdr-1.7.14.ExtP_NG/po/uk_UA.po 2010-04-10 15:45:13.061743013 +0200 @@ -36,6 +36,9 @@ msgid "none" msgstr "нічого" @@ -6721,7 +6760,7 @@ diff -ruN vdr-1.7.14/po/uk_UA.po vdr-1.7.14.ExtP_NG/po/uk_UA.po diff -ruN vdr-1.7.14/po/zh_CN.po vdr-1.7.14.ExtP_NG/po/zh_CN.po --- vdr-1.7.14/po/zh_CN.po 2010-03-12 17:41:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/po/zh_CN.po 2010-03-14 14:02:07.141965253 +0100 ++++ vdr-1.7.14.ExtP_NG/po/zh_CN.po 2010-04-10 15:45:13.092741645 +0200 @@ -39,6 +39,9 @@ msgid "none" msgstr "æ— " @@ -6744,7 +6783,7 @@ diff -ruN vdr-1.7.14/po/zh_CN.po vdr-1.7.14.ExtP_NG/po/zh_CN.po diff -ruN vdr-1.7.14/receiver.c vdr-1.7.14.ExtP_NG/receiver.c --- vdr-1.7.14/receiver.c 2010-02-28 15:25:32.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/receiver.c 2010-03-14 14:02:05.740980502 +0100 ++++ vdr-1.7.14.ExtP_NG/receiver.c 2010-04-10 15:45:11.056767270 +0200 @@ -82,7 +82,12 @@ (Channel->Ppid() == Channel->Vpid() || AddPid(Channel->Ppid())) && AddPids(Channel->Apids()) && @@ -6760,7 +6799,7 @@ diff -ruN vdr-1.7.14/receiver.c vdr-1.7.14.ExtP_NG/receiver.c } diff -ruN vdr-1.7.14/recorder.c vdr-1.7.14.ExtP_NG/recorder.c --- vdr-1.7.14/recorder.c 2010-01-29 17:37:22.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/recorder.c 2010-03-14 14:02:05.765979560 +0100 ++++ vdr-1.7.14.ExtP_NG/recorder.c 2010-04-10 15:45:11.083738273 +0200 @@ -87,7 +87,11 @@ bool cRecorder::NextFile(void) { @@ -6775,7 +6814,7 @@ diff -ruN vdr-1.7.14/recorder.c vdr-1.7.14.ExtP_NG/recorder.c } diff -ruN vdr-1.7.14/recording.c vdr-1.7.14.ExtP_NG/recording.c --- vdr-1.7.14/recording.c 2010-03-07 15:06:04.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/recording.c 2010-03-14 14:02:05.802979054 +0100 ++++ vdr-1.7.14.ExtP_NG/recording.c 2010-04-10 15:45:11.124740932 +0200 @@ -8,6 +8,9 @@ */ @@ -7311,7 +7350,7 @@ diff -ruN vdr-1.7.14/recording.c vdr-1.7.14.ExtP_NG/recording.c +#endif /* DVLFRIENDLYFNAMES */ diff -ruN vdr-1.7.14/recording.h vdr-1.7.14.ExtP_NG/recording.h --- vdr-1.7.14/recording.h 2010-03-07 15:06:15.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/recording.h 2010-03-14 14:02:05.812978705 +0100 ++++ vdr-1.7.14.ExtP_NG/recording.h 2010-04-10 15:45:11.134737044 +0200 @@ -23,6 +23,9 @@ #define TIMERMACRO_EPISODE "EPISODE" @@ -7486,7 +7525,7 @@ diff -ruN vdr-1.7.14/recording.h vdr-1.7.14.ExtP_NG/recording.h diff -ruN vdr-1.7.14/remux.c vdr-1.7.14.ExtP_NG/remux.c --- vdr-1.7.14/remux.c 2010-02-28 15:42:07.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/remux.c 2010-03-14 14:02:05.853979909 +0100 ++++ vdr-1.7.14.ExtP_NG/remux.c 2010-04-10 15:45:11.187744435 +0200 @@ -215,6 +215,32 @@ return i; } @@ -7604,7 +7643,7 @@ diff -ruN vdr-1.7.14/remux.c vdr-1.7.14.ExtP_NG/remux.c dbgpatpmt(" '%s'", ld->languageCode); diff -ruN vdr-1.7.14/remux.h vdr-1.7.14.ExtP_NG/remux.h --- vdr-1.7.14/remux.h 2010-01-29 17:51:26.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/remux.h 2010-03-14 14:02:05.863978011 +0100 ++++ vdr-1.7.14.ExtP_NG/remux.h 2010-04-10 15:45:11.199740063 +0200 @@ -170,6 +170,9 @@ int MakeStream(uchar *Target, uchar Type, int Pid); int MakeAC3Descriptor(uchar *Target); @@ -7661,7 +7700,7 @@ diff -ruN vdr-1.7.14/remux.h vdr-1.7.14.ExtP_NG/remux.h // TS to PES converter: diff -ruN vdr-1.7.14/sections.c vdr-1.7.14.ExtP_NG/sections.c --- vdr-1.7.14/sections.c 2007-10-14 14:52:07.000000000 +0200 -+++ vdr-1.7.14.ExtP_NG/sections.c 2010-03-14 14:02:05.930976827 +0100 ++++ vdr-1.7.14.ExtP_NG/sections.c 2010-04-10 15:45:11.300735330 +0200 @@ -198,7 +198,11 @@ if (fh) { // Read section data: @@ -7676,7 +7715,7 @@ diff -ruN vdr-1.7.14/sections.c vdr-1.7.14.ExtP_NG/sections.c if (r > 3) { // minimum number of bytes necessary to get section length diff -ruN vdr-1.7.14/skins.c vdr-1.7.14.ExtP_NG/skins.c --- vdr-1.7.14/skins.c 2009-06-06 17:12:31.000000000 +0200 -+++ vdr-1.7.14.ExtP_NG/skins.c 2010-03-14 14:02:06.000978845 +0100 ++++ vdr-1.7.14.ExtP_NG/skins.c 2010-04-10 15:45:11.417738004 +0200 @@ -238,7 +238,11 @@ } cSkinDisplay::Current()->SetMessage(Type, s); @@ -7703,7 +7742,7 @@ diff -ruN vdr-1.7.14/skins.c vdr-1.7.14.ExtP_NG/skins.c else if (!s && displayMessage) { diff -ruN vdr-1.7.14/status.c vdr-1.7.14.ExtP_NG/status.c --- vdr-1.7.14/status.c 2008-02-16 15:46:31.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/status.c 2010-03-14 14:02:06.131975916 +0100 ++++ vdr-1.7.14.ExtP_NG/status.c 2010-04-10 15:45:11.565737350 +0200 @@ -83,6 +83,17 @@ sm->OsdTitle(Title); } @@ -7813,7 +7852,7 @@ diff -ruN vdr-1.7.14/status.c vdr-1.7.14.ExtP_NG/status.c +#endif /* PINPLUGIN */ diff -ruN vdr-1.7.14/status.h vdr-1.7.14.ExtP_NG/status.h --- vdr-1.7.14/status.h 2008-02-16 16:00:33.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/status.h 2010-03-14 14:02:06.143975475 +0100 ++++ vdr-1.7.14.ExtP_NG/status.h 2010-04-10 15:45:11.579737535 +0200 @@ -14,6 +14,9 @@ #include "device.h" #include "player.h" @@ -7911,7 +7950,7 @@ diff -ruN vdr-1.7.14/status.h vdr-1.7.14.ExtP_NG/status.h #endif //__STATUS_H diff -ruN vdr-1.7.14/submenu.c vdr-1.7.14.ExtP_NG/submenu.c --- vdr-1.7.14/submenu.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/submenu.c 2010-03-14 14:02:06.157974094 +0100 ++++ vdr-1.7.14.ExtP_NG/submenu.c 2010-04-10 15:45:11.593741591 +0200 @@ -0,0 +1,949 @@ +#ifdef USE_SETUP +/**************************************************************************** @@ -8864,7 +8903,7 @@ diff -ruN vdr-1.7.14/submenu.c vdr-1.7.14.ExtP_NG/submenu.c +#endif /* SETUP */ diff -ruN vdr-1.7.14/submenu.h vdr-1.7.14.ExtP_NG/submenu.h --- vdr-1.7.14/submenu.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/submenu.h 2010-03-14 14:02:06.165975085 +0100 ++++ vdr-1.7.14.ExtP_NG/submenu.h 2010-04-10 15:45:11.601737459 +0200 @@ -0,0 +1,159 @@ +#ifdef USE_SETUP +/**************************************************************************** @@ -9027,7 +9066,7 @@ diff -ruN vdr-1.7.14/submenu.h vdr-1.7.14.ExtP_NG/submenu.h +#endif /* SETUP */ diff -ruN vdr-1.7.14/svdrp.c vdr-1.7.14.ExtP_NG/svdrp.c --- vdr-1.7.14/svdrp.c 2010-01-17 13:23:31.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/svdrp.c 2010-03-14 14:02:06.200977291 +0100 ++++ vdr-1.7.14.ExtP_NG/svdrp.c 2010-04-10 15:45:11.637740914 +0200 @@ -304,6 +304,10 @@ "REMO [ on | off ]\n" " Turns the remote control on or off. Without a parameter, the current\n" @@ -9090,7 +9129,7 @@ diff -ruN vdr-1.7.14/svdrp.c vdr-1.7.14.ExtP_NG/svdrp.c else if (CMD("UPDT")) CmdUPDT(s); diff -ruN vdr-1.7.14/svdrp.h vdr-1.7.14.ExtP_NG/svdrp.h --- vdr-1.7.14/svdrp.h 2007-04-30 14:28:28.000000000 +0200 -+++ vdr-1.7.14.ExtP_NG/svdrp.h 2010-03-14 14:02:06.207974563 +0100 ++++ vdr-1.7.14.ExtP_NG/svdrp.h 2010-04-10 15:45:11.646738241 +0200 @@ -79,6 +79,9 @@ void CmdPLUG(const char *Option); void CmdPUTE(const char *Option); @@ -9103,7 +9142,7 @@ diff -ruN vdr-1.7.14/svdrp.h vdr-1.7.14.ExtP_NG/svdrp.h void CmdUPDT(const char *Option); diff -ruN vdr-1.7.14/timers.c vdr-1.7.14.ExtP_NG/timers.c --- vdr-1.7.14/timers.c 2010-01-16 12:18:53.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/timers.c 2010-03-14 14:02:06.311972154 +0100 ++++ vdr-1.7.14.ExtP_NG/timers.c 2010-04-10 15:45:11.733740689 +0200 @@ -46,6 +46,9 @@ stop -= 2400; priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; @@ -9194,7 +9233,7 @@ diff -ruN vdr-1.7.14/timers.c vdr-1.7.14.ExtP_NG/timers.c cTimers Timers; diff -ruN vdr-1.7.14/timers.h vdr-1.7.14.ExtP_NG/timers.h --- vdr-1.7.14/timers.h 2008-02-16 15:33:23.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/timers.h 2010-03-14 14:02:06.323973088 +0100 ++++ vdr-1.7.14.ExtP_NG/timers.h 2010-04-10 15:45:11.743736984 +0200 @@ -37,6 +37,9 @@ int start; int stop; @@ -9227,7 +9266,7 @@ diff -ruN vdr-1.7.14/timers.h vdr-1.7.14.ExtP_NG/timers.h bool HasFlags(uint Flags) const; diff -ruN vdr-1.7.14/tinystr.c vdr-1.7.14.ExtP_NG/tinystr.c --- vdr-1.7.14/tinystr.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinystr.c 2010-03-14 14:02:06.341972566 +0100 ++++ vdr-1.7.14.ExtP_NG/tinystr.c 2010-04-10 15:45:11.756737883 +0200 @@ -0,0 +1,301 @@ +#ifdef USE_SETUP +/* @@ -9532,7 +9571,7 @@ diff -ruN vdr-1.7.14/tinystr.c vdr-1.7.14.ExtP_NG/tinystr.c +#endif /* SETUP */ diff -ruN vdr-1.7.14/tinystr.h vdr-1.7.14.ExtP_NG/tinystr.h --- vdr-1.7.14/tinystr.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinystr.h 2010-03-14 14:02:06.352972566 +0100 ++++ vdr-1.7.14.ExtP_NG/tinystr.h 2010-04-10 15:45:11.768736847 +0200 @@ -0,0 +1,244 @@ +#ifdef USE_SETUP +/* @@ -9780,7 +9819,7 @@ diff -ruN vdr-1.7.14/tinystr.h vdr-1.7.14.ExtP_NG/tinystr.h +#endif /* SETUP */ diff -ruN vdr-1.7.14/tinyxml.c vdr-1.7.14.ExtP_NG/tinyxml.c --- vdr-1.7.14/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinyxml.c 2010-03-14 14:02:06.368981995 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxml.c 2010-04-10 15:45:11.784736808 +0200 @@ -0,0 +1,1429 @@ +#ifdef USE_SETUP +/* @@ -11213,7 +11252,7 @@ diff -ruN vdr-1.7.14/tinyxml.c vdr-1.7.14.ExtP_NG/tinyxml.c +#endif /* SETUP */ diff -ruN vdr-1.7.14/tinyxml.h vdr-1.7.14.ExtP_NG/tinyxml.h --- vdr-1.7.14/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinyxml.h 2010-03-14 14:02:06.398975605 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxml.h 2010-04-10 15:45:11.801740955 +0200 @@ -0,0 +1,1372 @@ +#ifdef USE_SETUP +/* @@ -12589,7 +12628,7 @@ diff -ruN vdr-1.7.14/tinyxml.h vdr-1.7.14.ExtP_NG/tinyxml.h +#endif /* SETUP */ diff -ruN vdr-1.7.14/tinyxmlerror.c vdr-1.7.14.ExtP_NG/tinyxmlerror.c --- vdr-1.7.14/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinyxmlerror.c 2010-03-14 14:02:06.413972412 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxmlerror.c 2010-04-10 15:45:11.808773087 +0200 @@ -0,0 +1,53 @@ +#ifdef USE_SETUP +/* @@ -12646,7 +12685,7 @@ diff -ruN vdr-1.7.14/tinyxmlerror.c vdr-1.7.14.ExtP_NG/tinyxmlerror.c +#endif /* SETUP */ diff -ruN vdr-1.7.14/tinyxmlparser.c vdr-1.7.14.ExtP_NG/tinyxmlparser.c --- vdr-1.7.14/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/tinyxmlparser.c 2010-03-14 14:02:06.429972930 +0100 ++++ vdr-1.7.14.ExtP_NG/tinyxmlparser.c 2010-04-10 15:45:11.828740629 +0200 @@ -0,0 +1,1494 @@ +#ifdef USE_SETUP +/* @@ -14144,7 +14183,7 @@ diff -ruN vdr-1.7.14/tinyxmlparser.c vdr-1.7.14.ExtP_NG/tinyxmlparser.c +#endif /* SETUP */ diff -ruN vdr-1.7.14/vdr.c vdr-1.7.14.ExtP_NG/vdr.c --- vdr-1.7.14/vdr.c 2010-02-21 15:08:09.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/vdr.c 2010-03-14 14:02:06.592971751 +0100 ++++ vdr-1.7.14.ExtP_NG/vdr.c 2010-04-10 15:45:12.079739794 +0200 @@ -587,7 +587,12 @@ RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf")); SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); @@ -14252,7 +14291,7 @@ diff -ruN vdr-1.7.14/vdr.c vdr-1.7.14.ExtP_NG/vdr.c } diff -ruN vdr-1.7.14/vdrttxtsubshooks.c vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c --- vdr-1.7.14/vdrttxtsubshooks.c 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c 2010-03-14 14:02:06.599969246 +0100 ++++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c 2010-04-10 15:45:12.093736132 +0200 @@ -0,0 +1,62 @@ +/* + * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder @@ -14318,7 +14357,7 @@ diff -ruN vdr-1.7.14/vdrttxtsubshooks.c vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.c +} diff -ruN vdr-1.7.14/vdrttxtsubshooks.h vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h --- vdr-1.7.14/vdrttxtsubshooks.h 1970-01-01 01:00:00.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h 2010-03-14 14:02:06.613969643 +0100 ++++ vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h 2010-04-10 15:45:12.108759292 +0200 @@ -0,0 +1,46 @@ +/* + * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder @@ -14368,7 +14407,7 @@ diff -ruN vdr-1.7.14/vdrttxtsubshooks.h vdr-1.7.14.ExtP_NG/vdrttxtsubshooks.h +#endif diff -ruN vdr-1.7.14/videodir.c vdr-1.7.14.ExtP_NG/videodir.c --- vdr-1.7.14/videodir.c 2008-02-16 14:00:03.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/videodir.c 2010-03-14 14:02:06.627969737 +0100 ++++ vdr-1.7.14.ExtP_NG/videodir.c 2010-04-10 15:45:12.125736672 +0200 @@ -36,6 +36,11 @@ bool Next(void); void Store(void); @@ -14672,7 +14711,7 @@ diff -ruN vdr-1.7.14/videodir.c vdr-1.7.14.ExtP_NG/videodir.c cVideoDirectory Dir; diff -ruN vdr-1.7.14/videodir.h vdr-1.7.14.ExtP_NG/videodir.h --- vdr-1.7.14/videodir.h 2008-02-16 13:53:11.000000000 +0100 -+++ vdr-1.7.14.ExtP_NG/videodir.h 2010-03-14 14:02:06.636971442 +0100 ++++ vdr-1.7.14.ExtP_NG/videodir.h 2010-04-10 15:45:12.148736552 +0200 @@ -19,6 +19,9 @@ int CloseVideoFile(cUnbufferedFile *File); bool RenameVideoFile(const char *OldName, const char *NewName); |