From 7bc4e37a1ad082e4a69bdbe9e956c0ab35db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Wolf Date: Tue, 12 Apr 2016 18:02:52 +0200 Subject: [PATCH] Improved error handling and error messages --- src/audio/WaveFileReader.cpp | 42 ++++++++++++++++++++++++++++++++---- src/main.cpp | 4 ++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/audio/WaveFileReader.cpp b/src/audio/WaveFileReader.cpp index dee2ffc..45600fe 100644 --- a/src/audio/WaveFileReader.cpp +++ b/src/audio/WaveFileReader.cpp @@ -1,6 +1,8 @@ #include +#include #include "WaveFileReader.h" #include "ioTools.h" +#include using std::runtime_error; using fmt::format; @@ -31,7 +33,19 @@ WaveFileReader::WaveFileReader(boost::filesystem::path filePath) : { openFile(); + file.seekg(0, std::ios_base::end); + std::streamoff fileSize = file.tellg(); + file.seekg(0); + + auto remaining = [&](size_t byteCount) { + std::streamoff filePosition = file.tellg(); + return byteCount <= fileSize - filePosition; + }; + // Read header + if (!remaining(10)) { + throw runtime_error("WAVE file is corrupt. Header not found."); + } uint32_t rootChunkId = read(file); if (rootChunkId != fourcc('R', 'I', 'F', 'F')) { throw runtime_error("Unknown file format. Only WAVE files are supported."); @@ -45,7 +59,7 @@ WaveFileReader::WaveFileReader(boost::filesystem::path filePath) : // Read chunks until we reach the data chunk bool reachedDataChunk = false; bytesPerSample = 0; - do { + while (!reachedDataChunk && remaining(8)) { uint32_t chunkId = read(file); int chunkSize = read(file); switch (chunkId) { @@ -110,7 +124,12 @@ WaveFileReader::WaveFileReader(boost::filesystem::path filePath) : break; } } - } while (!reachedDataChunk); + } + + if (!reachedDataChunk) { + dataOffset = file.tellg(); + sampleCount = frameCount = 0; + } } WaveFileReader::WaveFileReader(const WaveFileReader& rhs, bool reset) : @@ -134,8 +153,23 @@ std::unique_ptr WaveFileReader::clone(bool reset) { } void WaveFileReader::openFile() { - file.exceptions(std::ifstream::failbit | std::ifstream::badbit); - file.open(filePath, std::ios::binary); + try { + file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + file.open(filePath, std::ios::binary); + + // Error messages on stream exceptions are mostly useless. + // Read some dummy data so that we can throw a decent exception in case the file is missing, locked, etc. + file.seekg(0, std::ios_base::end); + if (file.tellg()) { + file.seekg(0); + file.get(); + file.seekg(0); + } + } catch (const std::ifstream::failure&) { + std::array message; + strerror_s(message.data(), message.size(), errno); + throw runtime_error(message.data()); + } } int WaveFileReader::getSampleRate() { diff --git a/src/main.cpp b/src/main.cpp index 3f77a77..35567cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,7 +42,7 @@ unique_ptr createAudioStream(path filePath) { try { return std::make_unique(filePath); } catch (...) { - std::throw_with_nested(std::runtime_error("Could not open sound file.") ); + std::throw_with_nested(std::runtime_error(fmt::format("Could not open sound file {0}.", filePath))); } } @@ -145,7 +145,7 @@ int main(int argc, char *argv[]) { return 0; } catch (const exception& e) { // Generic error - std::cerr << "An error occurred. " << getMessage(e) << std::endl; + std::cerr << "An error occurred.\n" << getMessage(e) << std::endl; return 1; } }