X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/ebd60cac96b17be4c6fb0c64c7c43b4ef715c3e3..36940d42cf3cc58b40a5a6f5fe86bad50ff48ad7:/lib/dvb/db.cpp diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index a5a9a456..658c5866 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -10,6 +12,101 @@ DEFINE_REF(eDVBService); +RESULT eBouquet::addService(const eServiceReference &ref) +{ + list::iterator it = + std::find(m_services.begin(), m_services.end(), ref); + if ( it != m_services.end() ) + return -1; + m_services.push_back(ref); + return 0; +} + +RESULT eBouquet::removeService(const eServiceReference &ref) +{ + list::iterator it = + std::find(m_services.begin(), m_services.end(), ref); + if ( it == m_services.end() ) + return -1; + m_services.erase(it); + return 0; +} + +RESULT eBouquet::moveService(const eServiceReference &ref, unsigned int pos) +{ + if ( pos < 0 || pos >= m_services.size() ) + return -1; + ++pos; + list::iterator source=m_services.end(); + list::iterator dest=m_services.end(); + bool forward = false; + for (list::iterator it(m_services.begin()); it != m_services.end(); ++it) + { + if (dest == m_services.end() && !--pos) + dest = it; + if (*it == ref) + { + source = it; + forward = pos>0; + } + if (dest != m_services.end() && source != m_services.end()) + break; + } + if (dest == m_services.end() || source == m_services.end() || source == dest) + return -1; + while (source != dest) + { + if (forward) + std::iter_swap(source++, source); + else + std::iter_swap(source--, source); + } + return 0; +} + +RESULT eBouquet::flushChanges() +{ + FILE *f=fopen(m_path.c_str(), "wt"); + if (!f) + return -1; + if ( fprintf(f, "#NAME %s\r\n", m_bouquet_name.c_str()) < 0 ) + goto err; + for (list::iterator i(m_services.begin()); i != m_services.end(); ++i) + { + eServiceReference tmp = *i; + std::string str = tmp.path; + if ( (i->flags&eServiceReference::flagDirectory) == eServiceReference::flagDirectory ) + { + unsigned int p1 = str.find("FROM BOUQUET \""); + if (p1 == std::string::npos) + { + eDebug("doof... kaputt"); + continue; + } + str.erase(0, p1+14); + p1 = str.find("\""); + if (p1 == std::string::npos) + { + eDebug("doof2... kaputt"); + continue; + } + str.erase(p1); + tmp.path=str; + } + if ( fprintf(f, "#SERVICE %s\r\n", tmp.toString().c_str()) < 0 ) + goto err; + if ( i->name.length() ) + if ( fprintf(f, "#DESCRIPTION %s\r\n", i->name.c_str()) < 0 ) + goto err; + } + fclose(f); + return 0; +err: + fclose(f); + eDebug("couldn't write file %s", m_path.c_str()); + return -1; +} + eDVBService::eDVBService() { } @@ -29,15 +126,48 @@ eDVBService &eDVBService::operator=(const eDVBService &s) return *this; } +void eDVBService::genSortName() +{ + m_service_name_sort = removeDVBChars(m_service_name); + makeUpper(m_service_name_sort); + while ((!m_service_name_sort.empty()) && m_service_name_sort[0] == ' ') + m_service_name_sort.erase(0, 1); + + /* put unnamed services at the end, not at the beginning. */ + if (m_service_name_sort.empty()) + m_service_name_sort = "\xFF"; +} + RESULT eDVBService::getName(const eServiceReference &ref, std::string &name) { - name = m_service_name; + if (!ref.name.empty()) + name = ref.name; // use renamed service name.. + else if (!m_service_name.empty()) + name = m_service_name; + else + name = "(...)"; return 0; } -int eDVBService::getLength(const eServiceReference &ref) +RESULT eDVBService::getEvent(const eServiceReference &ref, ePtr &ptr) { - return -1; + time_t t=-1; + return eEPGCache::getInstance()->lookupEventTime(ref, t, ptr); +} + +bool eDVBService::isPlayable(const eServiceReference &ref, const eServiceReference &ignore) +{ + ePtr res_mgr; + if ( eDVBResourceManager::getInstance( res_mgr ) ) + eDebug("isPlayble... no res manager!!"); + else + { + eDVBChannelID chid, chid_ignore; + ((const eServiceReferenceDVB&)ref).getChannelID(chid); + ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore); + return res_mgr->canAllocateChannel(chid, chid_ignore); + } + return false; } int eDVBService::checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQuery &query) @@ -152,8 +282,6 @@ void eDVBDB::load() sat.fec = fec; sat.orbital_position = orbital_position; sat.inversion = inversion; - // ... -// t.setSatellite(frequency, symbol_rate, polarisation, fec, sat, inversion); feparm->setDVBS(sat); } else if (line[1]=='t') { @@ -216,9 +344,8 @@ void eDVBDB::load() line[strlen(line)-1]=0; s->m_service_name = line; - s->m_service_name_sort = removeDVBChars(line); - makeUpper(s->m_service_name_sort); - + s->genSortName(); + fgets(line, 256, f); if (strlen(line)) line[strlen(line)-1]=0; @@ -338,9 +465,148 @@ void eDVBDB::save() fclose(f); } +void eDVBDB::loadBouquet(const char *path) +{ + std::string bouquet_name = path; + if (!bouquet_name.length()) + { + eDebug("Bouquet load failed.. no path given.."); + return; + } + unsigned int pos = bouquet_name.rfind('/'); + if ( pos != std::string::npos ) + bouquet_name.erase(0, pos+1); + if (bouquet_name.empty()) + { + eDebug("Bouquet load failed.. no filename given.."); + return; + } + eBouquet &bouquet = m_bouquets[bouquet_name]; + bouquet.m_path = path; + std::list &list = bouquet.m_services; + list.clear(); + + eDebug("loading bouquet... %s", path); + FILE *fp=fopen(path, "rt"); + int entries=0; + if (!fp) + { + eDebug("failed to open."); + if ( strstr(path, "bouquets.tv") ) + { + eDebug("recreate bouquets.tv"); + bouquet.m_bouquet_name="Bouquets (TV)"; + bouquet.flushChanges(); + } + else if ( strstr(path, "bouquets.radio") ) + { + eDebug("recreate bouquets.radio"); + bouquet.m_bouquet_name="Bouquets (Radio)"; + bouquet.flushChanges(); + } + return; + } + char line[256]; + bool read_descr=false; + eServiceReference *e = NULL; + while (1) + { + if (!fgets(line, 256, fp)) + break; + line[strlen(line)-1]=0; + if (strlen(line) && line[strlen(line)-1]=='\r') + line[strlen(line)-1]=0; + if (!line[0]) + break; + if (line[0]=='#') + { + if (!strncmp(line, "#SERVICE ", 9) || !strncmp(line, "#SERVICE: ", 10)) + { + int offs = line[8] == ':' ? 10 : 9; + eServiceReference tmp(line+offs); + if (tmp.type != eServiceReference::idDVB) + { + eDebug("only DVB Bouquets supported"); + continue; + } + if ( (tmp.flags&eServiceReference::flagDirectory) == eServiceReference::flagDirectory ) + { + std::string str = tmp.path; + unsigned int pos = str.rfind('/'); + if ( pos != std::string::npos ) + str.erase(0, pos+1); + if (str.empty()) + { + eDebug("Bouquet load failed.. no filename given.."); + continue; + } + loadBouquet(tmp.path.c_str()); + char buf[256]; + snprintf(buf, 256, "(type == %d) FROM BOUQUET \"%s\" ORDER BY bouquet", tmp.data[0], str.c_str()); + tmp.path = buf; + } + list.push_back(tmp); + e = &list.back(); + read_descr=true; + ++entries; + } + else if (read_descr && !strncmp(line, "#DESCRIPTION ", 13)) + { + e->name = line+13; + read_descr=false; + } + else if (!strncmp(line, "#NAME ", 6)) + bouquet.m_bouquet_name=line+6; + continue; + } + } + fclose(fp); + eDebug("%d entries in Bouquet %s", entries, bouquet_name.c_str()); +} + +void eDVBDB::loadBouquets() +{ + loadBouquet("bouquets.tv"); + loadBouquet("bouquets.radio"); +// create default bouquets when missing + if ( m_bouquets.find("userbouquet.favourites.tv") == m_bouquets.end() ) + { + eBouquet &b = m_bouquets["userbouquet.favourites.tv"]; + b.m_path = "userbouquet.favourites.tv"; + b.m_bouquet_name = "Favourites (TV)"; + b.flushChanges(); + eServiceReference ref; + memset(ref.data, 0, sizeof(ref.data)); + ref.type=1; + ref.flags=7; + ref.data[0]=1; + ref.path="(type == 1) FROM BOUQUET \"userbouquet.favourites.tv\" ORDER BY bouquet"; + eBouquet &parent = m_bouquets["bouquets.tv"]; + parent.m_services.push_back(ref); + parent.flushChanges(); + } + if ( m_bouquets.find("userbouquet.favourites.radio") == m_bouquets.end() ) + { + eBouquet &b = m_bouquets["userbouquet.favourites.radio"]; + b.m_path = "userbouquet.favourites.radio"; + b.m_bouquet_name = "Favourites (Radio)"; + b.flushChanges(); + eServiceReference ref; + memset(ref.data, 0, sizeof(ref.data)); + ref.type=1; + ref.flags=7; + ref.data[0]=1; + ref.path="(type == 2) FROM BOUQUET \"userbouquet.favourites.radio\" ORDER BY bouquet"; + eBouquet &parent = m_bouquets["bouquets.radio"]; + parent.m_services.push_back(ref); + parent.flushChanges(); + } +} + eDVBDB::eDVBDB() { load(); + loadBouquets(); } eDVBDB::~eDVBDB() @@ -394,39 +660,72 @@ RESULT eDVBDB::getService(const eServiceReferenceDVB &reference, ePtr &query, eDVBChannelQuery *q) +RESULT eDVBDB::flush() { - query = new eDVBDBQuery(this, eServiceReference(), q); + save(); return 0; } -DEFINE_REF(eDVBDBQuery); - -eDVBDBQuery::eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query): m_db(db), m_query(query) +RESULT eDVBDB::getBouquet(const eServiceReference &ref, eBouquet* &bouquet) { - // TODO: use SOURCE ... - m_cursor = m_db->m_services.begin(); + std::string str = ref.path; + if (str.empty()) + { + eDebug("getBouquet failed.. no path given!"); + return -1; + } + unsigned int pos = str.find("FROM BOUQUET \""); + if ( pos != std::string::npos ) + { + str.erase(0, pos+14); + pos = str.find('"'); + if ( pos != std::string::npos ) + str.erase(pos); + else + str.clear(); + } + if (str.empty()) + { + eDebug("getBouquet failed.. couldn't parse bouquet name"); + return -1; + } + std::map::iterator i = + m_bouquets.find(str); + if (i == m_bouquets.end()) + { + bouquet = 0; + return -ENOENT; + } + bouquet = &i->second; + return 0; } -RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref) +RESULT eDVBDB::startQuery(ePtr &query, eDVBChannelQuery *q, const eServiceReference &source) { - while (m_cursor != m_db->m_services.end()) + if ( source.path.find("FROM") != std::string::npos ) { - ref = m_cursor->first; - - int res = (!m_query) || m_cursor->second->checkFilter(ref, *m_query); - - ++m_cursor; - - if (res) - return 0; + if ( source.path.find("BOUQUET") != std::string::npos ) + query = new eDVBDBBouquetQuery(this, source, q); + else if ( source.path.find("SATELLITES") != std::string::npos ) + query = new eDVBDBSatellitesQuery(this, source, q); + else if ( source.path.find("PROVIDERS") != std::string::npos ) + query = new eDVBDBProvidersQuery(this, source, q); + else + eFatal("invalid query %s", source.toString().c_str()); } - - ref = eServiceReferenceDVB(); - return 1; + else + query = new eDVBDBQuery(this, source, q); + return 0; } -int eDVBDBQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b) +DEFINE_REF(eDVBDBQueryBase); + +eDVBDBQueryBase::eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :m_db(db), m_query(query), m_source(source) +{ +} + +int eDVBDBQueryBase::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b) { ePtr a_service, b_service; @@ -449,7 +748,7 @@ int eDVBDBQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceR case eDVBChannelQuery::tType: return a.getServiceType() < b.getServiceType(); case eDVBChannelQuery::tBouquet: - return 1; + return 0; case eDVBChannelQuery::tSatellitePosition: return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16); default: @@ -458,6 +757,172 @@ int eDVBDBQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceR return 0; } +eDVBDBQuery::eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBQueryBase(db, source, query) +{ + m_cursor = m_db->m_services.begin(); +} + +RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref) +{ + while (m_cursor != m_db->m_services.end()) + { + ref = m_cursor->first; + + int res = (!m_query) || m_cursor->second->checkFilter(ref, *m_query); + + ++m_cursor; + + if (res) + return 0; + } + + ref.type = eServiceReference::idInvalid; + + return 1; +} + +eDVBDBBouquetQuery::eDVBDBBouquetQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBQueryBase(db, source, query), m_cursor(db->m_bouquets[query->m_bouquet_name].m_services.begin()) +{ +} + +RESULT eDVBDBBouquetQuery::getNextResult(eServiceReferenceDVB &ref) +{ + eBouquet &bouquet = m_db->m_bouquets[m_query->m_bouquet_name]; + std::list &list = bouquet.m_services; + while (m_cursor != list.end()) + { + ref = *((eServiceReferenceDVB*)&(*m_cursor)); + + std::map >::iterator it = + m_db->m_services.find(ref); + + int res = (!m_query) || it == m_db->m_services.end() || it->second->checkFilter(ref, *m_query); + + ++m_cursor; + + if (res) + return 0; + } + + ref.type = eServiceReference::idInvalid; + + return 1; +} + +eDVBDBListQuery::eDVBDBListQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBQueryBase(db, source, query), m_cursor(m_list.end()) +{ +} + +RESULT eDVBDBListQuery::getNextResult(eServiceReferenceDVB &ref) +{ + if (m_cursor != m_list.end()) + { + ref = *m_cursor++; + return 0; + } + ref.type = eServiceReference::idInvalid; + return 1; +} + +int eDVBDBListQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b) +{ + if ( m_query->m_sort == eDVBChannelQuery::tSatellitePosition ) + return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16); + return a.name < b.name; +} + +eDVBDBSatellitesQuery::eDVBDBSatellitesQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBListQuery(db, source, query) +{ + for (std::map >::iterator it(m_db->m_services.begin()); + it != m_db->m_services.end(); ++it) + { + int res = it->second->checkFilter(it->first, *query); + if (res) + { + unsigned int dvbnamespace = it->first.getDVBNamespace().get()&0xFFFF0000; + bool found=0; + for (std::list::iterator i(m_list.begin()); i != m_list.end(); ++i) + if ( (i->getDVBNamespace().get()&0xFFFF0000) == dvbnamespace ) + { + found=true; + break; + } + if (!found) + { + eServiceReferenceDVB ref; + ref.setDVBNamespace(dvbnamespace); + char buf[64]; +// TODO get real satellite name.. +// but i dont like to parse the satellites.xml here.. and in the python part + snprintf(buf, 64, "Services - %d", dvbnamespace>>16); + ref.name=buf; + snprintf(buf, 64, "(satellitePosition == %d) && ", dvbnamespace>>16); + ref.path=buf+source.path; + unsigned int pos=ref.path.find("FROM"); + ref.flags=eServiceReference::flagDirectory; + ref.path.erase(pos); + ref.path+="ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + m_list.push_back(ref); + + ref.path=buf+source.path; + pos=ref.path.find("FROM"); + ref.path.erase(pos+5); + ref.path+="PROVIDERS ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + snprintf(buf, 64, "Providers - %d", dvbnamespace>>16); + ref.name=buf; + m_list.push_back(ref); + } + } + } + m_cursor=m_list.begin(); +} + +eDVBDBProvidersQuery::eDVBDBProvidersQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBListQuery(db, source, query) +{ + for (std::map >::iterator it(m_db->m_services.begin()); + it != m_db->m_services.end(); ++it) + { + int res = it->second->checkFilter(it->first, *query); + if (res) + { + bool found=0; + + const char *provider_name = it->second->m_provider_name.length() ? + it->second->m_provider_name.c_str() : + "Unknown"; + + for (std::list::iterator i(m_list.begin()); i != m_list.end(); ++i) + if (i->name == provider_name) + { + found=true; + break; + } + if (!found) + { + eServiceReferenceDVB ref; + char buf[64]; + ref.name=provider_name; + snprintf(buf, 64, "(provider == \"%s\") && ", provider_name); + ref.path=buf+source.path; + unsigned int pos = ref.path.find("FROM"); + ref.flags=eServiceReference::flagDirectory; + ref.path.erase(pos); + ref.path+="ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + m_list.push_back(ref); + } + } + } + m_cursor=m_list.begin(); +} + /* ( <==|...> <"string"|int>)[||,&& (..)] */ static int decodeType(const std::string &type) @@ -507,7 +972,7 @@ RESULT parseExpression(ePtr &res, std::list::cons /* we had only one sub expression */ if (end_of_exp == end) { - eDebug("only one sub expression"); +// eDebug("only one sub expression"); return 0; } @@ -603,8 +1068,9 @@ RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) std::list tokens; std::string current_token; - - eDebug("splitting %s....", query.c_str()); + std::string bouquet_name; + +// eDebug("splitting %s....", query.c_str()); unsigned int i = 0; const char *splitchars="()"; int quotemode = 0, lastsplit = 0, lastalnum = 0; @@ -647,41 +1113,63 @@ RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) int sort = eDVBChannelQuery::tName; /* check for "ORDER BY ..." */ - if (tokens.size() > 2) + + std::list::iterator it = tokens.begin(); + while (it != tokens.end()) { - std::list::iterator i = tokens.end(); - --i; --i; --i; - if (*i == "ORDER") + if (*it == "ORDER") { - ++i; - if (*i == "BY") + tokens.erase(it++); + if (it != tokens.end() && *it == "BY") { - ++i; - sort = decodeType(*i); - tokens.pop_back(); // ... - tokens.pop_back(); // BY - tokens.pop_back(); // ORDER + tokens.erase(it++); + sort = decodeType(*it); + tokens.erase(it++); } else sort = -1; } + else if (*it == "FROM") + { + tokens.erase(it++); + if (it != tokens.end() && *it == "BOUQUET") + { + tokens.erase(it++); + bouquet_name = *it; + tokens.erase(it++); + } + else if (it != tokens.end() && *it == "SATELLITES") + tokens.erase(it++); + else if (it != tokens.end() && *it == "PROVIDERS") + tokens.erase(it++); + else + { + eDebug("FROM unknown %s", (*it).c_str()); + tokens.erase(it++); + } + } + else + ++it; } - + if (sort == -1) - { + { eWarning("ORDER BY .. string invalid."); res = 0; return -1; } - eDebug("sort by %d", sort); +// eDebug("sort by %d", sort); /* now we recursivly parse that. */ int r = parseExpression(res, tokens.begin(), tokens.end()); if (res) + { res->m_sort = sort; + res->m_bouquet_name = bouquet_name; + } - eDebug("return: %d", r); +// eDebug("return: %d", r); return r; }