X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/ddc3964ed95d01e72229dc9af968a327cd84e56c..ff00cc62b92da0226e4147cca49bbbb39d248e92:/lib/dvb/db.cpp diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index 1a2cd7df..25b0fb94 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -2,10 +2,11 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include DEFINE_REF(eDVBService); @@ -17,9 +18,89 @@ eDVBService::~eDVBService() { } +eDVBService &eDVBService::operator=(const eDVBService &s) +{ + m_service_name = s.m_service_name; + m_service_name_sort = s.m_service_name_sort; + m_provider_name = s.m_provider_name; + m_flags = s.m_flags; + m_ca = s.m_ca; + m_cache = s.m_cache; + return *this; +} + +RESULT eDVBService::getName(const eServiceReference &ref, std::string &name) +{ + if ( ref.name.length() ) + name = ref.name; + else + name = m_service_name; + return 0; +} + +int eDVBService::getLength(const eServiceReference &ref) +{ + return -1; +} + +int eDVBService::checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQuery &query) +{ + int res = 0; + switch (query.m_type) + { + case eDVBChannelQuery::tName: + res = m_service_name_sort.find(query.m_string) != std::string::npos; + break; + case eDVBChannelQuery::tProvider: + res = m_provider_name.find(query.m_string) != std::string::npos; + break; + case eDVBChannelQuery::tType: + res = ref.getServiceType() == query.m_int; + break; + case eDVBChannelQuery::tBouquet: + res = 0; + break; + case eDVBChannelQuery::tSatellitePosition: + res = (ref.getDVBNamespace().get() >> 16) == query.m_int; + break; + case eDVBChannelQuery::tChannelID: + { + eDVBChannelID chid; + ref.getChannelID(chid); + res = chid == query.m_channelid; + break; + } + case eDVBChannelQuery::tAND: + res = checkFilter(ref, *query.m_p1) && checkFilter(ref, *query.m_p2); + break; + case eDVBChannelQuery::tOR: + res = checkFilter(ref, *query.m_p1) || checkFilter(ref, *query.m_p2); + break; + } + + if (query.m_inverse) + return !res; + else + return res; +} + +int eDVBService::getCachePID(cacheID id) +{ + std::map::iterator it = m_cache.find(id); + if ( it != m_cache.end() ) + return it->second; + return -1; +} + +void eDVBService::setCachePID(cacheID id, int pid) +{ + m_cache[id] = pid; +} + DEFINE_REF(eDVBDB); -eDVBDB::eDVBDB() + /* THIS CODE IS BAD. it should be replaced by somethine better. */ +void eDVBDB::load() { eDebug("---- opening lame channel db"); FILE *f=fopen("lamedb", "rt"); @@ -39,7 +120,7 @@ eDVBDB::eDVBDB() fclose(f); return; } - + // clear all transponders while (!feof(f)) @@ -53,10 +134,10 @@ eDVBDB::eDVBDB() if (original_network_id == -1) continue; eDVBChannelID channelid = eDVBChannelID( - eDVBNamespace(dvb_namespace), - eTransportStreamID(transport_stream_id), + eDVBNamespace(dvb_namespace), + eTransportStreamID(transport_stream_id), eOriginalNetworkID(original_network_id)); - + ePtr feparm = new eDVBFrontendParameters; while (!feof(f)) { @@ -77,8 +158,23 @@ eDVBDB::eDVBDB() // ... // t.setSatellite(frequency, symbol_rate, polarisation, fec, sat, inversion); feparm->setDVBS(sat); - } - if (line[1]=='c') + } else if (line[1]=='t') + { + eDVBFrontendParametersTerrestrial ter; + int frequency, bandwidth, code_rate_HP, code_rate_LP, modulation, transmission_mode, guard_interval, hierarchy, inversion; + sscanf(line+2, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &bandwidth, &code_rate_HP, &code_rate_LP, &modulation, &transmission_mode, &guard_interval, &hierarchy, &inversion); + ter.frequency = frequency; + ter.bandwidth = bandwidth; + ter.code_rate_HP = code_rate_HP; + ter.code_rate_LP = code_rate_LP; + ter.modulation = modulation; + ter.transmission_mode = transmission_mode; + ter.guard_interval = guard_interval; + ter.hierarchy = hierarchy; + ter.inversion = inversion; + + feparm->setDVBT(ter); + } else if (line[1]=='c') { int frequency, symbol_rate, inversion=0, modulation=3; sscanf(line+2, "%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation); @@ -93,9 +189,9 @@ eDVBDB::eDVBDB() eDebug("services invalid, no services"); return; } - + // clear all services - + int count=0; while (!feof(f)) @@ -110,7 +206,7 @@ eDVBDB::eDVBDB() if (service_number == -1) continue; ePtr s = new eDVBService; - eServiceReferenceDVB ref = + eServiceReferenceDVB ref = eServiceReferenceDVB( eDVBNamespace(dvb_namespace), eTransportStreamID(transport_stream_id), @@ -121,7 +217,11 @@ eDVBDB::eDVBDB() fgets(line, 256, f); if (strlen(line)) line[strlen(line)-1]=0; - s->m_service_name=line; + + s->m_service_name = line; + s->m_service_name_sort = removeDVBChars(line); + makeUpper(s->m_service_name_sort); + fgets(line, 256, f); if (strlen(line)) line[strlen(line)-1]=0; @@ -168,18 +268,17 @@ eDVBDB::eDVBDB() } eDebug("loaded %d services", count); - + fclose(f); - } -eDVBDB::~eDVBDB() +void eDVBDB::save() { eDebug("---- saving lame channel db"); FILE *f=fopen("lamedb", "wt"); int channels=0, services=0; if (!f) - eFatal("couldn't save lame channel db!"); + eFatal("couldn't save lame channel db!"); fprintf(f, "eDVB services /3/\n"); fprintf(f, "transponders\n"); for (std::map::const_iterator i(m_channels.begin()); @@ -187,37 +286,53 @@ eDVBDB::~eDVBDB() { const eDVBChannelID &chid = i->first; const channel &ch = i->second; - + fprintf(f, "%08x:%04x:%04x\n", chid.dvbnamespace.get(), chid.transport_stream_id.get(), chid.original_network_id.get()); eDVBFrontendParametersSatellite sat; + eDVBFrontendParametersTerrestrial ter; if (!ch.m_frontendParameters->getDVBS(sat)) { - fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n", + fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n", sat.frequency, sat.symbol_rate, - sat.polarisation, sat.fec, sat.inversion, - sat.orbital_position); + sat.polarisation, sat.fec, sat.orbital_position, + sat.inversion); + } + if (!ch.m_frontendParameters->getDVBT(ter)) + { + fprintf(f, "\tt %d:%d:%d:%d:%d:%d:%d:%d:%d\n", + ter.frequency, ter.bandwidth, ter.code_rate_HP, + ter.code_rate_LP, ter.modulation, ter.transmission_mode, + ter.guard_interval, ter.hierarchy, ter.inversion); } fprintf(f, "/\n"); channels++; } fprintf(f, "end\nservices\n"); - + for (std::map >::iterator i(m_services.begin()); i != m_services.end(); ++i) { const eServiceReferenceDVB &s = i->first; - fprintf(f, "%04x:%08x:%04x:%04x:%d:%d\n", - s.getServiceID().get(), s.getDVBNamespace().get(), - s.getOriginalNetworkID().get(), s.getTransportStreamID().get(), + fprintf(f, "%04x:%08x:%04x:%04x:%d:%d\n", + s.getServiceID().get(), s.getDVBNamespace().get(), + s.getTransportStreamID().get(),s.getOriginalNetworkID().get(), s.getServiceType(), 0); - + fprintf(f, "%s\n", i->second->m_service_name.c_str()); - fprintf(f, "p=%s", i->second->m_provider_name.c_str()); + fprintf(f, "p:%s", i->second->m_provider_name.c_str()); + + // write cached pids + for (std::map::const_iterator ca(i->second->m_cache.begin()); + ca != i->second->m_cache.end(); ++ca) + fprintf(f, ",c:%02d%04x", ca->first, ca->second); + + // write cached ca pids for (std::set::const_iterator ca(i->second->m_ca.begin()); ca != i->second->m_ca.end(); ++ca) - fprintf(f, ",C=%04x", *ca); + fprintf(f, ",C:%04x", *ca); + fprintf(f, "\n"); services++; } @@ -226,6 +341,120 @@ eDVBDB::~eDVBDB() 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."); + 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::saveBouquet(const char *path) +{ + +} + +void eDVBDB::loadBouquets() +{ + loadBouquet("bouquets.tv"); + loadBouquet("bouquets.radio"); +} + +void eDVBDB::saveBouquets() +{ + +} + +eDVBDB::eDVBDB() +{ + load(); + loadBouquets(); +} + +eDVBDB::~eDVBDB() +{ +// save(); +} + RESULT eDVBDB::addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm) { channel ch; @@ -272,3 +501,385 @@ RESULT eDVBDB::getService(const eServiceReferenceDVB &reference, ePtr::iterator i = + m_bouquets.find(str); + if (i == m_bouquets.end()) + { + bouquet = 0; + return -ENOENT; + } + bouquet = &i->second; + return 0; +} + +RESULT eDVBDB::startQuery(ePtr &query, eDVBChannelQuery *q, const eServiceReference &source) +{ + if ( q && q->m_bouquet_name.length() ) + query = new eDVBDBBouquetQuery(this, source, q); + else + query = new eDVBDBQuery(this, source, q); + return 0; +} + +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; + + int sortmode = m_query ? m_query->m_sort : eDVBChannelQuery::tName; + + if ((sortmode == eDVBChannelQuery::tName) || (sortmode == eDVBChannelQuery::tProvider)) + { + if (m_db->getService(a, a_service)) + return 1; + if (m_db->getService(b, b_service)) + return 1; + } + + switch (sortmode) + { + case eDVBChannelQuery::tName: + return a_service->m_service_name_sort < b_service->m_service_name_sort; + case eDVBChannelQuery::tProvider: + return a_service->m_provider_name < b_service->m_provider_name; + case eDVBChannelQuery::tType: + return a.getServiceType() < b.getServiceType(); + case eDVBChannelQuery::tBouquet: + return 0; + case eDVBChannelQuery::tSatellitePosition: + return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16); + default: + return 1; + } + 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 = eServiceReferenceDVB(); + 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 = eServiceReferenceDVB(); + + return 1; +} + +/* ( <==|...> <"string"|int>)[||,&& (..)] */ + +static int decodeType(const std::string &type) +{ + if (type == "name") + return eDVBChannelQuery::tName; + else if (type == "provider") + return eDVBChannelQuery::tProvider; + else if (type == "type") + return eDVBChannelQuery::tType; + else if (type == "bouquet") + return eDVBChannelQuery::tBouquet; + else if (type == "satellitePosition") + return eDVBChannelQuery::tSatellitePosition; + else if (type == "channelID") + return eDVBChannelQuery::tChannelID; + else + return -1; +} + + /* never, NEVER write a parser in C++! */ +RESULT parseExpression(ePtr &res, std::list::const_iterator begin, std::list::const_iterator end) +{ + std::list::const_iterator end_of_exp; + if (*begin == "(") + { + end_of_exp = begin; + while (end_of_exp != end) + if (*end_of_exp == ")") + break; + else + ++end_of_exp; + + if (end_of_exp == end) + { + eDebug("expression parse: end of expression while searching for closing brace"); + return -1; + } + + ++begin; + // begin..end_of_exp + int r = parseExpression(res, begin, end_of_exp); + if (r) + return r; + ++end_of_exp; + + /* we had only one sub expression */ + if (end_of_exp == end) + { +// eDebug("only one sub expression"); + return 0; + } + + /* otherwise we have an operator here.. */ + + ePtr r2 = res; + res = new eDVBChannelQuery(); + res->m_sort = 0; + res->m_p1 = r2; + res->m_inverse = 0; + r2 = 0; + + if (*end_of_exp == "||") + res->m_type = eDVBChannelQuery::tOR; + else if (*end_of_exp == "&&") + res->m_type = eDVBChannelQuery::tAND; + else + { + eDebug("found operator %s, but only && and || are allowed!", end_of_exp->c_str()); + res = 0; + return 1; + } + + ++end_of_exp; + + return parseExpression(res->m_p2, end_of_exp, end); + } + + // "begin" "end" + std::string type, op, val; + + res = new eDVBChannelQuery(); + res->m_sort = 0; + + int cnt = 0; + while (begin != end) + { + switch (cnt) + { + case 0: + type = *begin; + break; + case 1: + op = *begin; + break; + case 2: + val = *begin; + break; + case 3: + eDebug("malformed query: got '%s', but expected only ", begin->c_str()); + return 1; + } + ++begin; + ++cnt; + } + + if (cnt != 3) + { + eDebug("malformed query: missing stuff"); + res = 0; + return 1; + } + + res->m_type = decodeType(type); + + if (res->m_type == -1) + { + eDebug("malformed query: invalid type %s", type.c_str()); + res = 0; + return 1; + } + + if (op == "==") + res->m_inverse = 0; + else if (op == "!=") + res->m_inverse = 1; + else + { + eDebug("invalid operator %s", op.c_str()); + res = 0; + return 1; + } + + res->m_string = val; + res->m_int = atoi(val.c_str()); +// res->m_channelid = eDVBChannelID(val); + + return 0; +} + +RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) +{ + std::list tokens; + + std::string current_token; + std::string bouquet_name; + +// eDebug("splitting %s....", query.c_str()); + unsigned int i = 0; + const char *splitchars="()"; + int quotemode = 0, lastsplit = 0, lastalnum = 0; + while (i <= query.size()) + { + int c = (i < query.size()) ? query[i] : ' '; + ++i; + + int issplit = !!strchr(splitchars, c); + int isaln = isalnum(c); + int iswhite = c == ' '; + int isquot = c == '\"'; + + if (quotemode) + { + iswhite = issplit = 0; + isaln = lastalnum; + } + + if (issplit || iswhite || isquot || lastsplit || (lastalnum != isaln)) + { + if (current_token.size()) + tokens.push_back(current_token); + current_token.clear(); + } + + if (!(iswhite || isquot)) + current_token += c; + + if (isquot) + quotemode = !quotemode; + lastsplit = issplit; + lastalnum = isaln; + } + +// for (std::list::const_iterator a(tokens.begin()); a != tokens.end(); ++a) +// { +// printf("%s\n", a->c_str()); +// } + + int sort = eDVBChannelQuery::tName; + /* check for "ORDER BY ..." */ + + while (tokens.size() > 2) + { + std::list::iterator it = tokens.end(); + --it; --it; --it; + if (*it == "ORDER") + { + ++it; + if (*it == "BY") + { + ++it; + sort = decodeType(*it); + tokens.pop_back(); // ... + tokens.pop_back(); // BY + tokens.pop_back(); // ORDER + } else + sort = -1; + } + else if (*it == "FROM") + { + ++it; + if (*it == "BOUQUET") + { + ++it; + bouquet_name = *it; + tokens.pop_back(); // ... + tokens.pop_back(); // FROM + tokens.pop_back(); // BOUQUET + } + } + else + break; + } + + if (sort == -1) + { + eWarning("ORDER BY .. string invalid."); + res = 0; + return -1; + } + +// 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); + return r; +} + +DEFINE_REF(eDVBChannelQuery);