FileSource.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2007 QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "FileSource.h"
00017 #include "ProgressPrinter.h"
00018 
00019 #include "base/TempDirectory.h"
00020 #include "base/Exceptions.h"
00021 
00022 #include <QHttp>
00023 #include <QFtp>
00024 #include <QFileInfo>
00025 #include <QDir>
00026 #include <QApplication>
00027 #include <QProgressDialog>
00028 #include <QHttpResponseHeader>
00029 
00030 #include <iostream>
00031 
00032 #define DEBUG_FILE_SOURCE 1
00033 
00034 int
00035 FileSource::m_count = 0;
00036 
00037 QMutex
00038 FileSource::m_fileCreationMutex;
00039 
00040 FileSource::RemoteRefCountMap
00041 FileSource::m_refCountMap;
00042 
00043 FileSource::RemoteLocalMap
00044 FileSource::m_remoteLocalMap;
00045 
00046 QMutex
00047 FileSource::m_mapMutex;
00048 
00049 FileSource::FileSource(QString fileOrUrl, ShowProgressType progressType) :
00050     m_url(fileOrUrl),
00051     m_ftp(0),
00052     m_http(0),
00053     m_localFile(0),
00054     m_ok(false),
00055     m_lastStatus(0),
00056     m_remote(isRemote(fileOrUrl)),
00057     m_done(false),
00058     m_leaveLocalFile(false),
00059     m_progressType(progressType),
00060     m_progressPrinter(0),
00061     m_progressDialog(0),
00062     m_progressShowTimer(this),
00063     m_refCounted(false)
00064 {
00065 #ifdef DEBUG_FILE_SOURCE
00066     std::cerr << "FileSource::FileSource(" << fileOrUrl.toStdString() << ")" << std::endl;
00067 #endif
00068 
00069     if (!canHandleScheme(m_url)) {
00070         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
00071         m_errorString = tr("Unsupported scheme in URL");
00072         return;
00073     }
00074 
00075     init();
00076 
00077     if (isRemote() &&
00078         (fileOrUrl.contains('%') ||
00079          fileOrUrl.contains("--"))) { // for IDNA
00080 
00081         waitForStatus();
00082 
00083         if (!isAvailable()) {
00084 
00085             // The URL was created on the assumption that the string
00086             // was human-readable.  Let's try again, this time
00087             // assuming it was already encoded.
00088             std::cerr << "FileSource::FileSource: Failed to retrieve URL \""
00089                       << fileOrUrl.toStdString() 
00090                       << "\" as human-readable URL; "
00091                       << "trying again treating it as encoded URL"
00092                       << std::endl;
00093 
00094             // even though our cache file doesn't exist (because the
00095             // resource was 404), we still need to ensure we're no
00096             // longer associating a filename with this url in the
00097             // refcount map -- or createCacheFile will think we've
00098             // already done all the work and no request will be sent
00099             deleteCacheFile();
00100 
00101             m_url.setEncodedUrl(fileOrUrl.toAscii());
00102 
00103             m_ok = false;
00104             m_done = false;
00105             m_lastStatus = 0;
00106             init();
00107         }
00108     }
00109 
00110     if (!isRemote()) {
00111         emit statusAvailable();
00112         emit ready();
00113     }
00114 }
00115 
00116 FileSource::FileSource(QUrl url, ShowProgressType progressType) :
00117     m_url(url),
00118     m_ftp(0),
00119     m_http(0),
00120     m_localFile(0),
00121     m_ok(false),
00122     m_lastStatus(0),
00123     m_remote(isRemote(url.toString())),
00124     m_done(false),
00125     m_leaveLocalFile(false),
00126     m_progressType(progressType),
00127     m_progressPrinter(0),
00128     m_progressDialog(0),
00129     m_progressShowTimer(this),
00130     m_refCounted(false)
00131 {
00132 #ifdef DEBUG_FILE_SOURCE
00133     std::cerr << "FileSource::FileSource(" << url.toString().toStdString() << ") [as url]" << std::endl;
00134 #endif
00135 
00136     if (!canHandleScheme(m_url)) {
00137         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
00138         m_errorString = tr("Unsupported scheme in URL");
00139         return;
00140     }
00141 
00142     init();
00143 }
00144 
00145 FileSource::FileSource(const FileSource &rf) :
00146     QObject(),
00147     m_url(rf.m_url),
00148     m_ftp(0),
00149     m_http(0),
00150     m_localFile(0),
00151     m_ok(rf.m_ok),
00152     m_lastStatus(rf.m_lastStatus),
00153     m_remote(rf.m_remote),
00154     m_done(false),
00155     m_leaveLocalFile(false),
00156     m_progressType(rf.m_progressType),
00157     m_progressPrinter(0),
00158     m_progressDialog(0),
00159     m_progressShowTimer(0),
00160     m_refCounted(false)
00161 {
00162 #ifdef DEBUG_FILE_SOURCE
00163     std::cerr << "FileSource::FileSource(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl;
00164 #endif
00165 
00166     if (!canHandleScheme(m_url)) {
00167         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
00168         m_errorString = tr("Unsupported scheme in URL");
00169         return;
00170     }
00171 
00172     if (!isRemote()) {
00173         m_localFilename = rf.m_localFilename;
00174     } else {
00175         QMutexLocker locker(&m_mapMutex);
00176 #ifdef DEBUG_FILE_SOURCE
00177         std::cerr << "FileSource::FileSource(copy ctor): ref count is "
00178                   << m_refCountMap[m_url] << std::endl;
00179 #endif
00180         if (m_refCountMap[m_url] > 0) {
00181             m_refCountMap[m_url]++;
00182 #ifdef DEBUG_FILE_SOURCE
00183             std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
00184 #endif
00185             m_localFilename = m_remoteLocalMap[m_url];
00186             m_refCounted = true;
00187         } else {
00188             m_ok = false;
00189             m_lastStatus = 404;
00190         }
00191     }
00192 
00193     m_done = true;
00194 }
00195 
00196 FileSource::~FileSource()
00197 {
00198 #ifdef DEBUG_FILE_SOURCE
00199     std::cerr << "FileSource(" << m_url.toString().toStdString() << ")::~FileSource" << std::endl;
00200 #endif
00201 
00202     cleanup();
00203 
00204     if (isRemote() && !m_leaveLocalFile) deleteCacheFile();
00205 }
00206 
00207 void
00208 FileSource::init()
00209 {
00210     if (!isRemote()) {
00211 #ifdef DEBUG_FILE_SOURCE
00212         std::cerr << "FileSource::init: Not a remote URL" << std::endl;
00213 #endif
00214         bool literal = false;
00215         m_localFilename = m_url.toLocalFile();
00216         if (m_localFilename == "") {
00217             // QUrl may have mishandled the scheme (e.g. in a DOS path)
00218             m_localFilename = m_url.toString();
00219             literal = true;
00220         }
00221 #ifdef DEBUG_FILE_SOURCE
00222         std::cerr << "FileSource::init: URL translates to local filename \""
00223                   << m_localFilename.toStdString() << "\"" << std::endl;
00224 #endif
00225         m_ok = true;
00226         m_lastStatus = 200;
00227 
00228         if (!QFileInfo(m_localFilename).exists()) {
00229             if (literal) {
00230                 m_lastStatus = 404;
00231             } else {
00232                 // Again, QUrl may have been mistreating us --
00233                 // e.g. dropping a part that looks like query data
00234                 m_localFilename = m_url.toString();
00235                 literal = true;
00236                 if (!QFileInfo(m_localFilename).exists()) {
00237                     m_lastStatus = 404;
00238                 }
00239             }
00240         }
00241 
00242         m_done = true;
00243         return;
00244     }
00245 
00246     if (createCacheFile()) {
00247 #ifdef DEBUG_FILE_SOURCE
00248         std::cerr << "FileSource::init: Already have this one" << std::endl;
00249 #endif
00250         m_ok = true;
00251         if (!QFileInfo(m_localFilename).exists()) {
00252             m_lastStatus = 404;
00253         } else {
00254             m_lastStatus = 200;
00255         }
00256         m_done = true;
00257         return;
00258     }
00259 
00260     if (m_localFilename == "") return;
00261     m_localFile = new QFile(m_localFilename);
00262     m_localFile->open(QFile::WriteOnly);
00263 
00264     QString scheme = m_url.scheme().toLower();
00265 
00266 #ifdef DEBUG_FILE_SOURCE
00267     std::cerr << "FileSource::init: Don't have local copy of \""
00268               << m_url.toString().toStdString() << "\", retrieving" << std::endl;
00269 #endif
00270 
00271     if (scheme == "http") {
00272         initHttp();
00273         std::cerr << "FileSource: initHttp succeeded" << std::endl;
00274     } else if (scheme == "ftp") {
00275         initFtp();
00276     } else {
00277         m_remote = false;
00278         m_ok = false;
00279     }
00280 
00281     if (m_ok) {
00282         
00283         QMutexLocker locker(&m_mapMutex);
00284 
00285         if (m_refCountMap[m_url] > 0) {
00286             // someone else has been doing the same thing at the same time,
00287             // but has got there first
00288             cleanup();
00289             m_refCountMap[m_url]++;
00290 #ifdef DEBUG_FILE_SOURCE
00291             std::cerr << "FileSource::init: Another FileSource has got there first, abandoning our download and using theirs" << std::endl;
00292 #endif
00293             m_localFilename = m_remoteLocalMap[m_url];
00294             m_refCounted = true;
00295             m_ok = true;
00296             if (!QFileInfo(m_localFilename).exists()) {
00297                 m_lastStatus = 404;
00298             }
00299             m_done = true;
00300             return;
00301         }
00302 
00303         m_remoteLocalMap[m_url] = m_localFilename;
00304         m_refCountMap[m_url]++;
00305         m_refCounted = true;
00306 
00307         switch (m_progressType) {
00308 
00309         case ProgressNone: break;
00310 
00311         case ProgressDialog:
00312             m_progressDialog = new QProgressDialog
00313                 (tr("Downloading %1...").arg(m_url.toString()),
00314                  tr("Cancel"), 0, 100);
00315             m_progressDialog->hide();
00316             connect(&m_progressShowTimer, SIGNAL(timeout()),
00317                     this, SLOT(showProgressDialog()));
00318             connect(m_progressDialog, SIGNAL(canceled()),
00319                     this, SLOT(cancelled()));
00320             m_progressShowTimer.setSingleShot(true);
00321             m_progressShowTimer.start(2000);
00322             break;
00323 
00324         case ProgressToConsole:
00325             m_progressPrinter = new ProgressPrinter(tr("Downloading..."));
00326             connect(this, SIGNAL(progress(int)),
00327                     m_progressPrinter, SLOT(progress(int)));
00328             break;
00329         }
00330     }
00331 }
00332 
00333 void
00334 FileSource::initHttp()
00335 {
00336     m_ok = true;
00337     m_http = new QHttp(m_url.host(), m_url.port(80));
00338     connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
00339     connect(m_http, SIGNAL(dataReadProgress(int, int)),
00340             this, SLOT(dataReadProgress(int, int)));
00341     connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
00342             this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &)));
00343 
00344     // I don't quite understand this.  url.path() returns a path
00345     // without percent encoding; for example, spaces appear as
00346     // literal spaces.  This generally won't work if sent to the
00347     // server directly.  You can retrieve a correctly encoded URL
00348     // from QUrl using url.toEncoded(), but that gives you the
00349     // whole URL; there doesn't seem to be any way to retrieve
00350     // only an encoded path.  Furthermore there doesn't seem to be
00351     // any way to convert a retrieved path into an encoded path
00352     // without explicitly specifying that you don't want the path
00353     // separators ("/") to be encoded.  (Besides being painful to
00354     // manage, I don't see how this can work correctly in any case
00355     // where a percent-encoded "/" is supposed to appear within a
00356     // path element?)  There also seems to be no way to retrieve
00357     // the path plus query string, i.e. everything that I need to
00358     // send to the HTTP server.  And no way for QHttp to take a
00359     // QUrl argument.  I'm obviously missing something.
00360 
00361     // So, two ways to do this: query the bits from the URL,
00362     // encode them individually, and glue them back together
00363     // again...
00364 /*
00365     QString path = QUrl::toPercentEncoding(m_url.path(), "/");
00366     QList<QPair<QString, QString> > query = m_url.queryItems();
00367     if (!query.empty()) {
00368         QStringList q2;
00369         for (QList<QPair<QString, QString> >::iterator i = query.begin();
00370              i != query.end(); ++i) {
00371             q2.push_back(QString("%1=%3")
00372                          .arg(QString(QUrl::toPercentEncoding(i->first)))
00373                          .arg(QString(QUrl::toPercentEncoding(i->second))));
00374         }
00375         path = QString("%1%2%3")
00376             .arg(path).arg("?")
00377             .arg(q2.join("&"));
00378     }
00379 */
00380 
00381     // ...or, much simpler but relying on knowledge about the
00382     // scheme://host/path/path/query etc format of the URL, we can
00383     // get the whole URL ready-encoded and then split it on "/" as
00384     // appropriate...
00385         
00386     QString path = "/" + QString(m_url.toEncoded()).section('/', 3);
00387 
00388 #ifdef DEBUG_FILE_SOURCE
00389     std::cerr << "FileSource: path is \""
00390               << path.toStdString() << "\"" << std::endl;
00391 #endif
00392         
00393     m_http->get(path, m_localFile);
00394 }
00395 
00396 void
00397 FileSource::initFtp()
00398 {
00399     m_ok = true;
00400     m_ftp = new QFtp;
00401     connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
00402     connect(m_ftp, SIGNAL(commandFinished(int, bool)),
00403             this, SLOT(ftpCommandFinished(int, bool)));
00404     connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
00405             this, SLOT(dataTransferProgress(qint64, qint64)));
00406     m_ftp->connectToHost(m_url.host(), m_url.port(21));
00407     
00408     QString username = m_url.userName();
00409     if (username == "") {
00410         username = "anonymous";
00411     }
00412     
00413     QString password = m_url.password();
00414     if (password == "") {
00415         password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
00416     }
00417     
00418     m_ftp->login(username, password);
00419     
00420     QString dirpath = m_url.path().section('/', 0, -2);
00421     QString filename = m_url.path().section('/', -1);
00422     
00423     if (dirpath == "") dirpath = "/";
00424     m_ftp->cd(dirpath);
00425     m_ftp->get(filename, m_localFile);
00426 }
00427 
00428 void
00429 FileSource::cleanup()
00430 {
00431     m_done = true;
00432     if (m_http) {
00433         QHttp *h = m_http;
00434         m_http = 0;
00435         h->abort();
00436         h->deleteLater();
00437     }
00438     if (m_ftp) {
00439         QFtp *f = m_ftp;
00440         m_ftp = 0;
00441         f->abort();
00442         f->deleteLater();
00443     }
00444     delete m_progressDialog;
00445     m_progressDialog = 0;
00446     delete m_progressPrinter;
00447     m_progressPrinter = 0;
00448     delete m_localFile; // does not actually delete the file
00449     m_localFile = 0;
00450 }
00451 
00452 bool
00453 FileSource::isRemote(QString fileOrUrl)
00454 {
00455     // Note that a "scheme" with length 1 is probably a DOS drive letter
00456     QString scheme = QUrl(fileOrUrl).scheme().toLower();
00457     if (scheme == "" || scheme == "file" || scheme.length() == 1) return false;
00458     return true;
00459 }
00460 
00461 bool
00462 FileSource::canHandleScheme(QUrl url)
00463 {
00464     // Note that a "scheme" with length 1 is probably a DOS drive letter
00465     QString scheme = url.scheme().toLower();
00466     return (scheme == "http" || scheme == "ftp" ||
00467             scheme == "file" || scheme == "" || scheme.length() == 1);
00468 }
00469 
00470 bool
00471 FileSource::isAvailable()
00472 {
00473     waitForStatus();
00474     bool available = true;
00475     if (!m_ok) available = false;
00476     else available = (m_lastStatus / 100 == 2);
00477 #ifdef DEBUG_FILE_SOURCE
00478     std::cerr << "FileSource::isAvailable: " << (available ? "yes" : "no")
00479               << std::endl;
00480 #endif
00481     return available;
00482 }
00483 
00484 void
00485 FileSource::waitForStatus()
00486 {
00487     while (m_ok && (!m_done && m_lastStatus == 0)) {
00488 //        std::cerr << "waitForStatus: processing (last status " << m_lastStatus << ")" << std::endl;
00489         QApplication::processEvents();
00490     }
00491 }
00492 
00493 void
00494 FileSource::waitForData()
00495 {
00496     while (m_ok && !m_done) {
00497 //        std::cerr << "FileSource::waitForData: calling QApplication::processEvents" << std::endl;
00498         QApplication::processEvents();
00499     }
00500 }
00501 
00502 void
00503 FileSource::setLeaveLocalFile(bool leave)
00504 {
00505     m_leaveLocalFile = leave;
00506 }
00507 
00508 bool
00509 FileSource::isOK() const
00510 {
00511     return m_ok;
00512 }
00513 
00514 bool
00515 FileSource::isDone() const
00516 {
00517     return m_done;
00518 }
00519 
00520 bool
00521 FileSource::isRemote() const
00522 {
00523     return m_remote;
00524 }
00525 
00526 QString
00527 FileSource::getLocation() const
00528 {
00529     return m_url.toString();
00530 }
00531 
00532 QString
00533 FileSource::getLocalFilename() const
00534 {
00535     return m_localFilename;
00536 }
00537 
00538 QString
00539 FileSource::getContentType() const
00540 {
00541     return m_contentType;
00542 }
00543 
00544 QString
00545 FileSource::getExtension() const
00546 {
00547     if (m_localFilename != "") {
00548         return QFileInfo(m_localFilename).suffix().toLower();
00549     } else {
00550         return QFileInfo(m_url.toLocalFile()).suffix().toLower();
00551     }
00552 }
00553 
00554 QString
00555 FileSource::getErrorString() const
00556 {
00557     return m_errorString;
00558 }
00559 
00560 void
00561 FileSource::dataReadProgress(int done, int total)
00562 {
00563     dataTransferProgress(done, total);
00564 }
00565 
00566 void
00567 FileSource::httpResponseHeaderReceived(const QHttpResponseHeader &resp)
00568 {
00569     m_lastStatus = resp.statusCode();
00570     if (m_lastStatus / 100 >= 4) {
00571         m_errorString = QString("%1 %2")
00572             .arg(resp.statusCode()).arg(resp.reasonPhrase());
00573 #ifdef DEBUG_FILE_SOURCE
00574         std::cerr << "FileSource::responseHeaderReceived: "
00575                   << m_errorString.toStdString() << std::endl;
00576 #endif
00577     } else {
00578 #ifdef DEBUG_FILE_SOURCE
00579         std::cerr << "FileSource::responseHeaderReceived: "
00580                   << m_lastStatus << std::endl;
00581 #endif
00582         if (resp.hasContentType()) m_contentType = resp.contentType();
00583     }
00584     emit statusAvailable();
00585 }
00586 
00587 void
00588 FileSource::ftpCommandFinished(int id, bool error)
00589 {
00590 #ifdef DEBUG_FILE_SOURCE
00591     std::cerr << "FileSource::ftpCommandFinished(" << id << ", " << error << ")" << std::endl;
00592 #endif
00593 
00594     if (!m_ftp) return;
00595 
00596     QFtp::Command command = m_ftp->currentCommand();
00597 
00598     if (!error) {
00599 #ifdef DEBUG_FILE_SOURCE
00600         std::cerr << "FileSource::ftpCommandFinished: success for command "
00601                   << command << std::endl;
00602 #endif
00603         return;
00604     }
00605 
00606     if (command == QFtp::ConnectToHost) {
00607         m_errorString = tr("Failed to connect to FTP server");
00608     } else if (command == QFtp::Login) {
00609         m_errorString = tr("Login failed");
00610     } else if (command == QFtp::Cd) {
00611         m_errorString = tr("Failed to change to correct directory");
00612     } else if (command == QFtp::Get) {
00613         m_errorString = tr("FTP download aborted");
00614     }
00615 
00616     m_lastStatus = 400; // for done()
00617 }
00618 
00619 void
00620 FileSource::dataTransferProgress(qint64 done, qint64 total)
00621 {
00622     int percent = int((double(done) / double(total)) * 100.0 - 0.1);
00623     emit progress(percent);
00624 
00625     if (!m_progressDialog) return;
00626 
00627     if (percent > 0) {
00628         m_progressDialog->setValue(percent);
00629         m_progressDialog->show();
00630     }
00631 }
00632 
00633 void
00634 FileSource::cancelled()
00635 {
00636     m_done = true;
00637     cleanup();
00638 
00639     m_ok = false;
00640     m_errorString = tr("Download cancelled");
00641 }
00642 
00643 void
00644 FileSource::done(bool error)
00645 {
00646     emit progress(100);
00647 
00648 #ifdef DEBUG_FILE_SOURCE
00649     std::cerr << "FileSource::done(" << error << ")" << std::endl;
00650 #endif
00651 
00652     if (m_done) return;
00653 
00654     if (error) {
00655         if (m_http) {
00656             m_errorString = m_http->errorString();
00657         } else if (m_ftp) {
00658             m_errorString = m_ftp->errorString();
00659         }
00660     }
00661 
00662     if (m_lastStatus / 100 >= 4) {
00663         error = true;
00664     }
00665 
00666     cleanup();
00667 
00668     if (!error) {
00669         QFileInfo fi(m_localFilename);
00670         if (!fi.exists()) {
00671             m_errorString = tr("Failed to create local file %1").arg(m_localFilename);
00672             error = true;
00673         } else if (fi.size() == 0) {
00674             m_errorString = tr("File contains no data!");
00675             error = true;
00676         }
00677     }
00678 
00679     if (error) {
00680 #ifdef DEBUG_FILE_SOURCE
00681         std::cerr << "FileSource::done: error is " << error << ", deleting cache file" << std::endl;
00682 #endif
00683         deleteCacheFile();
00684     }
00685 
00686     m_ok = !error;
00687     m_done = true;
00688     emit ready();
00689 }
00690 
00691 void
00692 FileSource::deleteCacheFile()
00693 {
00694 #ifdef DEBUG_FILE_SOURCE
00695     std::cerr << "FileSource::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl;
00696 #endif
00697 
00698     cleanup();
00699 
00700     if (m_localFilename == "") {
00701         return;
00702     }
00703 
00704     if (!isRemote()) {
00705 #ifdef DEBUG_FILE_SOURCE
00706         std::cerr << "not a cache file" << std::endl;
00707 #endif
00708         return;
00709     }
00710 
00711     if (m_refCounted) {
00712 
00713         QMutexLocker locker(&m_mapMutex);
00714         m_refCounted = false;
00715 
00716         if (m_refCountMap[m_url] > 0) {
00717             m_refCountMap[m_url]--;
00718 #ifdef DEBUG_FILE_SOURCE
00719             std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl;
00720 #endif
00721             if (m_refCountMap[m_url] > 0) {
00722                 m_done = true;
00723                 return;
00724             }
00725         }
00726     }
00727 
00728     m_fileCreationMutex.lock();
00729 
00730     if (!QFile(m_localFilename).remove()) {
00731 #ifdef DEBUG_FILE_SOURCE
00732         std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl;
00733 #endif
00734     } else {
00735 #ifdef DEBUG_FILE_SOURCE
00736         std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl;
00737 #endif
00738         m_localFilename = "";
00739     }
00740 
00741     m_fileCreationMutex.unlock();
00742 
00743     m_done = true;
00744 }
00745 
00746 void
00747 FileSource::showProgressDialog()
00748 {
00749     if (m_progressDialog) m_progressDialog->show();
00750 }
00751 
00752 bool
00753 FileSource::createCacheFile()
00754 {
00755     {
00756         QMutexLocker locker(&m_mapMutex);
00757 
00758 #ifdef DEBUG_FILE_SOURCE
00759         std::cerr << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl;
00760 #endif
00761 
00762         if (m_refCountMap[m_url] > 0) {
00763             m_refCountMap[m_url]++;
00764             m_localFilename = m_remoteLocalMap[m_url];
00765 #ifdef DEBUG_FILE_SOURCE
00766             std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
00767 #endif
00768             m_refCounted = true;
00769             return true;
00770         }
00771     }
00772 
00773     QDir dir;
00774     try {
00775         dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
00776     } catch (DirectoryCreationFailed f) {
00777 #ifdef DEBUG_FILE_SOURCE
00778         std::cerr << "FileSource::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;
00779 #endif
00780         return "";
00781     }
00782 
00783     QString filepart = m_url.path().section('/', -1, -1,
00784                                             QString::SectionSkipEmpty);
00785 
00786     QString extension = filepart.section('.', -1);
00787     QString base = filepart;
00788     if (extension != "") {
00789         base = base.left(base.length() - extension.length() - 1);
00790     }
00791     if (base == "") base = "remote";
00792 
00793     QString filename;
00794 
00795     if (extension == "") {
00796         filename = base;
00797     } else {
00798         filename = QString("%1.%2").arg(base).arg(extension);
00799     }
00800 
00801     QString filepath(dir.filePath(filename));
00802 
00803 #ifdef DEBUG_FILE_SOURCE
00804     std::cerr << "FileSource::createCacheFile: URL is \"" << m_url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl;
00805 #endif
00806 
00807     QMutexLocker fcLocker(&m_fileCreationMutex);
00808 
00809     ++m_count;
00810 
00811     if (QFileInfo(filepath).exists() ||
00812         !QFile(filepath).open(QFile::WriteOnly)) {
00813 
00814 #ifdef DEBUG_FILE_SOURCE
00815         std::cerr << "FileSource::createCacheFile: Failed to create local file \""
00816                   << filepath.toStdString() << "\" for URL \""
00817                   << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl;
00818 #endif
00819 
00820         if (extension == "") {
00821             filename = QString("%1_%2").arg(base).arg(m_count);
00822         } else {
00823             filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension);
00824         }
00825         filepath = dir.filePath(filename);
00826 
00827         if (QFileInfo(filepath).exists() ||
00828             !QFile(filepath).open(QFile::WriteOnly)) {
00829 
00830 #ifdef DEBUG_FILE_SOURCE
00831             std::cerr << "FileSource::createCacheFile: ERROR: Failed to create local file \""
00832                       << filepath.toStdString() << "\" for URL \""
00833                       << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl;
00834 #endif
00835 
00836             return "";
00837         }
00838     }
00839 
00840 #ifdef DEBUG_FILE_SOURCE
00841     std::cerr << "FileSource::createCacheFile: url "
00842               << m_url.toString().toStdString() << " -> local filename "
00843               << filepath.toStdString() << std::endl;
00844 #endif
00845     
00846     m_localFilename = filepath;
00847 
00848     return false;
00849 }
00850 

Generated on Wed Feb 20 15:45:25 2008 for SonicVisualiser by  doxygen 1.5.1