Mercurial > hg > svcore
comparison data/fileio/FileSource.cpp @ 384:6f6ab834449d spectrogram-cache-rejig
* Merge from trunk
| author | Chris Cannam | 
|---|---|
| date | Wed, 27 Feb 2008 11:59:42 +0000 | 
| parents | a6fab10ff9e6 | 
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 337:a6fab10ff9e6 | 384:6f6ab834449d | 
|---|---|
| 12 License, or (at your option) any later version. See the file | 12 License, or (at your option) any later version. See the file | 
| 13 COPYING included with this distribution for more information. | 13 COPYING included with this distribution for more information. | 
| 14 */ | 14 */ | 
| 15 | 15 | 
| 16 #include "FileSource.h" | 16 #include "FileSource.h" | 
| 17 #include "ProgressPrinter.h" | |
| 18 | |
| 17 #include "base/TempDirectory.h" | 19 #include "base/TempDirectory.h" | 
| 18 #include "base/Exceptions.h" | 20 #include "base/Exceptions.h" | 
| 19 | 21 | 
| 20 #include <QHttp> | 22 #include <QHttp> | 
| 21 #include <QFtp> | 23 #include <QFtp> | 
| 25 #include <QProgressDialog> | 27 #include <QProgressDialog> | 
| 26 #include <QHttpResponseHeader> | 28 #include <QHttpResponseHeader> | 
| 27 | 29 | 
| 28 #include <iostream> | 30 #include <iostream> | 
| 29 | 31 | 
| 30 //#define DEBUG_FILE_SOURCE 1 | 32 #define DEBUG_FILE_SOURCE 1 | 
| 31 | 33 | 
| 32 int | 34 int | 
| 33 FileSource::m_count = 0; | 35 FileSource::m_count = 0; | 
| 34 | 36 | 
| 35 QMutex | 37 QMutex | 
| 42 FileSource::m_remoteLocalMap; | 44 FileSource::m_remoteLocalMap; | 
| 43 | 45 | 
| 44 QMutex | 46 QMutex | 
| 45 FileSource::m_mapMutex; | 47 FileSource::m_mapMutex; | 
| 46 | 48 | 
| 47 FileSource::FileSource(QString fileOrUrl, bool showProgress) : | 49 FileSource::FileSource(QString fileOrUrl, ShowProgressType progressType) : | 
| 48 m_url(fileOrUrl), | 50 m_url(fileOrUrl), | 
| 49 m_ftp(0), | 51 m_ftp(0), | 
| 50 m_http(0), | 52 m_http(0), | 
| 51 m_localFile(0), | 53 m_localFile(0), | 
| 52 m_ok(false), | 54 m_ok(false), | 
| 53 m_lastStatus(0), | 55 m_lastStatus(0), | 
| 54 m_remote(isRemote(fileOrUrl)), | 56 m_remote(isRemote(fileOrUrl)), | 
| 55 m_done(false), | 57 m_done(false), | 
| 56 m_leaveLocalFile(false), | 58 m_leaveLocalFile(false), | 
| 59 m_progressType(progressType), | |
| 60 m_progressPrinter(0), | |
| 57 m_progressDialog(0), | 61 m_progressDialog(0), | 
| 58 m_progressShowTimer(this), | 62 m_progressShowTimer(this), | 
| 59 m_refCounted(false) | 63 m_refCounted(false) | 
| 60 { | 64 { | 
| 61 #ifdef DEBUG_FILE_SOURCE | 65 #ifdef DEBUG_FILE_SOURCE | 
| 66 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 70 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 
| 67 m_errorString = tr("Unsupported scheme in URL"); | 71 m_errorString = tr("Unsupported scheme in URL"); | 
| 68 return; | 72 return; | 
| 69 } | 73 } | 
| 70 | 74 | 
| 71 init(showProgress); | 75 init(); | 
| 72 | 76 | 
| 73 if (isRemote() && | 77 if (isRemote() && | 
| 74 (fileOrUrl.contains('%') || | 78 (fileOrUrl.contains('%') || | 
| 75 fileOrUrl.contains("--"))) { // for IDNA | 79 fileOrUrl.contains("--"))) { // for IDNA | 
| 76 | 80 | 
| 97 m_url.setEncodedUrl(fileOrUrl.toAscii()); | 101 m_url.setEncodedUrl(fileOrUrl.toAscii()); | 
| 98 | 102 | 
| 99 m_ok = false; | 103 m_ok = false; | 
| 100 m_done = false; | 104 m_done = false; | 
| 101 m_lastStatus = 0; | 105 m_lastStatus = 0; | 
| 102 init(showProgress); | 106 init(); | 
| 103 } | 107 } | 
| 104 } | 108 } | 
| 105 | 109 | 
| 106 if (!isRemote()) { | 110 if (!isRemote()) { | 
| 107 emit statusAvailable(); | 111 emit statusAvailable(); | 
| 108 emit ready(); | 112 emit ready(); | 
| 109 } | 113 } | 
| 110 } | 114 } | 
| 111 | 115 | 
| 112 FileSource::FileSource(QUrl url, bool showProgress) : | 116 FileSource::FileSource(QUrl url, ShowProgressType progressType) : | 
| 113 m_url(url), | 117 m_url(url), | 
| 114 m_ftp(0), | 118 m_ftp(0), | 
| 115 m_http(0), | 119 m_http(0), | 
| 116 m_localFile(0), | 120 m_localFile(0), | 
| 117 m_ok(false), | 121 m_ok(false), | 
| 118 m_lastStatus(0), | 122 m_lastStatus(0), | 
| 119 m_remote(isRemote(url.toString())), | 123 m_remote(isRemote(url.toString())), | 
| 120 m_done(false), | 124 m_done(false), | 
| 121 m_leaveLocalFile(false), | 125 m_leaveLocalFile(false), | 
| 126 m_progressType(progressType), | |
| 127 m_progressPrinter(0), | |
| 122 m_progressDialog(0), | 128 m_progressDialog(0), | 
| 123 m_progressShowTimer(this), | 129 m_progressShowTimer(this), | 
| 124 m_refCounted(false) | 130 m_refCounted(false) | 
| 125 { | 131 { | 
| 126 #ifdef DEBUG_FILE_SOURCE | 132 #ifdef DEBUG_FILE_SOURCE | 
| 131 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 137 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 
| 132 m_errorString = tr("Unsupported scheme in URL"); | 138 m_errorString = tr("Unsupported scheme in URL"); | 
| 133 return; | 139 return; | 
| 134 } | 140 } | 
| 135 | 141 | 
| 136 init(showProgress); | 142 init(); | 
| 137 } | 143 } | 
| 138 | 144 | 
| 139 FileSource::FileSource(const FileSource &rf) : | 145 FileSource::FileSource(const FileSource &rf) : | 
| 140 QObject(), | 146 QObject(), | 
| 141 m_url(rf.m_url), | 147 m_url(rf.m_url), | 
| 145 m_ok(rf.m_ok), | 151 m_ok(rf.m_ok), | 
| 146 m_lastStatus(rf.m_lastStatus), | 152 m_lastStatus(rf.m_lastStatus), | 
| 147 m_remote(rf.m_remote), | 153 m_remote(rf.m_remote), | 
| 148 m_done(false), | 154 m_done(false), | 
| 149 m_leaveLocalFile(false), | 155 m_leaveLocalFile(false), | 
| 156 m_progressType(rf.m_progressType), | |
| 157 m_progressPrinter(0), | |
| 150 m_progressDialog(0), | 158 m_progressDialog(0), | 
| 151 m_progressShowTimer(0), | 159 m_progressShowTimer(0), | 
| 152 m_refCounted(false) | 160 m_refCounted(false) | 
| 153 { | 161 { | 
| 154 #ifdef DEBUG_FILE_SOURCE | 162 #ifdef DEBUG_FILE_SOURCE | 
| 195 | 203 | 
| 196 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); | 204 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); | 
| 197 } | 205 } | 
| 198 | 206 | 
| 199 void | 207 void | 
| 200 FileSource::init(bool showProgress) | 208 FileSource::init() | 
| 201 { | 209 { | 
| 202 if (!isRemote()) { | 210 if (!isRemote()) { | 
| 211 #ifdef DEBUG_FILE_SOURCE | |
| 212 std::cerr << "FileSource::init: Not a remote URL" << std::endl; | |
| 213 #endif | |
| 214 bool literal = false; | |
| 203 m_localFilename = m_url.toLocalFile(); | 215 m_localFilename = m_url.toLocalFile(); | 
| 216 if (m_localFilename == "") { | |
| 217 // QUrl may have mishandled the scheme (e.g. in a DOS path) | |
| 218 m_localFilename = m_url.toString(); | |
| 219 literal = true; | |
| 220 } | |
| 221 #ifdef DEBUG_FILE_SOURCE | |
| 222 std::cerr << "FileSource::init: URL translates to local filename \"" | |
| 223 << m_localFilename.toStdString() << "\"" << std::endl; | |
| 224 #endif | |
| 225 m_ok = true; | |
| 226 m_lastStatus = 200; | |
| 227 | |
| 228 if (!QFileInfo(m_localFilename).exists()) { | |
| 229 if (literal) { | |
| 230 m_lastStatus = 404; | |
| 231 } else { | |
| 232 // Again, QUrl may have been mistreating us -- | |
| 233 // e.g. dropping a part that looks like query data | |
| 234 m_localFilename = m_url.toString(); | |
| 235 literal = true; | |
| 236 if (!QFileInfo(m_localFilename).exists()) { | |
| 237 m_lastStatus = 404; | |
| 238 } | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 m_done = true; | |
| 243 return; | |
| 244 } | |
| 245 | |
| 246 if (createCacheFile()) { | |
| 247 #ifdef DEBUG_FILE_SOURCE | |
| 248 std::cerr << "FileSource::init: Already have this one" << std::endl; | |
| 249 #endif | |
| 204 m_ok = true; | 250 m_ok = true; | 
| 205 if (!QFileInfo(m_localFilename).exists()) { | 251 if (!QFileInfo(m_localFilename).exists()) { | 
| 206 m_lastStatus = 404; | 252 m_lastStatus = 404; | 
| 207 } else { | 253 } else { | 
| 208 m_lastStatus = 200; | 254 m_lastStatus = 200; | 
| 209 } | 255 } | 
| 210 m_done = true; | 256 m_done = true; | 
| 211 return; | 257 return; | 
| 212 } | 258 } | 
| 213 | 259 | 
| 214 if (createCacheFile()) { | |
| 215 #ifdef DEBUG_FILE_SOURCE | |
| 216 std::cerr << "FileSource::init: Already have this one" << std::endl; | |
| 217 #endif | |
| 218 m_ok = true; | |
| 219 if (!QFileInfo(m_localFilename).exists()) { | |
| 220 m_lastStatus = 404; | |
| 221 } else { | |
| 222 m_lastStatus = 200; | |
| 223 } | |
| 224 m_done = true; | |
| 225 return; | |
| 226 } | |
| 227 | |
| 228 if (m_localFilename == "") return; | 260 if (m_localFilename == "") return; | 
| 229 m_localFile = new QFile(m_localFilename); | 261 m_localFile = new QFile(m_localFilename); | 
| 230 m_localFile->open(QFile::WriteOnly); | 262 m_localFile->open(QFile::WriteOnly); | 
| 231 | 263 | 
| 232 QString scheme = m_url.scheme().toLower(); | 264 QString scheme = m_url.scheme().toLower(); | 
| 236 << m_url.toString().toStdString() << "\", retrieving" << std::endl; | 268 << m_url.toString().toStdString() << "\", retrieving" << std::endl; | 
| 237 #endif | 269 #endif | 
| 238 | 270 | 
| 239 if (scheme == "http") { | 271 if (scheme == "http") { | 
| 240 initHttp(); | 272 initHttp(); | 
| 273 std::cerr << "FileSource: initHttp succeeded" << std::endl; | |
| 241 } else if (scheme == "ftp") { | 274 } else if (scheme == "ftp") { | 
| 242 initFtp(); | 275 initFtp(); | 
| 243 } else { | 276 } else { | 
| 244 m_remote = false; | 277 m_remote = false; | 
| 245 m_ok = false; | 278 m_ok = false; | 
| 269 | 302 | 
| 270 m_remoteLocalMap[m_url] = m_localFilename; | 303 m_remoteLocalMap[m_url] = m_localFilename; | 
| 271 m_refCountMap[m_url]++; | 304 m_refCountMap[m_url]++; | 
| 272 m_refCounted = true; | 305 m_refCounted = true; | 
| 273 | 306 | 
| 274 if (showProgress) { | 307 switch (m_progressType) { | 
| 275 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100); | 308 | 
| 309 case ProgressNone: break; | |
| 310 | |
| 311 case ProgressDialog: | |
| 312 m_progressDialog = new QProgressDialog | |
| 313 (tr("Downloading %1...").arg(m_url.toString()), | |
| 314 tr("Cancel"), 0, 100); | |
| 276 m_progressDialog->hide(); | 315 m_progressDialog->hide(); | 
| 277 connect(&m_progressShowTimer, SIGNAL(timeout()), | 316 connect(&m_progressShowTimer, SIGNAL(timeout()), | 
| 278 this, SLOT(showProgressDialog())); | 317 this, SLOT(showProgressDialog())); | 
| 279 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); | 318 connect(m_progressDialog, SIGNAL(canceled()), | 
| 319 this, SLOT(cancelled())); | |
| 280 m_progressShowTimer.setSingleShot(true); | 320 m_progressShowTimer.setSingleShot(true); | 
| 281 m_progressShowTimer.start(2000); | 321 m_progressShowTimer.start(2000); | 
| 322 break; | |
| 323 | |
| 324 case ProgressToConsole: | |
| 325 m_progressPrinter = new ProgressPrinter(tr("Downloading...")); | |
| 326 connect(this, SIGNAL(progress(int)), | |
| 327 m_progressPrinter, SLOT(progress(int))); | |
| 328 break; | |
| 282 } | 329 } | 
| 283 } | 330 } | 
| 284 } | 331 } | 
| 285 | 332 | 
| 286 void | 333 void | 
| 394 f->abort(); | 441 f->abort(); | 
| 395 f->deleteLater(); | 442 f->deleteLater(); | 
| 396 } | 443 } | 
| 397 delete m_progressDialog; | 444 delete m_progressDialog; | 
| 398 m_progressDialog = 0; | 445 m_progressDialog = 0; | 
| 446 delete m_progressPrinter; | |
| 447 m_progressPrinter = 0; | |
| 399 delete m_localFile; // does not actually delete the file | 448 delete m_localFile; // does not actually delete the file | 
| 400 m_localFile = 0; | 449 m_localFile = 0; | 
| 401 } | 450 } | 
| 402 | 451 | 
| 403 bool | 452 bool | 
| 404 FileSource::isRemote(QString fileOrUrl) | 453 FileSource::isRemote(QString fileOrUrl) | 
| 405 { | 454 { | 
| 455 // Note that a "scheme" with length 1 is probably a DOS drive letter | |
| 406 QString scheme = QUrl(fileOrUrl).scheme().toLower(); | 456 QString scheme = QUrl(fileOrUrl).scheme().toLower(); | 
| 407 return (scheme == "http" || scheme == "ftp"); | 457 if (scheme == "" || scheme == "file" || scheme.length() == 1) return false; | 
| 458 return true; | |
| 408 } | 459 } | 
| 409 | 460 | 
| 410 bool | 461 bool | 
| 411 FileSource::canHandleScheme(QUrl url) | 462 FileSource::canHandleScheme(QUrl url) | 
| 412 { | 463 { | 
| 464 // Note that a "scheme" with length 1 is probably a DOS drive letter | |
| 413 QString scheme = url.scheme().toLower(); | 465 QString scheme = url.scheme().toLower(); | 
| 414 return (scheme == "http" || scheme == "ftp" || | 466 return (scheme == "http" || scheme == "ftp" || | 
| 415 scheme == "file" || scheme == ""); | 467 scheme == "file" || scheme == "" || scheme.length() == 1); | 
| 416 } | 468 } | 
| 417 | 469 | 
| 418 bool | 470 bool | 
| 419 FileSource::isAvailable() | 471 FileSource::isAvailable() | 
| 420 { | 472 { | 
| 440 | 492 | 
| 441 void | 493 void | 
| 442 FileSource::waitForData() | 494 FileSource::waitForData() | 
| 443 { | 495 { | 
| 444 while (m_ok && !m_done) { | 496 while (m_ok && !m_done) { | 
| 497 // std::cerr << "FileSource::waitForData: calling QApplication::processEvents" << std::endl; | |
| 445 QApplication::processEvents(); | 498 QApplication::processEvents(); | 
| 446 } | 499 } | 
| 447 } | 500 } | 
| 448 | 501 | 
| 449 void | 502 void | 
| 793 m_localFilename = filepath; | 846 m_localFilename = filepath; | 
| 794 | 847 | 
| 795 return false; | 848 return false; | 
| 796 } | 849 } | 
| 797 | 850 | 
| 798 FileSourceProgressPrinter::FileSourceProgressPrinter() : | |
| 799 m_lastProgress(0) | |
| 800 { | |
| 801 } | |
| 802 | |
| 803 FileSourceProgressPrinter::~FileSourceProgressPrinter() | |
| 804 { | |
| 805 if (m_lastProgress > 0 && m_lastProgress != 100) { | |
| 806 std::cerr << "\r\n"; | |
| 807 } | |
| 808 } | |
| 809 | |
| 810 void | |
| 811 FileSourceProgressPrinter::progress(int progress) | |
| 812 { | |
| 813 if (progress == m_lastProgress) return; | |
| 814 if (progress == 100) std::cerr << "\r\n"; | |
| 815 else std::cerr << "\r" << progress << "%"; | |
| 816 m_lastProgress = progress; | |
| 817 } | |
| 818 | 
