Bug 1406503 - P5. Do not ignore small flac packets. r=jwwang

A FLAC packet may have a size as small as 11 bytes. We should parse as much data as we can and not make assumptions on when to stop early.

MozReview-Commit-ID: 9skvwbt15MY

--HG--
extra : rebase_source : e428ba40fb71a4607af5d3be7f7d61ae98631522
This commit is contained in:
Jean-Yves Avenard 2017-10-28 11:11:45 +02:00
Родитель 241e778f48
Коммит 14413d23f3
1 изменённых файлов: 27 добавлений и 22 удалений

Просмотреть файл

@ -44,11 +44,9 @@ public:
// From https://xiph.org/flac/format.html#frame_header
// A valid header is one that can be decoded without error and that has a
// valid CRC.
// aPacket must points to a buffer that is at least FLAC_MAX_FRAME_HEADER_SIZE
// bytes.
bool Parse(const uint8_t* aPacket)
bool Parse(const uint8_t* aPacket, size_t aBytes)
{
mp4_demuxer::BitReader br(aPacket, FLAC_MAX_FRAME_HEADER_SIZE * 8);
mp4_demuxer::BitReader br(aPacket, aBytes * 8);
// Frame sync code.
if ((br.ReadBits(15) & 0x7fff) != 0x7ffc) {
@ -230,27 +228,32 @@ public:
// mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
// signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
// so we check for the whole signature.
// aData must be pointing to a buffer at least
// aLength + FLAC_MAX_FRAME_HEADER_SIZE bytes.
int64_t FindNext(const uint8_t* aData, const uint32_t aLength)
{
// The non-variable size of a FLAC header is 32 bits followed by variable
// size data and a 8 bits CRC.
// There's no need to read the last 4 bytes, it can never make a complete
// header.
if (aLength < 4) {
return -1;
}
uint32_t modOffset = aLength % 4;
uint32_t i, j;
for (i = 0; i < modOffset; i++) {
if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(aData + i)) {
if (mHeader.Parse(aData + i, aLength - i)) {
return i;
}
}
}
for (; i < aLength; i += 4) {
for (; i < aLength - 4; i += 4) {
uint32_t x = BigEndian::readUint32(aData + i);
if (((x & ~(x + 0x01010101)) & 0x80808080)) {
for (j = 0; j < 4; j++) {
if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(aData + i + j)) {
if (mHeader.Parse(aData + i + j, aLength - i - j)) {
return i + j;
}
}
@ -282,15 +285,7 @@ public:
return false;
}
if (read < FLAC_MAX_FRAME_HEADER_SIZE) {
// Assume that we can't have a valid frame in such small content, we
// must have reached EOS.
// So we're done.
mEOS = true;
return false;
}
const size_t bufSize = read + innerOffset - FLAC_MAX_FRAME_HEADER_SIZE;
const size_t bufSize = read + innerOffset;
int64_t foundOffset =
FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
@ -299,9 +294,19 @@ public:
return true;
}
if (read < BUFFER_SIZE) {
// Nothing more to try on as we had reached EOS during the previous
// read.
mEOS = true;
return false;
}
// Scan the next block;
offset += bufSize;
buffer.RemoveElementsAt(0, bufSize);
// We rewind a bit to re-try what could have been an incomplete packet.
// The maximum size of a FLAC header being FLAC_MAX_FRAME_HEADER_SIZE so
// we need to retry just after that amount.
offset += bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1);
buffer.RemoveElementsAt(0, bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1));
innerOffset = buffer.Length();
} while (offset - originalOffset < FLAC_MAX_FRAME_SIZE);
@ -1046,12 +1051,12 @@ FlacTrackDemuxer::TimeAtEnd()
/* static */ bool
FlacDemuxer::FlacSniffer(const uint8_t* aData, const uint32_t aLength)
{
if (aLength < FLAC_MAX_FRAME_HEADER_SIZE) {
if (aLength < FLAC_MIN_FRAME_SIZE) {
return false;
}
flac::Frame frame;
return frame.FindNext(aData, aLength - FLAC_MAX_FRAME_HEADER_SIZE) >= 0;
return frame.FindNext(aData, aLength) >= 0;
}
} // namespace mozilla