private bool ReadFieldInstance(StreamBuffer sb, long maximumFieldSize)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            string identifier = sb.ReadString(FieldIdentifierLength);
            string strFieldSize = sb.ReadString(FieldSizeLength);

            int fieldSize;
            if (!Int32.TryParse(strFieldSize, out fieldSize))
            {
            #if DEBUG
                return false;//throw new InvalidDataException(String.Format("Size value for field {0} is not an int: {1}", identifier, strFieldSize));
            #else
                return false;
            #endif
            }
            Identifier = identifier;
            _data = new byte[fieldSize];
            sb.Read(_data, fieldSize);

            if (!IsValidData(_data))
                return false;

            Data = _data;
            return true;
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VbriHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        public VbriHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset)
            : base(firstFrame, firstFrameBuffer, offset, VbrHeaderType.Vbri)
        {
            /*
            FhG VBRI Header
            size    description
            4       'VBRI' (ID)
            2       version
            2       delay
            2       quality
            4       # bytes
            4       # frames
            2       table size (for TOC)
            2       table scale (for TOC)
            2       size of a table entry (max. size = 4 byte (must be stored in an integer))
            2       frames per table entry
            ??      dynamic table consisting out of frames with size 1-4 whole length in table size! (for TOC)
            */

            // name
            Name = firstFrameBuffer.ReadString(4);

            // version
            Version = (short)firstFrameBuffer.ReadBigEndianInt16();

            // delay
            _delay = firstFrameBuffer.ReadBigEndianInt16();

            // quality
            Quality = firstFrameBuffer.ReadBigEndianInt16();

            // size of the file, in bytes, of all the data
            FileSize = firstFrameBuffer.ReadBigEndianInt32();

            // amount of frames
            FrameCount = firstFrameBuffer.ReadBigEndianInt32();

            // number of entries in the table (for TOC)
            TableEntries = (short)firstFrameBuffer.ReadBigEndianInt16();

            // table scale (for TOC)
            TableScale = (short)firstFrameBuffer.ReadBigEndianInt16();

            // size of a table entry (in bytes)
            TableEntrySize = (short)firstFrameBuffer.ReadBigEndianInt16();

            // frames per table entry
            FramesPerTableEntry = (short)firstFrameBuffer.ReadBigEndianInt16();

            // dynamic table consisting out of frames
            TableLength = TableEntries * TableEntrySize;
            Toc = new int[TableEntries + 1];
            for (int i = 0; i <= TableEntries; i++)
            {
                int value = firstFrameBuffer.ReadBigEndianInt(TableEntrySize);
                Toc[i] = value * TableScale;
            }
            _totalLengthMilliseconds = firstFrame.AudioLength * FrameCount;
        }
        ////------------------------------------------------------------------------------------------------------------------------------
        private static Lyrics3v2Field ReadField(StreamBuffer sb, long maximumFieldSize)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            string identifier = sb.ReadString(FieldIdentifierLength, false, false);
            Lyrics3v2Field field = GetField(identifier);
            return field.ReadFieldInstance(sb, maximumFieldSize) ? field : null;
        }
예제 #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="XingHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        public XingHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset)
            : base(firstFrame, firstFrameBuffer, offset, VbrHeaderType.Xing)
        {
            /*
            XING VBR-Header
            size    description
            4       'Xing' or 'Info'
            4       flags (indicates which fields are used)
            4       frames (optional)
            4       bytes (optional)
            100     toc (optional)
            4       a VBR quality indicator: 0=best 100=worst (optional)
            --------- +
            120 bytes
            *
            * NOTE: the frames (frameCount) in the XING header does not include its own frame.
            * So the total frames is actually XING framecount + 1
            */

            // name of the tag as found in the file
            Name = firstFrameBuffer.ReadString(4);

            // The flags indicate which fields are used in the XING header
            Flags = firstFrameBuffer.ReadBigEndianInt32();

            // Extract total frames in the file (XING header excludes it's own frame)
            if ((Flags & XingHeaderFlags.FrameCountFlag) != 0)
                FrameCount = firstFrameBuffer.ReadBigEndianInt32();

            // Extract size of the file, in bytes
            if ((Flags & XingHeaderFlags.FileSizeFlag) != 0)
                FileSize = firstFrameBuffer.ReadBigEndianInt32();

            // Extract TOC (Table of Contents) for more accurate seeking
            if ((Flags & XingHeaderFlags.TocFlag) != 0)
            {
                Toc = new int[100];
                for (int i = 0; i < 100; i++)
                    Toc[i] = firstFrameBuffer.ReadByte();
            }

            if ((Flags & XingHeaderFlags.VbrScaleFlag) != 0)
                Quality = firstFrameBuffer.ReadBigEndianInt32();

            // The LAME tag is always 120 bytes after the XING header - regardless of which fields are used
            LameTag = LameTag.FindTag(firstFrameBuffer, offset + 120);
        }
예제 #5
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The VBRI header is located exactly 32 bytes after the end of the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="HeaderIndicator"/> 
        /// to see if the header contains a <see cref="VbriHeader"/> or not.
        /// </remarks>
        public static new VbriHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                // 32 bytes = data indicating silence
                const long Offset = MpaFrame.FrameHeaderSize + SilenceDataSize;
                buffer.Seek(Offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                return String.Compare(tagName, HeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0
                           ? new VbriHeader(firstFrame, buffer, Offset)
                           : null;
            }
        }
예제 #6
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The XING header is located after the side information in Layer III in the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="VbrHeaderIndicator"/> 
        /// to see if the header contains a <see cref="XingHeader"/> or not.
        /// </remarks>
        public static new XingHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            long offset = MpaFrame.FrameHeaderSize + firstFrame.SideInfoSize;
            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                buffer.Seek(offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                if ((String.Compare(tagName, VbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0)
                    || (String.Compare(tagName, CbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0))
                    return new XingHeader(firstFrame, buffer, offset);
            }
            return null;
        }
예제 #7
0
        private static string ReadTextField(StreamBuffer sb)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            int size = sb.ReadInt16();
            return sb.ReadString(size);
        }
예제 #8
0
        private static MusicMatchHeader ReadHeaderFooter(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition, IList<byte> identifierBytes, TagOrigin tagOrigin)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            stream.Position = startHeaderPosition;
            while (startHeaderPosition < endHeaderPosition)
            {
                int y = 0;
                while (stream.ReadByte() == identifierBytes[y++])
                {
                    startHeaderPosition++;
                    if (y != identifierBytes.Count)
                        continue;

                    if (tagOrigin == TagOrigin.Start)
                    {
                        MusicMatchHeader header = new MusicMatchHeader
                        {
                            Position = stream.Position - identifierBytes.Count,
                            Padding1 = new byte[2],
                            Padding2 = new byte[2],
                            Padding3 = new byte[2],
                            SpacePadding2 = new byte[226]
                        };

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding1, header.Padding1.Length);

                        // <8-byte numerical ASCII string>
                        header.XingEncoderVersion = stream.ReadString(8);

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding2, header.Padding2.Length);

                        // Xing encoder version <8-byte numerical ASCII string>
                        header.MusicMatchVersion = stream.ReadString(8);

                        // 0x00 0x00 Padding
                        stream.Read(header.Padding3, header.Padding3.Length);

                        // Space padding <226 * 0x20 >
                        stream.Read(header.SpacePadding2, header.SpacePadding2.Length);

                        ValidateHeader(header, null);
                        return header;
                    }

                    if (tagOrigin == TagOrigin.End)
                    {
                        MusicMatchHeader footer = new MusicMatchHeader
                        {
                            Position = stream.Position - identifierBytes.Count,
                            SpacePadding1 = new byte[13],
                            SpacePadding2 = new byte[12]
                        };

                        // Space padding <13 * 0x20>
                        stream.Read(footer.SpacePadding1, 13);

                        // version <4-byte numerical ASCII string> e.g. 3.05
                        footer.MusicMatchVersion = stream.ReadString(4);

                        // Space padding <12 * 0x20>
                        stream.Read(footer.SpacePadding2, 12);

                        ValidateHeader(null, footer);
                        return footer;
                    }
                }
                startHeaderPosition++;
            }
            return null;
        }
예제 #9
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private bool ReadStream(StreamBuffer sb)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            int length = sb.ReadInt32();
            Vendor = sb.ReadString(length);
            length = sb.ReadInt32();
            int commentsRead = 0;
            _comments.Clear();
            while ((commentsRead < length) && (sb.Position <= sb.Length))
            {
                _comments.Add(VorbisComment.ReadStream(sb));
                commentsRead++;
            }
            return true;
        }
예제 #10
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private static ApeItem ReadItem(ApeVersion version, StreamBuffer sb, long maximumItemSize)
        {
            if (sb == null)
                throw new ArgumentNullException("sb");

            // Find the item.
            long startPosition = sb.Position;
            long bytesToSkip = GetBytesUntilNextItem(version, sb, maximumItemSize);

            // Not found; return null.
            if (bytesToSkip == -1)
                return null;

            // Move the stream position to the start of the frame.
            sb.Position = startPosition + bytesToSkip;

            int valueSize = sb.ReadLittleEndianInt32();
            if ((valueSize <= 0) || (valueSize > ApeTag.MaxAllowedSize))
                return null;

            int flags = sb.ReadLittleEndianInt32();
            maximumItemSize -= 8;

            int itemKeyLengthBytes = 0;
            long maximumBytesToRead = maximumItemSize;
            if (maximumBytesToRead > 0)
            {
                for (int y = 0; y < maximumBytesToRead; y++)
                {
                    int character = sb.ReadByte();
                    if (character == 0x00) // 0x00 byte - string terminator.
                        break;

                    itemKeyLengthBytes++;
                }
            }

            // Name
            sb.Seek(-(itemKeyLengthBytes + 1), SeekOrigin.Current);
            string key = sb.ReadString(itemKeyLengthBytes, Encoding.UTF8);
            if ((key.Length < MinKeyLengthCharacters) || (itemKeyLengthBytes > MaxKeyLengthBytes))
                return null;

            // Skip Item key terminator (0x00 byte)
            int keyTerminator = sb.ReadByte();
            if (keyTerminator != 0x00)
                return null;

            ApeItem item = GetItem(version, key, flags);
            return item.ReadItem(version, valueSize, sb, maximumItemSize) ? item : null;
        }
예제 #11
0
 public void ReadStringTestLengthBytesAndEncoding()
 {
     const string Value = "This is a test. 日本語が含まれてます。";
     const string Expected = "This is a test. 日本語が含まれてます。";
     Encoding encoding = Encoding.UTF8;
     int lengthBytes = encoding.GetByteCount(Value);
     StreamBuffer target = new StreamBuffer(encoding.GetBytes(Value)) { Position = 0 };
     string actual = target.ReadString(lengthBytes, encoding);
     Assert.AreEqual(Expected, actual);
 }
예제 #12
0
 public void ReadStringTestLengthBytes()
 {
     const string Value = "This is a test.";
     const string Expected = "This is a test.";
     int lengthBytes = Encoding.ASCII.GetByteCount(Value);
     StreamBuffer target = new StreamBuffer(Encoding.ASCII.GetBytes(Value)) { Position = 0 };
     string actual = target.ReadString(lengthBytes);
     Assert.AreEqual(Expected, actual);
 }
예제 #13
0
 public void ReadStringTestEncodingAndCustomStringTerminatorAsString()
 {
     const string Value = "This is a test.||日本語が含まれてます。";
     const string Expected = "This is a test.";
     const string CustomStringTerminator = "||";
     Encoding encoding = Encoding.UTF8;
     StreamBuffer target = new StreamBuffer(encoding.GetBytes(Value)) { Position = 0 };
     string actual = target.ReadString(encoding, CustomStringTerminator);
     Assert.AreEqual(Expected, actual);
 }
예제 #14
0
        ////------------------------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// Finds a <see cref="LameTag"/> in the given stream.
        /// </summary>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        /// <returns>The <see cref="LameTag"/> when found; otherwise, null.</returns>
        public static LameTag FindTag(StreamBuffer firstFrameBuffer, long offset)
        {
            if (firstFrameBuffer == null)
                throw new ArgumentNullException("firstFrameBuffer");

            // If limiting the LAME string to 9 bytes "LAME X.YZu", the extension revision 0 could take 27 bytes and it would still fit a 64 kbit 48kHz frame.
            firstFrameBuffer.Seek(offset, SeekOrigin.Begin);
            string tagName = firstFrameBuffer.ReadString(4, false, false);
            return String.Compare(tagName, "LAME", StringComparison.OrdinalIgnoreCase) == 0 ? new LameTag(firstFrameBuffer) : null;
        }
예제 #15
0
        ////------------------------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="LameTag"/> class.
        /// </summary>
        /// <param name="firstFrameBuffer">The first frame buffer containing a <see cref="LameTag"/>.</param>
        public LameTag(StreamBuffer firstFrameBuffer)
        {
            // string lameTag = "LAME"
            firstFrameBuffer.ReadString(4);
            float ver;
            float.TryParse(firstFrameBuffer.ReadString(4), out ver);
            Version = ver;

            firstFrameBuffer.Seek(-8, SeekOrigin.Current);
            if (Version < 3.90f)
            {
                // Initial LAME info, 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)"
                // LAME prior to 3.90 writes only a 20 byte encoder string.
                EncoderVersion = firstFrameBuffer.ReadString(20);
            }
            else
            {
                EncoderVersion = firstFrameBuffer.ReadString(9);

                // Revision Information Tag + VBR Info
                int infoAndVbr = firstFrameBuffer.ReadByte();

                // Revision information in 4 MSB
                InfoTagRevision = infoAndVbr >> 4;
                if (InfoTagRevision == Formats.InfoTagRevision.Reserved)
                    throw new ArgumentException("InfoTagRevision bit is set to reserved (0xF)");

                // VBR info in 4 LSB
                VbrMethod = infoAndVbr & 0x0F;

                // lowpass information, multiply by 100 to get hz
                LowpassFilterValue = firstFrameBuffer.ReadByte() * 100;

                // Radio replay gain fields
                // Peak signal amplitude
                PeakSignalAmplitude = firstFrameBuffer.ReadFloat();

                // Radio Replay Gain
                RadioReplayGain = firstFrameBuffer.ReadInt16();

                // Audiophile Replay Gain
                AudiophileReplayGain = firstFrameBuffer.ReadInt16();

                // Encoding Flags + ATH type
                int encodingFlagsAndAthType = firstFrameBuffer.ReadByte();

                // Encoding Flags in 4 MSB
                EncodingFlags = encodingFlagsAndAthType >> 4;

                // LAME ATH Type in 4 LSB
                AthType = encodingFlagsAndAthType & 0x0F;

                // If ABR, this will be the specified bitrate
                // Otherwise (CBR/VBR), the minimal bitrate (255 means 255 or bigger)
                BitRate = firstFrameBuffer.ReadByte();

                // the 12 bit values (0-4095) of how many samples were added at start (encoder delay)
                // in X and how many 0-samples were padded at the end in Y to complete the last frame.
                EncoderDelays = firstFrameBuffer.ReadInt(3);
                EncoderDelaySamples = EncoderDelays & 0xFFF;
                EncoderDelayPaddingSamples = EncoderDelays >> 12;
                ////int numberSamplesInOriginalWav = frameCount

                Misc = firstFrameBuffer.ReadByte();

                // Any mp3 can be amplified by a factor 2 ^ ( x * 0.25) in a lossless manner by a tool like eg. mp3gain
                // if done so, this 8-bit field can be used to log such transformation happened so that any given time it can be undone.
                Mp3Gain = firstFrameBuffer.ReadByte();

                // Preset and surround info
                PresetSurroundInfo = firstFrameBuffer.ReadInt16();

                // 32 bit integer filed containing the exact length in bytes of the mp3 file originally made by LAME excluded ID3 tag info at the end.
                MusicLength = firstFrameBuffer.ReadBigEndianInt32();

                // Contains a CRC-16 of the complete mp3 music data as made originally by LAME.
                _musicCrc = (short)firstFrameBuffer.ReadBigEndianInt16();

                // contains a CRC-16 of the first 190 bytes (0x00 - 0xBD) of the Info header frame.
                // This field is calculated at the end, once all other fields are completed.
                _infoTagCrc = (short)firstFrameBuffer.ReadBigEndianInt16();
            }
        }