forked from mia/Aegisub
Don't error on truncated wave files
This commit is contained in:
parent
59a680e6e1
commit
e75fc089d3
1 changed files with 16 additions and 25 deletions
|
@ -139,11 +139,10 @@ class RiffWavPCMAudioProvider : public PCMAudioProvider {
|
||||||
|
|
||||||
static bool CheckFourcc(const char (&str1)[4], const char (&str2)[5])
|
static bool CheckFourcc(const char (&str1)[4], const char (&str2)[5])
|
||||||
{
|
{
|
||||||
return
|
return str1[0] == str2[0]
|
||||||
(str1[0] == str2[0]) &&
|
&& str1[1] == str2[1]
|
||||||
(str1[1] == str2[1]) &&
|
&& str1[2] == str2[2]
|
||||||
(str1[2] == str2[2]) &&
|
&& str1[3] == str2[3];
|
||||||
(str1[3] == str2[3]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -160,12 +159,12 @@ public:
|
||||||
if (!CheckFourcc(header.format, "WAVE"))
|
if (!CheckFourcc(header.format, "WAVE"))
|
||||||
throw agi::AudioDataNotFoundError("File is not a RIFF WAV file", nullptr);
|
throw agi::AudioDataNotFoundError("File is not a RIFF WAV file", nullptr);
|
||||||
|
|
||||||
// Count how much more data we can have in the entire file
|
|
||||||
// The first 4 bytes are already eaten by the header.format field
|
|
||||||
uint32_t data_left = header.ch.size - 4;
|
|
||||||
// How far into the file we have processed.
|
// How far into the file we have processed.
|
||||||
// Must be incremented by the riff chunk size fields.
|
// Must be incremented by the riff chunk size fields.
|
||||||
uint32_t filepos = sizeof(header);
|
uint32_t filepos = sizeof(header);
|
||||||
|
// Count how much more data we can have in the entire file
|
||||||
|
// The first 4 bytes are already eaten by the header.format field
|
||||||
|
auto total_data = std::min<uint32_t>(header.ch.size - 4 + filepos, file->size());
|
||||||
|
|
||||||
bool got_fmt_header = false;
|
bool got_fmt_header = false;
|
||||||
|
|
||||||
|
@ -173,11 +172,8 @@ public:
|
||||||
num_samples = 0;
|
num_samples = 0;
|
||||||
|
|
||||||
// Continue reading chunks until out of data
|
// Continue reading chunks until out of data
|
||||||
while (data_left) {
|
while (filepos + sizeof(ChunkHeader) < total_data) {
|
||||||
auto const& ch = Read<ChunkHeader>(filepos);
|
auto const& ch = Read<ChunkHeader>(filepos);
|
||||||
|
|
||||||
// Update counters
|
|
||||||
data_left -= sizeof(ch);
|
|
||||||
filepos += sizeof(ch);
|
filepos += sizeof(ch);
|
||||||
|
|
||||||
if (CheckFourcc(ch.type, "fmt ")) {
|
if (CheckFourcc(ch.type, "fmt ")) {
|
||||||
|
@ -194,14 +190,13 @@ public:
|
||||||
channels = fmt.channels;
|
channels = fmt.channels;
|
||||||
bytes_per_sample = (fmt.significant_bits_sample + 7) / 8; // round up to nearest whole byte
|
bytes_per_sample = (fmt.significant_bits_sample + 7) / 8; // round up to nearest whole byte
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (CheckFourcc(ch.type, "data")) {
|
else if (CheckFourcc(ch.type, "data")) {
|
||||||
// This won't pick up 'data' chunks inside 'wavl' chunks
|
// This won't pick up 'data' chunks inside 'wavl' chunks
|
||||||
// since the 'wavl' chunks wrap those.
|
// since the 'wavl' chunks wrap those.
|
||||||
|
|
||||||
if (!got_fmt_header) throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", nullptr);
|
if (!got_fmt_header) throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", nullptr);
|
||||||
|
|
||||||
auto samples = ch.size / bytes_per_sample / channels;
|
auto samples = std::min(total_data - filepos, ch.size) / bytes_per_sample / channels;
|
||||||
index_points.push_back(IndexPoint{filepos, samples});
|
index_points.push_back(IndexPoint{filepos, samples});
|
||||||
num_samples += samples;
|
num_samples += samples;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +205,6 @@ public:
|
||||||
|
|
||||||
// Update counters
|
// Update counters
|
||||||
// Make sure they're word aligned
|
// Make sure they're word aligned
|
||||||
data_left -= (ch.size + 1) & ~1;
|
|
||||||
filepos += (ch.size + 1) & ~1;
|
filepos += (ch.size + 1) & ~1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,11 +291,11 @@ public:
|
||||||
if (!CheckGuid(header.format_guid, w64GuidWAVE))
|
if (!CheckGuid(header.format_guid, w64GuidWAVE))
|
||||||
throw agi::AudioDataNotFoundError("File is not a Wave64 WAVE file", nullptr);
|
throw agi::AudioDataNotFoundError("File is not a Wave64 WAVE file", nullptr);
|
||||||
|
|
||||||
// Count how much more data we can have in the entire file
|
|
||||||
uint64_t data_left = header.file_size - sizeof(RiffChunk);
|
|
||||||
// How far into the file we have processed.
|
// How far into the file we have processed.
|
||||||
// Must be incremented by the riff chunk size fields.
|
// Must be incremented by the riff chunk size fields.
|
||||||
uint64_t filepos = sizeof(header);
|
uint64_t filepos = sizeof(header);
|
||||||
|
// Count how much more data we can have in the entire file
|
||||||
|
auto total_data = std::min<uint64_t>(header.file_size, file->size());
|
||||||
|
|
||||||
bool got_fmt_header = false;
|
bool got_fmt_header = false;
|
||||||
|
|
||||||
|
@ -309,22 +303,20 @@ public:
|
||||||
num_samples = 0;
|
num_samples = 0;
|
||||||
|
|
||||||
// Continue reading chunks until out of data
|
// Continue reading chunks until out of data
|
||||||
while (data_left) {
|
while (filepos + 24 < total_data) {
|
||||||
uint8_t *chunk_guid = (uint8_t*)EnsureRangeAccessible(filepos, 16);
|
uint8_t *chunk_guid = (uint8_t*)EnsureRangeAccessible(filepos, 16);
|
||||||
auto chunk_size = Read<uint64_t>(filepos + 16);
|
auto chunk_size = std::min(total_data - filepos, Read<uint64_t>(filepos + 16)) - 24;
|
||||||
|
filepos += 24;
|
||||||
|
|
||||||
if (CheckGuid(chunk_guid, w64Guidfmt)) {
|
if (CheckGuid(chunk_guid, w64Guidfmt)) {
|
||||||
if (got_fmt_header)
|
if (got_fmt_header)
|
||||||
throw agi::AudioProviderOpenError("Bad file, found more than one 'fmt' chunk", nullptr);
|
throw agi::AudioProviderOpenError("Bad file, found more than one 'fmt' chunk", nullptr);
|
||||||
|
|
||||||
auto const& fmt = Read<FormatChunk>(filepos);
|
auto const& fmt = Read<FormatChunk>(filepos);
|
||||||
got_fmt_header = true;
|
|
||||||
|
|
||||||
if (fmt.format.wFormatTag == 3)
|
|
||||||
throw agi::AudioProviderOpenError("File is IEEE 32 bit float format which isn't supported. Bug the developers if this matters.", nullptr);
|
|
||||||
if (fmt.format.wFormatTag != 1)
|
if (fmt.format.wFormatTag != 1)
|
||||||
throw agi::AudioProviderOpenError("Can't use file, not PCM encoding", nullptr);
|
throw agi::AudioProviderOpenError("File is not uncompressed PCM", nullptr);
|
||||||
|
|
||||||
|
got_fmt_header = true;
|
||||||
// Set stuff inherited from the AudioProvider class
|
// Set stuff inherited from the AudioProvider class
|
||||||
sample_rate = fmt.format.nSamplesPerSec;
|
sample_rate = fmt.format.nSamplesPerSec;
|
||||||
channels = fmt.format.nChannels;
|
channels = fmt.format.nChannels;
|
||||||
|
@ -343,7 +335,6 @@ public:
|
||||||
|
|
||||||
// Update counters
|
// Update counters
|
||||||
// Make sure they're 64 bit aligned
|
// Make sure they're 64 bit aligned
|
||||||
data_left -= (chunk_size + 7) & ~7;
|
|
||||||
filepos += (chunk_size + 7) & ~7;
|
filepos += (chunk_size + 7) & ~7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue