+ if ( i == eit->section_number )
+ {
+ for (int x=i; x <= eit->segment_last_section_number; ++x)
+ calcedSections.insert(tmpval|(x&0xFF));
+ }
+ else
+ calcedSections.insert(tmpval|(i&0xFF));
+ }
+ cache->sectionRead(data, source, this);
+ }
+ }
+}
+
+RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
+// if t == -1 we search the current event...
+{
+ singleLock s(cache_lock);
+ uniqueEPGKey key(handleGroup(service));
+
+ // check if EPG for this service is ready...
+ eventCache::iterator It = eventDB.find( key );
+ if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
+ {
+ if (t==-1)
+ t = ::time(0);
+ timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) : // find > or equal
+ It->second.second.upper_bound(t); // just >
+ if ( i != It->second.second.end() )
+ {
+ if ( direction < 0 || (direction == 0 && i->first > t) )
+ {
+ timeMap::iterator x = i;
+ --x;
+ if ( x != It->second.second.end() )
+ {
+ time_t start_time = x->first;
+ if (direction >= 0)
+ {
+ if (t < start_time)
+ return -1;
+ if (t > (start_time+x->second->getDuration()))
+ return -1;
+ }
+ i = x;
+ }
+ else
+ return -1;
+ }
+ result = i->second;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result, int direction)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventTime(service, t, data, direction);
+ if ( !ret && data )
+ result = data->get();
+ return ret;
+}
+
+RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventTime(service, t, data, direction);
+ if ( !ret && data )
+ result = new Event((uint8_t*)data->get());
+ return ret;
+}
+
+RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result, int direction)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventTime(service, t, data, direction);
+ if ( !ret && data )
+ {
+ Event ev((uint8_t*)data->get());
+ result = new eServiceEvent();
+ const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
+ ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
+ }
+ return ret;
+}
+
+RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
+{
+ singleLock s(cache_lock);
+ uniqueEPGKey key(handleGroup(service));
+
+ eventCache::iterator It = eventDB.find( key );
+ if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
+ {
+ eventMap::iterator i( It->second.first.find( event_id ));
+ if ( i != It->second.first.end() )
+ {
+ result = i->second;
+ return 0;
+ }
+ else
+ {
+ result = 0;
+ eDebug("[EPGC] event %04x not found in epgcache", event_id);
+ }
+ }
+ return -1;
+}
+
+RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventId(service, event_id, data);
+ if ( !ret && data )
+ result = data->get();
+ return ret;
+}
+
+RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventId(service, event_id, data);
+ if ( !ret && data )
+ result = new Event((uint8_t*)data->get());
+ return ret;
+}
+
+RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
+{
+ singleLock s(cache_lock);
+ const eventData *data=0;
+ RESULT ret = lookupEventId(service, event_id, data);
+ if ( !ret && data )
+ {
+ Event ev((uint8_t*)data->get());
+ result = new eServiceEvent();
+ const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
+ ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
+ }
+ return ret;
+}
+
+RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
+{
+ singleLock s(cache_lock);
+ const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
+ if (begin == -1)
+ begin = ::time(0);
+ eventCache::iterator It = eventDB.find(ref);
+ if ( It != eventDB.end() && It->second.second.size() )
+ {
+ m_timemap_cursor = It->second.second.lower_bound(begin);
+ if ( m_timemap_cursor != It->second.second.end() )
+ {
+ if ( m_timemap_cursor->first != begin )
+ {
+ timeMap::iterator x = m_timemap_cursor;
+ --x;
+ if ( x != It->second.second.end() )
+ {
+ time_t start_time = x->first;
+ if ( begin > start_time && begin < (start_time+x->second->getDuration()))
+ m_timemap_cursor = x;
+ }
+ }
+ }
+
+ if (minutes != -1)
+ m_timemap_end = It->second.second.lower_bound(begin+minutes*60);
+ else
+ m_timemap_end = It->second.second.end();
+
+ currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
+ return m_timemap_cursor == m_timemap_end ? -1 : 0;
+ }
+ return -1;
+}
+
+RESULT eEPGCache::getNextTimeEntry(const eventData *& result)
+{
+ if ( m_timemap_cursor != m_timemap_end )
+ {
+ result = m_timemap_cursor++->second;
+ return 0;
+ }
+ return -1;
+}
+
+RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result)
+{
+ if ( m_timemap_cursor != m_timemap_end )
+ {
+ result = m_timemap_cursor++->second->get();
+ return 0;
+ }
+ return -1;
+}
+
+RESULT eEPGCache::getNextTimeEntry(Event *&result)
+{
+ if ( m_timemap_cursor != m_timemap_end )
+ {
+ result = new Event((uint8_t*)m_timemap_cursor++->second->get());
+ return 0;
+ }
+ return -1;
+}
+
+RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
+{
+ if ( m_timemap_cursor != m_timemap_end )
+ {
+ Event ev((uint8_t*)m_timemap_cursor++->second->get());
+ result = new eServiceEvent();
+ return result->parseFrom(&ev, currentQueryTsidOnid);
+ }
+ return -1;
+}
+
+void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name )
+{
+ ePyObject tmp;
+ int spos=0, tpos=0;
+ char c;
+ while(spos < argcount)
+ {
+ bool inc_refcount=false;
+ switch((c=argstring[spos++]))
+ {
+ case '0': // PyLong 0
+ tmp = PyLong_FromLong(0);
+ break;
+ case 'I': // Event Id
+ tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject();
+ break;
+ case 'B': // Event Begin Time
+ tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject();
+ break;
+ case 'D': // Event Duration
+ tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject();
+ break;
+ case 'T': // Event Title
+ tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
+ break;
+ case 'S': // Event Short Description
+ tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject();
+ break;
+ case 'E': // Event Extended Description
+ tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
+ break;
+ case 'C': // Current Time
+ tmp = nowTime;
+ inc_refcount = true;
+ break;
+ case 'R': // service reference string
+ tmp = service;
+ inc_refcount = true;
+ break;
+ case 'n': // short service name
+ case 'N': // service name
+ tmp = service_name;
+ inc_refcount = true;
+ break;
+ case 'X':
+ ++argcount;
+ continue;
+ default: // ignore unknown
+ eDebug("fillTuple unknown '%c'... insert 'None' in result", c);
+ }
+ if (!tmp)
+ {
+ tmp = Py_None;
+ inc_refcount = true;
+ }
+ if (inc_refcount)
+ Py_INCREF(tmp);
+ PyTuple_SET_ITEM(tuple, tpos++, tmp);
+ }
+}
+
+int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs)
+{
+ if (convertFunc)
+ {
+ fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name);
+ ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
+ if (!result)
+ {
+ if (service_name)
+ Py_DECREF(service_name);
+ if (nowTime)
+ Py_DECREF(nowTime);
+ Py_DECREF(convertFuncArgs);
+ Py_DECREF(dest_list);
+ PyErr_SetString(PyExc_StandardError,
+ "error in convertFunc execute");
+ eDebug("error in convertFunc execute");
+ return -1;
+ }
+ PyList_Append(dest_list, result);
+ Py_DECREF(result);
+ }
+ else
+ {
+ ePyObject tuple = PyTuple_New(argcount);
+ fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name);
+ PyList_Append(dest_list, tuple);
+ Py_DECREF(tuple);
+ }
+ return 0;
+}
+
+// here we get a python list
+// the first entry in the list is a python string to specify the format of the returned tuples (in a list)
+// 0 = PyLong(0)
+// I = Event Id
+// B = Event Begin Time
+// D = Event Duration
+// T = Event Title
+// S = Event Short Description
+// E = Event Extended Description
+// C = Current Time
+// R = Service Reference
+// N = Service Name
+// n = Short Service Name
+// X = Return a minimum of one tuple per service in the result list... even when no event was found.
+// The returned tuple is filled with all available infos... non avail is filled as None
+// The position and existence of 'X' in the format string has no influence on the result tuple... its completely ignored..
+// then for each service follows a tuple
+// first tuple entry is the servicereference (as string... use the ref.toString() function)
+// the second is the type of query
+// 2 = event_id
+// -1 = event before given start_time
+// 0 = event intersects given start_time
+// +1 = event after given start_time
+// the third
+// when type is eventid it is the event_id
+// when type is time then it is the start_time ( -1 for now_time )
+// the fourth is the end_time .. ( optional .. for query all events in time range)
+
+PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
+{
+ ePyObject convertFuncArgs;
+ int argcount=0;
+ const char *argstring=NULL;
+ if (!PyList_Check(list))
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("no list");
+ return NULL;
+ }
+ int listIt=0;
+ int listSize=PyList_Size(list);
+ if (!listSize)
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "not params given");
+ eDebug("not params given");
+ return NULL;
+ }
+ else
+ {
+ ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference!
+ if (PyString_Check(argv))
+ {
+ argstring = PyString_AS_STRING(argv);
+ ++listIt;
+ }
+ else
+ argstring = "I"; // just event id as default
+ argcount = strlen(argstring);
+// eDebug("have %d args('%s')", argcount, argstring);
+ }
+
+ bool forceReturnOne = strchr(argstring, 'X') ? true : false;
+ if (forceReturnOne)
+ --argcount;
+
+ if (convertFunc)
+ {
+ if (!PyCallable_Check(convertFunc))
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "convertFunc must be callable");
+ eDebug("convertFunc is not callable");
+ return NULL;
+ }
+ convertFuncArgs = PyTuple_New(argcount);
+ }
+
+ ePyObject nowTime = strchr(argstring, 'C') ?
+ PyLong_FromLong(::time(0)) :
+ ePyObject();
+
+ int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
+
+ // create dest list
+ ePyObject dest_list=PyList_New(0);
+ while(listSize > listIt)
+ {
+ ePyObject item=PyList_GET_ITEM(list, listIt++); // borrowed reference!
+ if (PyTuple_Check(item))
+ {
+ bool service_changed=false;
+ int type=0;
+ long event_id=-1;
+ time_t stime=-1;
+ int minutes=0;
+ int tupleSize=PyTuple_Size(item);
+ int tupleIt=0;
+ ePyObject service;
+ while(tupleSize > tupleIt) // parse query args
+ {
+ ePyObject entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference!
+ switch(tupleIt++)
+ {
+ case 0:
+ {
+ if (!PyString_Check(entry))
+ {
+ eDebug("tuple entry 0 is no a string");
+ goto skip_entry;
+ }
+ service = entry;
+ break;
+ }
+ case 1:
+ type=PyInt_AsLong(entry);
+ if (type < -1 || type > 2)
+ {
+ eDebug("unknown type %d", type);
+ goto skip_entry;
+ }
+ break;
+ case 2:
+ event_id=stime=PyInt_AsLong(entry);
+ break;
+ case 3:
+ minutes=PyInt_AsLong(entry);
+ break;
+ default:
+ eDebug("unneeded extra argument");
+ break;
+ }
+ }
+
+ if (minutes && stime == -1)
+ stime = ::time(0);
+
+ eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
+ if (ref.type != eServiceReference::idDVB)
+ {
+ eDebug("service reference for epg query is not valid");
+ continue;
+ }
+
+ // redirect subservice querys to parent service
+ eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
+ if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
+ {
+ eServiceCenterPtr service_center;
+ if (!eServiceCenter::getPrivInstance(service_center))
+ {
+ dvb_ref.setTransportStreamID( dvb_ref.getParentTransportStreamID() );
+ dvb_ref.setServiceID( dvb_ref.getParentServiceID() );
+ dvb_ref.setParentTransportStreamID(eTransportStreamID(0));
+ dvb_ref.setParentServiceID(eServiceID(0));
+ dvb_ref.name="";
+ service = PyString_FromString(dvb_ref.toString().c_str());
+ service_changed = true;
+ }
+ }
+
+ ePyObject service_name;
+ if (must_get_service_name)
+ {
+ ePtr<iStaticServiceInformation> sptr;
+ eServiceCenterPtr service_center;
+ eServiceCenter::getPrivInstance(service_center);
+ if (service_center)
+ {
+ service_center->info(ref, sptr);
+ if (sptr)
+ {
+ std::string name;
+ sptr->getName(ref, name);
+
+ if (must_get_service_name == 1)
+ {
+ size_t pos;
+ // filter short name brakets
+ while((pos = name.find("\xc2\x86")) != std::string::npos)
+ name.erase(pos,2);
+ while((pos = name.find("\xc2\x87")) != std::string::npos)
+ name.erase(pos,2);
+ }
+ else
+ name = buildShortName(name);
+
+ if (name.length())
+ service_name = PyString_FromString(name.c_str());
+ }
+ }
+ if (!service_name)
+ service_name = PyString_FromString("<n/a>");
+ }
+ if (minutes)
+ {
+ singleLock s(cache_lock);
+ if (!startTimeQuery(ref, stime, minutes))
+ {
+ while ( m_timemap_cursor != m_timemap_end )
+ {
+ Event ev((uint8_t*)m_timemap_cursor++->second->get());
+ eServiceEvent evt;
+ evt.parseFrom(&ev, currentQueryTsidOnid);
+ if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+ return 0; // error
+ }
+ }
+ else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+ return 0; // error
+ }
+ else
+ {
+ eServiceEvent evt;
+ const eventData *ev_data=0;
+ if (stime)
+ {
+ singleLock s(cache_lock);
+ if (type == 2)
+ lookupEventId(ref, event_id, ev_data);
+ else
+ lookupEventTime(ref, stime, ev_data, type);
+ if (ev_data)
+ {
+ const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
+ Event ev((uint8_t*)ev_data->get());
+ evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+ }
+ }
+ if (ev_data)
+ {
+ if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+ return 0; // error
+ }
+ else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+ return 0; // error
+ }
+ if (service_changed)
+ Py_DECREF(service);
+ if (service_name)
+ Py_DECREF(service_name);
+ }
+skip_entry:
+ ;
+ }
+ if (convertFuncArgs)
+ Py_DECREF(convertFuncArgs);
+ if (nowTime)
+ Py_DECREF(nowTime);
+ return dest_list;
+}
+
+void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, eServiceEvent *ptr, ePyObject service_name, ePyObject service_reference)
+{
+ ePyObject tmp;
+ int pos=0;
+ while(pos < argcount)
+ {
+ bool inc_refcount=false;
+ switch(argstring[pos])
+ {
+ case '0': // PyLong 0
+ tmp = PyLong_FromLong(0);
+ break;
+ case 'I': // Event Id
+ tmp = PyLong_FromLong(evData->getEventID());
+ break;
+ case 'B': // Event Begin Time
+ if (ptr)
+ tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject();
+ else
+ tmp = PyLong_FromLong(evData->getStartTime());
+ break;
+ case 'D': // Event Duration
+ if (ptr)
+ tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject();
+ else
+ tmp = PyLong_FromLong(evData->getDuration());
+ break;
+ case 'T': // Event Title
+ tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
+ break;
+ case 'S': // Event Short Description
+ tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject();
+ break;
+ case 'E': // Event Extended Description
+ tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
+ break;
+ case 'R': // service reference string
+ tmp = service_reference;
+ inc_refcount = true;
+ break;
+ case 'n': // short service name
+ case 'N': // service name
+ tmp = service_name;
+ inc_refcount = true;
+ break;
+ default: // ignore unknown
+ eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]);
+ }
+ if (!tmp)
+ {
+ tmp = Py_None;
+ inc_refcount = true;
+ }
+ if (inc_refcount)
+ Py_INCREF(tmp);
+ PyTuple_SET_ITEM(tuple, pos++, tmp);
+ }
+}
+
+// here we get a python tuple
+// the first entry in the tuple is a python string to specify the format of the returned tuples (in a list)
+// I = Event Id
+// B = Event Begin Time
+// D = Event Duration
+// T = Event Title
+// S = Event Short Description
+// E = Event Extended Description
+// R = Service Reference
+// N = Service Name
+// n = Short Service Name
+// the second tuple entry is the MAX matches value
+// the third tuple entry is the type of query
+// 0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
+// 1 = search events with exactly title name (EXAKT_TITLE_SEARCH)
+// 2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
+// when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
+// the fourth is the servicereference string
+// the fifth is the eventid
+// when type is 1 or 2 (EXAKT_TITLE_SEARCH or PARTIAL_TITLE_SEARCH)
+// the fourth is the search text
+// the fifth is
+// 0 = case sensitive (CASE_CHECK)
+// 1 = case insensitive (NO_CASECHECK)
+
+PyObject *eEPGCache::search(ePyObject arg)
+{
+ ePyObject ret;
+ int descridx = -1;
+ __u32 descr[512];
+ int eventid = -1;
+ const char *argstring=0;
+ char *refstr=0;
+ int argcount=0;
+ int querytype=-1;
+ bool needServiceEvent=false;
+ int maxmatches=0;
+ int must_get_service_name = 0;
+ bool must_get_service_reference = false;
+
+ if (PyTuple_Check(arg))
+ {
+ int tuplesize=PyTuple_Size(arg);
+ if (tuplesize > 0)
+ {
+ ePyObject obj = PyTuple_GET_ITEM(arg,0);
+ if (PyString_Check(obj))
+ {
+#if PY_VERSION_HEX < 0x02060000
+ argcount = PyString_GET_SIZE(obj);
+#else
+ argcount = PyString_Size(obj);
+#endif
+ argstring = PyString_AS_STRING(obj);
+ for (int i=0; i < argcount; ++i)
+ switch(argstring[i])
+ {
+ case 'S':
+ case 'E':
+ case 'T':
+ needServiceEvent=true;
+ break;
+ case 'N':
+ must_get_service_name = 1;
+ break;
+ case 'n':
+ must_get_service_name = 2;
+ break;
+ case 'R':
+ must_get_service_reference = true;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("tuple arg 0 is not a string");
+ return NULL;
+ }
+ }
+ if (tuplesize > 1)
+ maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
+ if (tuplesize > 2)
+ {
+ querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
+ if (tuplesize > 4 && querytype == 0)
+ {
+ ePyObject obj = PyTuple_GET_ITEM(arg, 3);
+ if (PyString_Check(obj))
+ {
+ refstr = PyString_AS_STRING(obj);
+ eServiceReferenceDVB ref(refstr);
+ if (ref.valid())
+ {
+ eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
+ singleLock s(cache_lock);
+ const eventData *evData = 0;
+ lookupEventId(ref, eventid, evData);
+ if (evData)
+ {
+ __u8 *data = evData->EITdata;
+ int tmp = evData->ByteSize-10;
+ __u32 *p = (__u32*)(data+10);
+ // search short and extended event descriptors
+ while(tmp>3)
+ {
+ __u32 crc = *p++;
+ descriptorMap::iterator it =
+ eventData::descriptors.find(crc);
+ if (it != eventData::descriptors.end())
+ {
+ __u8 *descr_data = it->second.second;
+ switch(descr_data[0])
+ {
+ case 0x4D ... 0x4E:
+ descr[++descridx]=crc;
+ default:
+ break;
+ }
+ }
+ tmp-=4;
+ }
+ }
+ if (descridx<0)
+ eDebug("event not found");
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError, "type error");
+ eDebug("tuple arg 4 is not a valid service reference string");
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError, "type error");
+ eDebug("tuple arg 4 is not a string");
+ return NULL;
+ }
+ }
+ else if (tuplesize > 4 && (querytype == 1 || querytype == 2) )
+ {
+ ePyObject obj = PyTuple_GET_ITEM(arg, 3);
+ if (PyString_Check(obj))
+ {
+ int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
+ const char *str = PyString_AS_STRING(obj);
+#if PY_VERSION_HEX < 0x02060000
+ int textlen = PyString_GET_SIZE(obj);
+#else
+ int textlen = PyString_Size(obj);
+#endif
+ if (querytype == 1)
+ eDebug("lookup for events with '%s' as title(%s)", str, casetype?"ignore case":"case sensitive");
+ else
+ eDebug("lookup for events with '%s' in title(%s)", str, casetype?"ignore case":"case sensitive");
+ singleLock s(cache_lock);
+ for (descriptorMap::iterator it(eventData::descriptors.begin());
+ it != eventData::descriptors.end() && descridx < 511; ++it)
+ {
+ __u8 *data = it->second.second;
+ if ( data[0] == 0x4D ) // short event descriptor
+ {
+ int title_len = data[5];
+ if ( querytype == 1 )
+ {
+ int offs = 6;
+ // skip DVB-Text Encoding!
+ if (data[6] == 0x10)
+ {
+ offs+=3;
+ title_len-=3;
+ }
+ else if(data[6] > 0 && data[6] < 0x20)
+ {
+ offs+=1;
+ title_len-=1;
+ }
+ if (title_len != textlen)
+ continue;
+ if ( casetype )
+ {
+ if ( !strncasecmp((const char*)data+offs, str, title_len) )
+ {
+// std::string s((const char*)data+offs, title_len);
+// eDebug("match1 %s %s", str, s.c_str() );
+ descr[++descridx] = it->first;
+ }
+ }
+ else if ( !strncmp((const char*)data+offs, str, title_len) )
+ {
+// std::string s((const char*)data+offs, title_len);
+// eDebug("match2 %s %s", str, s.c_str() );
+ descr[++descridx] = it->first;
+ }
+ }
+ else
+ {
+ int idx=0;
+ while((title_len-idx) >= textlen)
+ {
+ if (casetype)
+ {
+ if (!strncasecmp((const char*)data+6+idx, str, textlen) )
+ {
+ descr[++descridx] = it->first;
+// std::string s((const char*)data+6, title_len);
+// eDebug("match 3 %s %s", str, s.c_str() );
+ break;
+ }
+ }
+ else if (!strncmp((const char*)data+6+idx, str, textlen) )
+ {
+ descr[++descridx] = it->first;
+// std::string s((const char*)data+6, title_len);
+// eDebug("match 4 %s %s", str, s.c_str() );
+ break;
+ }
+ ++idx;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("tuple arg 4 is not a string");
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype);
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("not enough args in tuple");
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_StandardError,
+ "type error");
+ eDebug("arg 0 is not a tuple");
+ return NULL;
+ }
+
+ if (descridx > -1)
+ {
+ int maxcount=maxmatches;
+ eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
+ // ref is only valid in SIMILAR_BROADCASTING_SEARCH
+ // in this case we start searching with the base service
+ bool first = ref.valid() ? true : false;
+ singleLock s(cache_lock);
+ eventCache::iterator cit(ref.valid() ? eventDB.find(ref) : eventDB.begin());
+ while(cit != eventDB.end() && maxcount)
+ {
+ if ( ref.valid() && !first && cit->first == ref )
+ {
+ // do not scan base service twice ( only in SIMILAR BROADCASTING SEARCH )
+ ++cit;
+ continue;
+ }
+ ePyObject service_name;
+ ePyObject service_reference;
+ timeMap &evmap = cit->second.second;
+ // check all events
+ for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
+ {
+ int evid = evit->second->getEventID();
+ if ( evid == eventid)
+ continue;
+ __u8 *data = evit->second->EITdata;
+ int tmp = evit->second->ByteSize-10;
+ __u32 *p = (__u32*)(data+10);
+ // check if any of our descriptor used by this event
+ int cnt=-1;
+ while(tmp>3)
+ {
+ __u32 crc32 = *p++;
+ for ( int i=0; i <= descridx; ++i)
+ {
+ if (descr[i] == crc32) // found...
+ ++cnt;
+ }
+ tmp-=4;
+ }
+ if ( (querytype == 0 && cnt == descridx) ||
+ ((querytype == 1 || querytype == 2) && cnt != -1) )
+ {
+ const uniqueEPGKey &service = cit->first;
+ eServiceReference ref =
+ eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid);
+ if (ref.valid())
+ {
+ // create servive event
+ eServiceEvent ptr;
+ const eventData *ev_data=0;
+ if (needServiceEvent)
+ {
+ if (lookupEventId(ref, evid, ev_data))
+ eDebug("event not found !!!!!!!!!!!");
+ else
+ {
+ const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
+ Event ev((uint8_t*)ev_data->get());
+ ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+ }
+ }
+ // create service name
+ if (must_get_service_name && !service_name)
+ {
+ ePtr<iStaticServiceInformation> sptr;
+ eServiceCenterPtr service_center;
+ eServiceCenter::getPrivInstance(service_center);
+ if (service_center)
+ {
+ service_center->info(ref, sptr);
+ if (sptr)
+ {
+ std::string name;
+ sptr->getName(ref, name);
+
+ if (must_get_service_name == 1)
+ {
+ size_t pos;
+ // filter short name brakets
+ while((pos = name.find("\xc2\x86")) != std::string::npos)
+ name.erase(pos,2);
+ while((pos = name.find("\xc2\x87")) != std::string::npos)
+ name.erase(pos,2);
+ }
+ else
+ name = buildShortName(name);
+
+ if (name.length())
+ service_name = PyString_FromString(name.c_str());
+ }
+ }
+ if (!service_name)
+ service_name = PyString_FromString("<n/a>");
+ }
+ // create servicereference string
+ if (must_get_service_reference && !service_reference)
+ service_reference = PyString_FromString(ref.toString().c_str());
+ // create list
+ if (!ret)
+ ret = PyList_New(0);
+ // create tuple
+ ePyObject tuple = PyTuple_New(argcount);
+ // fill tuple
+ fillTuple2(tuple, argstring, argcount, evit->second, ev_data ? &ptr : 0, service_name, service_reference);
+ PyList_Append(ret, tuple);
+ Py_DECREF(tuple);
+ --maxcount;
+ }
+ }
+ }
+ if (service_name)
+ Py_DECREF(service_name);
+ if (service_reference)
+ Py_DECREF(service_reference);
+ if (first)
+ {
+ // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
+ first=false;
+ cit=eventDB.begin();
+ }
+ else
+ ++cit;
+ }
+ }
+
+ if (!ret)
+ Py_RETURN_NONE;
+
+ return ret;
+}
+
+#ifdef ENABLE_PRIVATE_EPG
+#include <dvbsi++/descriptor_tag.h>
+#include <dvbsi++/unknown_descriptor.h>
+#include <dvbsi++/private_data_specifier_descriptor.h>
+
+void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
+{
+ ePtr<eTable<ProgramMapSection> > ptr;
+ if (!pmthandler->getPMT(ptr) && ptr)
+ {
+ std::vector<ProgramMapSection*>::const_iterator i;
+ for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
+ {
+ const ProgramMapSection &pmt = **i;
+
+ ElementaryStreamInfoConstIterator es;
+ for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
+ {
+ int tmp=0;
+ switch ((*es)->getType())
+ {
+ case 0x05: // private
+ for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
+ desc != (*es)->getDescriptors()->end(); ++desc)
+ {
+ switch ((*desc)->getTag())
+ {
+ case PRIVATE_DATA_SPECIFIER_DESCRIPTOR:
+ if (((PrivateDataSpecifierDescriptor*)(*desc))->getPrivateDataSpecifier() == 190)
+ tmp |= 1;
+ break;
+ case 0x90:
+ {
+ UnknownDescriptor *descr = (UnknownDescriptor*)*desc;
+ int descr_len = descr->getLength();
+ if (descr_len == 4)
+ {
+ uint8_t data[descr_len+2];
+ descr->writeToBuffer(data);
+ if ( !data[2] && !data[3] && data[4] == 0xFF && data[5] == 0xFF )
+ tmp |= 2;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ default: