Example #1
0
        /// <summary>Initializes a new instance of the <see cref="ID3v2Header"/> class.</summary>
        /// <param name="version">The version.</param>
        /// <param name="revision">The revision.</param>
        /// <param name="flags">The flags.</param>
        /// <param name="size">The size.</param>
        /// <exception cref="NotSupportedException"></exception>
        public ID3v2Header(byte version, byte revision, ID3v2HeaderFlags flags, int size)
        {
            Version    = version;
            m_Revision = revision;
            Flags      = flags;
            m_BodySize = size;

            switch (Version)
            {
            case 2:
                Flags = (ID3v2HeaderFlags)((int)Flags & 0xC0);
                throw new NotImplementedException("Missing ID3v2.2 implementation.");

            case 3:
                Flags = (ID3v2HeaderFlags)((int)Flags & 0xE0);
                break;

            case 4:
                Flags = (ID3v2HeaderFlags)((int)Flags & 0xF0);
                break;

            default: throw new NotSupportedException(string.Format("ID3v2.{0} is not supported!", Version));
            }
            m_Data    = new byte[10];
            m_Data[0] = (byte)'I';
            m_Data[1] = (byte)'D';
            m_Data[2] = (byte)'3';
            m_Data[3] = Version;
            m_Data[4] = 0;
            m_Data[5] = (byte)((int)Flags & 0xF0);
            ID3v2EnUnsync.Int32(m_BodySize, m_Data, 6);
        }
Example #2
0
        private void ReadHeaderFlags()
        {
            _HeaderFlags = (ID3v2HeaderFlags)TStream.ReadByte(TStream.FS);

            if ((_HeaderFlags & ID3v2HeaderFlags.Experimental) == ID3v2HeaderFlags.Experimental)
            {
                _Errors.Add(new ID3Exception("This file contain Experimental ID3", ExceptionLevels.Warning));
            }
        }
Example #3
0
        /// <summary>
        /// Internally parses the current data and loads all fields.
        /// </summary>
        protected void ParseData()
        {
            if ((m_Data[0] != (byte)'3') || (m_Data[1] != (byte)'D') || (m_Data[2] != (byte)'I'))
            {
                throw new InvalidDataException(string.Format("Missing ID3 identifier!"));
            }

            m_Version  = m_Data[3];
            m_Revision = m_Data[4];
            m_Flags    = CheckFlags(m_Data[5]);
            m_BodySize = ID3v2DeUnsync.Int32(m_Data, 6);
        }
Example #4
0
        /// <summary>Retrieves the tag as byte array.</summary>
        /// <returns></returns>
        public byte[] ToArray()
        {
            var buffer             = new FifoBuffer();
            ID3v2HeaderFlags flags = ID3v2HeaderFlags.None;

            /* we do not like extended headers so we won't write them
             * if (m_ExtendedHeader != null)
             * {
             *  buffer.Enqueue(m_ExtendedHeader.Data);
             *  flags |= ID3v2HeaderFlags.ExtendedHeader;
             * }
             */
            foreach (ID3v2Frame frame in frames)
            {
                buffer.Enqueue(frame.RawData);
            }
            int bodySize = buffer.Length;

            // no one likes footers so we won't write them
            var header = new ID3v2Header(Header.Version, Header.Revision, flags, bodySize);

            buffer.Prepend(header.Data);
            return(buffer.ToArray());
        }
Example #5
0
        private static Dictionary <ID3Tag, object> ParseID3v2(byte[] data)
        {
            // TODO: add support for ID3v2.2.0 shorter frame IDs

            Dictionary <ID3Tag, object> tags = new Dictionary <ID3Tag, object>();

            if (data.Length < 21) // there must be at least one header (10 bytes) containing one frame (at least 10 byte header + 1 byte)
            {
                return(tags);
            }

            using (MemoryStream stream = new MemoryStream(data))
            {
                byte[] header = new byte[10];
                if (stream.Read(header, 0, header.Length) != header.Length)
                {
                    throw new MetaParseException("Unable to read full ID3v2 tag header");
                }
                if (header[0] != 'I' || header[1] != 'D' || header[2] != '3')
                {
                    return(tags);
                }

                byte   versionMajor = header[3];
                byte   versionMinor = header[4];
                string version      = $"ID3v2.{versionMajor}.{versionMinor}";
                if (versionMajor != 3 && versionMajor != 4)
                {
                    throw new NotImplementedException($"Only ID3v2.3.0 and ID3v2.4.0 are supported. Detected version: {version}");
                }
                tags[ID3Tag.Version] = version;

                ID3v2HeaderFlags flags = (ID3v2HeaderFlags)header[5];
                int size = BitConverter.ToInt32(header.Skip(6).Take(4).Reverse().ToArray(), 0);

                if (flags.HasFlag(ID3v2HeaderFlags.ExtendedHeader))
                {
                    byte[] extendedHeader = new byte[10];
                    if (stream.Read(extendedHeader, 0, extendedHeader.Length) != extendedHeader.Length)
                    {
                        throw new MetaParseException("Unable to read full ID3v2 extended header");
                    }

                    int extendedSize = BitConverter.ToInt32(extendedHeader.Take(4).Reverse().ToArray(), 0);
                    ID3v2ExtendedFlags extendedFlags = (ID3v2ExtendedFlags)((extendedHeader[4] << 8) | extendedHeader[5]);
                    int sizeOfPadding = BitConverter.ToInt32(extendedHeader.Skip(6).Take(4).Reverse().ToArray(), 0);

                    Trace.WriteLine($"[{tags[ID3Tag.Version]}] Ignoring extended header");
                    stream.Position += extendedSize;
                }

                while (stream.Position < size - 10)
                {
                    byte[] frameHeader = new byte[10];
                    if (stream.Read(frameHeader, 0, frameHeader.Length) != frameHeader.Length)
                    {
                        throw new MetaParseException("Unable to read full ID3v2 frame header");
                    }
                    string frameID = Encoding.ASCII.GetString(frameHeader, 0, 4);
                    if (frameID == "\0\0\0\0")
                    {
                        break; // TODO: done?
                    }
                    int             frameSize  = BitConverter.ToInt32(frameHeader.Skip(4).Take(4).Reverse().ToArray(), 0);
                    ID3v2FrameFlags frameFlags = (ID3v2FrameFlags)((frameHeader[8] << 8) | frameHeader[9]);

                    switch (frameID)
                    {
                    case "TALB":
                        tags[ID3Tag.Album] = ParseTextualFrame(stream, frameSize);
                        break;

                    case "TIT2":
                        tags[ID3Tag.Title] = ParseTextualFrame(stream, frameSize);
                        break;

                    case "TPE2":
                        tags[ID3Tag.Artist] = ParseTextualFrame(stream, frameSize);
                        break;

                    case "TYER":
                        tags[ID3Tag.Year] = Int32.Parse(ParseTextualFrame(stream, frameSize));
                        break;

                    case "TRCK":
                        string track = ParseTextualFrame(stream, frameSize);
                        if (track.Contains('/'))
                        {
                            tags[ID3Tag.Track] = Int32.Parse(track.Split('/')[0]);     // "<current>/<total>"
                        }
                        else
                        {
                            tags[ID3Tag.Track] = Int32.Parse(track);
                        }
                        break;

                    default:
                        Trace.WriteLine($"[{tags[ID3Tag.Version]}] Ignoring frame ID: \"{frameID}\"");
                        stream.Position += frameSize;
                        break;
                    }
                }
            }

            return(tags);
        }