From 78a146aa0717978da10790dd3bfccdf2e48c8e16 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 6 Aug 2017 15:14:57 -0700 Subject: [PATCH] - Added IDecoder::Exhausted() method that returns true if the input source has been completely depleted, false otherwise - Fixed a memory leak in LogWindow - Fixed CddaDataStream to only allow reading one track at a time. This is a safety mechanism so clients can't thrash the read head. This also means remote clients can stream real-time transcoded CD audio. - Fixed some bugs in TranscodingDataStream where temp files weren't always getting cleaned up properly until a restart --- src/core/sdk/IDecoder.h | 1 + src/musikcube/app/window/LogWindow.cpp | 1 + src/plugins/cddadecoder/CddaDataStream.cpp | 101 +++------------- src/plugins/cddadecoder/CddaDataStream.h | 14 +-- src/plugins/cddadecoder/CddaDecoder.cpp | 7 ++ src/plugins/cddadecoder/CddaDecoder.h | 12 +- src/plugins/flacdecoder/FlacDecoder.cpp | 12 +- src/plugins/flacdecoder/FlacDecoder.h | 12 +- src/plugins/m4adecoder/M4aDecoder.cpp | 111 +++++++++--------- src/plugins/m4adecoder/M4aDecoder.h | 12 +- src/plugins/nomaddecoder/NomadDecoder.cpp | 15 ++- src/plugins/nomaddecoder/NomadDecoder.h | 13 +- src/plugins/oggdecoder/OggDecoder.cpp | 3 + src/plugins/oggdecoder/OggDecoder.h | 12 +- .../TranscodingDataStream.cpp | 40 +++++-- 15 files changed, 174 insertions(+), 192 deletions(-) diff --git a/src/core/sdk/IDecoder.h b/src/core/sdk/IDecoder.h index 1c3c13746..bce101ee7 100644 --- a/src/core/sdk/IDecoder.h +++ b/src/core/sdk/IDecoder.h @@ -46,6 +46,7 @@ namespace musik { namespace core { namespace sdk { virtual bool GetBuffer(IBuffer *buffer) = 0; virtual double GetDuration() = 0; virtual bool Open(IDataStream *stream) = 0; + virtual bool Exhausted() = 0; }; } } } diff --git a/src/musikcube/app/window/LogWindow.cpp b/src/musikcube/app/window/LogWindow.cpp index 8e14a97d1..3e1e44d33 100755 --- a/src/musikcube/app/window/LogWindow.cpp +++ b/src/musikcube/app/window/LogWindow.cpp @@ -59,6 +59,7 @@ LogWindow::LogWindow(IWindow *parent) } LogWindow::~LogWindow() { + delete this->adapter; } IScrollAdapter& LogWindow::GetScrollAdapter() { diff --git a/src/plugins/cddadecoder/CddaDataStream.cpp b/src/plugins/cddadecoder/CddaDataStream.cpp index 3419c8eef..4eb9a3bdc 100755 --- a/src/plugins/cddadecoder/CddaDataStream.cpp +++ b/src/plugins/cddadecoder/CddaDataStream.cpp @@ -39,18 +39,8 @@ #include #include -#if ENABLE_LOOKAHEAD_BUFFER - /* as it turns out having a small lookahead buffer is better than a - large one. if the buffer is too large, the device seems to start to - power down, then takes a while to power back up. we just want a little - but of wiggle room, but to generally keep the device reading small - chunks of data constantly. */ - #define MAX_SECTORS_IN_LOOKAHEAD 20 - #define MAX_SECTORS_PER_READ 10 - #define BUFFER_SIZE_BYTES (MAX_SECTORS_IN_LOOKAHEAD * BYTES_PER_SECTOR) -#endif - static std::mutex driveAccessMutex; /* one track can read at a time */ +static CddaDataStream* activeRead = nullptr; CddaDataStream::CddaDataStream() { this->closed = false; @@ -58,11 +48,6 @@ CddaDataStream::CddaDataStream() { this->position = this->length = 0; memset(&this->toc, 0, sizeof(this->toc)); this->startSector = this->stopSector = 0; - -#if ENABLE_LOOKAHEAD_BUFFER - this->lookahead = new char[BUFFER_SIZE_BYTES]; - this->lookaheadOffset = this->lookaheadTotal = 0; -#endif } CddaDataStream::~CddaDataStream() { @@ -154,8 +139,14 @@ bool CddaDataStream::Close() { this->drive = INVALID_HANDLE_VALUE; } - this->closed = true; + { + std::lock_guard lock(driveAccessMutex); + if (activeRead == this) { + activeRead = nullptr; + } + } + this->closed = true; return true; } @@ -168,6 +159,17 @@ void CddaDataStream::Destroy() { } PositionType CddaDataStream::Read(void* buffer, PositionType readBytes) { + { + std::lock_guard lock(driveAccessMutex); + if (activeRead == nullptr) { + activeRead = this; + } + } + + if (activeRead != this) { + return (PositionType) ReadError::DeviceBusy; + } + if (this->position >= this->length) { return 0; } @@ -187,12 +189,6 @@ bool CddaDataStream::SetPosition(PositionType position) { this->position++; } -#if ENABLE_LOOKAHEAD_BUFFER - this->RefillInternalBuffer(); - this->lookaheadOffset = 0; - Sleep(250); -#endif - return true; } @@ -220,70 +216,12 @@ const char* CddaDataStream::Uri() { return uri.c_str(); } -#if ENABLE_LOOKAHEAD_BUFFER -void CddaDataStream::RefillInternalBuffer() { - std::unique_lock lock(driveAccessMutex); - - LONGLONG pos = this->position; - int iterations = MAX_SECTORS_IN_LOOKAHEAD / MAX_SECTORS_PER_READ; - DWORD totalBytesRead = 0; - - RAW_READ_INFO rawReadInfo = { 0 }; - rawReadInfo.SectorCount = MAX_SECTORS_PER_READ; - rawReadInfo.TrackMode = CDDA; - - DWORD bytesActuallyRead = 0; - - while (iterations > 0) { - UINT sectorOffset = this->startSector + (int)(pos / BYTES_PER_SECTOR); - rawReadInfo.DiskOffset.QuadPart = sectorOffset * 2048; - - DeviceIoControl( - this->drive, - IOCTL_CDROM_RAW_READ, - &rawReadInfo, - sizeof(rawReadInfo), - &this->lookahead[totalBytesRead], - BYTES_PER_SECTOR * MAX_SECTORS_PER_READ, - &bytesActuallyRead, - 0); - - totalBytesRead += bytesActuallyRead; - pos += bytesActuallyRead; - - if (totalBytesRead == 0) { - break; - } - - --iterations; - } - - this->lookaheadOffset = 0; - this->lookaheadTotal = totalBytesRead; -} -#endif - HRESULT CddaDataStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) { if (this->closed) { pdwBytesRead = 0; return S_FALSE; } -#if ENABLE_LOOKAHEAD_BUFFER - size_t avail = this->lookaheadTotal - this->lookaheadOffset; - - if (avail == 0) { - this->RefillInternalBuffer(); - avail = this->lookaheadTotal; - } - - DWORD readSize = min(avail, (size_t) dwBytesToRead); - if (readSize >= 0) { - memcpy(pbBuffer, &this->lookahead[this->lookaheadOffset], readSize); - this->position += readSize; - this->lookaheadOffset += readSize; - } -#else DWORD readSize = 0; LONGLONG pos = this->position; UINT sectorOffset = this->startSector + (int)(pos / BYTES_PER_SECTOR); @@ -304,7 +242,6 @@ HRESULT CddaDataStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, L 0); this->position += readSize; -#endif if (pdwBytesRead) { *pdwBytesRead = readSize; diff --git a/src/plugins/cddadecoder/CddaDataStream.h b/src/plugins/cddadecoder/CddaDataStream.h index 35dacb0c8..147c85220 100755 --- a/src/plugins/cddadecoder/CddaDataStream.h +++ b/src/plugins/cddadecoder/CddaDataStream.h @@ -37,13 +37,16 @@ #include "ntddcdrm.h" #include "devioctl.h" #include - -#define ENABLE_LOOKAHEAD_BUFFER 0 +#include using namespace musik::core::sdk; class CddaDataStream : public IDataStream { public: + enum class ReadError : int { + DeviceBusy = -128 + }; + CddaDataStream(); ~CddaDataStream(); @@ -73,11 +76,4 @@ class CddaDataStream : public IDataStream { UINT firstSector, startSector, stopSector; unsigned long channels; volatile bool closed; - -#if ENABLE_LOOKAHEAD_BUFFER - char* lookahead; - DWORD lookaheadOffset; - DWORD lookaheadTotal; - void RefillInternalBuffer(); -#endif }; \ No newline at end of file diff --git a/src/plugins/cddadecoder/CddaDecoder.cpp b/src/plugins/cddadecoder/CddaDecoder.cpp index 9348a244f..86f925081 100644 --- a/src/plugins/cddadecoder/CddaDecoder.cpp +++ b/src/plugins/cddadecoder/CddaDecoder.cpp @@ -43,6 +43,7 @@ CddaDecoder::CddaDecoder() { this->duration = -1.0f; this->data = nullptr; this->buffer = new BYTE[CDDA_BUFFER_SIZE]; + this->exhausted = false; } CddaDecoder::~CddaDecoder() { @@ -87,6 +88,11 @@ bool CddaDecoder::GetBuffer(IBuffer *buffer) { PositionType count = this->data->Read( (void *) this->buffer, CDDA_BUFFER_SIZE); + if (count == (PositionType) CddaDataStream::ReadError::DeviceBusy) { + this->exhausted = false; /* stream not exhausted, waiting for data */ + return false; + } + if (count > 0) { short* t = (short*) this->buffer; @@ -99,5 +105,6 @@ bool CddaDecoder::GetBuffer(IBuffer *buffer) { return true; } + this->exhausted = true; return false; } diff --git a/src/plugins/cddadecoder/CddaDecoder.h b/src/plugins/cddadecoder/CddaDecoder.h index 4139113d4..0728b7260 100644 --- a/src/plugins/cddadecoder/CddaDecoder.h +++ b/src/plugins/cddadecoder/CddaDecoder.h @@ -47,14 +47,16 @@ class CddaDecoder : public IDecoder { CddaDecoder(); ~CddaDecoder(); - virtual bool Open(IDataStream* data); - virtual void Destroy(); - virtual double SetPosition(double seconds); - virtual double GetDuration(); - virtual bool GetBuffer(IBuffer *buffer); + virtual bool Open(IDataStream* data) override; + virtual void Destroy() override; + virtual double SetPosition(double seconds) override; + virtual double GetDuration() override; + virtual bool GetBuffer(IBuffer *buffer) override; + virtual bool Exhausted() override { return this->exhausted; } private: CddaDataStream* data; double duration; BYTE* buffer; + bool exhausted; }; diff --git a/src/plugins/flacdecoder/FlacDecoder.cpp b/src/plugins/flacdecoder/FlacDecoder.cpp index f7770cc85..72817c4af 100644 --- a/src/plugins/flacdecoder/FlacDecoder.cpp +++ b/src/plugins/flacdecoder/FlacDecoder.cpp @@ -47,7 +47,8 @@ FlacDecoder::FlacDecoder() , sampleRate(0) , bitsPerSample(0) , totalSamples(0) -, duration(-1.0f) { +, duration(-1.0f) +, exhausted(false) { this->decoder = FLAC__stream_decoder_new(); } @@ -62,18 +63,21 @@ FlacDecoder::~FlacDecoder() { } FLAC__StreamDecoderReadStatus FlacDecoder::FlacRead( - const FLAC__StreamDecoder *decoder, + const FLAC__StreamDecoder *dec, FLAC__byte buffer[], size_t *bytes, void *clientData) { - size_t readBytes = (size_t)((FlacDecoder*) clientData)->stream->Read(buffer,(long)(*bytes)); + auto decoder = (FlacDecoder*) clientData; + size_t readBytes = (size_t) decoder->stream->Read(buffer,(long)(*bytes)); *bytes = readBytes; if (readBytes == 0) { + decoder->exhausted = true; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } - else if(readBytes == (size_t) -1) { + else if (readBytes == (size_t) -1) { + decoder->exhausted = true; return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } diff --git a/src/plugins/flacdecoder/FlacDecoder.h b/src/plugins/flacdecoder/FlacDecoder.h index 427749720..2e0cd0564 100644 --- a/src/plugins/flacdecoder/FlacDecoder.h +++ b/src/plugins/flacdecoder/FlacDecoder.h @@ -47,11 +47,12 @@ class FlacDecoder : public musik::core::sdk::IDecoder { FlacDecoder(); ~FlacDecoder(); - virtual void Destroy(); - virtual double SetPosition(double seconds); - virtual bool GetBuffer(IBuffer *buffer); - virtual double GetDuration(); - virtual bool Open(musik::core::sdk::IDataStream *stream); + virtual void Destroy() override; + virtual double SetPosition(double seconds) override; + virtual bool GetBuffer(IBuffer *buffer) override; + virtual double GetDuration() override; + virtual bool Open(musik::core::sdk::IDataStream *stream) override; + virtual bool Exhausted() override { return this->exhausted; } private: static FLAC__StreamDecoderReadStatus FlacRead( @@ -104,6 +105,7 @@ class FlacDecoder : public musik::core::sdk::IDecoder { uint64_t totalSamples; int bitsPerSample; double duration; + bool exhausted; float *outputBuffer; unsigned long outputBufferSize; diff --git a/src/plugins/m4adecoder/M4aDecoder.cpp b/src/plugins/m4adecoder/M4aDecoder.cpp index c07c7f440..b05a3ce1e 100644 --- a/src/plugins/m4adecoder/M4aDecoder.cpp +++ b/src/plugins/m4adecoder/M4aDecoder.cpp @@ -83,6 +83,7 @@ M4aDecoder::M4aDecoder() { this->decoderFile = nullptr; memset(&decoderCallbacks, 0, sizeof(this->decoderCallbacks)); this->duration = -1.0f; + this->exhausted = false; } M4aDecoder::~M4aDecoder() { @@ -90,7 +91,9 @@ M4aDecoder::~M4aDecoder() { bool M4aDecoder::Open(musik::core::sdk::IDataStream *stream) { decoder = NeAACDecOpen(); + if (!decoder) { + this->exhausted = true; return false; } @@ -177,63 +180,57 @@ double M4aDecoder::GetDuration() { } bool M4aDecoder::GetBuffer(IBuffer* target) { - if (this->decoderSampleId < 0) { - return false; + if (this->decoderSampleId >= 0) { + void* sampleBuffer = NULL; + unsigned char* encodedData = NULL; + unsigned int encodedDataLength = 0; + NeAACDecFrameInfo frameInfo; + + long duration = mp4ff_get_sample_duration( + decoderFile, audioTrackId, decoderSampleId); + + if (duration > 0) { + /* read the raw data required */ + + int rc = + mp4ff_read_sample( + decoderFile, + audioTrackId, + decoderSampleId, + &encodedData, + &encodedDataLength); + + decoderSampleId++; + + if (rc == 0 || encodedData == NULL) { + this->exhausted = true; + return false; + } + + sampleBuffer = + NeAACDecDecode( + decoder, + &frameInfo, + encodedData, + encodedDataLength); + + free(encodedData); + + if (frameInfo.error <= 0 && decoderSampleId <= this->totalSamples) { + target->SetSampleRate(frameInfo.samplerate); + target->SetChannels(frameInfo.channels); + target->SetSamples(frameInfo.samples); + + memcpy( + static_cast(target->BufferPointer()), + static_cast(sampleBuffer), + sizeof(float) * frameInfo.samples); + + return true; + } + } } - void* sampleBuffer = NULL; - unsigned char* encodedData = NULL; - unsigned int encodedDataLength = 0; - NeAACDecFrameInfo frameInfo; - - long duration = mp4ff_get_sample_duration( - decoderFile, audioTrackId, decoderSampleId); - - if (duration <= 0) { - return false; - } - - /* read the raw data required */ - - int rc = - mp4ff_read_sample( - decoderFile, - audioTrackId, - decoderSampleId, - &encodedData, - &encodedDataLength); - - decoderSampleId++; - - if (rc == 0 || encodedData == NULL) { - return false; - } - - sampleBuffer = - NeAACDecDecode( - decoder, - &frameInfo, - encodedData, - encodedDataLength); - - free(encodedData); - - if (frameInfo.error > 0) { - return false; - } - - if (decoderSampleId > this->totalSamples) { - return false; - } - - target->SetSampleRate(frameInfo.samplerate); - target->SetChannels(frameInfo.channels); - target->SetSamples(frameInfo.samples); - - memcpy( - static_cast(target->BufferPointer()), - static_cast(sampleBuffer), - sizeof(float) * frameInfo.samples); - - return true; + this->exhausted = true; + return false; } diff --git a/src/plugins/m4adecoder/M4aDecoder.h b/src/plugins/m4adecoder/M4aDecoder.h index 1a5b207e5..de7d0909f 100644 --- a/src/plugins/m4adecoder/M4aDecoder.h +++ b/src/plugins/m4adecoder/M4aDecoder.h @@ -43,11 +43,12 @@ class M4aDecoder : public musik::core::sdk::IDecoder { M4aDecoder(); ~M4aDecoder(); - virtual void Destroy(); - virtual double SetPosition(double seconds); - virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer); - virtual double GetDuration(); - virtual bool Open(musik::core::sdk::IDataStream *stream); + virtual void Destroy() override; + virtual double SetPosition(double seconds) override; + virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer) override; + virtual double GetDuration() override; + virtual bool Open(musik::core::sdk::IDataStream *stream) override; + virtual bool Exhausted() override { return this->exhausted; } private: NeAACDecHandle decoder; @@ -59,4 +60,5 @@ class M4aDecoder : public musik::core::sdk::IDecoder { unsigned char channelCount; long decoderSampleId; double duration; + bool exhausted; }; diff --git a/src/plugins/nomaddecoder/NomadDecoder.cpp b/src/plugins/nomaddecoder/NomadDecoder.cpp index 76fea4bf5..4394337d8 100644 --- a/src/plugins/nomaddecoder/NomadDecoder.cpp +++ b/src/plugins/nomaddecoder/NomadDecoder.cpp @@ -77,6 +77,7 @@ static int nomadClose(void *datasource) { } NomadDecoder::NomadDecoder() { + this->exhausted = false; this->duration = -1.0f; this->nomadContext = nullptr; this->callbacks.read = &nomadRead; @@ -118,7 +119,12 @@ bool NomadDecoder::GetBuffer(IBuffer *buffer) { buffer->SetSamples(read > 0 ? read : 0); buffer->SetSampleRate(info->sample_rate); - return (read > 0) ? true : false; + if (read > 0) { + return true; + } + + this->exhausted = true; + return false; } bool NomadDecoder::Open(IDataStream *stream) { @@ -148,7 +154,12 @@ bool NomadDecoder::Open(IDataStream *stream) { this->nomadContext = nullptr; } - return result ? false : true; + if (!result) { + return true; + } + + this->exhausted = false; + return false; } /* adapted from http://stackoverflow.com/a/3520427 */ diff --git a/src/plugins/nomaddecoder/NomadDecoder.h b/src/plugins/nomaddecoder/NomadDecoder.h index 637126f52..25f7113af 100644 --- a/src/plugins/nomaddecoder/NomadDecoder.h +++ b/src/plugins/nomaddecoder/NomadDecoder.h @@ -46,15 +46,16 @@ class NomadDecoder : public musik::core::sdk::IDecoder { NomadDecoder(); ~NomadDecoder(); - virtual bool Open(musik::core::sdk::IDataStream *dataStream); - virtual double SetPosition(double seconds); - virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer); - virtual double GetDuration(); - virtual void Destroy(); + virtual bool Open(musik::core::sdk::IDataStream *dataStream) override; + virtual double SetPosition(double seconds) override; + virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer) override; + virtual double GetDuration() override; + virtual void Destroy() override; + virtual bool Exhausted() override { return this->exhausted; } private: size_t GetId3v2HeaderLength(musik::core::sdk::IDataStream *stream); - + bool exhausted; double duration; nomad_callbacks callbacks; nomad *nomadContext; diff --git a/src/plugins/oggdecoder/OggDecoder.cpp b/src/plugins/oggdecoder/OggDecoder.cpp index 5a4902c74..97f5fca50 100644 --- a/src/plugins/oggdecoder/OggDecoder.cpp +++ b/src/plugins/oggdecoder/OggDecoder.cpp @@ -39,6 +39,7 @@ OggDecoder::OggDecoder() { this->duration = -1.0f; + this->exhausted = false; this->oggCallbacks.read_func = &OggRead; this->oggCallbacks.seek_func = &OggSeek; this->oggCallbacks.tell_func = &OggTell; @@ -99,6 +100,7 @@ bool OggDecoder::Open(musik::core::sdk::IDataStream *fileStream) { this->fileStream = fileStream; if (ov_open_callbacks(this, &this->oggFile, NULL, 0, this->oggCallbacks) != 0) { + this->exhausted = true; return false; } @@ -137,6 +139,7 @@ bool OggDecoder::GetBuffer(IBuffer *buffer) { &bitstream); if (samplesRead == 0) { + this->exhausted = true; return false; } diff --git a/src/plugins/oggdecoder/OggDecoder.h b/src/plugins/oggdecoder/OggDecoder.h index 9d32f22af..c4c0da7ac 100644 --- a/src/plugins/oggdecoder/OggDecoder.h +++ b/src/plugins/oggdecoder/OggDecoder.h @@ -45,11 +45,12 @@ class OggDecoder : public IDecoder { OggDecoder(); ~OggDecoder(); - virtual void Destroy(); - virtual double SetPosition(double second); - virtual bool GetBuffer(IBuffer *buffer); - virtual double GetDuration(); - virtual bool Open(musik::core::sdk::IDataStream *fileStream); + virtual void Destroy() override; + virtual double SetPosition(double second) override; + virtual bool GetBuffer(IBuffer *buffer) override; + virtual double GetDuration() override; + virtual bool Open(musik::core::sdk::IDataStream *fileStream) override; + virtual bool Exhausted() { return this->exhausted; } /* libvorbis callbacks */ static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource); @@ -59,6 +60,7 @@ class OggDecoder : public IDecoder { private: musik::core::sdk::IDataStream *fileStream; + bool exhausted; OggVorbis_File oggFile; ov_callbacks oggCallbacks; double duration; diff --git a/src/plugins/websocket_remote/TranscodingDataStream.cpp b/src/plugins/websocket_remote/TranscodingDataStream.cpp index cfbf33d74..42bd458ee 100644 --- a/src/plugins/websocket_remote/TranscodingDataStream.cpp +++ b/src/plugins/websocket_remote/TranscodingDataStream.cpp @@ -215,6 +215,10 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead) hasBuffer = this->decoder->GetBuffer(this->pcmBuffer); } + if (!hasBuffer && !decoder->Exhausted()) { + goto internal_error; + } + /* done with spillover. read new data... */ while (hasBuffer && bytesWritten < (size_t) bytesToRead) { /* calculated according to lame.h */ @@ -314,26 +318,36 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead) if (bytesWritten == 0) { encodedBytes.reset(); - size_t count = lame_encode_flush( + /* 7200 bytes minimum is required for the flush op; see lame.h */ + if (encodedBytes.length < 7200) { + encodedBytes.realloc(7200); + } + + int count = lame_encode_flush( lame, encodedBytes.data, encodedBytes.length); - memcpy(dst + bytesWritten, encodedBytes.data, count); + this->eof = true; - if (this->outFile) { - fwrite(encodedBytes.data, 1, count, this->outFile); - fclose(this->outFile); - this->outFile = nullptr; + if (count >= 0) { + memcpy(dst + bytesWritten, encodedBytes.data, count); - boost::system::error_code ec; - boost::filesystem::rename(this->tempFilename, this->finalFilename, ec); - if (ec) { - boost::filesystem::remove(this->tempFilename, ec); + if (this->outFile) { + fwrite(encodedBytes.data, 1, count, this->outFile); + fclose(this->outFile); + this->outFile = nullptr; + + boost::system::error_code ec; + boost::filesystem::rename(this->tempFilename, this->finalFilename, ec); + if (ec) { + boost::filesystem::remove(this->tempFilename, ec); + } } } - - this->eof = true; + else { + goto internal_error; + } } this->position += bytesWritten; @@ -343,6 +357,8 @@ internal_error: this->eof = true; fclose(this->outFile); this->outFile = nullptr; + boost::system::error_code ec; + boost::filesystem::remove(this->tempFilename, ec); return 0; }