comparison data/fileio/RemoteFile.cpp @ 316:3a6725f285d6

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 96ef9746c560
children
comparison
equal deleted inserted replaced
315:96ef9746c560 316:3a6725f285d6
40 RemoteFile::m_remoteLocalMap; 40 RemoteFile::m_remoteLocalMap;
41 41
42 QMutex 42 QMutex
43 RemoteFile::m_mapMutex; 43 RemoteFile::m_mapMutex;
44 44
45 RemoteFile::RemoteFile(QUrl url) : 45 RemoteFile::RemoteFile(QString fileOrUrl, bool showProgress) :
46 m_url(fileOrUrl),
47 m_ftp(0),
48 m_http(0),
49 m_localFile(0),
50 m_ok(false),
51 m_lastStatus(0),
52 m_remote(isRemote(fileOrUrl)),
53 m_done(false),
54 m_leaveLocalFile(false),
55 m_progressDialog(0),
56 m_progressShowTimer(this),
57 m_refCounted(false)
58 {
59 std::cerr << "RemoteFile::RemoteFile(" << fileOrUrl.toStdString() << ")" << std::endl;
60
61 if (!canHandleScheme(m_url)) {
62 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
63 m_errorString = tr("Unsupported scheme in URL");
64 return;
65 }
66
67 init(showProgress);
68
69 if (isRemote() &&
70 (fileOrUrl.contains('%') ||
71 fileOrUrl.contains("--"))) { // for IDNA
72
73 waitForStatus();
74
75 if (!isAvailable()) {
76 // The URL was created on the assumption that the string
77 // was human-readable. Let's try again, this time
78 // assuming it was already encoded.
79 std::cerr << "RemoteFile::RemoteFile: Failed to retrieve URL \""
80 << fileOrUrl.toStdString()
81 << "\" as human-readable URL; "
82 << "trying again treating it as encoded URL"
83 << std::endl;
84 m_url.setEncodedUrl(fileOrUrl.toAscii());
85 init(showProgress);
86 }
87 }
88 }
89
90 RemoteFile::RemoteFile(QUrl url, bool showProgress) :
46 m_url(url), 91 m_url(url),
47 m_ftp(0), 92 m_ftp(0),
48 m_http(0), 93 m_http(0),
49 m_localFile(0), 94 m_localFile(0),
50 m_ok(false), 95 m_ok(false),
51 m_lastStatus(0), 96 m_lastStatus(0),
97 m_remote(isRemote(url.toString())),
52 m_done(false), 98 m_done(false),
99 m_leaveLocalFile(false),
53 m_progressDialog(0), 100 m_progressDialog(0),
54 m_progressShowTimer(this), 101 m_progressShowTimer(this),
55 m_referenced(false) 102 m_refCounted(false)
56 { 103 {
57 if (!canHandleScheme(url)) { 104 std::cerr << "RemoteFile::RemoteFile(" << url.toString().toStdString() << ") [as url]" << std::endl;
58 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl; 105
106 if (!canHandleScheme(m_url)) {
107 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
108 m_errorString = tr("Unsupported scheme in URL");
59 return; 109 return;
60 } 110 }
61 111
62 QMutexLocker locker(&m_mapMutex); 112 init(showProgress);
63 113 }
64 std::cerr << "RemoteFile::RemoteFile: refcount is " << m_refCountMap[m_url] << std::endl; 114
65 115 RemoteFile::RemoteFile(const RemoteFile &rf) :
66 if (m_refCountMap[m_url] > 0) { 116 QObject(),
67 m_refCountMap[m_url]++; 117 m_url(rf.m_url),
68 m_localFilename = m_remoteLocalMap[m_url]; 118 m_ftp(0),
69 std::cerr << "raising it" << std::endl; 119 m_http(0),
120 m_localFile(0),
121 m_ok(rf.m_ok),
122 m_lastStatus(rf.m_lastStatus),
123 m_remote(rf.m_remote),
124 m_done(false),
125 m_leaveLocalFile(false),
126 m_progressDialog(0),
127 m_progressShowTimer(0),
128 m_refCounted(false)
129 {
130 std::cerr << "RemoteFile::RemoteFile(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl;
131
132 if (!canHandleScheme(m_url)) {
133 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
134 m_errorString = tr("Unsupported scheme in URL");
135 return;
136 }
137
138 if (!isRemote()) {
139 m_localFilename = rf.m_localFilename;
140 } else {
141 QMutexLocker locker(&m_mapMutex);
142 std::cerr << "RemoteFile::RemoteFile(copy ctor): ref count is "
143 << m_refCountMap[m_url] << std::endl;
144 if (m_refCountMap[m_url] > 0) {
145 m_refCountMap[m_url]++;
146 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
147 m_localFilename = m_remoteLocalMap[m_url];
148 m_refCounted = true;
149 } else {
150 m_ok = false;
151 m_lastStatus = 404;
152 }
153 }
154
155 m_done = true;
156 }
157
158 RemoteFile::~RemoteFile()
159 {
160 std::cerr << "RemoteFile(" << m_url.toString().toStdString() << ")::~RemoteFile" << std::endl;
161
162 cleanup();
163
164 if (isRemote() && !m_leaveLocalFile) deleteCacheFile();
165 }
166
167 void
168 RemoteFile::init(bool showProgress)
169 {
170 if (!isRemote()) {
171 m_localFilename = m_url.toLocalFile();
70 m_ok = true; 172 m_ok = true;
173 if (!QFileInfo(m_localFilename).exists()) {
174 m_lastStatus = 404;
175 } else {
176 m_lastStatus = 200;
177 }
71 m_done = true; 178 m_done = true;
72 m_referenced = true;
73 return; 179 return;
74 } 180 }
75 181
76 m_localFilename = createLocalFile(url); 182 if (createCacheFile()) {
183 std::cerr << "RemoteFile::init: Already have this one" << std::endl;
184 m_ok = true;
185 if (!QFileInfo(m_localFilename).exists()) {
186 m_lastStatus = 404;
187 } else {
188 m_lastStatus = 200;
189 }
190 m_done = true;
191 return;
192 }
193
77 if (m_localFilename == "") return; 194 if (m_localFilename == "") return;
78 m_localFile = new QFile(m_localFilename); 195 m_localFile = new QFile(m_localFilename);
79 m_localFile->open(QFile::WriteOnly); 196 m_localFile->open(QFile::WriteOnly);
80 197
81 QString scheme = url.scheme().toLower(); 198 QString scheme = m_url.scheme().toLower();
199
200 std::cerr << "RemoteFile::init: Don't have local copy of \""
201 << m_url.toString().toStdString() << "\", retrieving" << std::endl;
82 202
83 if (scheme == "http") { 203 if (scheme == "http") {
84 204 initHttp();
85 m_ok = true; 205 } else if (scheme == "ftp") {
86 m_http = new QHttp(url.host(), url.port(80)); 206 initFtp();
87 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); 207 } else {
88 connect(m_http, SIGNAL(dataReadProgress(int, int)), 208 m_remote = false;
89 this, SLOT(dataReadProgress(int, int))); 209 m_ok = false;
90 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), 210 }
91 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); 211
92 212 if (m_ok) {
93 // I don't quite understand this. url.path() returns a path 213
94 // without percent encoding; for example, spaces appear as 214 QMutexLocker locker(&m_mapMutex);
95 // literal spaces. This generally won't work if sent to the 215
96 // server directly. You can retrieve a correctly encoded URL 216 if (m_refCountMap[m_url] > 0) {
97 // from QUrl using url.toEncoded(), but that gives you the 217 // someone else has been doing the same thing at the same time,
98 // whole URL; there doesn't seem to be any way to retrieve 218 // but has got there first
99 // only an encoded path. Furthermore there doesn't seem to be 219 cleanup();
100 // any way to convert a retrieved path into an encoded path 220 m_refCountMap[m_url]++;
101 // without explicitly specifying that you don't want the path 221 std::cerr << "RemoteFile::init: Another RemoteFile has got there first, abandoning our download and using theirs" << std::endl;
102 // separators ("/") to be encoded. (Besides being painful to 222 m_localFilename = m_remoteLocalMap[m_url];
103 // manage, I don't see how this can work correctly in any case 223 m_refCounted = true;
104 // where a percent-encoded "/" is supposed to appear within a 224 m_ok = true;
105 // path element?) There also seems to be no way to retrieve 225 if (!QFileInfo(m_localFilename).exists()) {
106 // the path plus query string, i.e. everything that I need to 226 m_lastStatus = 404;
107 // send to the HTTP server. And no way for QHttp to take a
108 // QUrl argument. I'm obviously missing something.
109
110 // So, two ways to do this: query the bits from the URL,
111 // encode them individually, and glue them back together
112 // again...
113 /*
114 QString path = QUrl::toPercentEncoding(url.path(), "/");
115 QList<QPair<QString, QString> > query = url.queryItems();
116 if (!query.empty()) {
117 QStringList q2;
118 for (QList<QPair<QString, QString> >::iterator i = query.begin();
119 i != query.end(); ++i) {
120 q2.push_back(QString("%1=%3")
121 .arg(QString(QUrl::toPercentEncoding(i->first)))
122 .arg(QString(QUrl::toPercentEncoding(i->second))));
123 } 227 }
124 path = QString("%1%2%3") 228 m_done = true;
125 .arg(path).arg("?") 229 return;
126 .arg(q2.join("&")); 230 }
127 }
128 */
129
130 // ...or, much simpler but relying on knowledge about the
131 // scheme://host/path/path/query etc format of the URL, we can
132 // get the whole URL ready-encoded and then split it on "/" as
133 // appropriate...
134
135 QString path = "/" + QString(url.toEncoded()).section('/', 3);
136
137 std::cerr << "RemoteFile: path is \""
138 << path.toStdString() << "\"" << std::endl;
139
140 m_http->get(path, m_localFile);
141
142 } else if (scheme == "ftp") {
143
144 m_ok = true;
145 m_ftp = new QFtp;
146 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
147 connect(m_ftp, SIGNAL(commandFinished(int, bool)),
148 this, SLOT(ftpCommandFinished(int, bool)));
149 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
150 this, SLOT(dataTransferProgress(qint64, qint64)));
151 m_ftp->connectToHost(url.host(), url.port(21));
152
153 QString username = url.userName();
154 if (username == "") {
155 username = "anonymous";
156 }
157
158 QString password = url.password();
159 if (password == "") {
160 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
161 }
162
163 m_ftp->login(username, password);
164
165 QString dirpath = url.path().section('/', 0, -2);
166 QString filename = url.path().section('/', -1);
167
168 if (dirpath == "") dirpath = "/";
169 m_ftp->cd(dirpath);
170 m_ftp->get(filename, m_localFile);
171 }
172
173 if (m_ok) {
174 231
175 m_remoteLocalMap[m_url] = m_localFilename; 232 m_remoteLocalMap[m_url] = m_localFilename;
176 m_refCountMap[m_url]++; 233 m_refCountMap[m_url]++;
177 m_referenced = true; 234 m_refCounted = true;
178 235
179 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); 236 if (showProgress) {
180 m_progressDialog->hide(); 237 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100);
181 connect(&m_progressShowTimer, SIGNAL(timeout()), 238 m_progressDialog->hide();
182 this, SLOT(showProgressDialog())); 239 connect(&m_progressShowTimer, SIGNAL(timeout()),
183 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); 240 this, SLOT(showProgressDialog()));
184 m_progressShowTimer.setSingleShot(true); 241 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled()));
185 m_progressShowTimer.start(2000); 242 m_progressShowTimer.setSingleShot(true);
186 } 243 m_progressShowTimer.start(2000);
187 } 244 }
188 245 }
189 RemoteFile::~RemoteFile() 246 }
190 { 247
191 cleanup(); 248 void
249 RemoteFile::initHttp()
250 {
251 m_ok = true;
252 m_http = new QHttp(m_url.host(), m_url.port(80));
253 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
254 connect(m_http, SIGNAL(dataReadProgress(int, int)),
255 this, SLOT(dataReadProgress(int, int)));
256 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
257 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &)));
258
259 // I don't quite understand this. url.path() returns a path
260 // without percent encoding; for example, spaces appear as
261 // literal spaces. This generally won't work if sent to the
262 // server directly. You can retrieve a correctly encoded URL
263 // from QUrl using url.toEncoded(), but that gives you the
264 // whole URL; there doesn't seem to be any way to retrieve
265 // only an encoded path. Furthermore there doesn't seem to be
266 // any way to convert a retrieved path into an encoded path
267 // without explicitly specifying that you don't want the path
268 // separators ("/") to be encoded. (Besides being painful to
269 // manage, I don't see how this can work correctly in any case
270 // where a percent-encoded "/" is supposed to appear within a
271 // path element?) There also seems to be no way to retrieve
272 // the path plus query string, i.e. everything that I need to
273 // send to the HTTP server. And no way for QHttp to take a
274 // QUrl argument. I'm obviously missing something.
275
276 // So, two ways to do this: query the bits from the URL,
277 // encode them individually, and glue them back together
278 // again...
279 /*
280 QString path = QUrl::toPercentEncoding(m_url.path(), "/");
281 QList<QPair<QString, QString> > query = m_url.queryItems();
282 if (!query.empty()) {
283 QStringList q2;
284 for (QList<QPair<QString, QString> >::iterator i = query.begin();
285 i != query.end(); ++i) {
286 q2.push_back(QString("%1=%3")
287 .arg(QString(QUrl::toPercentEncoding(i->first)))
288 .arg(QString(QUrl::toPercentEncoding(i->second))));
289 }
290 path = QString("%1%2%3")
291 .arg(path).arg("?")
292 .arg(q2.join("&"));
293 }
294 */
295
296 // ...or, much simpler but relying on knowledge about the
297 // scheme://host/path/path/query etc format of the URL, we can
298 // get the whole URL ready-encoded and then split it on "/" as
299 // appropriate...
300
301 QString path = "/" + QString(m_url.toEncoded()).section('/', 3);
302
303 std::cerr << "RemoteFile: path is \""
304 << path.toStdString() << "\"" << std::endl;
305
306 m_http->get(path, m_localFile);
307 }
308
309 void
310 RemoteFile::initFtp()
311 {
312 m_ok = true;
313 m_ftp = new QFtp;
314 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
315 connect(m_ftp, SIGNAL(commandFinished(int, bool)),
316 this, SLOT(ftpCommandFinished(int, bool)));
317 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
318 this, SLOT(dataTransferProgress(qint64, qint64)));
319 m_ftp->connectToHost(m_url.host(), m_url.port(21));
320
321 QString username = m_url.userName();
322 if (username == "") {
323 username = "anonymous";
324 }
325
326 QString password = m_url.password();
327 if (password == "") {
328 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
329 }
330
331 m_ftp->login(username, password);
332
333 QString dirpath = m_url.path().section('/', 0, -2);
334 QString filename = m_url.path().section('/', -1);
335
336 if (dirpath == "") dirpath = "/";
337 m_ftp->cd(dirpath);
338 m_ftp->get(filename, m_localFile);
192 } 339 }
193 340
194 void 341 void
195 RemoteFile::cleanup() 342 RemoteFile::cleanup()
196 { 343 {
214 } 361 }
215 362
216 bool 363 bool
217 RemoteFile::isRemote(QString fileOrUrl) 364 RemoteFile::isRemote(QString fileOrUrl)
218 { 365 {
219 return (fileOrUrl.startsWith("http:") || fileOrUrl.startsWith("ftp:")); 366 QString scheme = QUrl(fileOrUrl).scheme().toLower();
367 return (scheme == "http" || scheme == "ftp");
220 } 368 }
221 369
222 bool 370 bool
223 RemoteFile::canHandleScheme(QUrl url) 371 RemoteFile::canHandleScheme(QUrl url)
224 { 372 {
225 QString scheme = url.scheme().toLower(); 373 QString scheme = url.scheme().toLower();
226 return (scheme == "http" || scheme == "ftp"); 374 return (scheme == "http" || scheme == "ftp" ||
375 scheme == "file" || scheme == "");
227 } 376 }
228 377
229 bool 378 bool
230 RemoteFile::isAvailable() 379 RemoteFile::isAvailable()
231 { 380 {
232 while (m_ok && (!m_done && m_lastStatus == 0)) { 381 waitForStatus();
233 QApplication::processEvents();
234 }
235 bool available = true; 382 bool available = true;
236 if (!m_ok) available = false; 383 if (!m_ok) available = false;
237 else available = (m_lastStatus / 100 == 2); 384 else available = (m_lastStatus / 100 == 2);
238 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no") 385 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no")
239 << std::endl; 386 << std::endl;
240 return available; 387 return available;
241 } 388 }
242 389
243 void 390 void
244 RemoteFile::wait() 391 RemoteFile::waitForStatus()
392 {
393 while (m_ok && (!m_done && m_lastStatus == 0)) {
394 // std::cerr << "waitForStatus: processing (last status " << m_lastStatus << ")" << std::endl;
395 QApplication::processEvents();
396 }
397 }
398
399 void
400 RemoteFile::waitForData()
245 { 401 {
246 while (m_ok && !m_done) { 402 while (m_ok && !m_done) {
247 QApplication::processEvents(); 403 QApplication::processEvents();
248 } 404 }
249 } 405 }
250 406
407 void
408 RemoteFile::setLeaveLocalFile(bool leave)
409 {
410 m_leaveLocalFile = leave;
411 }
412
251 bool 413 bool
252 RemoteFile::isOK() const 414 RemoteFile::isOK() const
253 { 415 {
254 return m_ok; 416 return m_ok;
255 } 417 }
258 RemoteFile::isDone() const 420 RemoteFile::isDone() const
259 { 421 {
260 return m_done; 422 return m_done;
261 } 423 }
262 424
425 bool
426 RemoteFile::isRemote() const
427 {
428 return m_remote;
429 }
430
431 QString
432 RemoteFile::getLocation() const
433 {
434 return m_url.toString();
435 }
436
263 QString 437 QString
264 RemoteFile::getLocalFilename() const 438 RemoteFile::getLocalFilename() const
265 { 439 {
266 return m_localFilename; 440 return m_localFilename;
441 }
442
443 QString
444 RemoteFile::getContentType() const
445 {
446 return m_contentType;
447 }
448
449 QString
450 RemoteFile::getExtension() const
451 {
452 if (m_localFilename != "") {
453 return QFileInfo(m_localFilename).suffix().toLower();
454 } else {
455 return QFileInfo(m_url.toLocalFile()).suffix().toLower();
456 }
267 } 457 }
268 458
269 QString 459 QString
270 RemoteFile::getErrorString() const 460 RemoteFile::getErrorString() const
271 { 461 {
337 } 527 }
338 528
339 void 529 void
340 RemoteFile::cancelled() 530 RemoteFile::cancelled()
341 { 531 {
342 deleteLocalFile();
343 m_done = true; 532 m_done = true;
533 cleanup();
534
344 m_ok = false; 535 m_ok = false;
345 m_errorString = tr("Download cancelled"); 536 m_errorString = tr("Download cancelled");
346 } 537 }
347 538
348 void 539 void
378 error = true; 569 error = true;
379 } 570 }
380 } 571 }
381 572
382 if (error) { 573 if (error) {
383 deleteLocalFile(); 574 std::cerr << "RemoteFile::done: error is " << error << ", deleting cache file" << std::endl;
575 deleteCacheFile();
384 } 576 }
385 577
386 m_ok = !error; 578 m_ok = !error;
387 m_done = true; 579 m_done = true;
388 emit ready(); 580 emit ready();
389 } 581 }
390 582
391 void 583 void
392 RemoteFile::deleteLocalFile() 584 RemoteFile::deleteCacheFile()
393 { 585 {
394 // std::cerr << "RemoteFile::deleteLocalFile" << std::endl; 586 std::cerr << "RemoteFile::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl;
395 587
396 cleanup(); 588 cleanup();
397 589
398 if (m_localFilename == "") return; 590 if (m_localFilename == "") {
399 591 return;
400 if (m_referenced) { 592 }
593
594 if (!isRemote()) {
595 std::cerr << "not a cache file" << std::endl;
596 return;
597 }
598
599 if (m_refCounted) {
401 600
402 QMutexLocker locker(&m_mapMutex); 601 QMutexLocker locker(&m_mapMutex);
403 m_referenced = false; 602 m_refCounted = false;
404 603
405 if (m_refCountMap[m_url] > 0) { 604 if (m_refCountMap[m_url] > 0) {
406 m_refCountMap[m_url]--; 605 m_refCountMap[m_url]--;
606 std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl;
407 if (m_refCountMap[m_url] > 0) { 607 if (m_refCountMap[m_url] > 0) {
408 m_done = true; 608 m_done = true;
409 return; 609 return;
410 } 610 }
411 } 611 }
412 } 612 }
413 613
414 m_fileCreationMutex.lock(); 614 m_fileCreationMutex.lock();
415 615
416 if (!QFile(m_localFilename).remove()) { 616 if (!QFile(m_localFilename).remove()) {
417 std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; 617 std::cerr << "RemoteFile::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl;
418 } else { 618 } else {
619 std::cerr << "RemoteFile::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl;
419 m_localFilename = ""; 620 m_localFilename = "";
420 } 621 }
421 622
422 m_fileCreationMutex.unlock(); 623 m_fileCreationMutex.unlock();
423 624
428 RemoteFile::showProgressDialog() 629 RemoteFile::showProgressDialog()
429 { 630 {
430 if (m_progressDialog) m_progressDialog->show(); 631 if (m_progressDialog) m_progressDialog->show();
431 } 632 }
432 633
433 QString 634 bool
434 RemoteFile::createLocalFile(QUrl url) 635 RemoteFile::createCacheFile()
435 { 636 {
637 {
638 QMutexLocker locker(&m_mapMutex);
639
640 std::cerr << "RemoteFile::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl;
641
642 if (m_refCountMap[m_url] > 0) {
643 m_refCountMap[m_url]++;
644 m_localFilename = m_remoteLocalMap[m_url];
645 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
646 m_refCounted = true;
647 return true;
648 }
649 }
650
436 QDir dir; 651 QDir dir;
437 try { 652 try {
438 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); 653 dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
439 } catch (DirectoryCreationFailed f) { 654 } catch (DirectoryCreationFailed f) {
440 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; 655 std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;
441 return ""; 656 return "";
442 } 657 }
443 658
444 QString filepart = url.path().section('/', -1, -1, 659 QString filepart = m_url.path().section('/', -1, -1,
445 QString::SectionSkipEmpty); 660 QString::SectionSkipEmpty);
446 661
447 QString extension = filepart.section('.', -1); 662 QString extension = filepart.section('.', -1);
448 QString base = filepart; 663 QString base = filepart;
449 if (extension != "") { 664 if (extension != "") {
450 base = base.left(base.length() - extension.length() - 1); 665 base = base.left(base.length() - extension.length() - 1);
459 filename = QString("%1.%2").arg(base).arg(extension); 674 filename = QString("%1.%2").arg(base).arg(extension);
460 } 675 }
461 676
462 QString filepath(dir.filePath(filename)); 677 QString filepath(dir.filePath(filename));
463 678
464 std::cerr << "RemoteFile::createLocalFile: URL is \"" << url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl; 679 std::cerr << "RemoteFile::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;
465 680
466 m_fileCreationMutex.lock(); 681 QMutexLocker fcLocker(&m_fileCreationMutex);
682
467 ++m_count; 683 ++m_count;
468 684
469 if (QFileInfo(filepath).exists() || 685 if (QFileInfo(filepath).exists() ||
470 !QFile(filepath).open(QFile::WriteOnly)) { 686 !QFile(filepath).open(QFile::WriteOnly)) {
471 687
472 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \"" 688 std::cerr << "RemoteFile::createCacheFile: Failed to create local file \""
473 << filepath.toStdString() << "\" for URL \"" 689 << filepath.toStdString() << "\" for URL \""
474 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; 690 << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl;
475 691
476 692
477 if (extension == "") { 693 if (extension == "") {
478 filename = QString("%1_%2").arg(base).arg(m_count); 694 filename = QString("%1_%2").arg(base).arg(m_count);
479 } else { 695 } else {
482 filepath = dir.filePath(filename); 698 filepath = dir.filePath(filename);
483 699
484 if (QFileInfo(filepath).exists() || 700 if (QFileInfo(filepath).exists() ||
485 !QFile(filepath).open(QFile::WriteOnly)) { 701 !QFile(filepath).open(QFile::WriteOnly)) {
486 702
487 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \"" 703 std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create local file \""
488 << filepath.toStdString() << "\" for URL \"" 704 << filepath.toStdString() << "\" for URL \""
489 << url.toString().toStdString() << "\" (or file already exists)" << std::endl; 705 << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl;
490 706
491 m_fileCreationMutex.unlock();
492 return ""; 707 return "";
493 } 708 }
494 } 709 }
495 710
496 m_fileCreationMutex.unlock(); 711 std::cerr << "RemoteFile::createCacheFile: url "
497 712 << m_url.toString().toStdString() << " -> local filename "
498 std::cerr << "RemoteFile::createLocalFile: url "
499 << url.toString().toStdString() << " -> local filename "
500 << filepath.toStdString() << std::endl; 713 << filepath.toStdString() << std::endl;
501 714
502 return filepath; 715 m_localFilename = filepath;
503 } 716
717 return false;
718 }