Quantcast
Channel: naudio Work Item Rss Feed
Viewing all articles
Browse latest Browse all 738

Created Unassigned: Incorrect handling of wave riff pad byte [16443]

$
0
0
Hi,

one of our customers sent to us a file (attached) which causes NAudio to crash (telling that no riff fmt chunk was found) we inspect the file and found it, but only after other riff chunks with odd length.

The problem lies in an incorrect handling of RIFF size if the size value is odd and not even.

Taken from Wikipedia:
All chunks have the following format:
* 4 bytes: an ASCII identifier for this chunk (examples are "fmt " and "data"; note the space in "fmt ").
* 4 bytes: an unsigned, little-endian 32-bit integer with the length of this chunk (except this field itself and the chunk identifier).
* variable-sized field: the chunk data itself, of the size given in the previous field.
* __a pad byte, if the chunk's length is not even.__

The bug explains also why sometime NAudio was unable to decode some riff chunks that other DAW software handles correctly.

The solution was to modify the WaveFileChunkReader.ReadWaveHeader(Stream stream) method, so when it encounters a odd length it will advance the stream by just one byte just after the stream.Position += chunkLength; line. Now it seems to work correctly.

Here's the modified method:
```
public void ReadWaveHeader(Stream stream)
{
this.dataChunkPosition = -1;
this.waveFormat = null;
this.riffChunks = new List<RiffChunk>();
this.dataChunkLength = 0;

BinaryReader br = new BinaryReader(stream);
ReadRiffHeader(br);
this.riffSize = br.ReadUInt32(); // read the file size (minus 8 bytes)

if (br.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE"))
{
throw new FormatException("Not a WAVE file - no WAVE header");
}

if (isRf64)
{
ReadDs64Chunk(br);
}

int dataChunkID = ChunkIdentifier.ChunkIdentifierToInt32("data");
int formatChunkId = ChunkIdentifier.ChunkIdentifierToInt32("fmt ");

// sometimes a file has more data than is specified after the RIFF header
long stopPosition = Math.Min(riffSize + 8, stream.Length);

// this -8 is so we can be sure that there are at least 8 bytes for a chunk id and length
while (stream.Position <= stopPosition - 8)
{
Int32 chunkIdentifier = br.ReadInt32();
Int32 chunkLength = br.ReadInt32();
if (chunkIdentifier == dataChunkID)
{
dataChunkPosition = stream.Position;
if (!isRf64) // we already know the dataChunkLength if this is an RF64 file
{
dataChunkLength = chunkLength;
}
stream.Position += chunkLength;
}
else if (chunkIdentifier == formatChunkId)
{
waveFormat = WaveFormat.FromFormatChunk(br, chunkLength);
}
else
{
// check for invalid chunk length
if (chunkLength < 0 || chunkLength > stream.Length - stream.Position)
{
if (strictMode)
{
Debug.Assert(false, String.Format("Invalid chunk length {0}, pos: {1}. length: {2}",
chunkLength, stream.Position, stream.Length));
}
// an exception will be thrown further down if we haven't got a format and data chunk yet,
// otherwise we will tolerate this file despite it having corrupt data at the end
break;
}
if (storeAllChunks)
{
riffChunks.Add(GetRiffChunk(stream, chunkIdentifier, chunkLength));
}
stream.Position += chunkLength;

// REVEL SOFTWARE - UG If the data length is odd we need to pad to word boundary. Data length does not count padding bytes.
// See https://forums.adobe.com/message/3798778 or http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/Docs/riffmci.pdf
if (chunkLength % 2 > 0)
stream.Position += 1;
}
}

if (waveFormat == null)
{
throw new FormatException("Invalid WAV file - No fmt chunk found");
}
if (dataChunkPosition == -1)
{
throw new FormatException("Invalid WAV file - No data chunk found");
}
}
```

Viewing all articles
Browse latest Browse all 738

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>