MythTV  0.26-pre
pls.cpp
Go to the documentation of this file.
00001 /*
00002   playlistfile (.pls) parser
00003   Eskil Heyn Olsen, 2005, distributed under the GPL as part of mythtv.
00004 
00005   Update July 2010 updated for Qt4 (Paul Harrison)
00006 
00007 */
00008 
00009 // c
00010 //#include "iostream"
00011 #include <string>
00012 
00013 // qt
00014 #include <QPair>
00015 #include <QList>
00016 #include <QMap>
00017 #include <QStringList>
00018 
00019 // mythtv
00020 #include <mythlogging.h>
00021 
00022 // mythmusic
00023 #include "pls.h"
00024 
00025 
00026 using namespace std;
00027 
00028 class CfgReader
00029 {
00030   public:
00031     CfgReader()
00032     {
00033     }
00034     ~CfgReader()
00035     {
00036     }
00037 
00038     typedef QPair<QString,QString> KeyValue;
00039     typedef QList<KeyValue> KeyValueList;
00040     typedef QMap<QString, KeyValueList> ConfigMap;
00041 
00042     void parse(const char *d, int l)
00043     {
00044         const char *ptr = d;
00045         int line = 1;
00046         bool done = l <= 0;
00047 
00048         QString current_section = "";
00049         KeyValueList keyvals;
00050 
00051         while(!done)
00052         {
00053             switch(*ptr)
00054             {
00055                 case '\0':
00056                     done = true;
00057                     break;
00058                 case '#':
00059                 {
00060                     const char *end = strchr(ptr, '\n');
00061                     if (!end) done = true;
00062                     ptr = end;
00063                     break;
00064                 }
00065                 case '\n':
00066                     ptr ++;
00067                     line ++;
00068                     break;
00069                 case '[':
00070                 {
00071                     ptr ++;
00072                     const char *nl = strchr(ptr, '\n');
00073                     const char *end = strchr(ptr, ']');
00074 
00075                     if (!nl) nl = d + l;
00076 
00077                     if (!end || nl < end)
00078                     {
00079                         LOG(VB_GENERAL, LOG_ERR,
00080                             QString("CfgReader:: Badly formatted section, "
00081                                     "line %1").arg(line));
00082                         done = true;
00083                     }
00084 
00085                     if (current_section.length() > 0)
00086                     {
00087                         cfg[current_section] = keyvals;
00088                         keyvals = KeyValueList();
00089                     }
00090 
00091                     current_section = std::string(ptr, end - ptr).c_str();
00092                     if (current_section.length() == 0)
00093                     {
00094                         LOG(VB_GENERAL, LOG_ERR,
00095                             QString("CfgReader:: Badly formatted section, "
00096                                     "line %1").arg(line));
00097                         done = true;
00098                     }
00099                     ptr = end + 1;
00100                     break;
00101                 }
00102                 default:
00103                 {
00104                     if (current_section.length() > 0)
00105                     {
00106                         const char *eq = strchr(ptr, '=');
00107                         const char *nl = strchr(ptr, '\n');
00108 
00109                         if (!nl) nl = d + l;
00110 
00111                         if (!eq || nl < eq) 
00112                         {
00113                             LOG(VB_GENERAL, LOG_ERR,
00114                                 QString("CfgReader:: Badly formatted line %1")
00115                                     .arg(line));
00116                             done = true;
00117                         }
00118                         else
00119                         {
00120                             QString key = string(ptr, eq - ptr).c_str();
00121                             QString val = string(eq + 1, nl - eq - 1).c_str();
00122                             keyvals.push_back(KeyValue(key, val));
00123                             ptr = nl;
00124                         }
00125                     }
00126                     else
00127                     {
00128                         LOG(VB_GENERAL, LOG_ERR,
00129                             QString("CfgReader:: Badly formatted line %1")
00130                                 .arg(line));
00131                         done = true;
00132                     }
00133                     break;
00134                 }
00135             }
00136 
00137             if (ptr - d == l) 
00138                 done = true;
00139         }
00140 
00141         if (current_section.length() > 0)
00142             cfg[current_section] = keyvals;
00143     }
00144 
00145     QList<QString> getSections(void)
00146     {
00147         QList<QString> res;
00148         for (ConfigMap::iterator it = cfg.begin(); it != cfg.end(); ++it)
00149             res.push_back(it.key());
00150         return res;
00151     }
00152 
00153     QList<QString> getKeys(const QString &section)
00154     {
00155         KeyValueList keylist = cfg[section];
00156         QList<QString> res;
00157         for (KeyValueList::iterator it = keylist.begin();
00158              it != keylist.end(); ++it)
00159         {
00160             res.push_back((*it).first);
00161         }
00162         return res;
00163     }
00164 
00165     QString getStrVal(const QString &section, const QString &key,
00166                       const QString &def = "")
00167     {
00168         KeyValueList keylist = cfg[section];
00169         QString res = def;
00170         for (KeyValueList::iterator it = keylist.begin();
00171              it != keylist.end(); ++it)
00172         {
00173             if ((*it).first == key) 
00174             {
00175                 res =(*it).second;
00176                 break;
00177             }
00178         }
00179         return res;
00180     }
00181 
00182     int getIntVal(const QString &section, const QString &key, int def=0) 
00183     {
00184         QString def_str;
00185         def_str.setNum (def);
00186         return getStrVal(section, key, def_str).toInt();
00187     }
00188 
00189   private:
00190     ConfigMap cfg;
00191 };
00192 
00193 /****************************************************************************/
00194 
00195 PlayListFile::PlayListFile(void) : m_version(0)
00196 {
00197 }
00198 
00199 PlayListFile::~PlayListFile(void)
00200 {
00201     clear();
00202 }
00203 
00204 int PlayListFile::parse(PlayListFile *pls, QTextStream *stream, const QString &extension)
00205 {
00206     int result = 0;
00207 
00208     if (extension == "pls")
00209         result = PlayListFile::parsePLS(pls, stream);
00210     else if (extension == "m3u")
00211         result = PlayListFile::parseM3U(pls, stream);
00212 
00213     return result;
00214 }
00215 
00216 int PlayListFile::parsePLS(PlayListFile *pls, QTextStream *stream)
00217 {
00218     int parsed = 0;
00219     QString d = stream->readAll();
00220     CfgReader cfg;
00221     cfg.parse(d.toAscii(), d.length());
00222 
00223     int num_entries = cfg.getIntVal("playlist", "numberofentries", -1);
00224 
00225     // Some pls files have "numberofentries", some has "NumberOfEntries".
00226     if (num_entries == -1) 
00227         num_entries = cfg.getIntVal("playlist", "NumberOfEntries", -1);
00228 
00229     for (int n = 1; n <= num_entries; n++)
00230     {
00231         PlayListFileEntry *e = new PlayListFileEntry();
00232         QString t_key = QString("Title%1").arg(n);
00233         QString f_key = QString("File%1").arg(n);
00234         QString l_key = QString("Length%1").arg(n);
00235 
00236         e->setFile(cfg.getStrVal("playlist", f_key));
00237         e->setTitle(cfg.getStrVal("playlist", t_key));
00238         e->setLength(cfg.getIntVal("playlist", l_key));
00239 
00240         pls->add(e);
00241         parsed++;
00242     }
00243 
00244     return parsed;
00245 }
00246 
00247 #define M3U_HEADER  "#EXTM3U"
00248 #define M3U_INFO    "#EXTINF"
00249 
00250 int PlayListFile::parseM3U(PlayListFile *pls, QTextStream *stream)
00251 {
00252     QString data = stream->readAll();
00253     QStringList lines = data.split("\r\n");
00254 
00255     QStringList::iterator it;
00256     for (it = lines.begin(); it != lines.end(); ++it)
00257     {
00258         // ignore empty lines
00259         if (it->isEmpty())
00260             continue;
00261 
00262         // ignore the M3U header
00263         if (it->startsWith(M3U_HEADER))
00264             continue;
00265 
00266         // for now ignore M3U info lines
00267         if (it->startsWith(M3U_INFO))
00268             continue;
00269 
00270         // add to the playlist
00271         PlayListFileEntry *e = new PlayListFileEntry();
00272         e->setFile(*it);
00273         e->setTitle(*it);
00274         e->setLength(-1);
00275 
00276         pls->add(e);
00277     }
00278 
00279     return pls->size();
00280 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends