Improved error handling and error messages

This commit is contained in:
Daniel Wolf 2016-04-12 18:02:52 +02:00
parent 04c828506d
commit 7bc4e37a1a
2 changed files with 40 additions and 6 deletions

View File

@ -1,6 +1,8 @@
#include <format.h> #include <format.h>
#include <string.h>
#include "WaveFileReader.h" #include "WaveFileReader.h"
#include "ioTools.h" #include "ioTools.h"
#include <array>
using std::runtime_error; using std::runtime_error;
using fmt::format; using fmt::format;
@ -31,7 +33,19 @@ WaveFileReader::WaveFileReader(boost::filesystem::path filePath) :
{ {
openFile(); 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 // Read header
if (!remaining(10)) {
throw runtime_error("WAVE file is corrupt. Header not found.");
}
uint32_t rootChunkId = read<uint32_t>(file); uint32_t rootChunkId = read<uint32_t>(file);
if (rootChunkId != fourcc('R', 'I', 'F', 'F')) { if (rootChunkId != fourcc('R', 'I', 'F', 'F')) {
throw runtime_error("Unknown file format. Only WAVE files are supported."); 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 // Read chunks until we reach the data chunk
bool reachedDataChunk = false; bool reachedDataChunk = false;
bytesPerSample = 0; bytesPerSample = 0;
do { while (!reachedDataChunk && remaining(8)) {
uint32_t chunkId = read<uint32_t>(file); uint32_t chunkId = read<uint32_t>(file);
int chunkSize = read<uint32_t>(file); int chunkSize = read<uint32_t>(file);
switch (chunkId) { switch (chunkId) {
@ -110,7 +124,12 @@ WaveFileReader::WaveFileReader(boost::filesystem::path filePath) :
break; break;
} }
} }
} while (!reachedDataChunk); }
if (!reachedDataChunk) {
dataOffset = file.tellg();
sampleCount = frameCount = 0;
}
} }
WaveFileReader::WaveFileReader(const WaveFileReader& rhs, bool reset) : WaveFileReader::WaveFileReader(const WaveFileReader& rhs, bool reset) :
@ -134,8 +153,23 @@ std::unique_ptr<AudioStream> WaveFileReader::clone(bool reset) {
} }
void WaveFileReader::openFile() { void WaveFileReader::openFile() {
try {
file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
file.open(filePath, std::ios::binary); 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<char, 256> message;
strerror_s(message.data(), message.size(), errno);
throw runtime_error(message.data());
}
} }
int WaveFileReader::getSampleRate() { int WaveFileReader::getSampleRate() {

View File

@ -42,7 +42,7 @@ unique_ptr<AudioStream> createAudioStream(path filePath) {
try { try {
return std::make_unique<WaveFileReader>(filePath); return std::make_unique<WaveFileReader>(filePath);
} catch (...) { } 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; return 0;
} catch (const exception& e) { } catch (const exception& e) {
// Generic error // Generic error
std::cerr << "An error occurred. " << getMessage(e) << std::endl; std::cerr << "An error occurred.\n" << getMessage(e) << std::endl;
return 1; return 1;
} }
} }