/// <summary>
        /// Gets the ID3v2 tag size from a specified stream.  Returns 0 if no tag exists.
        /// </summary>
        /// <param name="stream">The stream.</param>
        public static int GetTagSize(Stream stream)
        {
            try
            {
                if (stream.Length >= 16)
                {
                    stream.Position = 0;

                    byte[] identifier = stream.Read(3);

                    // 'ID3' identifier
                    if (!(identifier[0] == 0x49 && identifier[1] == 0x44 && identifier[2] == 0x33))
                    {
                        return 0;
                    }

                    IID3v2Header header = new ID3v2Header(stream, false);
                    int tagSize = header.TagSize;
                    if (tagSize != 0)
                        return tagSize + 10 + (header.IsFooterPresent ? 10 : 0);
                    else
                        return 0;
                }
                return 0;
            }
            finally
            {
                stream.Position = 0;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Gets the ID3v2 tag size from a specified stream.  Returns 0 if no tag exists.
        /// </summary>
        /// <param name="stream">The stream.</param>
        public static int GetTagSize(Stream stream)
        {
            try
            {
                if (stream.Length >= 16)
                {
                    stream.Position = 0;

                    byte[] identifier = stream.Read(3);

                    // 'ID3' identifier
                    if (!(identifier[0] == 0x49 && identifier[1] == 0x44 && identifier[2] == 0x33))
                    {
                        return(0);
                    }

                    IID3v2Header header  = new ID3v2Header(stream, false);
                    int          tagSize = header.TagSize;
                    if (tagSize != 0)
                    {
                        return(tagSize + 10 + (header.IsFooterPresent ? 10 : 0));
                    }
                    else
                    {
                        return(0);
                    }
                }
                return(0);
            }
            finally
            {
                stream.Position = 0;
            }
        }
Beispiel #3
0
 public static int GetTagSize(Stream stream)
 {
     if (stream.Length >= 0x10)
     {
         stream.Position = 0;
         byte[] buffer1 = Utils.Read(stream, 3);
         if (((buffer1[0] != 0x49) || (buffer1[1] != 0x44)) || (buffer1[2] != 0x33))
         {
             return 0;
         }
         IID3v2Header header1 = new ID3v2Header(stream, false);
         int num1 = header1.TagSize;
         if (num1 != 0)
         {
             return ((num1 + 10) + (header1.IsFooterPresent ? 10 : 0));
         }
     }
     return 0;
 }
Beispiel #4
0
 public static int GetTagSize(Stream stream)
 {
     if (stream.Length >= 0x10)
     {
         stream.Position = 0;
         byte[] buffer1 = Utils.Read(stream, 3);
         if (((buffer1[0] != 0x49) || (buffer1[1] != 0x44)) || (buffer1[2] != 0x33))
         {
             return(0);
         }
         IID3v2Header header1 = new ID3v2Header(stream, false);
         int          num1    = header1.TagSize;
         if (num1 != 0)
         {
             return((num1 + 10) + (header1.IsFooterPresent ? 10 : 0));
         }
     }
     return(0);
 }
Beispiel #5
0
        /// <summary>
        /// Reads the raw data from a specified stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        public void Read(Stream stream)
        {
            // Check for 'ID3' marker
            byte[] identifier = stream.Read(3);
            if (!(identifier[0] == 0x49 && identifier[1] == 0x44 && identifier[2] == 0x33))
            {
                return;
            }

            // Read the header
            _id3v2Header = new ID3v2Header(stream, false);

            TagReadingInfo tagReadingInfo = new TagReadingInfo(_id3v2Header.TagVersion);

            if (_id3v2Header.UsesUnsynchronization)
            {
                tagReadingInfo.TagVersionOptions = TagVersionOptions.Unsynchronized;
            }
            else
            {
                tagReadingInfo.TagVersionOptions = TagVersionOptions.None;
            }

            if (_id3v2Header.HasExtendedHeader)
            {
                _id3v2ExtendedHeader = new ID3v2ExtendedHeader(tagReadingInfo, stream);
            }

            int frameIDSize = (tagReadingInfo.TagVersion == ID3v2TagVersion.ID3v22 ? 3 : 4);
            int bytesRead;
            int readUntil;

            #region <<< ID3v2.4 - Guess if syncsafe frame size was used or not >>>

            if (_id3v2Header.TagVersion == ID3v2TagVersion.ID3v24)
            {
                bool isID3v24SyncSafe = true;

                bytesRead = 0;
                readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize;
                long initialPosition = stream.Position;
                while (bytesRead < readUntil)
                {
                    byte[] frameIDBytes = stream.Read(frameIDSize);

                    // TODO: Noticed some tags contain 0x00 'E' 'N' as a FrameID.  Frame is well structured
                    // and other frames follow.  I believe the below (keep reading+looking) will cover this issue.

                    // If character is not a letter or number, padding reached, audio began,
                    // or otherwise the frame is not readable
                    if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A ||
                        frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A ||
                        frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A ||
                        frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A)
                    {
                        // TODO: Try to keep reading and look for a valid frame
                        if (frameIDBytes[0] != 0 && frameIDBytes[0] != 0xFF)
                        {
                            /*String msg = String.Format("Out of range FrameID - 0x{0:X}|0x{1:X}|0x{2:X}|0x{3:X}",
                             *                         tmpFrameIDBytes[0], tmpFrameIDBytes[1], tmpFrameIDBytes[2],
                             *                         tmpFrameIDBytes[3]);
                             * Trace.WriteLine(msg);*/
                        }

                        break;
                    }

                    int frameSize = stream.ReadInt32();
                    if (frameSize > 0xFF)
                    {
                        if ((frameSize & 0x80) == 0x80)
                        {
                            isID3v24SyncSafe = false; break;
                        }
                        if ((frameSize & 0x8000) == 0x8000)
                        {
                            isID3v24SyncSafe = false; break;
                        }
                        if ((frameSize & 0x800000) == 0x800000)
                        {
                            isID3v24SyncSafe = false; break;
                        }

                        if (bytesRead + frameSize + 10 == _id3v2Header.TagSize)
                        {
                            // Could give a false positive, but relatively unlikely (famous last words, huh?)
                            isID3v24SyncSafe = false;
                            break;
                        }
                        else
                        {
                            stream.Seek(-4, SeekOrigin.Current); // go back to read sync-safe version
                            int syncSafeFrameSize = ID3v2Utils.ReadInt32SyncSafe(stream);

                            long currentPosition = stream.Position;

                            bool isValidAtSyncSafe    = true;
                            bool isValidAtNonSyncSafe = true;

                            // TODO - if it's the last frame and there is padding, both would indicate false
                            // Use the one that returns some padding bytes opposed to bytes with non-zero values (could be frame data)

                            // If non sync-safe reads past the end of the tag, then it's sync safe
                            // Testing non-sync safe since it will always be bigger than the sync safe integer
                            if (currentPosition + frameSize + 2 >= readUntil)
                            {
                                isID3v24SyncSafe = true; break;
                            }

                            // Test non-sync safe
                            stream.Seek(currentPosition + frameSize + 2, SeekOrigin.Begin);
                            frameIDBytes = stream.Read(frameIDSize);
                            if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A ||
                                frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A ||
                                frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A ||
                                frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A)
                            {
                                isValidAtNonSyncSafe = false;
                            }

                            // Test sync-safe
                            stream.Seek(currentPosition + syncSafeFrameSize + 2, SeekOrigin.Begin);
                            frameIDBytes = stream.Read(frameIDSize);
                            if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A ||
                                frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A ||
                                frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A ||
                                frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A)
                            {
                                isValidAtSyncSafe = false;
                            }

                            // if they're equal, we'll just have to go with syncsafe, since that's the spec

                            if (isValidAtNonSyncSafe != isValidAtSyncSafe)
                            {
                                isID3v24SyncSafe = isValidAtSyncSafe;
                            }
                            break;
                        }
                    }

                    stream.Seek(frameSize + 2, SeekOrigin.Current);
                    bytesRead += frameSize + 10;
                }

                stream.Position = initialPosition;
                if (isID3v24SyncSafe == false)
                {
                    tagReadingInfo.TagVersionOptions |= TagVersionOptions.UseNonSyncSafeFrameSizeID3v24;
                }
            }
            else if (_id3v2Header.TagVersion == ID3v2TagVersion.ID3v22)
            {
                bool isID3v22CorrectSize = true;

                bytesRead = 0;
                readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize;
                long initialPosition = stream.Position;

                stream.Read(frameIDSize);
                UnknownFrame unknownFrame = new UnknownFrame(null, tagReadingInfo, stream);
                bytesRead += unknownFrame.FrameHeader.FrameSizeTotal;
                if (bytesRead < readUntil)
                {
                    byte[] frameIDBytes = stream.Read(frameIDSize);

                    // TODO: Noticed some tags contain 0x00 'E' 'N' as a FrameID.  Frame is well structured
                    // and other frames follow.  I believe the below (keep reading+looking) will cover this issue.

                    // If character is not a letter or number, padding reached, audio began,
                    // or otherwise the frame is not readable
                    if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A)
                    {
                        if (frameIDBytes[1] >= 0x30 && frameIDBytes[1] <= 0x5A &&
                            frameIDBytes[2] >= 0x30 && frameIDBytes[2] <= 0x5A)
                        {
                            Trace.WriteLine("ID3v2.2 frame size off by 1 byte");
                            isID3v22CorrectSize = false;
                        }
                    }
                }

                stream.Position = initialPosition;
                if (isID3v22CorrectSize == false)
                {
                    tagReadingInfo.TagVersionOptions |= TagVersionOptions.AddOneByteToSize;
                }
            }

            #endregion <<< ID3v2.4 - Guess if syncsafe frame size was used or not >>>

            readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize;
            Read(stream, _id3v2Header.TagVersion, tagReadingInfo, readUntil, frameIDSize);
        }
Beispiel #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ID3v2Tag"/> class.
 /// </summary>
 public ID3v2Tag()
 {
     _id3v2Header         = new ID3v2Header();
     _id3v2ExtendedHeader = new ID3v2ExtendedHeader();
 }