summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
authorDimitar Petrovski <dimeptr@gmail.com>2012-11-30 13:53:29 +0100
committerDimitar Petrovski <dimeptr@gmail.com>2012-11-30 13:53:29 +0100
commitc0c90a946c0f5a6722f312e7156ba01c9e743d56 (patch)
treedc984296d4eda579f9632ee032bf1a62266bcc40 /util.c
parent16676f55d7aabc55a7b2894dbdf79a462749767f (diff)
parent250c584c8b52ca6fadc75acc1f8f9e6c2830c014 (diff)
downloadvdr-plugin-eepg-c0c90a946c0f5a6722f312e7156ba01c9e743d56.tar.gz
vdr-plugin-eepg-c0c90a946c0f5a6722f312e7156ba01c9e743d56.tar.bz2
Merge branch 'experimental'
Conflicts: eepg.c
Diffstat (limited to 'util.c')
-rw-r--r--util.c392
1 files changed, 392 insertions, 0 deletions
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..415f213
--- /dev/null
+++ b/util.c
@@ -0,0 +1,392 @@
+/*
+ * util.c
+ *
+ * Created on: 23.5.2012
+ * Author: d.petrovski
+ */
+#include "util.h"
+#include "log.h"
+#include "equivhandler.h"
+#include <vdr/channels.h>
+#include <vdr/thread.h>
+#include <vdr/epg.h>
+
+#include <map>
+
+namespace util
+{
+
+int AvailableSources[32];
+int NumberOfAvailableSources = 0;
+
+int Yesterday;
+int YesterdayEpoch;
+int YesterdayEpochUTC;
+
+struct hufftab *tables[2][128];
+int table_size[2][128];
+
+EFormat Format;
+cEquivHandler* EquivHandler;
+
+cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos)
+{
+ cChannel *VC = Channels.GetByChannelID(channelID, true);
+ if(!VC && searchOtherPos){
+ //look on other satpositions
+ for(int i = 0;i < NumberOfAvailableSources;i++){
+ channelID = tChannelID(AvailableSources[i], channelID.Nid(), channelID.Tid(), channelID.Sid());
+ VC = Channels.GetByChannelID(channelID, true);
+ if(VC){
+ //found this actually on satellite nextdoor...
+ break;
+ }
+ }
+ }
+
+ return VC;
+}
+
+/*
+ * Convert local time to UTC
+ */
+time_t LocalTime2UTC (time_t t)
+{
+ struct tm *temp;
+
+ temp = gmtime (&t);
+ temp->tm_isdst = -1;
+ return mktime (temp);
+}
+
+/*
+ * Convert UTC to local time
+ */
+time_t UTC2LocalTime (time_t t)
+{
+ return 2 * t - LocalTime2UTC (t);
+}
+
+void GetLocalTimeOffset (void)
+{
+ time_t timeLocal;
+ struct tm *tmCurrent;
+
+ timeLocal = time (NULL);
+ timeLocal -= 86400;
+ tmCurrent = gmtime (&timeLocal);
+ Yesterday = tmCurrent->tm_wday;
+ tmCurrent->tm_hour = 0;
+ tmCurrent->tm_min = 0;
+ tmCurrent->tm_sec = 0;
+ tmCurrent->tm_isdst = -1;
+ YesterdayEpoch = mktime (tmCurrent);
+ YesterdayEpochUTC = UTC2LocalTime (mktime (tmCurrent));
+}
+
+void CleanString (unsigned char *String)
+{
+
+// LogD (1, prep("Unclean: %s"), String);
+ unsigned char *Src;
+ unsigned char *Dst;
+ int Spaces;
+ int pC;
+ Src = String;
+ Dst = String;
+ Spaces = 0;
+ pC = 0;
+ while (*Src) {
+ // corrections
+ if (*Src == 0x8c) { // iso-8859-2 LATIN CAPITAL LETTER S WITH ACUTE
+ *Src = 0xa6;
+ }
+ if (*Src == 0x8f) { // iso-8859-2 LATIN CAPITAL LETTER Z WITH ACUTE
+ *Src = 0xac;
+ }
+
+ if (*Src!=0x0A && *Src < 0x20) { //don't remove newline
+ *Src = 0x20;
+ }
+ if (*Src == 0x20) {
+ Spaces++;
+ if (pC == 0) {
+ Spaces++;
+ }
+ } else {
+ Spaces = 0;
+ }
+ if (Spaces < 2) {
+ *Dst = *Src;
+ Dst++;
+ pC++;
+ }
+ Src++;
+ }
+ if (Spaces > 0 && String && String < Dst) {
+ Dst--;
+ *Dst = 0;
+ } else {
+ *Dst = 0;
+ }
+// LogD (1, prep("Clean: %s"), String);
+}
+
+struct tChannelIDCompare
+{
+ bool operator() (const tChannelID& lhs, const tChannelID& rhs) const
+ {
+ if (lhs.Source() < rhs.Source()) return true;
+ bool eq = lhs.Source() == rhs.Source();
+ if (eq && lhs.Nid() < rhs.Nid()) return true;
+ eq &= lhs.Nid() == rhs.Nid();
+ if (eq && lhs.Tid() < rhs.Tid()) return true;
+ eq &= lhs.Tid() == rhs.Tid();
+ if (eq && lhs.Sid() < rhs.Sid()) return true;
+ eq &= lhs.Sid() == rhs.Sid();
+ if (eq && lhs.Rid() < rhs.Rid()) return true;
+ return false;
+ }
+};
+
+cTimeMs LastAddEventThread;
+enum { INSERT_TIMEOUT_IN_MS = 10000 };
+
+class cAddEventThread : public cThread
+{
+private:
+ cTimeMs LastHandleEvent;
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare> *map_list;
+// enum { INSERT_TIMEOUT_IN_MS = 10000 };
+protected:
+ virtual void Action(void);
+public:
+ cAddEventThread(void);
+ ~cAddEventThread(void);
+ void AddEvent(cEvent *Event, tChannelID ChannelID);
+};
+
+cAddEventThread::cAddEventThread(void)
+:cThread("cAddEEPGEventThread"), LastHandleEvent()
+{
+ map_list = new std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>;
+}
+
+cAddEventThread::~cAddEventThread(void)
+{
+// LOCK_THREAD;
+ Cancel(3);
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it;
+ for ( it=map_list->begin() ; it != map_list->end(); it++ )
+ (*it).second->Clear();
+}
+
+void cAddEventThread::Action(void)
+{
+ //LogD (0, prep("Action"));
+ SetPriority(19);
+ while (Running() && !LastHandleEvent.TimedOut()) {
+ std::map<tChannelID, cList<cEvent>*, tChannelIDCompare>::iterator it;
+
+ cSchedulesLock SchedulesLock(true, 10);
+ cSchedules *schedules = (cSchedules *) cSchedules::Schedules(SchedulesLock);
+ Lock();
+
+ it = map_list->begin();
+ while (schedules && it != map_list->end()) {
+ cSchedule *schedule = (cSchedule *) schedules->GetSchedule(
+ Channels.GetByChannelID((*it).first), true);
+ while (((*it).second->First()) != NULL) {
+ cEvent* event = (*it).second->First();
+
+ cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime());
+ if (pEqvEvent){
+// LogD (0, prep("schedule->DelEvent(event) size:%d"), (*it).second->Count());
+ (*it).second->Del(event);
+// schedule->DelEvent(pEqvEvent);
+ } else {
+
+ (*it).second->Del(event, false);
+ EpgHandlers.DropOutdated(schedule, event->StartTime(), event->EndTime(), event->TableID(),
+ event->Version());
+ schedule->AddEvent(event);
+ }
+ }
+ EpgHandlers.SortSchedule(schedule);
+ //sortSchedules(schedules, (*it).first);
+ //schedule->Sort();
+ delete (*it).second;
+ map_list->erase(it);
+ it = map_list->begin();
+
+ }
+ Unlock();
+ cCondWait::SleepMs(10);
+ }
+}
+
+void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+ LOCK_THREAD;
+ if (map_list->count(ChannelID) == 0) {
+ cList<cEvent>* list = new cList<cEvent>;
+ list->Add(Event);
+ map_list->insert(std::make_pair(ChannelID, list));
+ } else {
+ map_list->find(ChannelID)->second->Add(Event);
+ }
+// LogD (0, prep("AddEventT %s channel: <%s> map size:%d"), Event->Title(), *ChannelID.ToString(), map_list->size());
+ LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS);
+}
+
+static cAddEventThread AddEventThread;
+
+// ---
+
+void AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+// LogD (0, prep("AddEvent %s channel: <%s>"), Event->Title(), *ChannelID.ToString());
+ AddEventThread.AddEvent(Event, ChannelID);
+// if (!AddEventThread.Active())
+// AddEventThread.Start();
+ if (!AddEventThread.Active() && LastAddEventThread.TimedOut()){
+ LastAddEventThread.Set(INSERT_TIMEOUT_IN_MS * 2);
+ AddEventThread.Start();
+ }
+
+}
+
+/** \brief Decode an EPG string as necessary
+ *
+ * \param src - Possibly encoded string
+ * \param size - Size of the buffer
+ *
+ * \retval NULL - Can't decode
+ * \return A decoded string
+ */
+char *freesat_huffman_decode (const unsigned char *src, size_t size)
+{
+ int tableid;
+
+ if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) {
+ int uncompressed_len = 30;
+ char *uncompressed = (char *) calloc (1, uncompressed_len + 1);
+ unsigned value = 0, byte = 2, bit = 0;
+ int p = 0;
+ unsigned char lastch = START;
+
+ tableid = src[1] - 1;
+ while (byte < 6 && byte < size) {
+ value |= src[byte] << ((5 - byte) * 8);
+ byte++;
+ }
+ //freesat_table_load (); /**< Load the tables as necessary */
+
+ do {
+ bool found = false;
+ unsigned bitShift = 0;
+ if (lastch == ESCAPE) {
+ char nextCh = (value >> 24) & 0xff;
+ found = true;
+ // Encoded in the next 8 bits.
+ // Terminated by the first ASCII character.
+ bitShift = 8;
+ if ((nextCh & 0x80) == 0)
+ lastch = nextCh;
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ } else {
+ int j;
+ for (j = 0; j < table_size[tableid][lastch]; j++) {
+ unsigned mask = 0, maskbit = 0x80000000;
+ short kk;
+ for (kk = 0; kk < tables[tableid][lastch][j].bits; kk++) {
+ mask |= maskbit;
+ maskbit >>= 1;
+ }
+ if ((value & mask) == tables[tableid][lastch][j].value) {
+ char nextCh = tables[tableid][lastch][j].next;
+ bitShift = tables[tableid][lastch][j].bits;
+ if (nextCh != STOP && nextCh != ESCAPE) {
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ }
+ found = true;
+ lastch = nextCh;
+ break;
+ }
+ }
+ }
+ if (found) {
+ // Shift up by the number of bits.
+ unsigned b;
+ for (b = 0; b < bitShift; b++) {
+ value = (value << 1) & 0xfffffffe;
+ if (byte < size)
+ value |= (src[byte] >> (7 - bit)) & 1;
+ if (bit == 7) {
+ bit = 0;
+ byte++;
+ } else
+ bit++;
+ }
+ } else {
+ LogE (0, prep("Missing table %d entry: <%s>"), tableid + 1, uncompressed);
+ // Entry missing in table.
+ return uncompressed;
+ }
+ } while (lastch != STOP && value != 0);
+
+ return uncompressed;
+ }
+ return NULL;
+}
+
+void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
+{
+ if (from[0] == 0x1f) {
+ char *temp = freesat_huffman_decode (from, len);
+ if (temp) {
+ len = strlen (temp);
+ len = len < buffsize - 1 ? len : buffsize - 1;
+ strncpy (buffer, temp, len);
+ buffer[len] = 0;
+ free (temp);
+ return;
+ }
+ }
+
+ SI::String convStr;
+ SI::CharArray charArray;
+ charArray.assign(from, len);
+ convStr.setData(charArray, len);
+ //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
+ convStr.getText(buffer, buffsize);
+ //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
+}
+
+void sortSchedules(cSchedules * Schedules, tChannelID channelID){
+
+ LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString());
+
+ cChannel *pChannel = GetChannelByID (channelID, false);
+ cSchedule *pSchedule;
+ if (pChannel) {
+ pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true));
+ pSchedule->Sort();
+ Schedules->SetModified(pSchedule);
+ }
+ if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0)
+ EquivHandler->sortEquivalents(channelID, Schedules);
+}
+
+}
+