Support 'file://' URLs also when saving
This commit is contained in:
parent
7efa7a0d5a
commit
3288d49d62
|
@ -69,7 +69,7 @@ void restoreOriginalFileFromBackupFile(
|
|||
}
|
||||
// remove original file and restore backup
|
||||
std::remove(originalPath.c_str());
|
||||
if (std::rename(backupPath.c_str(), originalPath.c_str())) {
|
||||
if (std::rename(BasicFileInfo::pathForOpen(backupPath), BasicFileInfo::pathForOpen(originalPath))) {
|
||||
// can't rename/move the file (maybe backup dir on another partition) -> make a copy instead
|
||||
try {
|
||||
// need to open all streams again
|
||||
|
@ -153,10 +153,10 @@ void createBackupFile(const std::string &backupDir, const std::string &originalP
|
|||
|
||||
// test whether the backup path is still unused; otherwise continue loop
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||
if (GetFileAttributes(BasicFileInfo::pathForOpen(backupPath)) == INVALID_FILE_ATTRIBUTES) {
|
||||
#else
|
||||
struct stat backupStat;
|
||||
if (stat(backupPath.c_str(), &backupStat)) {
|
||||
if (stat(BasicFileInfo::pathForOpen(backupPath), &backupStat)) {
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ void createBackupFile(const std::string &backupDir, const std::string &originalP
|
|||
}
|
||||
|
||||
// rename original file
|
||||
if (std::rename(originalPath.c_str(), backupPath.c_str())) {
|
||||
if (std::rename(BasicFileInfo::pathForOpen(originalPath), BasicFileInfo::pathForOpen(backupPath))) {
|
||||
// can't rename/move the file (maybe backup dir on another partition) -> make a copy instead
|
||||
try {
|
||||
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||
|
@ -177,9 +177,9 @@ void createBackupFile(const std::string &backupDir, const std::string &originalP
|
|||
if (backupStream.is_open()) {
|
||||
backupStream.close();
|
||||
}
|
||||
backupStream.open(backupPath, ios_base::out | ios_base::binary);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(backupPath), ios_base::out | ios_base::binary);
|
||||
// ensure originalStream is opened with read permissions
|
||||
originalStream.open(originalPath, ios_base::in | ios_base::binary);
|
||||
originalStream.open(BasicFileInfo::pathForOpen(originalPath), ios_base::in | ios_base::binary);
|
||||
// do the actual copying
|
||||
backupStream << originalStream.rdbuf();
|
||||
// streams are closed in the next try-block
|
||||
|
@ -201,11 +201,11 @@ void createBackupFile(const std::string &backupDir, const std::string &originalP
|
|||
}
|
||||
// open backup stream
|
||||
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||
backupStream.open(backupPath, ios_base::in | ios_base::binary);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(backupPath), ios_base::in | ios_base::binary);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
// can't open the new file
|
||||
// -> try to re-rename backup file in the error case to restore previous state
|
||||
if (std::rename(backupPath.c_str(), originalPath.c_str())) {
|
||||
if (std::rename(BasicFileInfo::pathForOpen(backupPath), BasicFileInfo::pathForOpen(originalPath))) {
|
||||
throw std::ios_base::failure("Unable to restore original file from backup file \"" % backupPath % "\" after failure: " + failure.what());
|
||||
} else {
|
||||
throw std::ios_base::failure(argsToString("Unable to open backup file: ", failure.what()));
|
||||
|
|
|
@ -59,8 +59,7 @@ void BasicFileInfo::open(bool readOnly)
|
|||
void BasicFileInfo::reopen(bool readOnly)
|
||||
{
|
||||
invalidated();
|
||||
m_file.open(startsWith(m_path, "file:/") ? m_path.data() + 6 : m_path.data(),
|
||||
(m_readOnly = readOnly) ? ios_base::in | ios_base::binary : ios_base::in | ios_base::out | ios_base::binary);
|
||||
m_file.open(pathForOpen(path()), (m_readOnly = readOnly) ? ios_base::in | ios_base::binary : ios_base::in | ios_base::out | ios_base::binary);
|
||||
m_file.seekg(0, ios_base::end);
|
||||
m_size = static_cast<std::uint64_t>(m_file.tellg());
|
||||
m_file.seekg(0, ios_base::beg);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "./global.h"
|
||||
|
||||
#include <c++utilities/conversion/stringconversion.h>
|
||||
#include <c++utilities/io/nativefilestream.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -20,7 +21,7 @@ public:
|
|||
|
||||
// methods to control associated file stream
|
||||
void open(bool readOnly = false);
|
||||
void reopen(bool readonly = false);
|
||||
void reopen(bool readOnly = false);
|
||||
bool isOpen() const;
|
||||
bool isReadOnly() const;
|
||||
void close();
|
||||
|
@ -39,6 +40,7 @@ public:
|
|||
std::string pathWithoutExtension() const;
|
||||
static std::string containingDirectory(const std::string &path);
|
||||
std::string containingDirectory() const;
|
||||
static const char *pathForOpen(const std::string &url);
|
||||
|
||||
// methods to get, set the file size
|
||||
std::uint64_t size() const;
|
||||
|
@ -129,6 +131,17 @@ inline void BasicFileInfo::reportPathChanged(const std::string &newPath)
|
|||
m_path = newPath;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns removes the "file:/" prefix from \a url to be able to pass it to functions
|
||||
* like open(), stat() and truncate().
|
||||
* \remarks If \a url is already a plain path it won't changed.
|
||||
* \returns Returns a pointer the URL data itself. No copy is made.
|
||||
*/
|
||||
inline const char *BasicFileInfo::pathForOpen(const std::string &url)
|
||||
{
|
||||
return ConversionUtilities::startsWith(url, "file:/") ? url.data() + 6 : url.data();
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
||||
#endif // TAG_PARSER_BASICFILEINFO_H
|
||||
|
|
|
@ -1497,7 +1497,7 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
try {
|
||||
BackupHelper::createBackupFile(fileInfo().backupDirectory(), fileInfo().path(), backupPath, outputStream, backupStream);
|
||||
// recreate original file, define buffer variables
|
||||
outputStream.open(fileInfo().path(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(
|
||||
DiagLevel::Critical, argsToString("Creation of temporary file (to rewrite the original file) failed: ", failure.what()), context);
|
||||
|
@ -1507,9 +1507,9 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
// open the current file as backupStream and create a new outputStream at the specified "save file path"
|
||||
try {
|
||||
backupStream.exceptions(ios_base::badbit | ios_base::failbit);
|
||||
backupStream.open(fileInfo().path(), ios_base::in | ios_base::binary);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::binary);
|
||||
fileInfo().close();
|
||||
outputStream.open(fileInfo().saveFilePath(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().saveFilePath()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(DiagLevel::Critical, argsToString("Opening streams to write output file failed: ", failure.what()), context);
|
||||
throw;
|
||||
|
|
|
@ -1516,7 +1516,7 @@ void MediaFileInfo::makeMp3File(Diagnostics &diag, AbortableProgressFeedback &pr
|
|||
}
|
||||
progress.updateStep("Removing ID3v1 tag ...");
|
||||
stream().close();
|
||||
if (truncate(path().data(), static_cast<std::streamoff>(size() - 128)) == 0) {
|
||||
if (truncate(BasicFileInfo::pathForOpen(path()), static_cast<std::streamoff>(size() - 128)) == 0) {
|
||||
reportSizeChanged(size() - 128);
|
||||
} else {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to truncate file to remove ID3v1 tag.", context);
|
||||
|
@ -1630,7 +1630,7 @@ void MediaFileInfo::makeMp3File(Diagnostics &diag, AbortableProgressFeedback &pr
|
|||
try {
|
||||
BackupHelper::createBackupFile(backupDirectory(), path(), backupPath, outputStream, backupStream);
|
||||
// recreate original file, define buffer variables
|
||||
outputStream.open(path(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(path()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(
|
||||
DiagLevel::Critical, argsToString("Creation of temporary file (to rewrite the original file) failed: ", failure.what()), context);
|
||||
|
@ -1641,8 +1641,8 @@ void MediaFileInfo::makeMp3File(Diagnostics &diag, AbortableProgressFeedback &pr
|
|||
try {
|
||||
close();
|
||||
backupStream.exceptions(ios_base::badbit | ios_base::failbit);
|
||||
backupStream.open(path(), ios_base::in | ios_base::binary);
|
||||
outputStream.open(m_saveFilePath, ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(path()), ios_base::in | ios_base::binary);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(m_saveFilePath), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(DiagLevel::Critical, argsToString("Opening streams to write output file failed: ", failure.what()), context);
|
||||
throw;
|
||||
|
@ -1653,12 +1653,13 @@ void MediaFileInfo::makeMp3File(Diagnostics &diag, AbortableProgressFeedback &pr
|
|||
// reopen original file to ensure it is opened for writing
|
||||
try {
|
||||
close();
|
||||
outputStream.open(path(), ios_base::in | ios_base::out | ios_base::binary);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(path()), ios_base::in | ios_base::out | ios_base::binary);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(DiagLevel::Critical, argsToString("Opening the file with write permissions failed: ", failure.what()), context);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// TODO: fix code duplication
|
||||
|
||||
// start actual writing
|
||||
try {
|
||||
|
@ -1757,7 +1758,7 @@ void MediaFileInfo::makeMp3File(Diagnostics &diag, AbortableProgressFeedback &pr
|
|||
// -> close stream before truncating
|
||||
outputStream.close();
|
||||
// -> truncate file
|
||||
if (truncate(path().c_str(), static_cast<streamoff>(newSize)) == 0) {
|
||||
if (truncate(BasicFileInfo::pathForOpen(path()), static_cast<streamoff>(newSize)) == 0) {
|
||||
reportSizeChanged(newSize);
|
||||
} else {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to truncate the file.", context);
|
||||
|
|
|
@ -518,7 +518,7 @@ calculatePadding:
|
|||
try {
|
||||
BackupHelper::createBackupFile(fileInfo().backupDirectory(), fileInfo().path(), backupPath, outputStream, backupStream);
|
||||
// recreate original file, define buffer variables
|
||||
outputStream.open(fileInfo().path(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(
|
||||
DiagLevel::Critical, argsToString("Creation of temporary file (to rewrite the original file) failed: ", failure.what()), context);
|
||||
|
@ -528,9 +528,9 @@ calculatePadding:
|
|||
// open the current file as backupStream and create a new outputStream at the specified "save file path"
|
||||
try {
|
||||
backupStream.exceptions(ios_base::badbit | ios_base::failbit);
|
||||
backupStream.open(fileInfo().path(), ios_base::in | ios_base::binary);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::binary);
|
||||
fileInfo().close();
|
||||
outputStream.open(fileInfo().saveFilePath(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().saveFilePath()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(DiagLevel::Critical, argsToString("Opening streams to write output file failed: ", failure.what()), context);
|
||||
throw;
|
||||
|
@ -821,7 +821,7 @@ calculatePadding:
|
|||
}
|
||||
// the outputStream needs to be reopened to be able to read again
|
||||
outputStream.close();
|
||||
outputStream.open(fileInfo().path(), ios_base::in | ios_base::out | ios_base::binary);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::out | ios_base::binary);
|
||||
setStream(outputStream);
|
||||
} else {
|
||||
const auto newSize = static_cast<std::uint64_t>(outputStream.tellp());
|
||||
|
@ -830,13 +830,13 @@ calculatePadding:
|
|||
// -> close stream before truncating
|
||||
outputStream.close();
|
||||
// -> truncate file
|
||||
if (truncate(fileInfo().path().c_str(), static_cast<iostream::off_type>(newSize)) == 0) {
|
||||
if (truncate(BasicFileInfo::pathForOpen(fileInfo().path()), static_cast<iostream::off_type>(newSize)) == 0) {
|
||||
fileInfo().reportSizeChanged(newSize);
|
||||
} else {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to truncate the file.", context);
|
||||
}
|
||||
// -> reopen the stream again
|
||||
outputStream.open(fileInfo().path(), ios_base::in | ios_base::out | ios_base::binary);
|
||||
outputStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::out | ios_base::binary);
|
||||
} else {
|
||||
// file is longer after the modification -> just report new size
|
||||
fileInfo().reportSizeChanged(newSize);
|
||||
|
|
|
@ -377,7 +377,7 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
try {
|
||||
BackupHelper::createBackupFile(fileInfo().backupDirectory(), fileInfo().path(), backupPath, fileInfo().stream(), backupStream);
|
||||
// recreate original file, define buffer variables
|
||||
fileInfo().stream().open(fileInfo().path(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
fileInfo().stream().open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(
|
||||
DiagLevel::Critical, argsToString("Creation of temporary file (to rewrite the original file) failed: ", failure.what()), context);
|
||||
|
@ -387,9 +387,9 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
// open the current file as backupStream and create a new outputStream at the specified "save file path"
|
||||
try {
|
||||
backupStream.exceptions(ios_base::badbit | ios_base::failbit);
|
||||
backupStream.open(fileInfo().path(), ios_base::in | ios_base::binary);
|
||||
backupStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::binary);
|
||||
fileInfo().close();
|
||||
fileInfo().stream().open(fileInfo().saveFilePath(), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
fileInfo().stream().open(BasicFileInfo::pathForOpen(fileInfo().saveFilePath()), ios_base::out | ios_base::binary | ios_base::trunc);
|
||||
} catch (const std::ios_base::failure &failure) {
|
||||
diag.emplace_back(DiagLevel::Critical, argsToString("Opening streams to write output file failed: ", failure.what()), context);
|
||||
throw;
|
||||
|
|
Loading…
Reference in New Issue