1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Sonic Visualiser
5     An audio file viewer and annotation editor.
6     Centre for Digital Music, Queen Mary, University of London.
7     This file copyright 2007 QMUL.
8 
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #include "PlaylistFileReader.h"
17 
18 #include <QFile>
19 #include <QTextStream>
20 #include <QStringList>
21 #include <QFileInfo>
22 #include <QDir>
23 
24 #include <iostream>
25 
PlaylistFileReader(QString path)26 PlaylistFileReader::PlaylistFileReader(QString path) :
27     m_source(path),
28     m_file(nullptr)
29 {
30     if (!m_source.isAvailable()) {
31         m_error = QFile::tr("File or URL \"%1\" could not be retrieved")
32             .arg(path);
33         return;
34     }
35     init();
36 }
37 
PlaylistFileReader(FileSource source)38 PlaylistFileReader::PlaylistFileReader(FileSource source) :
39     m_source(source),
40     m_file(nullptr)
41 {
42     if (!m_source.isAvailable()) {
43         m_error = QFile::tr("File or URL \"%1\" could not be retrieved")
44             .arg(source.getLocation());
45         return;
46     }
47     init();
48 }
49 
~PlaylistFileReader()50 PlaylistFileReader::~PlaylistFileReader()
51 {
52     if (m_file) m_file->close();
53     delete m_file;
54 }
55 
56 void
init()57 PlaylistFileReader::init()
58 {
59     if (!m_source.isAvailable()) return;
60 
61     m_source.waitForData();
62 
63     QString filename = m_source.getLocalFilename();
64 
65     m_file = new QFile(filename);
66     bool good = false;
67 
68     if (!m_file->exists()) {
69         m_error = QFile::tr("File \"%1\" does not exist")
70             .arg(m_source.getLocation());
71     } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) {
72         m_error = QFile::tr("Failed to open file \"%1\"")
73             .arg(m_source.getLocation());
74     } else {
75         good = true;
76     }
77 
78     if (good) {
79         if (!m_source.isRemote()) {
80             m_basedir = QFileInfo(filename).dir().canonicalPath();
81         }
82     }
83 
84     if (!good) {
85         delete m_file;
86         m_file = nullptr;
87     }
88 }
89 
90 bool
isOK() const91 PlaylistFileReader::isOK() const
92 {
93     return (m_file != nullptr);
94 }
95 
96 QString
getError() const97 PlaylistFileReader::getError() const
98 {
99     return m_error;
100 }
101 
102 PlaylistFileReader::Playlist
load() const103 PlaylistFileReader::load() const
104 {
105     if (!m_file) return Playlist();
106 
107     QTextStream in(m_file);
108     in.seek(0);
109 
110     Playlist playlist;
111 
112     while (!in.atEnd()) {
113 
114         // cope with old-style Mac line endings (c.f. CSVFileReader)
115         // as well as DOS/Unix style
116 
117         QString chunk = in.readLine();
118         QStringList lines = chunk.split('\r', QString::SkipEmptyParts);
119 
120         for (int li = 0; li < lines.size(); ++li) {
121 
122             QString line = lines[li];
123 
124             if (line.startsWith("#")) continue;
125 
126             // line is expected to be a URL or a file path.  If it
127             // appears to be a local relative file path, then we
128             // should check whether it can be resolved relative to the
129             // location of the playlist file and, if so, do so.
130 
131             if (!FileSource::isRemote(line)) {
132                 if (QFileInfo(line).isRelative() && m_basedir != "") {
133                     QString testpath = QDir(m_basedir).filePath(line);
134                     if (QFileInfo(testpath).exists() &&
135                         QFileInfo(testpath).isFile()) {
136                         cerr << "Path \"" << line
137                                   << "\" is relative, resolving to \""
138                                   << testpath << "\""
139                                   << endl;
140                         line = testpath;
141                     }
142                 }
143             }
144 
145             playlist.push_back(line);
146         }
147     }
148 
149     return playlist;
150 }
151 
152 void
getSupportedExtensions(std::set<QString> & extensions)153 PlaylistFileReader::getSupportedExtensions(std::set<QString> &extensions)
154 {
155     extensions.insert("m3u");
156 }
157