comparison data/fileio/FileSource.cpp @ 706:579b2da21e7a

Make FileSource capable of handling resource files. Without this, we failed to open the silent resource file used as a placeholder in templates and thus failed to replace it with the proper file after loading the template -- the consequence was that (although the right audio file ended up being shown as the main model) any derived models were not regenerated
author Chris Cannam
date Fri, 07 Oct 2011 17:04:09 +0100
parents 1424aa29ae95
children 3b2409646cc0
comparison
equal deleted inserted replaced
705:66de0ad10bb3 706:579b2da21e7a
75 m_http(0), 75 m_http(0),
76 m_localFile(0), 76 m_localFile(0),
77 m_preferredContentType(preferredContentType), 77 m_preferredContentType(preferredContentType),
78 m_ok(false), 78 m_ok(false),
79 m_lastStatus(0), 79 m_lastStatus(0),
80 m_resource(fileOrUrl.startsWith(':')),
80 m_remote(isRemote(fileOrUrl)), 81 m_remote(isRemote(fileOrUrl)),
81 m_done(false), 82 m_done(false),
82 m_leaveLocalFile(false), 83 m_leaveLocalFile(false),
83 m_reporter(reporter), 84 m_reporter(reporter),
84 m_refCounted(false) 85 m_refCounted(false)
85 { 86 {
87 if (m_resource) { // qrc file
88 m_url = QUrl("qrc" + fileOrUrl);
89 }
90
86 if (m_url.toString() == "") { 91 if (m_url.toString() == "") {
87 m_url = QUrl(fileOrUrl, QUrl::TolerantMode); 92 m_url = QUrl(fileOrUrl, QUrl::TolerantMode);
88 } 93 }
89 94
90 #ifdef DEBUG_FILE_SOURCE 95 #ifdef DEBUG_FILE_SOURCE
91 SVDEBUG << "FileSource::FileSource(" << fileOrUrl << "): url <" << m_url.toString() << ">" << endl; 96 std::cerr << "FileSource::FileSource(" << fileOrUrl << "): url <" << m_url.toString() << ">" << std::endl;
92 incCount(m_url.toString()); 97 incCount(m_url.toString());
93 #endif 98 #endif
94 99
95 if (!canHandleScheme(m_url)) { 100 if (!canHandleScheme(m_url)) {
96 SVDEBUG << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << endl; 101 SVDEBUG << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString() << "\"" << endl;
101 init(); 106 init();
102 107
103 if (!isRemote() && 108 if (!isRemote() &&
104 !isAvailable()) { 109 !isAvailable()) {
105 #ifdef DEBUG_FILE_SOURCE 110 #ifdef DEBUG_FILE_SOURCE
106 std::cerr << "FileSource::FileSource: Failed to open local file with URL \"" << m_url.toString() << "; trying again assuming filename was encoded" << std::endl; 111 std::cerr << "FileSource::FileSource: Failed to open local file with URL \"" << m_url.toString() << "\"; trying again assuming filename was encoded" << std::endl;
107 #endif 112 #endif
108 m_url = QUrl::fromEncoded(fileOrUrl.toAscii()); 113 m_url = QUrl::fromEncoded(fileOrUrl.toAscii());
109 init(); 114 init();
110 } 115 }
111 116
157 m_ftp(0), 162 m_ftp(0),
158 m_http(0), 163 m_http(0),
159 m_localFile(0), 164 m_localFile(0),
160 m_ok(false), 165 m_ok(false),
161 m_lastStatus(0), 166 m_lastStatus(0),
167 m_resource(false),
162 m_remote(isRemote(url.toString())), 168 m_remote(isRemote(url.toString())),
163 m_done(false), 169 m_done(false),
164 m_leaveLocalFile(false), 170 m_leaveLocalFile(false),
165 m_reporter(reporter), 171 m_reporter(reporter),
166 m_refCounted(false) 172 m_refCounted(false)
189 m_ftp(0), 195 m_ftp(0),
190 m_http(0), 196 m_http(0),
191 m_localFile(0), 197 m_localFile(0),
192 m_ok(rf.m_ok), 198 m_ok(rf.m_ok),
193 m_lastStatus(rf.m_lastStatus), 199 m_lastStatus(rf.m_lastStatus),
200 m_resource(rf.m_resource),
194 m_remote(rf.m_remote), 201 m_remote(rf.m_remote),
195 m_done(false), 202 m_done(false),
196 m_leaveLocalFile(false), 203 m_leaveLocalFile(false),
197 m_reporter(rf.m_reporter), 204 m_reporter(rf.m_reporter),
198 m_refCounted(false) 205 m_refCounted(false)
253 } 260 }
254 261
255 void 262 void
256 FileSource::init() 263 FileSource::init()
257 { 264 {
258 if (!isRemote()) { 265 if (isResource()) {
259 #ifdef DEBUG_FILE_SOURCE 266 #ifdef DEBUG_FILE_SOURCE
260 SVDEBUG << "FileSource::init: Not a remote URL" << endl; 267 std::cerr << "FileSource::init: Is a resource" << std::endl;
268 #endif
269 QString resourceFile = m_url.toString();
270 resourceFile.replace(QRegExp("^qrc:"), ":");
271
272 if (!QFileInfo(resourceFile).exists()) {
273 #ifdef DEBUG_FILE_SOURCE
274 std::cerr << "FileSource::init: Resource file of this name does not exist, switching to non-resource URL" << std::endl;
275 #endif
276 m_url = resourceFile;
277 m_resource = false;
278 }
279 }
280
281 if (!isRemote() && !isResource()) {
282 #ifdef DEBUG_FILE_SOURCE
283 std::cerr << "FileSource::init: Not a remote URL" << std::endl;
261 #endif 284 #endif
262 bool literal = false; 285 bool literal = false;
263 m_localFilename = m_url.toLocalFile(); 286 m_localFilename = m_url.toLocalFile();
264 if (m_localFilename == "") { 287 if (m_localFilename == "") {
265 // QUrl may have mishandled the scheme (e.g. in a DOS path) 288 // QUrl may have mishandled the scheme (e.g. in a DOS path)
267 literal = true; 290 literal = true;
268 } 291 }
269 m_localFilename = QFileInfo(m_localFilename).absoluteFilePath(); 292 m_localFilename = QFileInfo(m_localFilename).absoluteFilePath();
270 293
271 #ifdef DEBUG_FILE_SOURCE 294 #ifdef DEBUG_FILE_SOURCE
272 SVDEBUG << "FileSource::init: URL translates to local filename \"" 295 std::cerr << "FileSource::init: URL translates to local filename \""
273 << m_localFilename << "\" (with literal=" << literal << ")" << endl; 296 << m_localFilename << "\" (with literal=" << literal << ")"
297 << std::endl;
274 #endif 298 #endif
275 m_ok = true; 299 m_ok = true;
276 m_lastStatus = 200; 300 m_lastStatus = 200;
277 301
278 if (!QFileInfo(m_localFilename).exists()) { 302 if (!QFileInfo(m_localFilename).exists()) {
279 if (literal) { 303 if (literal) {
280 m_lastStatus = 404; 304 m_lastStatus = 404;
281 } else { 305 } else {
282 #ifdef DEBUG_FILE_SOURCE 306 #ifdef DEBUG_FILE_SOURCE
283 SVDEBUG << "FileSource::init: Local file of this name does not exist, trying URL as a literal filename" << endl; 307 std::cerr << "FileSource::init: Local file of this name does not exist, trying URL as a literal filename" << std::endl;
284 #endif 308 #endif
285 // Again, QUrl may have been mistreating us -- 309 // Again, QUrl may have been mistreating us --
286 // e.g. dropping a part that looks like query data 310 // e.g. dropping a part that looks like query data
287 m_localFilename = m_url.toString(); 311 m_localFilename = m_url.toString();
288 literal = true; 312 literal = true;
296 return; 320 return;
297 } 321 }
298 322
299 if (createCacheFile()) { 323 if (createCacheFile()) {
300 #ifdef DEBUG_FILE_SOURCE 324 #ifdef DEBUG_FILE_SOURCE
301 SVDEBUG << "FileSource::init: Already have this one" << endl; 325 std::cerr << "FileSource::init: Already have this one" << std::endl;
302 #endif 326 #endif
303 m_ok = true; 327 m_ok = true;
304 if (!QFileInfo(m_localFilename).exists()) { 328 if (!QFileInfo(m_localFilename).exists()) {
305 m_lastStatus = 404; 329 m_lastStatus = 404;
306 } else { 330 } else {
309 m_done = true; 333 m_done = true;
310 return; 334 return;
311 } 335 }
312 336
313 if (m_localFilename == "") return; 337 if (m_localFilename == "") return;
338
314 m_localFile = new QFile(m_localFilename); 339 m_localFile = new QFile(m_localFilename);
315 m_localFile->open(QFile::WriteOnly); 340 m_localFile->open(QFile::WriteOnly);
316 341
317 QString scheme = m_url.scheme().toLower(); 342 if (isResource()) {
318 343
319 #ifdef DEBUG_FILE_SOURCE 344 // Absent resource file case was dealt with at the top -- this
320 SVDEBUG << "FileSource::init: Don't have local copy of \"" 345 // is the successful case
321 << m_url.toString() << "\", retrieving" << endl; 346
322 #endif 347 QString resourceFileName = m_url.toString();
323 348 resourceFileName.replace(QRegExp("^qrc:"), ":");
324 if (scheme == "http") { 349 QFile resourceFile(resourceFileName);
325 initHttp(); 350 resourceFile.open(QFile::ReadOnly);
326 #ifdef DEBUG_FILE_SOURCE 351 QByteArray ba(resourceFile.readAll());
327 std::cerr << "FileSource: initHttp succeeded" << std::endl; 352
328 #endif 353 #ifdef DEBUG_FILE_SOURCE
329 } else if (scheme == "ftp") { 354 std::cerr << "Copying " << ba.size() << " bytes from resource file to cache file" << std::endl;
330 initFtp(); 355 #endif
356
357 qint64 written = m_localFile->write(ba);
358 m_localFile->close();
359 delete m_localFile;
360 m_localFile = 0;
361
362 if (written != ba.size()) {
363 #ifdef DEBUG_FILE_SOURCE
364 std::cerr << "Copy failed (wrote " << written << " bytes)" << std::endl;
365 #endif
366 m_ok = false;
367 return;
368 } else {
369 m_ok = true;
370 m_lastStatus = 200;
371 m_done = true;
372 }
373
331 } else { 374 } else {
332 m_remote = false; 375
333 m_ok = false; 376 QString scheme = m_url.scheme().toLower();
377
378 #ifdef DEBUG_FILE_SOURCE
379 std::cerr << "FileSource::init: Don't have local copy of \""
380 << m_url.toString() << "\", retrieving" << std::endl;
381 #endif
382
383 if (scheme == "http") {
384 initHttp();
385 #ifdef DEBUG_FILE_SOURCE
386 std::cerr << "FileSource: initHttp succeeded" << std::endl;
387 #endif
388 } else if (scheme == "ftp") {
389 initFtp();
390 } else {
391 m_remote = false;
392 m_ok = false;
393 }
334 } 394 }
335 395
336 if (m_ok) { 396 if (m_ok) {
337 397
338 QMutexLocker locker(&m_mapMutex); 398 QMutexLocker locker(&m_mapMutex);
341 // someone else has been doing the same thing at the same time, 401 // someone else has been doing the same thing at the same time,
342 // but has got there first 402 // but has got there first
343 cleanup(); 403 cleanup();
344 m_refCountMap[m_url]++; 404 m_refCountMap[m_url]++;
345 #ifdef DEBUG_FILE_SOURCE 405 #ifdef DEBUG_FILE_SOURCE
346 SVDEBUG << "FileSource::init: Another FileSource has got there first, abandoning our download and using theirs" << endl; 406 std::cerr << "FileSource::init: Another FileSource has got there first, abandoning our download and using theirs" << std::endl;
347 #endif 407 #endif
348 m_localFilename = m_remoteLocalMap[m_url]; 408 m_localFilename = m_remoteLocalMap[m_url];
349 m_refCounted = true; 409 m_refCounted = true;
350 m_ok = true; 410 m_ok = true;
351 if (!QFileInfo(m_localFilename).exists()) { 411 if (!QFileInfo(m_localFilename).exists()) {
357 417
358 m_remoteLocalMap[m_url] = m_localFilename; 418 m_remoteLocalMap[m_url] = m_localFilename;
359 m_refCountMap[m_url]++; 419 m_refCountMap[m_url]++;
360 m_refCounted = true; 420 m_refCounted = true;
361 421
362 if (m_reporter) { 422 if (m_reporter && !m_done) {
363 m_reporter->setMessage 423 m_reporter->setMessage
364 (tr("Downloading %1...").arg(m_url.toString())); 424 (tr("Downloading %1...").arg(m_url.toString()));
365 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); 425 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
366 connect(this, SIGNAL(progress(int)), 426 connect(this, SIGNAL(progress(int)),
367 m_reporter, SLOT(setProgress(int))); 427 m_reporter, SLOT(setProgress(int)));
515 FileSource::canHandleScheme(QUrl url) 575 FileSource::canHandleScheme(QUrl url)
516 { 576 {
517 // Note that a "scheme" with length 1 is probably a DOS drive letter 577 // Note that a "scheme" with length 1 is probably a DOS drive letter
518 QString scheme = url.scheme().toLower(); 578 QString scheme = url.scheme().toLower();
519 return (scheme == "http" || scheme == "ftp" || 579 return (scheme == "http" || scheme == "ftp" ||
520 scheme == "file" || scheme == "" || scheme.length() == 1); 580 scheme == "file" || scheme == "qrc" ||
581 scheme == "" || scheme.length() == 1);
521 } 582 }
522 583
523 bool 584 bool
524 FileSource::isAvailable() 585 FileSource::isAvailable()
525 { 586 {
567 628
568 bool 629 bool
569 FileSource::isDone() const 630 FileSource::isDone() const
570 { 631 {
571 return m_done; 632 return m_done;
633 }
634
635 bool
636 FileSource::isResource() const
637 {
638 return m_resource;
572 } 639 }
573 640
574 bool 641 bool
575 FileSource::isRemote() const 642 FileSource::isRemote() const
576 { 643 {
879 } 946 }
880 947
881 QString filepath(dir.filePath(filename)); 948 QString filepath(dir.filePath(filename));
882 949
883 #ifdef DEBUG_FILE_SOURCE 950 #ifdef DEBUG_FILE_SOURCE
884 SVDEBUG << "FileSource::createCacheFile: URL is \"" << m_url.toString() << "\", dir is \"" << dir.path() << "\", base \"" << base << "\", extension \"" << extension << "\", filebase \"" << filename << "\", filename \"" << filepath << "\"" << endl; 951 std::cerr << "FileSource::createCacheFile: URL is \"" << m_url.toString() << "\", dir is \"" << dir.path() << "\", base \"" << base << "\", extension \"" << extension << "\", filebase \"" << filename << "\", filename \"" << filepath << "\"" << std::endl;
885 #endif 952 #endif
886 953
887 QMutexLocker fcLocker(&m_fileCreationMutex); 954 QMutexLocker fcLocker(&m_fileCreationMutex);
888 955
889 ++m_count; 956 ++m_count;
916 return ""; 983 return "";
917 } 984 }
918 } 985 }
919 986
920 #ifdef DEBUG_FILE_SOURCE 987 #ifdef DEBUG_FILE_SOURCE
921 SVDEBUG << "FileSource::createCacheFile: url " 988 std::cerr << "FileSource::createCacheFile: url "
922 << m_url.toString() << " -> local filename " 989 << m_url.toString() << " -> local filename "
923 << filepath << endl; 990 << filepath << std::endl;
924 #endif 991 #endif
925 992
926 m_localFilename = filepath; 993 m_localFilename = filepath;
927 994
928 return false; 995 return false;