1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49:41 +02:00

Bug1829, more: check all errors flushing and closing export files...

... MP3 export already did this, the other five needed work.
This commit is contained in:
Paul Licameli 2018-01-22 14:52:27 -05:00
parent b3b4ace739
commit 38568f611d
11 changed files with 104 additions and 17 deletions

View File

@ -209,10 +209,17 @@ int ufile_close(AVIOContext *pb)
{ {
std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque }; std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque };
if (f) bool success = true;
f->Close(); if (f) {
success = f->Flush() && f->Close();
pb->opaque = nullptr;
}
return 0; // We're not certain that a close error is for want of space, but we'll
// guess that
return success ? 0 : -ENOSPC;
// Implicitly destroy the wxFile object here
} }
// Open a file with a (possibly) Unicode filename // Open a file with a (possibly) Unicode filename

View File

@ -928,6 +928,18 @@ private:
// Deleter adaptor for functions like av_free that take a pointer // Deleter adaptor for functions like av_free that take a pointer
template<typename T, typename R, R(*Fn)(T*)> struct AV_Deleter { template<typename T, typename R, R(*Fn)(T*)> struct AV_Deleter {
inline R operator() (T* p) const
{
R result{};
if (p)
result = Fn(p);
return result;
}
};
// Specialization of previous for void return
template<typename T, void(*Fn)(T*)>
struct AV_Deleter<T, void, Fn> {
inline void operator() (T* p) const inline void operator() (T* p) const
{ {
if (p) if (p)
@ -959,9 +971,19 @@ using AVCodecContextHolder = std::unique_ptr<
using AVDictionaryCleanup = std::unique_ptr< using AVDictionaryCleanup = std::unique_ptr<
AVDictionary*, AV_Deleter<AVDictionary*, void, av_dict_free> AVDictionary*, AV_Deleter<AVDictionary*, void, av_dict_free>
>; >;
using UFileHolder = std::unique_ptr< struct UFileHolder : public std::unique_ptr<
AVIOContext, AV_Deleter<AVIOContext, int, ufile_close> AVIOContext, AV_Deleter<AVIOContext, int, ufile_close>
>; >
{
// Close explicitly, not ignoring return values.
int close()
{
auto result = get_deleter() ( get() );
release();
return result;
}
};
template<typename T> using AVMallocHolder = std::unique_ptr< template<typename T> using AVMallocHolder = std::unique_ptr<
T, AV_Deleter<void, void, av_free> T, AV_Deleter<void, void, av_free>
>; >;

View File

@ -288,7 +288,7 @@ OSType sf_header_mactype(int format)
ODLock libSndFileMutex; ODLock libSndFileMutex;
void SFFileCloser::operator() (SNDFILE *sf) const int SFFileCloser::operator() (SNDFILE *sf) const
{ {
auto err = SFCall<int>(sf_close, sf); auto err = SFCall<int>(sf_close, sf);
if (err) { if (err) {
@ -299,4 +299,5 @@ void SFFileCloser::operator() (SNDFILE *sf) const
(_("Error (file may not have been written): %s"), (_("Error (file may not have been written): %s"),
buffer)); buffer));
} }
return err;
} }

View File

@ -127,7 +127,16 @@ inline R SFCall(F fun, Args&&... args)
} }
//RAII for SNDFILE* //RAII for SNDFILE*
struct SFFileCloser { void operator () (SNDFILE*) const; }; struct SFFileCloser { int operator () (SNDFILE*) const; };
using SFFile = std::unique_ptr<SNDFILE, SFFileCloser>; struct SFFile : public std::unique_ptr<SNDFILE, SFFileCloser>
{
// Close explicitly, not ignoring return values.
int close()
{
auto result = get_deleter() ( get() );
release();
return result;
}
};
#endif #endif

View File

@ -52,11 +52,18 @@ bool FileIO::IsOpened()
return mOpen; return mOpen;
} }
void FileIO::Close() bool FileIO::Close()
{ {
mOutputStream.reset(); bool success = true;
if (mOutputStream) {
// mOutputStream->Sync() returns void! Rrr!
success = mOutputStream->GetFile()->Flush() &&
mOutputStream->Close();
mOutputStream.reset();
}
mInputStream.reset(); mInputStream.reset();
mOpen = false; mOpen = false;
return success;
} }
wxInputStream & FileIO::Read(void *buf, size_t size) wxInputStream & FileIO::Read(void *buf, size_t size)

View File

@ -32,7 +32,7 @@ class FileIO
bool IsOpened(); bool IsOpened();
void Close(); bool Close();
wxInputStream & Read(void *buffer, size_t size); wxInputStream & Read(void *buffer, size_t size);
wxOutputStream & Write(const void *buffer, size_t size); wxOutputStream & Write(const void *buffer, size_t size);
@ -41,7 +41,7 @@ class FileIO
wxString mName; wxString mName;
FileIOMode mMode; FileIOMode mMode;
std::unique_ptr<wxInputStream> mInputStream; std::unique_ptr<wxInputStream> mInputStream;
std::unique_ptr<wxOutputStream> mOutputStream; std::unique_ptr<wxFFileOutputStream> mOutputStream;
bool mOpen; bool mOpen;
}; };

View File

@ -945,6 +945,12 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project,
if ( !Finalize() ) // Finalize makes its own messages if ( !Finalize() ) // Finalize makes its own messages
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
if ( mUfileCloser.close() != 0 ) {
// TODO: more precise message
AudacityMessageBox(_("Unable to export"));
return ProgressResult::Cancelled;
}
return updateResult; return updateResult;
} }

View File

@ -335,10 +335,13 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
mMetadata.reset(); mMetadata.reset();
auto cleanup2 = finally( [&] { auto cleanup2 = finally( [&] {
if (!(updateResult == ProgressResult::Success ||
updateResult == ProgressResult::Stopped)) {
#ifndef LEGACY_FLAC #ifndef LEGACY_FLAC
f.Detach(); // libflac closes the file f.Detach(); // libflac closes the file
#endif #endif
encoder.finish(); encoder.finish();
}
} ); } );
const WaveTrackConstArray waveTracks = const WaveTrackConstArray waveTracks =
@ -389,6 +392,20 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
} }
} }
if (updateResult == ProgressResult::Success ||
updateResult == ProgressResult::Stopped) {
#ifndef LEGACY_FLAC
f.Detach(); // libflac closes the file
#endif
if (!encoder.finish())
// Do not reassign updateResult, see cleanup2
return ProgressResult::Failed;
#ifdef LEGACY_FLAC
if (!f.Flush() || !f.Close())
return ProgressResult::Failed;
#endif
}
return updateResult; return updateResult;
} }

View File

@ -330,7 +330,11 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
} }
outFile.Close(); if ( !outFile.Close() ) {
// TODO: more precise message
AudacityMessageBox(_("Unable to export"));
return ProgressResult::Cancelled;
}
return updateResult; return updateResult;
} }

View File

@ -359,7 +359,11 @@ ProgressResult ExportOGG::Export(AudacityProject *project,
} }
} }
outFile.Close(); if ( !outFile.Close() ) {
updateResult = ProgressResult::Cancelled;
// TODO: more precise message
AudacityMessageBox(_("Unable to export"));
}
return updateResult; return updateResult;
} }

View File

@ -530,7 +530,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
// Install the WAV metata in a "LIST" chunk at the end of the file // Install the WAV metata in a "LIST" chunk at the end of the file
if (updateResult == ProgressResult::Success || if (updateResult == ProgressResult::Success ||
updateResult == ProgressResult::Stopped) updateResult == ProgressResult::Stopped) {
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV || if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
(sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) { (sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
if (!AddStrings(project, sf.get(), metadata, sf_format)) { if (!AddStrings(project, sf.get(), metadata, sf_format)) {
@ -538,6 +538,12 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
AudacityMessageBox(_("Unable to export")); AudacityMessageBox(_("Unable to export"));
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
} }
}
if (0 != sf.close()) {
// TODO: more precise message
AudacityMessageBox(_("Unable to export"));
return ProgressResult::Cancelled;
}
} }
} }
@ -545,6 +551,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
updateResult == ProgressResult::Stopped) updateResult == ProgressResult::Stopped)
if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) || if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) ||
((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)) ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV))
// Note: file has closed, and gets reopened and closed again here:
if (!AddID3Chunk(fName, metadata, sf_format) ) { if (!AddID3Chunk(fName, metadata, sf_format) ) {
// TODO: more precise message // TODO: more precise message
AudacityMessageBox(_("Unable to export")); AudacityMessageBox(_("Unable to export"));
@ -845,6 +852,9 @@ bool ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
if (4 != f.Write(&sz, 4)) if (4 != f.Write(&sz, 4))
return false; return false;
if (!f.Flush())
return false;
if (!f.Close()) if (!f.Close())
return false; return false;
} }