1

Closed

IndexOutOfRangeException when getting Length of certain files

description

Hi, I am trying to use NLayer with my NAudio-backed app, however it's not handling certain files - refer to the attached file.

I'm getting:
System.IndexOutOfRangeException : Index was outside the bounds of the array.
   at NLayer.Decoder.LayerIIDecoderBase.GetCRC(MpegFrame frame, Int32[] rateTable, Int32[][] allocLookupTable, Boolean readScfsiBits, UInt32& crc) in LayerIIDecoderBase.cs: line 37
   at NLayer.Decoder.LayerIIDecoder.GetCRC(MpegFrame frame, ref UInt32 crc) in LayerIIDecoder.cs: line 15
   at NLayer.Decoder.MpegFrame.ValidateCRC() in MpegFrame.cs: line 212
   at NLayer.Decoder.MpegFrame.Validate() in MpegFrame.cs: line 130
   at NLayer.Decoder.FrameBase.Validate(Int64 offset, MpegStreamReader reader) in FrameBase.cs: line 27
   at NLayer.Decoder.MpegStreamReader.FindNextFrame() in MpegStreamReader.cs: line 111
   at NLayer.Decoder.MpegStreamReader.ReadToEnd() in MpegStreamReader.cs: line 572
   at NLayer.Decoder.MpegStreamReader.get_SampleCount() in MpegStreamReader.cs: line 600
   at NLayer.MpegFile.get_Length() in MpegFile.cs: line 52
   at NLayer.NAudioSupport.ManagedMpegStream.get_Length() in ManagedMpegStream.cs: line 72
   at MyApp.UnitTests.NLayerTest() in UnitTests.cs: line 88
The rateTable argument that gets passed has a capacity of 8 however this is not checked in the first loop where this exception occurs. Any hints in which direction I should be looking please?

file attachments

Closed Sep 11 at 10:17 PM by ioctlLR

comments

ioctlLR wrote Jun 9 at 4:27 PM

I won't be able to look at this very soon, but I immediately see the layer 2 decoder in use but a layer 3 file extension... Are we sure the file doesn't have a corrupted frame header, or something that is causing NLayer to get out of sync with the file?

ioctlLR wrote Jun 10 at 12:53 PM

Ah, I found it. In ID3Frame.cs, line 46: It is looking for ID3v2 tags to be version 2.3, while this file uses 2.4. I have a quick fix that'll make it work, but it's not at all "thought-through" so YMMV...
if (Read(3, buf) == 7)
{
    // v2.3
    if (buf[0] == 0x3)
    {
        byte flagsMask;
        switch (buf[0])
        {
            case 3:
                flagsMask = 0x1F;
                break;
            case 4:
                flagsMask = 0x0F;
                break;
            default:
                return -1;
        }

        // ignore the flags (we don't need them for the validation)

        // get the size (7 bits per byte [MSB cleared])
        var size = (buf[3] << 21)
                    | (buf[4] << 14)
                    | (buf[5] << 7)
                    | (buf[6]);

        // finally, check to make sure that all the right bits are cleared
        if (!(((buf[2] & flagsMask) | (buf[3] & 0x80) | (buf[4] & 0x80) | (buf[5] & 0x80) | (buf[6] & 0x80)) != 0 || buf[1] == 0xFF))
        {
            return size + 10;   // don't forget the sync, flag & size bytes!
        }
    }
    // v2.4
    else if (buf[0] == 0x4)
    {
        var size = (buf[3] << 21)
                    | (buf[4] << 14)
                    | (buf[5] << 7)
                    | (buf[6]);
        return size + 10;   // don't forget the sync, flag & size bytes!
    }
}

tomaskohl wrote Jun 11 at 4:00 AM

I can confirm this solved the issue - thanks!