Mercurial > hg > svcore
comparison data/fileio/FileSource.cpp @ 317:c324d410b096
* RemoteFile -> FileSource
now it's used all over the place for local files as well.
author | Chris Cannam |
---|---|
date | Thu, 18 Oct 2007 16:20:26 +0000 |
parents | data/fileio/RemoteFile.cpp@3a6725f285d6 |
children | 82a2d3161e14 |
comparison
equal
deleted
inserted
replaced
316:3a6725f285d6 | 317:c324d410b096 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2007 QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "FileSource.h" | |
17 #include "base/TempDirectory.h" | |
18 #include "base/Exceptions.h" | |
19 | |
20 #include <QHttp> | |
21 #include <QFtp> | |
22 #include <QFileInfo> | |
23 #include <QDir> | |
24 #include <QApplication> | |
25 #include <QProgressDialog> | |
26 #include <QHttpResponseHeader> | |
27 | |
28 #include <iostream> | |
29 | |
30 int | |
31 FileSource::m_count = 0; | |
32 | |
33 QMutex | |
34 FileSource::m_fileCreationMutex; | |
35 | |
36 FileSource::RemoteRefCountMap | |
37 FileSource::m_refCountMap; | |
38 | |
39 FileSource::RemoteLocalMap | |
40 FileSource::m_remoteLocalMap; | |
41 | |
42 QMutex | |
43 FileSource::m_mapMutex; | |
44 | |
45 FileSource::FileSource(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 << "FileSource::FileSource(" << fileOrUrl.toStdString() << ")" << std::endl; | |
60 | |
61 if (!canHandleScheme(m_url)) { | |
62 std::cerr << "FileSource::FileSource: 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 << "FileSource::FileSource: 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 FileSource::FileSource(QUrl url, bool showProgress) : | |
91 m_url(url), | |
92 m_ftp(0), | |
93 m_http(0), | |
94 m_localFile(0), | |
95 m_ok(false), | |
96 m_lastStatus(0), | |
97 m_remote(isRemote(url.toString())), | |
98 m_done(false), | |
99 m_leaveLocalFile(false), | |
100 m_progressDialog(0), | |
101 m_progressShowTimer(this), | |
102 m_refCounted(false) | |
103 { | |
104 std::cerr << "FileSource::FileSource(" << url.toString().toStdString() << ") [as url]" << std::endl; | |
105 | |
106 if (!canHandleScheme(m_url)) { | |
107 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | |
108 m_errorString = tr("Unsupported scheme in URL"); | |
109 return; | |
110 } | |
111 | |
112 init(showProgress); | |
113 } | |
114 | |
115 FileSource::FileSource(const FileSource &rf) : | |
116 QObject(), | |
117 m_url(rf.m_url), | |
118 m_ftp(0), | |
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 << "FileSource::FileSource(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl; | |
131 | |
132 if (!canHandleScheme(m_url)) { | |
133 std::cerr << "FileSource::FileSource: 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 << "FileSource::FileSource(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 FileSource::~FileSource() | |
159 { | |
160 std::cerr << "FileSource(" << m_url.toString().toStdString() << ")::~FileSource" << std::endl; | |
161 | |
162 cleanup(); | |
163 | |
164 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); | |
165 } | |
166 | |
167 void | |
168 FileSource::init(bool showProgress) | |
169 { | |
170 if (!isRemote()) { | |
171 m_localFilename = m_url.toLocalFile(); | |
172 m_ok = true; | |
173 if (!QFileInfo(m_localFilename).exists()) { | |
174 m_lastStatus = 404; | |
175 } else { | |
176 m_lastStatus = 200; | |
177 } | |
178 m_done = true; | |
179 return; | |
180 } | |
181 | |
182 if (createCacheFile()) { | |
183 std::cerr << "FileSource::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 | |
194 if (m_localFilename == "") return; | |
195 m_localFile = new QFile(m_localFilename); | |
196 m_localFile->open(QFile::WriteOnly); | |
197 | |
198 QString scheme = m_url.scheme().toLower(); | |
199 | |
200 std::cerr << "FileSource::init: Don't have local copy of \"" | |
201 << m_url.toString().toStdString() << "\", retrieving" << std::endl; | |
202 | |
203 if (scheme == "http") { | |
204 initHttp(); | |
205 } else if (scheme == "ftp") { | |
206 initFtp(); | |
207 } else { | |
208 m_remote = false; | |
209 m_ok = false; | |
210 } | |
211 | |
212 if (m_ok) { | |
213 | |
214 QMutexLocker locker(&m_mapMutex); | |
215 | |
216 if (m_refCountMap[m_url] > 0) { | |
217 // someone else has been doing the same thing at the same time, | |
218 // but has got there first | |
219 cleanup(); | |
220 m_refCountMap[m_url]++; | |
221 std::cerr << "FileSource::init: Another FileSource has got there first, abandoning our download and using theirs" << std::endl; | |
222 m_localFilename = m_remoteLocalMap[m_url]; | |
223 m_refCounted = true; | |
224 m_ok = true; | |
225 if (!QFileInfo(m_localFilename).exists()) { | |
226 m_lastStatus = 404; | |
227 } | |
228 m_done = true; | |
229 return; | |
230 } | |
231 | |
232 m_remoteLocalMap[m_url] = m_localFilename; | |
233 m_refCountMap[m_url]++; | |
234 m_refCounted = true; | |
235 | |
236 if (showProgress) { | |
237 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100); | |
238 m_progressDialog->hide(); | |
239 connect(&m_progressShowTimer, SIGNAL(timeout()), | |
240 this, SLOT(showProgressDialog())); | |
241 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); | |
242 m_progressShowTimer.setSingleShot(true); | |
243 m_progressShowTimer.start(2000); | |
244 } | |
245 } | |
246 } | |
247 | |
248 void | |
249 FileSource::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 << "FileSource: path is \"" | |
304 << path.toStdString() << "\"" << std::endl; | |
305 | |
306 m_http->get(path, m_localFile); | |
307 } | |
308 | |
309 void | |
310 FileSource::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); | |
339 } | |
340 | |
341 void | |
342 FileSource::cleanup() | |
343 { | |
344 m_done = true; | |
345 if (m_http) { | |
346 QHttp *h = m_http; | |
347 m_http = 0; | |
348 h->abort(); | |
349 h->deleteLater(); | |
350 } | |
351 if (m_ftp) { | |
352 QFtp *f = m_ftp; | |
353 m_ftp = 0; | |
354 f->abort(); | |
355 f->deleteLater(); | |
356 } | |
357 delete m_progressDialog; | |
358 m_progressDialog = 0; | |
359 delete m_localFile; // does not actually delete the file | |
360 m_localFile = 0; | |
361 } | |
362 | |
363 bool | |
364 FileSource::isRemote(QString fileOrUrl) | |
365 { | |
366 QString scheme = QUrl(fileOrUrl).scheme().toLower(); | |
367 return (scheme == "http" || scheme == "ftp"); | |
368 } | |
369 | |
370 bool | |
371 FileSource::canHandleScheme(QUrl url) | |
372 { | |
373 QString scheme = url.scheme().toLower(); | |
374 return (scheme == "http" || scheme == "ftp" || | |
375 scheme == "file" || scheme == ""); | |
376 } | |
377 | |
378 bool | |
379 FileSource::isAvailable() | |
380 { | |
381 waitForStatus(); | |
382 bool available = true; | |
383 if (!m_ok) available = false; | |
384 else available = (m_lastStatus / 100 == 2); | |
385 std::cerr << "FileSource::isAvailable: " << (available ? "yes" : "no") | |
386 << std::endl; | |
387 return available; | |
388 } | |
389 | |
390 void | |
391 FileSource::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 FileSource::waitForData() | |
401 { | |
402 while (m_ok && !m_done) { | |
403 QApplication::processEvents(); | |
404 } | |
405 } | |
406 | |
407 void | |
408 FileSource::setLeaveLocalFile(bool leave) | |
409 { | |
410 m_leaveLocalFile = leave; | |
411 } | |
412 | |
413 bool | |
414 FileSource::isOK() const | |
415 { | |
416 return m_ok; | |
417 } | |
418 | |
419 bool | |
420 FileSource::isDone() const | |
421 { | |
422 return m_done; | |
423 } | |
424 | |
425 bool | |
426 FileSource::isRemote() const | |
427 { | |
428 return m_remote; | |
429 } | |
430 | |
431 QString | |
432 FileSource::getLocation() const | |
433 { | |
434 return m_url.toString(); | |
435 } | |
436 | |
437 QString | |
438 FileSource::getLocalFilename() const | |
439 { | |
440 return m_localFilename; | |
441 } | |
442 | |
443 QString | |
444 FileSource::getContentType() const | |
445 { | |
446 return m_contentType; | |
447 } | |
448 | |
449 QString | |
450 FileSource::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 } | |
457 } | |
458 | |
459 QString | |
460 FileSource::getErrorString() const | |
461 { | |
462 return m_errorString; | |
463 } | |
464 | |
465 void | |
466 FileSource::dataReadProgress(int done, int total) | |
467 { | |
468 dataTransferProgress(done, total); | |
469 } | |
470 | |
471 void | |
472 FileSource::httpResponseHeaderReceived(const QHttpResponseHeader &resp) | |
473 { | |
474 m_lastStatus = resp.statusCode(); | |
475 if (m_lastStatus / 100 >= 4) { | |
476 m_errorString = QString("%1 %2") | |
477 .arg(resp.statusCode()).arg(resp.reasonPhrase()); | |
478 std::cerr << "FileSource::responseHeaderReceived: " | |
479 << m_errorString.toStdString() << std::endl; | |
480 } else { | |
481 std::cerr << "FileSource::responseHeaderReceived: " | |
482 << m_lastStatus << std::endl; | |
483 if (resp.hasContentType()) m_contentType = resp.contentType(); | |
484 } | |
485 } | |
486 | |
487 void | |
488 FileSource::ftpCommandFinished(int id, bool error) | |
489 { | |
490 std::cerr << "FileSource::ftpCommandFinished(" << id << ", " << error << ")" << std::endl; | |
491 | |
492 if (!m_ftp) return; | |
493 | |
494 QFtp::Command command = m_ftp->currentCommand(); | |
495 | |
496 if (!error) { | |
497 std::cerr << "FileSource::ftpCommandFinished: success for command " | |
498 << command << std::endl; | |
499 return; | |
500 } | |
501 | |
502 if (command == QFtp::ConnectToHost) { | |
503 m_errorString = tr("Failed to connect to FTP server"); | |
504 } else if (command == QFtp::Login) { | |
505 m_errorString = tr("Login failed"); | |
506 } else if (command == QFtp::Cd) { | |
507 m_errorString = tr("Failed to change to correct directory"); | |
508 } else if (command == QFtp::Get) { | |
509 m_errorString = tr("FTP download aborted"); | |
510 } | |
511 | |
512 m_lastStatus = 400; // for done() | |
513 } | |
514 | |
515 void | |
516 FileSource::dataTransferProgress(qint64 done, qint64 total) | |
517 { | |
518 if (!m_progressDialog) return; | |
519 | |
520 int percent = int((double(done) / double(total)) * 100.0 - 0.1); | |
521 emit progress(percent); | |
522 | |
523 if (percent > 0) { | |
524 m_progressDialog->setValue(percent); | |
525 m_progressDialog->show(); | |
526 } | |
527 } | |
528 | |
529 void | |
530 FileSource::cancelled() | |
531 { | |
532 m_done = true; | |
533 cleanup(); | |
534 | |
535 m_ok = false; | |
536 m_errorString = tr("Download cancelled"); | |
537 } | |
538 | |
539 void | |
540 FileSource::done(bool error) | |
541 { | |
542 std::cerr << "FileSource::done(" << error << ")" << std::endl; | |
543 | |
544 if (m_done) return; | |
545 | |
546 emit progress(100); | |
547 | |
548 if (error) { | |
549 if (m_http) { | |
550 m_errorString = m_http->errorString(); | |
551 } else if (m_ftp) { | |
552 m_errorString = m_ftp->errorString(); | |
553 } | |
554 } | |
555 | |
556 if (m_lastStatus / 100 >= 4) { | |
557 error = true; | |
558 } | |
559 | |
560 cleanup(); | |
561 | |
562 if (!error) { | |
563 QFileInfo fi(m_localFilename); | |
564 if (!fi.exists()) { | |
565 m_errorString = tr("Failed to create local file %1").arg(m_localFilename); | |
566 error = true; | |
567 } else if (fi.size() == 0) { | |
568 m_errorString = tr("File contains no data!"); | |
569 error = true; | |
570 } | |
571 } | |
572 | |
573 if (error) { | |
574 std::cerr << "FileSource::done: error is " << error << ", deleting cache file" << std::endl; | |
575 deleteCacheFile(); | |
576 } | |
577 | |
578 m_ok = !error; | |
579 m_done = true; | |
580 emit ready(); | |
581 } | |
582 | |
583 void | |
584 FileSource::deleteCacheFile() | |
585 { | |
586 std::cerr << "FileSource::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl; | |
587 | |
588 cleanup(); | |
589 | |
590 if (m_localFilename == "") { | |
591 return; | |
592 } | |
593 | |
594 if (!isRemote()) { | |
595 std::cerr << "not a cache file" << std::endl; | |
596 return; | |
597 } | |
598 | |
599 if (m_refCounted) { | |
600 | |
601 QMutexLocker locker(&m_mapMutex); | |
602 m_refCounted = false; | |
603 | |
604 if (m_refCountMap[m_url] > 0) { | |
605 m_refCountMap[m_url]--; | |
606 std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl; | |
607 if (m_refCountMap[m_url] > 0) { | |
608 m_done = true; | |
609 return; | |
610 } | |
611 } | |
612 } | |
613 | |
614 m_fileCreationMutex.lock(); | |
615 | |
616 if (!QFile(m_localFilename).remove()) { | |
617 std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; | |
618 } else { | |
619 std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl; | |
620 m_localFilename = ""; | |
621 } | |
622 | |
623 m_fileCreationMutex.unlock(); | |
624 | |
625 m_done = true; | |
626 } | |
627 | |
628 void | |
629 FileSource::showProgressDialog() | |
630 { | |
631 if (m_progressDialog) m_progressDialog->show(); | |
632 } | |
633 | |
634 bool | |
635 FileSource::createCacheFile() | |
636 { | |
637 { | |
638 QMutexLocker locker(&m_mapMutex); | |
639 | |
640 std::cerr << "FileSource::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 | |
651 QDir dir; | |
652 try { | |
653 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); | |
654 } catch (DirectoryCreationFailed f) { | |
655 std::cerr << "FileSource::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; | |
656 return ""; | |
657 } | |
658 | |
659 QString filepart = m_url.path().section('/', -1, -1, | |
660 QString::SectionSkipEmpty); | |
661 | |
662 QString extension = filepart.section('.', -1); | |
663 QString base = filepart; | |
664 if (extension != "") { | |
665 base = base.left(base.length() - extension.length() - 1); | |
666 } | |
667 if (base == "") base = "remote"; | |
668 | |
669 QString filename; | |
670 | |
671 if (extension == "") { | |
672 filename = base; | |
673 } else { | |
674 filename = QString("%1.%2").arg(base).arg(extension); | |
675 } | |
676 | |
677 QString filepath(dir.filePath(filename)); | |
678 | |
679 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; | |
680 | |
681 QMutexLocker fcLocker(&m_fileCreationMutex); | |
682 | |
683 ++m_count; | |
684 | |
685 if (QFileInfo(filepath).exists() || | |
686 !QFile(filepath).open(QFile::WriteOnly)) { | |
687 | |
688 std::cerr << "FileSource::createCacheFile: Failed to create local file \"" | |
689 << filepath.toStdString() << "\" for URL \"" | |
690 << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; | |
691 | |
692 | |
693 if (extension == "") { | |
694 filename = QString("%1_%2").arg(base).arg(m_count); | |
695 } else { | |
696 filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension); | |
697 } | |
698 filepath = dir.filePath(filename); | |
699 | |
700 if (QFileInfo(filepath).exists() || | |
701 !QFile(filepath).open(QFile::WriteOnly)) { | |
702 | |
703 std::cerr << "FileSource::createCacheFile: ERROR: Failed to create local file \"" | |
704 << filepath.toStdString() << "\" for URL \"" | |
705 << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl; | |
706 | |
707 return ""; | |
708 } | |
709 } | |
710 | |
711 std::cerr << "FileSource::createCacheFile: url " | |
712 << m_url.toString().toStdString() << " -> local filename " | |
713 << filepath.toStdString() << std::endl; | |
714 | |
715 m_localFilename = filepath; | |
716 | |
717 return false; | |
718 } |