add pid cache
[enigma2.git] / lib / dvb / db.cpp
1 #include <errno.h>
2 #include <lib/dvb/db.h>
3 #include <lib/dvb/frontend.h>
4 #include <lib/base/eerror.h>
5 #include <lib/dvb_si/sdt.h>
6 #include <lib/dvb_si/descriptor_tag.h>
7 #include <lib/dvb_si/service_descriptor.h>
8 #include <lib/dvb_si/satellite_delivery_system_descriptor.h>
9
10 DEFINE_REF(eDVBService);
11
12 eDVBService::eDVBService()
13 {
14 }
15
16 eDVBService::~eDVBService()
17 {
18 }
19
20 eDVBService &eDVBService::operator=(const eDVBService &s)
21 {
22         m_service_name = s.m_service_name;
23         m_provider_name = s.m_provider_name;
24         m_flags = s.m_flags;
25         m_ca = s.m_ca;
26         m_cache = s.m_cache;
27         return *this;
28 }
29
30 RESULT eDVBService::getName(const eServiceReference &ref, std::string &name)
31 {
32         name = m_service_name;
33         return 0;
34 }
35
36 int eDVBService::checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQuery &query)
37 {
38         int res = 0;
39         switch (query.m_type)
40         {
41         case eDVBChannelQuery::tName:
42                 res = m_service_name.find(query.m_string) != std::string::npos;
43                 break;
44         case eDVBChannelQuery::tProvider:
45                 res = m_provider_name.find(query.m_string) != std::string::npos;
46                 break;
47         case eDVBChannelQuery::tType:
48                 res = ref.getServiceType() == query.m_int;
49                 break;
50         case eDVBChannelQuery::tBouquet:
51                 res = 0;
52                 break;
53         case eDVBChannelQuery::tSatellitePosition:
54                 res = (ref.getDVBNamespace().get() >> 16) == query.m_int;
55                 break;
56         case eDVBChannelQuery::tChannelID:
57         {
58                 eDVBChannelID chid;
59                 ref.getChannelID(chid);
60                 res = chid == query.m_channelid;
61                 break;
62         }
63         case eDVBChannelQuery::tAND:
64                 res = checkFilter(ref, *query.m_p1) && checkFilter(ref, *query.m_p2);
65                 break;
66         case eDVBChannelQuery::tOR:
67                 res = checkFilter(ref, *query.m_p1) || checkFilter(ref, *query.m_p2);
68                 break;
69         }
70
71         if (query.m_inverse)
72                 return !res;
73         else
74                 return res;
75 }
76
77 int eDVBService::getCachePID(cacheID id)
78 {
79         std::map<int, int>::iterator it = m_cache.find(id);
80         if ( it != m_cache.end() )
81                 return it->second;
82         return -1;
83 }
84
85 void eDVBService::setCachePID(cacheID id, int pid)
86 {
87         m_cache[id] = pid;
88 }
89
90 DEFINE_REF(eDVBDB);
91
92 eDVBDB::eDVBDB()
93 {
94         eDebug("---- opening lame channel db");
95         FILE *f=fopen("lamedb", "rt");
96         if (!f)
97                 return;
98         char line[256];
99         if ((!fgets(line, 256, f)) || strncmp(line, "eDVB services", 13))
100         {
101                 eDebug("not a servicefile");
102                 fclose(f);
103                 return;
104         }
105         eDebug("reading services");
106         if ((!fgets(line, 256, f)) || strcmp(line, "transponders\n"))
107         {
108                 eDebug("services invalid, no transponders");
109                 fclose(f);
110                 return;
111         }
112         
113         // clear all transponders
114
115         while (!feof(f))
116         {
117                 if (!fgets(line, 256, f))
118                         break;
119                 if (!strcmp(line, "end\n"))
120                         break;
121                 int dvb_namespace=-1, transport_stream_id=-1, original_network_id=-1;
122                 sscanf(line, "%x:%x:%x", &dvb_namespace, &transport_stream_id, &original_network_id);
123                 if (original_network_id == -1)
124                         continue;
125                 eDVBChannelID channelid = eDVBChannelID(
126                         eDVBNamespace(dvb_namespace), 
127                         eTransportStreamID(transport_stream_id), 
128                         eOriginalNetworkID(original_network_id));
129                 
130                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
131                 while (!feof(f))
132                 {
133                         fgets(line, 256, f);
134                         if (!strcmp(line, "/\n"))
135                                 break;
136                         if (line[1]=='s')
137                         {
138                                 eDVBFrontendParametersSatellite sat;
139                                 int frequency, symbol_rate, polarisation, fec, orbital_position, inversion;
140                                 sscanf(line+2, "%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &inversion, &orbital_position);
141                                 sat.frequency = frequency;
142                                 sat.symbol_rate = symbol_rate;
143                                 sat.polarisation = polarisation;
144                                 sat.fec = fec;
145                                 sat.orbital_position = orbital_position;
146                                 sat.inversion = inversion;
147                                 // ...
148 //                              t.setSatellite(frequency, symbol_rate, polarisation, fec, sat, inversion);
149                                 feparm->setDVBS(sat);
150                         }
151                         if (line[1]=='c')
152                         {
153                                 int frequency, symbol_rate, inversion=0, modulation=3;
154                                 sscanf(line+2, "%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation);
155 //                              t.setCable(frequency, symbol_rate, inversion, modulation);
156                         }
157                 }
158                 addChannelToList(channelid, feparm);
159         }
160
161         if ((!fgets(line, 256, f)) || strcmp(line, "services\n"))
162         {
163                 eDebug("services invalid, no services");
164                 return;
165         }
166         
167         // clear all services
168         
169         int count=0;
170
171         while (!feof(f))
172         {
173                 if (!fgets(line, 256, f))
174                         break;
175                 if (!strcmp(line, "end\n"))
176                         break;
177
178                 int service_id=-1, dvb_namespace, transport_stream_id=-1, original_network_id=-1, service_type=-1, service_number=-1;
179                 sscanf(line, "%x:%x:%x:%x:%d:%d", &service_id, &dvb_namespace, &transport_stream_id, &original_network_id, &service_type, &service_number);
180                 if (service_number == -1)
181                         continue;
182                 ePtr<eDVBService> s = new eDVBService;
183                 eServiceReferenceDVB ref = 
184                                                 eServiceReferenceDVB(
185                                                 eDVBNamespace(dvb_namespace),
186                                                 eTransportStreamID(transport_stream_id),
187                                                 eOriginalNetworkID(original_network_id),
188                                                 eServiceID(service_id),
189                                                 service_type);
190                 count++;
191                 fgets(line, 256, f);
192                 if (strlen(line))
193                         line[strlen(line)-1]=0;
194                 s->m_service_name=line;
195                 fgets(line, 256, f);
196                 if (strlen(line))
197                         line[strlen(line)-1]=0;
198
199                 std::string str=line;
200
201                 if (str[1]!=':')        // old ... (only service_provider)
202                 {
203                         s->m_provider_name=line;
204                 } else
205                         while ((!str.empty()) && str[1]==':') // new: p:, f:, c:%02d...
206                         {
207                                 unsigned int c=str.find(',');
208                                 char p=str[0];
209                                 std::string v;
210                                 if (c == std::string::npos)
211                                 {
212                                         v=str.substr(2);
213                                         str="";
214                                 } else
215                                 {
216                                         v=str.substr(2, c-2);
217                                         str=str.substr(c+1);
218                                 }
219 //                              eDebug("%c ... %s", p, v.c_str());
220                                 if (p == 'p')
221                                         s->m_provider_name=v;
222                                 else if (p == 'f')
223                                 {
224                                         sscanf(v.c_str(), "%x", &s->m_flags);
225                                 } else if (p == 'c')
226                                 {
227                                         int cid, val;
228                                         sscanf(v.c_str(), "%02d%04x", &cid, &val);
229                                         s->m_cache[cid]=val;
230                                 } else if (p == 'C')
231                                 {
232                                         int val;
233                                         sscanf(v.c_str(), "%04x", &val);
234                                         s->m_ca.insert(val);
235                                 }
236                         }
237                 addService(ref, s);
238         }
239
240         eDebug("loaded %d services", count);
241         
242         fclose(f);
243         
244 }
245
246 eDVBDB::~eDVBDB()
247 {
248         eDebug("---- saving lame channel db");
249         FILE *f=fopen("lamedb", "wt");
250         int channels=0, services=0;
251         if (!f)
252                 eFatal("couldn't save lame channel db!"); 
253         fprintf(f, "eDVB services /3/\n");
254         fprintf(f, "transponders\n");
255         for (std::map<eDVBChannelID, channel>::const_iterator i(m_channels.begin());
256                         i != m_channels.end(); ++i)
257         {
258                 const eDVBChannelID &chid = i->first;
259                 const channel &ch = i->second;
260                 
261                 fprintf(f, "%08x:%04x:%04x\n", chid.dvbnamespace.get(),
262                                 chid.transport_stream_id.get(), chid.original_network_id.get());
263                 eDVBFrontendParametersSatellite sat;
264                 if (!ch.m_frontendParameters->getDVBS(sat))
265                 {
266                         fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n", 
267                                 sat.frequency, sat.symbol_rate,
268                                 sat.polarisation, sat.fec, sat.inversion,
269                                 sat.orbital_position);
270                 }
271                 fprintf(f, "/\n");
272                 channels++;
273         }
274         fprintf(f, "end\nservices\n");
275         
276         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i(m_services.begin());
277                 i != m_services.end(); ++i)
278         {
279                 const eServiceReferenceDVB &s = i->first;
280                 fprintf(f, "%04x:%08x:%04x:%04x:%d:%d\n", 
281                                 s.getServiceID().get(), s.getDVBNamespace().get(), 
282                                 s.getTransportStreamID().get(),s.getOriginalNetworkID().get(), 
283                                 s.getServiceType(),
284                                 0);
285                 
286                 fprintf(f, "%s\n", i->second->m_service_name.c_str());
287                 fprintf(f, "p:%s", i->second->m_provider_name.c_str());
288                 for (std::set<int>::const_iterator ca(i->second->m_ca.begin());
289                         ca != i->second->m_ca.end(); ++ca)
290                         fprintf(f, ",C:%04x", *ca);
291                 fprintf(f, "\n");
292                 services++;
293         }
294         fprintf(f, "end\nHave a lot of bugs!\n");
295         eDebug("saved %d channels and %d services!", channels, services);
296         fclose(f);
297 }
298
299 RESULT eDVBDB::addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm)
300 {
301         channel ch;
302         assert(feparm);
303         ch.m_frontendParameters = feparm;
304         m_channels.insert(std::pair<eDVBChannelID, channel>(id, ch));
305         return 0;
306 }
307
308 RESULT eDVBDB::removeChannel(const eDVBChannelID &id)
309 {
310         m_channels.erase(id);
311         return 0;
312 }
313
314 RESULT eDVBDB::getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm)
315 {
316         std::map<eDVBChannelID, channel>::iterator i = m_channels.find(id);
317         if (i == m_channels.end())
318         {
319                 parm = 0;
320                 return -ENOENT;
321         }
322         parm = i->second.m_frontendParameters;
323         return 0;
324 }
325
326 RESULT eDVBDB::addService(const eServiceReferenceDVB &serviceref, eDVBService *service)
327 {
328         m_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(serviceref, service));
329         return 0;
330 }
331
332 RESULT eDVBDB::getService(const eServiceReferenceDVB &reference, ePtr<eDVBService> &service)
333 {
334         std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i;
335         i = m_services.find(reference);
336         if (i == m_services.end())
337         {
338                 service = 0;
339                 return -ENOENT;
340         }
341         service = i->second;
342         return 0;
343 }
344
345 RESULT eDVBDB::startQuery(ePtr<iDVBChannelListQuery> &query, eDVBChannelQuery *q)
346 {
347         query = new eDVBDBQuery(this, eServiceReference(), q);
348         return 0;
349 }
350
351 DEFINE_REF(eDVBDBQuery);
352
353 eDVBDBQuery::eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query): m_db(db), m_query(query)
354 {
355                 // TODO: use SOURCE ...
356         m_cursor = m_db->m_services.begin();
357 }
358
359 RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref)
360 {
361         while (m_cursor != m_db->m_services.end())
362         {
363                 ref = m_cursor->first;
364                 
365                 int res = (!m_query) || m_cursor->second->checkFilter(ref, *m_query);
366
367                 ++m_cursor;
368                 
369                 if (res)
370                         return 0;
371         }
372         return 1;
373 }
374
375 /* (<name|provider|type|bouquet|satpos|chid> <==|...> <"string"|int>)[AND (..)] */
376
377         /* never, NEVER write a parser in C++! */
378 RESULT parseExpression(ePtr<eDVBChannelQuery> &res, std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
379 {
380         std::list<std::string>::const_iterator end_of_exp;
381         if (*begin == "(")
382         {
383                 end_of_exp = begin;
384                 while (end_of_exp != end)
385                         if (*end_of_exp == ")")
386                                 break;
387                         else
388                                 ++end_of_exp;
389         
390                 if (end_of_exp == end)
391                 {
392                         eDebug("expression parse: end of expression while searching for closing brace");
393                         return -1;
394                 }
395                 
396                 ++begin;
397                 // begin..end_of_exp
398                 int r = parseExpression(res, begin, end_of_exp);
399                 if (r)
400                         return r;
401                 ++end_of_exp;
402                 
403                         /* we had only one sub expression */
404                 if (end_of_exp == end)
405                         return 1;
406                 
407                         /* otherwise we have an operator here.. */
408                 
409                 ePtr<eDVBChannelQuery> r2 = res;
410                 res = new eDVBChannelQuery();
411                 res->m_p1 = r2;
412                 res->m_inverse = 0;
413                 r2 = 0;
414                 
415                 if (*end_of_exp == "||")
416                         res->m_type = eDVBChannelQuery::tOR;
417                 else if (*end_of_exp == "&&")
418                         res->m_type = eDVBChannelQuery::tAND;
419                 else
420                 {
421                         eDebug("found operator %s, but only && and || are allowed!", end_of_exp->c_str());
422                         res = 0;
423                         return 1;
424                 }
425                 
426                 ++end_of_exp;
427                 
428                 return parseExpression(res->m_p2, end_of_exp, end);
429         }
430         
431         // "begin" <op> "end"
432         std::string type, op, val;
433         
434         res = new eDVBChannelQuery();
435         
436         int cnt = 0;
437         while (begin != end)
438         {
439                 switch (cnt)
440                 {
441                 case 0:
442                         type = *begin;
443                         break;
444                 case 1:
445                         op = *begin;
446                         break;
447                 case 2:
448                         val = *begin;
449                         break;
450                 case 3:
451                         eDebug("malformed query: got '%s', but expected only <type> <op> <val>", begin->c_str());
452                         return 1;
453                 }
454                 ++begin;
455                 ++cnt;
456         }
457         
458         if (cnt != 3)
459         {
460                 eDebug("malformed query: missing stuff");
461                 res = 0;
462                 return 1;
463         }
464         
465         if (type == "name")
466                 res->m_type = eDVBChannelQuery::tName;
467         else if (type == "provider")
468                 res->m_type = eDVBChannelQuery::tProvider;
469         else if (type == "type")
470                 res->m_type = eDVBChannelQuery::tType;
471         else if (type == "bouquet")
472                 res->m_type = eDVBChannelQuery::tBouquet;
473         else if (type == "satellitePosition")
474                 res->m_type = eDVBChannelQuery::tSatellitePosition;
475         else if (type == "channelID")
476                 res->m_type = eDVBChannelQuery::tChannelID;
477         else
478         {
479                 eDebug("malformed query: invalid type %s", type.c_str());
480                 res = 0;
481                 return 1;
482         }
483         
484         eDebug("type is %d, nice!", res->m_type);
485         
486         if (op == "==")
487                 res->m_inverse = 0;
488         else if (op == "!=")
489                 res->m_inverse = 1;
490         else
491         {
492                 eDebug("invalid operator %s", op.c_str());
493                 res = 0;
494                 return 1;
495         }
496         
497         res->m_string = val;
498         res->m_int = atoi(val.c_str());
499 //      res->m_channelid = eDVBChannelID(val);
500         
501         return 0;
502 }
503
504 RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, std::string query)
505 {
506         std::list<std::string> tokens;
507         
508         std::string current_token;
509         
510 //      eDebug("splitting %s....", query.c_str());
511         unsigned int i = 0;
512         const char *splitchars="()";
513         int quotemode = 0, lastsplit = 0, lastalnum = 0;
514         while (i <= query.size())
515         {
516                 int c = (i < query.size()) ? query[i] : ' ';
517                 ++i;
518                 
519                 int issplit = !!strchr(splitchars, c);
520                 int isaln = isalnum(c);
521                 int iswhite = c == ' ';
522                 int isquot = c == '\"';
523                 
524                 if (quotemode)
525                 {
526                         iswhite = issplit = 0;
527                         isaln = lastalnum;
528                 }
529                 
530                 if (issplit || iswhite || isquot || lastsplit || (lastalnum != isaln))
531                 {
532                         if (current_token.size())
533                                 tokens.push_back(current_token);
534                         current_token.clear();
535                 }
536                 
537                 if (!(iswhite || isquot))
538                         current_token += c;
539                 
540                 if (isquot)
541                         quotemode = !quotemode;
542                 lastsplit = issplit;
543                 lastalnum = isaln;
544         }
545         
546 //      for (std::list<std::string>::const_iterator a(tokens.begin()); a != tokens.end(); ++a)
547 //      {
548 //              printf("%s\n", a->c_str());
549 //      }
550         
551                 /* now we recursivly parse that. */
552         return  parseExpression(res, tokens.begin(), tokens.end());
553 /*      
554         res = new eDVBChannelQuery();
555         res->m_type = eDVBChannelQuery::tName;
556         res->m_inverse = 0;
557         res->m_string = query;
558         return 0; */
559 }
560
561 DEFINE_REF(eDVBChannelQuery);