/// <summary>
        /// Set the frame text
        /// </summary>
        /// <param name="frameId">Frame type</param>
        /// <param name="message">Value set in frame</param>
        private void SetTextFrame(string frameId, string message)
        {
            var frame = FindFrame(frameId);

            if (frame != null)
            {
                if (!String.IsNullOrEmpty(message))
                {
                    ((FrameText)frame).Text = message;
                }
                else
                {
                    _frameModel.Remove(frame);
                }
            }
            else
            {
                if (!String.IsNullOrEmpty(message))
                {
                    FrameText frameText = (FrameText)FrameFactory.Build(frameId);
                    frameText.Text     = message;
                    frameText.TextCode = _textCode;
                    _frameModel.Add(frameText);
                }
            }
        }
Exemple #2
0
        private TagModel GetFrameModel()
        {
            var frameModel = new TagModel();
            var frameText  = new FrameText("TIT2");

            frameText.TextCode = TextCode.Ascii;
            frameText.Text     = _song;
            frameModel.Add(frameText);

            frameText          = new FrameText("TPE1");
            frameText.TextCode = TextCode.Ascii;
            frameText.Text     = _artist;
            frameModel.Add(frameText);

            frameText          = new FrameText("TALB");
            frameText.TextCode = TextCode.Ascii;
            frameText.Text     = _album;
            frameModel.Add(frameText);

            frameText          = new FrameText("TYER");
            frameText.TextCode = TextCode.Ascii;
            frameText.Text     = _year;
            frameModel.Add(frameText);

            frameText          = new FrameText("TRCK");
            frameText.TextCode = TextCode.Ascii;
            frameText.Text     = _track.ToString(CultureInfo.InvariantCulture);
            frameModel.Add(frameText);

            var frameFullText = new FrameFullText("COMM");

            frameFullText.TextCode    = TextCode.Ascii;
            frameFullText.Language    = "eng";
            frameFullText.Description = "";
            frameFullText.Text        = _comment;
            frameModel.Add(frameFullText);

            if (_genre >= 0 && _genre < _genres.Length)
            {
                // from suggestion in http://sourceforge.net/tracker2/?func=detail&aid=920249&group_id=89188&atid=589317
                frameText          = new FrameText("TCON");
                frameText.TextCode = TextCode.Ascii;
                frameText.Text     = _genres[_genre];
                frameModel.Add(frameText);
            }

            //TODO: Fix this code!!!!!!!!
            frameModel.Header.TagSize        = 0; //TODO: Invalid size, not filled in until write
            frameModel.Header.Version        = 3; // ID3v2.[3].[0]
            frameModel.Header.Revision       = 0;
            frameModel.Header.Unsync         = false;
            frameModel.Header.Experimental   = false;
            frameModel.Header.Footer         = false;
            frameModel.Header.ExtendedHeader = false;

            return(frameModel);
        }
Exemple #3
0
        public static TagModel Deserialize([NotNull] Stream stream)
        {
            var frameModel = new TagModel();

            frameModel.Header.Deserialize(stream); // load the ID3v2 header
            if (frameModel.Header.Version != 3 & frameModel.Header.Version != 4)
            {
                throw new NotImplementedException("ID3v2 Version " + frameModel.Header.Version + " is not supported.");
            }

            var id3TagSize = frameModel.Header.TagSize;

            MemoryStream memory = null;

            try
            {
                if (frameModel.Header.Unsync)
                {
                    memory      = new MemoryStream();
                    id3TagSize -= Sync.Unsafe(stream, memory, id3TagSize);
                    stream      = memory; // This is now the stream
                    if (id3TagSize <= 0)
                    {
                        throw new InvalidTagException("Data is missing after the header.");
                    }
                }

                uint rawSize;
                // load the extended header
                if (frameModel.Header.ExtendedHeader)
                {
                    frameModel.ExtendedHeader.Deserialize(stream);
                    rawSize = id3TagSize - frameModel.ExtendedHeader.Size;
                    if (id3TagSize <= 0)
                    {
                        throw new InvalidTagException("Data is missing after the extended header.");
                    }
                }
                else
                {
                    rawSize = id3TagSize;
                }

                // Read the frames
                if (rawSize <= 0)
                {
                    throw new InvalidTagException("No frames are present in the Tag, there must be at least one present.");
                }

                // Load the tag frames
                uint index       = 0;
                var  frameHelper = new FrameHelper(frameModel.Header);
                // repeat while there is at least one complete frame available, 10 is the minimum size of a valid frame
                // but what happens when there's only, say, 5 bytes of padding?
                // we need to read a single byte to inspect for padding, then if not, read a whole tag.
                while (index < rawSize)
                {
                    var frameId = new byte[4];
                    stream.Read(frameId, 0, 1);
                    if (frameId[0] == 0)
                    {
                        // We reached the padding area between the frames and the end of the tag,
                        // signified by a zero byte where the frame name should be.

                        // we could double check we actually know what's going on
                        // and check the padding goes exactly to the end of the id3 tag
                        // but in fact it doesn't give us any benefit.
                        //
                        // one of the following cases must apply:
                        //
                        // 1) if the id3 tag specifies more bytes than the frames use up,
                        //    and that space is exactly filled with zeros to the first audio frame,
                        //    it complies with the standard and everything is happy.
                        //
                        // 2) if the id3 tag specifies more bytes than the frames use up,
                        //    and that space isn't completely filled with zeros,
                        //    we assume the software that generated the tag
                        //    forgot to zero-fill it properly.
                        //
                        // 3) if the zero padding extends past the start of the id3 tag,
                        //    we assume the audio payload starts with skippable stuff too.
                        //
                        // 4) if the audio payload doesn't start with a valid mpeg audio frame header,
                        //    (VBR headers have valid mpeg audio frame headers)
                        //    we assume there's a tag in a format we don't recognise.
                        //    It still has to comply with the mpeg sync rules,
                        //    so we will have to use that to find the start of the audio.
                        //
                        // in all cases, we read the specified length of the id3 tag
                        // and let the higher-level processing inspect the audio payload
                        // to decide what is audio, what is extra padding,
                        // and what is unrecognised (non-id3) tags.

                        // how much does the tag size say should be left?
                        frameModel.Header.PaddingSize = rawSize - index;

                        //// advance the stream past any zero bytes,
                        //// and verify the real measured size against that specified in the tag
                        //uint observed = SeekEndOfPadding(src) + 1;
                        //if( frameModel.Header.PaddingSize != observed )
                        //    throw new InvalidPaddingException(observed, frameModel.Header.PaddingSize);

                        // advance the stream to the specified end of the tag
                        // this skips any non-zero rubbish in the padding without looking at it.
                        stream.Seek(frameModel.Header.PaddingSize - 1, SeekOrigin.Current);

                        break;
                    }
                    if (index + 10 > rawSize)
                    {
                        // 10 is the minimum size of a valid frame;
                        // we read one already, if less than 9 chars left it's an error.
                        throw new InvalidTagException("Tag is corrupt, must be formed of complete frames.");
                    }
                    // read another 3 chars
                    stream.Read(frameId, 1, 3);
                    index += 4; // have read 4 bytes
                                //TODO: Validate key valid ranges
                    using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
                    {
                        var frameSize = Swap.UInt32(reader.ReadUInt32());
                        index += 4; // have read 4 bytes
                        // ID3v2.4 now has sync-safe sizes
                        if (frameModel.Header.Version == 4)
                        {
                            frameSize = Sync.Unsafe(frameSize);
                        }

                        // The size of the frame can't be larger than the available space
                        if (frameSize > rawSize - index)
                        {
                            throw new InvalidFrameException(
                                      "A frame is corrupt, it can't be larger than the available space remaining.");
                        }

                        var flags = Swap.UInt16(reader.ReadUInt16());
                        index += 2; // read 2 bytes
                        var frameData = new byte[frameSize];
                        reader.Read(frameData, 0, (int)frameSize);
                        index += frameSize; // read more bytes
                        frameModel.Add(frameHelper.Build(Encoding.UTF8.GetString(frameId, 0, 4), flags, frameData));
                    }
                }
                return(frameModel);
            }
            finally
            {
                memory?.Close();
            }
        }