annotate data/fileio/FileSource.h @ 1308:80c77916fe85 mp3-gapless

Update m4a files to exports from CoreAudio, rather than FAAC; update tests accordingly, and add test for spurious data after end of decode
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 29 Nov 2016 14:25:57 +0000
parents 329ddaf7415d
children ad5f892c0c4d
rev   line source
Chris@208 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@208 2
Chris@208 3 /*
Chris@208 4 Sonic Visualiser
Chris@208 5 An audio file viewer and annotation editor.
Chris@208 6 Centre for Digital Music, Queen Mary, University of London.
Chris@208 7 This file copyright 2007 QMUL.
Chris@208 8
Chris@208 9 This program is free software; you can redistribute it and/or
Chris@208 10 modify it under the terms of the GNU General Public License as
Chris@208 11 published by the Free Software Foundation; either version 2 of the
Chris@208 12 License, or (at your option) any later version. See the file
Chris@208 13 COPYING included with this distribution for more information.
Chris@208 14 */
Chris@208 15
Chris@465 16 #ifndef _FILE_SOURCE_H_
Chris@465 17 #define _FILE_SOURCE_H_
Chris@208 18
Chris@208 19 #include <QUrl>
Chris@208 20 #include <QMutex>
Chris@208 21 #include <QString>
Chris@210 22 #include <QTimer>
Chris@762 23 #include <QNetworkReply>
Chris@208 24
Chris@304 25 #include <map>
Chris@304 26
Chris@686 27 #include "base/Debug.h"
Chris@686 28
Chris@208 29 class QFile;
Chris@392 30 class ProgressReporter;
Chris@208 31
Chris@325 32 /**
Chris@325 33 * FileSource is a class used to refer to the contents of a file that
Chris@325 34 * may be either local or at a remote location such as a HTTP URL.
Chris@325 35 *
Chris@325 36 * When a FileSource object is constructed, the file or URL passed to
Chris@325 37 * its constructor is tested for validity, and if it refers to a
Chris@325 38 * remote HTTP or FTP location it is retrieved asynchronously (the Qt
Chris@325 39 * event loop must be running) and cached locally. You can then query
Chris@325 40 * a local path for the file and refer to that as a normal filename.
Chris@325 41 *
Chris@325 42 * Use isAvailable() to test whether the file or remote URL exists,
Chris@325 43 * and isOK() to test for internal validity or transmission errors.
Chris@325 44 * Call waitForStatus() to block until the availability and validity
Chris@325 45 * of the URL have been established so that isAvailable may be called,
Chris@325 46 * and waitForData() to block until the entire file has been cached.
Chris@325 47 *
Chris@325 48 * FileSource handles reference counting for cache files. You can
Chris@325 49 * construct many FileSource objects with the same URL and you will
Chris@325 50 * receive the same cached file for each; it is also reasonable to
Chris@325 51 * pass FileSource objects by value. FileSource only makes sense for
Chris@325 52 * stateless URLs that result in the same data on each request.
Chris@325 53 *
Chris@469 54 * Cached files share a lifetime with their "owning" FileSource
Chris@469 55 * objects; when the last FileSource referring to a given URL is
Chris@469 56 * deleted or goes out of scope, its cached file (if any) is also
Chris@469 57 * removed.
Chris@325 58 */
Chris@317 59 class FileSource : public QObject
Chris@208 60 {
Chris@208 61 Q_OBJECT
Chris@208 62
Chris@208 63 public:
Chris@325 64 /**
Chris@325 65 * Construct a FileSource using the given local file path or URL.
Chris@357 66 * The URL may be raw or encoded.
Chris@357 67 *
Chris@392 68 * If a ProgressReporter is provided, it will be updated with
Chris@392 69 * progress status. Note that the progress() signal will also be
Chris@392 70 * emitted regularly during retrieval, even if no reporter is
Chris@392 71 * supplied here. Caller retains ownership of the reporter object.
Chris@325 72 */
Chris@520 73 FileSource(QString fileOrUrl,
Chris@520 74 ProgressReporter *reporter = 0,
Chris@520 75 QString preferredContentType = "");
Chris@325 76
Chris@325 77 /**
Chris@357 78 * Construct a FileSource using the given remote URL.
Chris@357 79 *
Chris@392 80 * If a ProgressReporter is provided, it will be updated with
Chris@392 81 * progress status. Note that the progress() signal will also be
Chris@392 82 * emitted regularly during retrieval, even if no reporter is
Chris@392 83 * supplied here. Caller retains ownership of the reporter object.
Chris@325 84 */
Chris@469 85 FileSource(QUrl url, ProgressReporter *reporter = 0);
Chris@325 86
Chris@317 87 FileSource(const FileSource &);
Chris@316 88
Chris@317 89 virtual ~FileSource();
Chris@208 90
Chris@325 91 /**
Chris@325 92 * Block on a sub-event-loop until the availability of the file or
Chris@325 93 * remote URL is known.
Chris@325 94 */
Chris@325 95 void waitForStatus();
Chris@325 96
Chris@325 97 /**
Chris@325 98 * Block on a sub-event-loop until the whole of the data has been
Chris@325 99 * retrieved (if it is remote).
Chris@325 100 */
Chris@325 101 void waitForData();
Chris@325 102
Chris@325 103 /**
Chris@981 104 * Return true if the FileSource object is valid and neither error
Chris@981 105 * nor cancellation occurred while retrieving the file or remote
Chris@981 106 * URL. Non-existence of the file or URL is not an error -- call
Chris@981 107 * isAvailable() to test for that.
Chris@325 108 */
Chris@325 109 bool isOK() const;
Chris@325 110
Chris@325 111 /**
Chris@325 112 * Return true if the file or remote URL exists. This may block
Chris@325 113 * on a sub-event-loop (calling waitForStatus) if the status is
Chris@325 114 * not yet available.
Chris@325 115 */
Chris@210 116 bool isAvailable();
Chris@210 117
Chris@325 118 /**
Chris@325 119 * Return true if the entire file has been retrieved and is
Chris@325 120 * available.
Chris@325 121 */
Chris@325 122 bool isDone() const;
Chris@316 123
Chris@325 124 /**
Chris@981 125 * Return true if the operation was cancelled by the user through
Chris@981 126 * the ProgressReporter interface. Note that the cancelled()
Chris@981 127 * signal will have been emitted, and isOK() will also return
Chris@981 128 * false in this case.
Chris@981 129 */
Chris@981 130 bool wasCancelled() const;
Chris@981 131
Chris@981 132 /**
Chris@706 133 * Return true if this FileSource is referring to a QRC resource.
Chris@706 134 */
Chris@706 135 bool isResource() const;
Chris@706 136
Chris@706 137 /**
Chris@325 138 * Return true if this FileSource is referring to a remote URL.
Chris@325 139 */
Chris@325 140 bool isRemote() const;
Chris@325 141
Chris@325 142 /**
Chris@325 143 * Return the location filename or URL as passed to the
Chris@325 144 * constructor.
Chris@325 145 */
Chris@325 146 QString getLocation() const;
Chris@325 147
Chris@325 148 /**
Chris@325 149 * Return the name of the local file this FileSource refers to.
Chris@325 150 * This is the filename that should be used when reading normally
Chris@325 151 * from the FileSource. If the filename passed to the constructor
Chris@325 152 * was a local file, this will return the same filename; otherwise
Chris@325 153 * this will be the name of the temporary cache file owned by the
Chris@325 154 * FileSource.
Chris@325 155 */
Chris@325 156 QString getLocalFilename() const;
Chris@325 157
Chris@325 158 /**
Chris@678 159 * Return the base name, i.e. the final path element (including
Chris@678 160 * extension, if any) of the location.
Chris@678 161 */
Chris@678 162 QString getBasename() const;
Chris@678 163
Chris@678 164 /**
Chris@325 165 * Return the MIME content type of this file, if known.
Chris@325 166 */
Chris@325 167 QString getContentType() const;
Chris@325 168
Chris@325 169 /**
Chris@1098 170 * Return the file extension for this file, if any. The returned
Chris@1098 171 * extension is always lower-case.
Chris@325 172 */
Chris@325 173 QString getExtension() const;
Chris@325 174
Chris@325 175 /**
Chris@325 176 * Return an error message, if isOK() is false.
Chris@325 177 */
Chris@325 178 QString getErrorString() const;
Chris@325 179
Chris@325 180 /**
Chris@325 181 * Specify whether any local, cached file should remain on disc
Chris@325 182 * after this FileSource has been destroyed. The default is false
Chris@469 183 * (cached files share their FileSource owners' lifespans).
Chris@325 184 */
Chris@316 185 void setLeaveLocalFile(bool leave);
Chris@208 186
Chris@325 187 /**
Chris@325 188 * Return true if the given filename or URL refers to a remote
Chris@325 189 * URL.
Chris@325 190 */
Chris@325 191 static bool isRemote(QString fileOrUrl);
Chris@210 192
Chris@325 193 /**
Chris@325 194 * Return true if FileSource can handle the retrieval scheme for
Chris@325 195 * the given URL (or if the URL is for a local file).
Chris@325 196 */
Chris@208 197 static bool canHandleScheme(QUrl url);
Chris@208 198
Chris@1033 199 /**
Chris@1033 200 * Print some stats, if FileSource was compiled with debugging.
Chris@1033 201 * It's safe to leave a call to this function in release code, as
Chris@1033 202 * long as FileSource itself is compiled with release flags.
Chris@1033 203 */
Chris@1033 204 static void debugReport();
Chris@1033 205
Chris@208 206 signals:
Chris@325 207 /**
Chris@325 208 * Emitted during URL retrieval, when the retrieval progress
Chris@325 209 * notches up to a new percentage.
Chris@325 210 */
Chris@208 211 void progress(int percent);
Chris@325 212
Chris@325 213 /**
Chris@325 214 * Emitted when the file's existence has been tested and/or
Chris@325 215 * response header received. Calls to isAvailable() after this
Chris@325 216 * has been emitted will not block.
Chris@325 217 */
Chris@325 218 void statusAvailable();
Chris@325 219
Chris@325 220 /**
Chris@325 221 * Emitted when the entire file data has been retrieved and the
Chris@325 222 * local file is complete (if no error has occurred).
Chris@325 223 */
Chris@208 224 void ready();
Chris@208 225
Chris@208 226 protected slots:
Chris@764 227 void metaDataChanged();
Chris@762 228 void readyRead();
Chris@762 229 void replyFailed(QNetworkReply::NetworkError);
Chris@762 230 void replyFinished();
Chris@762 231 void downloadProgress(qint64 done, qint64 total);
Chris@210 232 void cancelled();
Chris@208 233
Chris@208 234 protected:
Chris@317 235 FileSource &operator=(const FileSource &); // not provided
Chris@316 236
chris@831 237 QString m_rawFileOrUrl;
Chris@304 238 QUrl m_url;
Chris@208 239 QFile *m_localFile;
Chris@762 240 QNetworkReply *m_reply;
Chris@208 241 QString m_localFilename;
Chris@208 242 QString m_errorString;
Chris@315 243 QString m_contentType;
Chris@520 244 QString m_preferredContentType;
Chris@208 245 bool m_ok;
Chris@981 246 bool m_cancelled;
Chris@210 247 int m_lastStatus;
Chris@706 248 bool m_resource;
Chris@316 249 bool m_remote;
Chris@208 250 bool m_done;
Chris@316 251 bool m_leaveLocalFile;
Chris@392 252 ProgressReporter *m_reporter;
Chris@208 253
Chris@304 254 typedef std::map<QUrl, int> RemoteRefCountMap;
Chris@304 255 typedef std::map<QUrl, QString> RemoteLocalMap;
Chris@304 256 static RemoteRefCountMap m_refCountMap;
Chris@304 257 static RemoteLocalMap m_remoteLocalMap;
Chris@304 258 static QMutex m_mapMutex;
Chris@316 259 bool m_refCounted;
Chris@316 260
Chris@357 261 void init();
Chris@762 262 void initRemote();
Chris@304 263
Chris@211 264 void cleanup();
Chris@211 265
Chris@316 266 // Create a local file for m_url. If it already existed, return true.
Chris@316 267 // The local filename is stored in m_localFilename.
Chris@316 268 bool createCacheFile();
Chris@316 269 void deleteCacheFile();
Chris@208 270
Chris@208 271 static QMutex m_fileCreationMutex;
Chris@208 272 static int m_count;
Chris@208 273 };
Chris@208 274
Chris@208 275 #endif