annotate data/fileio/FileSource.h @ 363:0e30c8ec15a0

* Add wave file model method for reading more than one channel at once, avoiding ludicrously expensive backward seeks and double-reads when playing multi-channel files or using them as inputs to feature extraction plugins
author Chris Cannam
date Thu, 24 Jan 2008 14:35:43 +0000
parents b92513201610
children 183ee2a55fc7
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@208 16 #ifndef _REMOTE_FILE_H_
Chris@208 17 #define _REMOTE_FILE_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@208 23
Chris@304 24 #include <map>
Chris@304 25
Chris@208 26 class QFtp;
Chris@208 27 class QHttp;
Chris@208 28 class QFile;
Chris@208 29 class QProgressDialog;
Chris@210 30 class QHttpResponseHeader;
Chris@357 31 class ProgressPrinter;
Chris@208 32
Chris@325 33 /**
Chris@325 34 * FileSource is a class used to refer to the contents of a file that
Chris@325 35 * may be either local or at a remote location such as a HTTP URL.
Chris@325 36 *
Chris@325 37 * When a FileSource object is constructed, the file or URL passed to
Chris@325 38 * its constructor is tested for validity, and if it refers to a
Chris@325 39 * remote HTTP or FTP location it is retrieved asynchronously (the Qt
Chris@325 40 * event loop must be running) and cached locally. You can then query
Chris@325 41 * a local path for the file and refer to that as a normal filename.
Chris@325 42 *
Chris@325 43 * Use isAvailable() to test whether the file or remote URL exists,
Chris@325 44 * and isOK() to test for internal validity or transmission errors.
Chris@325 45 * Call waitForStatus() to block until the availability and validity
Chris@325 46 * of the URL have been established so that isAvailable may be called,
Chris@325 47 * and waitForData() to block until the entire file has been cached.
Chris@325 48 *
Chris@325 49 * FileSource handles reference counting for cache files. You can
Chris@325 50 * construct many FileSource objects with the same URL and you will
Chris@325 51 * receive the same cached file for each; it is also reasonable to
Chris@325 52 * pass FileSource objects by value. FileSource only makes sense for
Chris@325 53 * stateless URLs that result in the same data on each request.
Chris@325 54 *
Chris@325 55 * Cached files share a lifetime with their "owning" FileSource
Chris@325 56 * objects; when the last FileSource referring to a given URL is
Chris@325 57 * deleted or goes out of scope, its cached file (if any) is also
Chris@325 58 * removed.
Chris@325 59 */
Chris@317 60 class FileSource : public QObject
Chris@208 61 {
Chris@208 62 Q_OBJECT
Chris@208 63
Chris@208 64 public:
Chris@325 65
Chris@357 66 enum ShowProgressType {
Chris@357 67 ProgressNone,
Chris@357 68 ProgressDialog,
Chris@357 69 ProgressToConsole
Chris@357 70 };
Chris@357 71
Chris@325 72 /**
Chris@325 73 * Construct a FileSource using the given local file path or URL.
Chris@357 74 * The URL may be raw or encoded.
Chris@357 75 *
Chris@357 76 * If progressType is ProgressDialog, a progress dialog will be
Chris@357 77 * shown for any network transfers; if it is ProgressToConsole, a
Chris@357 78 * progress indication will be sent to the console.
Chris@357 79 * Note that the progress() signal will also be emitted regularly
Chris@357 80 * during retrieval, even if progressType is ProgressNone.
Chris@325 81 */
Chris@357 82 FileSource(QString fileOrUrl,
Chris@357 83 ShowProgressType progressType = ProgressNone);
Chris@325 84
Chris@325 85 /**
Chris@357 86 * Construct a FileSource using the given remote URL.
Chris@357 87 *
Chris@357 88 * If progressType is ProgressDialog, a progress dialog will be
Chris@357 89 * shown for any network transfers; if it is ProgressToConsole, a
Chris@357 90 * progress indication will be sent to the console.
Chris@357 91 * Note that the progress() signal also will be emitted regularly
Chris@357 92 * during retrieval, even if progressType is ProgressNone.
Chris@325 93 */
Chris@357 94 FileSource(QUrl url,
Chris@357 95 ShowProgressType progressType = ProgressNone);
Chris@325 96
Chris@317 97 FileSource(const FileSource &);
Chris@316 98
Chris@317 99 virtual ~FileSource();
Chris@208 100
Chris@325 101 /**
Chris@325 102 * Block on a sub-event-loop until the availability of the file or
Chris@325 103 * remote URL is known.
Chris@325 104 */
Chris@325 105 void waitForStatus();
Chris@325 106
Chris@325 107 /**
Chris@325 108 * Block on a sub-event-loop until the whole of the data has been
Chris@325 109 * retrieved (if it is remote).
Chris@325 110 */
Chris@325 111 void waitForData();
Chris@325 112
Chris@325 113 /**
Chris@325 114 * Return true if the FileSource object is valid and no error
Chris@325 115 * occurred in looking up the file or remote URL. Non-existence
Chris@325 116 * of the file or URL is not an error -- call isAvailable() to
Chris@325 117 * test for that.
Chris@325 118 */
Chris@325 119 bool isOK() const;
Chris@325 120
Chris@325 121 /**
Chris@325 122 * Return true if the file or remote URL exists. This may block
Chris@325 123 * on a sub-event-loop (calling waitForStatus) if the status is
Chris@325 124 * not yet available.
Chris@325 125 */
Chris@210 126 bool isAvailable();
Chris@210 127
Chris@325 128 /**
Chris@325 129 * Return true if the entire file has been retrieved and is
Chris@325 130 * available.
Chris@325 131 */
Chris@325 132 bool isDone() const;
Chris@316 133
Chris@325 134 /**
Chris@325 135 * Return true if this FileSource is referring to a remote URL.
Chris@325 136 */
Chris@325 137 bool isRemote() const;
Chris@325 138
Chris@325 139 /**
Chris@325 140 * Return the location filename or URL as passed to the
Chris@325 141 * constructor.
Chris@325 142 */
Chris@325 143 QString getLocation() const;
Chris@325 144
Chris@325 145 /**
Chris@325 146 * Return the name of the local file this FileSource refers to.
Chris@325 147 * This is the filename that should be used when reading normally
Chris@325 148 * from the FileSource. If the filename passed to the constructor
Chris@325 149 * was a local file, this will return the same filename; otherwise
Chris@325 150 * this will be the name of the temporary cache file owned by the
Chris@325 151 * FileSource.
Chris@325 152 */
Chris@325 153 QString getLocalFilename() const;
Chris@325 154
Chris@325 155 /**
Chris@325 156 * Return the MIME content type of this file, if known.
Chris@325 157 */
Chris@325 158 QString getContentType() const;
Chris@325 159
Chris@325 160 /**
Chris@325 161 * Return the file extension for this file, if any.
Chris@325 162 */
Chris@325 163 QString getExtension() const;
Chris@325 164
Chris@325 165 /**
Chris@325 166 * Return an error message, if isOK() is false.
Chris@325 167 */
Chris@325 168 QString getErrorString() const;
Chris@325 169
Chris@325 170 /**
Chris@325 171 * Specify whether any local, cached file should remain on disc
Chris@325 172 * after this FileSource has been destroyed. The default is false
Chris@325 173 * (cached files share their FileSource owners' lifespans).
Chris@325 174 */
Chris@316 175 void setLeaveLocalFile(bool leave);
Chris@208 176
Chris@325 177 /**
Chris@325 178 * Return true if the given filename or URL refers to a remote
Chris@325 179 * URL.
Chris@325 180 */
Chris@325 181 static bool isRemote(QString fileOrUrl);
Chris@210 182
Chris@325 183 /**
Chris@325 184 * Return true if FileSource can handle the retrieval scheme for
Chris@325 185 * the given URL (or if the URL is for a local file).
Chris@325 186 */
Chris@208 187 static bool canHandleScheme(QUrl url);
Chris@208 188
Chris@208 189 signals:
Chris@325 190 /**
Chris@325 191 * Emitted during URL retrieval, when the retrieval progress
Chris@325 192 * notches up to a new percentage.
Chris@325 193 */
Chris@208 194 void progress(int percent);
Chris@325 195
Chris@325 196 /**
Chris@325 197 * Emitted when the file's existence has been tested and/or
Chris@325 198 * response header received. Calls to isAvailable() after this
Chris@325 199 * has been emitted will not block.
Chris@325 200 */
Chris@325 201 void statusAvailable();
Chris@325 202
Chris@325 203 /**
Chris@325 204 * Emitted when the entire file data has been retrieved and the
Chris@325 205 * local file is complete (if no error has occurred).
Chris@325 206 */
Chris@208 207 void ready();
Chris@208 208
Chris@208 209 protected slots:
Chris@208 210 void dataReadProgress(int done, int total);
Chris@214 211 void httpResponseHeaderReceived(const QHttpResponseHeader &resp);
Chris@214 212 void ftpCommandFinished(int, bool);
Chris@208 213 void dataTransferProgress(qint64 done, qint64 total);
Chris@208 214 void done(bool error);
Chris@210 215 void showProgressDialog();
Chris@210 216 void cancelled();
Chris@208 217
Chris@208 218 protected:
Chris@317 219 FileSource &operator=(const FileSource &); // not provided
Chris@316 220
Chris@304 221 QUrl m_url;
Chris@208 222 QFtp *m_ftp;
Chris@208 223 QHttp *m_http;
Chris@208 224 QFile *m_localFile;
Chris@208 225 QString m_localFilename;
Chris@208 226 QString m_errorString;
Chris@315 227 QString m_contentType;
Chris@208 228 bool m_ok;
Chris@210 229 int m_lastStatus;
Chris@316 230 bool m_remote;
Chris@208 231 bool m_done;
Chris@316 232 bool m_leaveLocalFile;
Chris@357 233 ShowProgressType m_progressType;
Chris@357 234 ProgressPrinter *m_progressPrinter;
Chris@208 235 QProgressDialog *m_progressDialog;
Chris@210 236 QTimer m_progressShowTimer;
Chris@208 237
Chris@304 238 typedef std::map<QUrl, int> RemoteRefCountMap;
Chris@304 239 typedef std::map<QUrl, QString> RemoteLocalMap;
Chris@304 240 static RemoteRefCountMap m_refCountMap;
Chris@304 241 static RemoteLocalMap m_remoteLocalMap;
Chris@304 242 static QMutex m_mapMutex;
Chris@316 243 bool m_refCounted;
Chris@316 244
Chris@357 245 void init();
Chris@316 246 void initHttp();
Chris@316 247 void initFtp();
Chris@304 248
Chris@211 249 void cleanup();
Chris@211 250
Chris@316 251 // Create a local file for m_url. If it already existed, return true.
Chris@316 252 // The local filename is stored in m_localFilename.
Chris@316 253 bool createCacheFile();
Chris@316 254 void deleteCacheFile();
Chris@208 255
Chris@208 256 static QMutex m_fileCreationMutex;
Chris@208 257 static int m_count;
Chris@208 258 };
Chris@208 259
Chris@208 260 #endif